/* =========================================================
   Стили черновика новой главной (index_v1.php).

   Общие вещи — шапка, подвал, .card, .btn, .grid-3, .reveal, .pull,
   .ico, .progress — уже определены в assets/app.css и переопределяются
   здесь только там, где странице нужно что-то своё (например тёмный
   финальный блок вместо светлого .pull). Дублировать то, что уже есть
   в app.css, здесь не нужно.
   ========================================================= */

:root{
  /* тёмная EhoAI-палитра — только для «Как это работает» и модалки */
  --dbg:#0A1622; --dpanel:#101F30; --dpanel2:#16293D;
  --dink:#EAF2FA; --dmid:#A8BDD3; --dsoft:#728CA8;
  --dmint:#5FC6A3; --dblue:#5AA7F0;
}

body{position:relative}
/* Едва заметное зерно поверх страницы — снимает ощущение «плоской
   векторной картинки», на глаз не читается как узор. */
body::before{content:"";position:fixed;inset:0;z-index:90;pointer-events:none;opacity:.025;mix-blend-mode:overlay;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}

/* Якоря сквозь всю страницу не должны прятаться под фиксированной шапкой */
[id]{scroll-margin-top:calc(var(--header-h) + 14px)}

/* Прогресс-бар (сам элемент и его подключение к скроллу — из app.js/
   app.css); здесь только более живой градиент вместо ровного синего. */
.progress{background:linear-gradient(90deg,var(--blue),var(--mint))}

/* Кнопки: база уже в app.css, добавляем только стрелку-анимацию и
   тёмный вариант для контраста на .how-wrap/.pull. */
.btn svg{transition:transform .18s var(--ease)}
.btn:hover svg{transform:translateX(3px)}
.btn-dark{background:rgba(255,255,255,.1);border-color:rgba(255,255,255,.26);color:#fff}
.btn-dark:hover{background:rgba(255,255,255,.18)}

/* Карточки: добавляем только hover-подъём + 3D-наклон под курсор
   (сам наклон считает JS, здесь — плавность и происхождение). */
.card{transition:box-shadow .2s var(--ease),border-color .2s var(--ease),transform .18s var(--ease);will-change:transform}
.card:hover{box-shadow:var(--sh-2);border-color:var(--line-2)}
.mat-grid,.grid-3,.cases-grid{perspective:1200px}

/* =========================================================
   HERO — обычный блок в потоке, без пина и без «занавеса».

   Раньше hero держался на экране (position:sticky) на весь отрезок
   прокрутки, а «Моменты» наезжали сверху непрозрачной шторкой со
   скруглением и тенью (.stack-wrap/.stack-cover). Пока пин не
   заканчивался, прокрутка визуально не двигала почти ничего — человек
   листает, страница как будто не отвечает, и это читается как
   зависание, а не как приём. Теперь hero — обычный блок и уезжает
   вверх, как любой другой; следующая секция начинается сразу за ним.
   Отклик шара на прокрутку никуда не делся — он просто больше не
   удерживает сам скролл ради своей реплики (см. home_v1.js).
   ========================================================= */
.hero{padding:var(--s7) 0 var(--s9);background:radial-gradient(120% 90% at 82% 0%,var(--sky-2) 0%,var(--bg) 60%);overflow:hidden}
/* .hero-marquee (отступ и масштаб ленты) — см. блок «скролл-бегущая
   строка» ниже по файлу, рядом с самим компонентом. */
/* align-items:end пробовали как ответ на «пустоту снизу» — не подошло,
   стопка съезжала к кнопкам и читалась прижатой, а не собранной. Назад
   к center, но с колонкой шире (360px вместо 300) и стопкой крупнее
   (ниже) — то же «место позволяет», только через размер, а не через
   позицию: стопка не подгоняется под чужой нижний край, а сама
   становится достаточно весомой, чтобы не выглядеть потерянной. */
/* Раньше .hero-grid был из двух ячеек: текстовая колонка одним div
   (эйебров+h1+лид+чипы+поиск+кнопки все вместе) и .photo-stack второй.
   На мобильном грид схлопывался в 1 колонку, но порядок в DOM решал
   всё — стопка фото оказывалась в самом низу, после двух кнопок на всю
   ширину, оторванной от заголовка, который она должна поддерживать.
   Теперь каждая смысловая группа — отдельный прямой ребёнок .hero-grid
   с именованной областью: на десктопе картинка по-прежнему одной
   колонкой справа (span на все 4 строки), а на мобильном порядок
   строк можно задать заново, не трогая PHP-разметку — фото встаёт
   сразу после лида, до чипов и кнопок. */
/* Колонка расширена с 360 до 500, затем до 540px — телефон рядом со
   стопкой (см. .phone-mock ниже) вырос со 148 до 180px, старой ширины
   колонки на двоих уже не хватало. */
/* .hero-search-row — поиск и кнопка одной строкой НА ВСЮ ширину героя
   ("searchrow searchrow" — обе колонки), под intro+occ слева и photo
   справа, а не в колонке фото под телефоном/стопкой (был и такой заход
   — совпадение по высоте без общего flex-родителя, читалось как
   случайность, а не как ряд). Раз строка на всю ширину, текстовая
   колонка (intro/occ) и колонка фото обе стали короче на одну строку —
   photo, отцентрированный по высоте СВОЕЙ колонки (align-items:center),
   поднимается сам. */
/* minmax(0,1fr), а не голый 1fr — с обычным 1fr грид-трек не сжимается
   у́же min-content своего содержимого: список причин и разбор конкретной
   поломки (.hero-actions/.hero-occ, nowrap+overflow-x, min-width:auto
   по умолчанию) — там же, у самих правил ниже. */
.hero-grid{
  display:grid;grid-template-columns:minmax(0,1fr) 540px;column-gap:var(--s8);align-items:center;
  grid-template-areas:"intro photo" "occ photo" "searchrow searchrow";
}
@media(max-width:940px){
  .hero-grid{grid-template-columns:minmax(0,1fr);grid-template-areas:"intro" "photo" "occ" "searchrow"}
}
.hero-intro{grid-area:intro}
.hero-occ{grid-area:occ}
.hero-search-row{grid-area:searchrow;display:flex;align-items:center;justify-content:space-between;gap:var(--s4);margin:var(--s5) 0 0}
@media(max-width:640px){.hero-search-row{flex-direction:column;align-items:stretch}}
.hero-photo{grid-area:photo}

/* Раньше .eyebrow была голой строкой текста с точкой — на исходной
   главной (index.php, assets/home.css) это белая пилюля с рамкой и
   тенью, а точка пульсирует кольцом (@keyframes ping). Заголовок здесь
   уже проверялся на Unbounded — начертание вытянуло hero заметно
   тяжелее и крупнее, чем на исходной главной, где h1 остаётся на
   обычном Manrope (см. .hero h1 в assets/home.css), а акцентное слово
   выделено не цветом, а курсивной Literata (.hero h1 em там же). Тот
   же приём — ниже: и пилюля, и em, взяты дословно оттуда, а не
   выдуманы заново. */
.eyebrow{
  display:inline-flex;align-items:center;gap:var(--s3);height:32px;padding:0 var(--s4) 0 var(--s3);
  border-radius:9px;background:#fff;border:1px solid var(--line);
  font-size:13px;font-weight:600;color:var(--ink-mid);box-shadow:var(--sh-1);
}
/* height:32px рассчитан на одну строку — «Цифровой архив памяти ·
   Разработано в Татарстане» на узких телефонах (~375px и уже) не
   помещается в одну строку при этом кегле, переносится, и фикс-высота
   плюс скругление на 9px тогда режут вторую строку текста, а не
   аккуратно подрастают под неё. auto-высота с вертикальным padding —
   пилюля просто становится на пиксели выше, когда переносится, вместо
   того чтобы ломаться; чуть меньший кегль и зазор — попытка вообще не
   переноситься там, где место позволяет. */
@media(max-width:480px){
  .eyebrow{height:auto;min-height:32px;padding:6px var(--s4) 6px var(--s3);
    font-size:12px;gap:7px;line-height:1.3}
}
.eyebrow i{width:7px;height:7px;border-radius:50%;background:var(--blue);flex:none;position:relative}
.eyebrow i::after{content:"";position:absolute;inset:-4px;border-radius:50%;border:1px solid var(--blue);opacity:0;animation:ping 2.6s var(--ease) infinite}
@keyframes ping{0%{transform:scale(.6);opacity:.7}70%{transform:scale(1.5);opacity:0}100%{opacity:0}}
@media(prefers-reduced-motion:reduce){.eyebrow i::after{animation:none}}
.hero h1{max-width:15em;margin-top:var(--s6)}
.hero h1 em{font-family:Literata,Georgia,serif;font-style:italic;font-weight:300;color:var(--blue)}
.hero-lede{font-size:18.5px;color:var(--ink-mid);max-width:46ch;margin-top:var(--s4)}
.hero-occ{display:flex;flex-wrap:wrap;gap:8px;margin:var(--s5) 0 0}
.occ-chip{font-size:13px;padding:7px 13px;border-radius:999px;background:#fff;border:1px solid var(--line-2);color:var(--ink-mid);transition:border-color .18s,color .18s}
.occ-chip:hover{border-color:var(--blue);color:var(--blue-deep)}
.occ-chip-link{background:none;border-color:transparent;color:var(--blue);font-weight:600;padding-left:4px}
.occ-chip-link:hover{border-color:transparent;color:var(--blue-deep)}
/* На мобильном flex-wrap разворачивал 4-5 бейджиков в 2-3 строки —
   в узкой колонке дороже по высоте, чем по ширине. nowrap+overflow-x
   превращает тот же ряд в горизонтальный свайп, тем же приёмом, что и
   .hero-photo-row выше — один жест вместо трёх строк текста. */
@media(max-width:940px){
  /* min-width:0 — .hero-occ тут прямой grid-item (.hero-grid), у
     grid-элементов тот же default min-width:auto, что и у flex —
     без сброса ряд нескрываемых nowrap-чипов распирает грид-трек
     вширь и режется overflow:hidden у .hero выше по дереву (тот же
     класс бага, что чинили у .hero-actions). */
  .hero-occ{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;
    padding-bottom:2px;min-width:0}
  .hero-occ::-webkit-scrollbar{display:none}
  .hero-occ .occ-chip,.hero-occ .occ-chip-link{flex:0 0 auto;white-space:nowrap}
}

/* Раньше поле было прижато к ширине своей грид-колонки (588px на
   типичном 1440px экране) — с уходом второй кнопки из .hero-actions
   строка выросла на всю ширину блока (.hero-search-row, flex), и поле
   получило flex:1: текст запроса растягивается вместе со строкой, а не
   упирается в ту же старую ширину. Потолок остаётся — без него текст на
   широком мониторе разъезжается пустотой вокруг короткого запроса. */
.hero-ask{flex:1 1 auto;min-width:0;max-width:820px}
/* Переключатель способа переехал внутрь .ask-box (см. комментарий в
   index_v1.php) — был отдельной пилюлей-строкой над полем, две детали
   вместо одной. Теперь это два маленьких круглых значка у правого края
   поля, тем же приёмом, что переключатель месяц/год на tarify.php:
   активный — белый кружок с тенью на сером подложке, остальное едва
   заметно, пока не нажато. */
.ask-box{display:flex;align-items:center;gap:10px;background:#fff;border:1px solid var(--line-2);border-radius:var(--r-card);padding:9px 9px 9px 16px;box-shadow:var(--sh-1)}
.ask-box .ic{color:var(--blue);flex:none}
/* min-width:0 — без него flex-item с текстом по умолчанию отказывается
   сжиматься уже своего min-content (тот же класс бага, что у .hero-
   actions/.hero-occ, см. разбор в .hero-grid выше) и не даёт .ask-hit
   рядом места, раздвигая поле. overflow+ellipsis — сам текст при этом
   не обрубается молча, а красиво подрезается многоточием: то же
   поведение, что у .hs-line в оригинальной главной (index.php). */
.ask-line{flex:1;font-size:15px;min-height:20px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ask-mode{display:flex;gap:2px;background:var(--sky);border-radius:999px;padding:3px;flex:none}
.ask-mode button{border:0;background:none;display:flex;align-items:center;justify-content:center;
  width:30px;height:30px;border-radius:50%;cursor:pointer;color:var(--ink-soft);transition:background .18s,color .18s}
.ask-mode button svg{width:15px;height:15px}
.ask-mode button.on{background:#fff;color:var(--blue);box-shadow:var(--sh-1)}
.ask-caret{display:inline-block;width:1px;height:16px;background:var(--blue);margin-left:2px;animation:blink 1s step-end infinite;vertical-align:-3px}
@keyframes blink{50%{opacity:0}}
/* .ask-hit раньше стояла отдельной строкой ПОД полем — тянула .hero-ask
   на две строки высоты. В оригинальной главной (index.php, .hs-hit)
   тот же значок «нашлось» живёт ВНУТРИ строки поиска, flex:none-бейдж
   после текста — сюда перенесено дословно то же поведение (тот же
   мятный бейдж, тот же сдвиг по X, а не по Y — там нет вертикали для
   сдвига, это уже не отдельная строка). */
.ask-hit{display:inline-flex;align-items:center;gap:6px;flex:none;
  height:26px;padding:0 10px;border-radius:8px;background:var(--mint-pale);
  font-size:12.5px;font-weight:600;color:var(--mint);white-space:nowrap;
  opacity:0;transform:translateX(6px);transition:opacity .3s var(--ease),transform .3s var(--ease)}
.ask-hit.show{opacity:1;transform:none}
.ask-hit i{width:5px;height:5px;border-radius:50%;background:var(--mint);flex:none}
@media(prefers-reduced-motion:reduce){.ask-hit{transition:none}}
/* Тесно на планшетной ширине — полю поиска и так впритык между иконкой
   и переключателем режима, бейдж «нашлось» первым идёт за борт: тот
   же выбор, что в оригинальной главной (index.php, .hs-hit{display:
   none} на мобильном) — там прячется чуть раньше, у нас точка та же
   по духу, подобрана под ширину именно этого поля. */
@media(max-width:640px){.ask-hit{display:none}}

/* Кнопка теперь одна — свайп-полоса (nowrap+overflow-x), нужная под
   ДВЕ кнопки, что не помещались в ряд, здесь больше нечего прокручивать
   и незачем городить: одной кнопке хватает обычного переноса, а ниже
   400px её саму по себе тянет на всю ширину — то самое общее правило
   app.css, тут оно как раз уместно, отменять нечего. Отступ сверху
   теперь на обёртке .hero-search-row — сама кнопка в ней просто flex-
   ребёнок рядом с полем, второй такой же отступ ей не нужен. */
.hero-actions{display:flex;gap:12px;flex-wrap:wrap;flex:none}

/* ---- стопка полароидов, вместо шара ----

   Шар прошёл два круга правок (сперва невидимый из-за схлопнувшегося
   в 0 .orb-zone, потом видимый, но читавшийся мутным пятном — 3D-сфера
   держится на контрасте с тёмным фоном, а hero светлый) и оба раза
   упирался в один и тот же корень: абстрактная техническая картинка
   спорит со светлым, тёплым фоном о контрасте вместо того, чтобы
   просто показать то, ради чего архив существует, — лица. Стопка
   снимков ничего не рисует и ни с чем не борется за контраст.

   .photo-stack получает тот же явный width:100% (не auto), что раньше
   спас .orb-zone от той же ошибки: будучи грид-элементом с margin:0
   auto для центрирования, без явной ширины он схлопнется в 0 — авто-
   отступы в CSS Grid выключают растяжение по колонке. Разница на этот
   раз в том, что внутри есть настоящий контент (карточки в потоке), и
   без фикса эффект был бы «всё видно, но сплющено», а не «ничего не
   видно» — тем проще было бы просмотреть. */
/* Квадрат 1:1 держал стопку заметно короче текстовой колонки и
   выглядела мелкой рядом с настоящим объёмом заголовка. Портретные
   4:5 — то же соотношение, что у самих карточек внутри, — дают стопке
   больше вертикального присутствия. Плюс сама стопка крупнее (360px,
   колонка расширена выше вместе с ней): места хватало, просто им не
   пользовались. */
/* .hero-photo-row держит рядом два предмета — макет телефона и стопку
   фото. Раньше телефон был сдвинут под стопку отрицательным margin-left
   — казалось, что так он «выглядывает из-за» карточек, тем же приёмом,
   что и сами полароиды друг за другом. На деле отрицательный отступ во
   flex-строке не создаёт зазора между соседями — сдвигает только общий
   центр группы, — и повёрнутые (-10deg) уголки заднего полароида
   отчётливо заезжали на скруглённый угол телефона: не «стопка слегка
   перекрывает», а фото поверх экрана. Проверено и вживую (getBoundingClientRect
   двух прямоугольников), и на глаз на самой странице.

   Правильный способ дать предметам «стоять рядом, почти соприкасаясь»
   — настоящий gap между flex-элементами, а не отрицательный margin у
   одного из них. Здесь ровно тот зазор, при котором повёрнутые рамки
   уже не пересекаются ни при какой раскладке (посчитано по фактическим
   прямоугольникам, с запасом в несколько пикселей).

   .hero-photo — просто слот сетки (grid-area, ниже) и держатель
   подсказки под свайпом; сам ряд/свайп — .hero-photo-row внутри него
   (см. index_v1.php и разбор на мобильном ниже). */
.hero-photo{position:relative;width:100%;max-width:540px;margin:0 auto}
.hero-photo-row{position:relative;width:100%;
  display:flex;align-items:center;justify-content:center;gap:46px}
/* display:contents на десктопе — обёртка нужна только на мобильном
   (единица свайпа), на десктопе она не должна становиться лишним
   flex-элементом между .hero-photo-row и телефоном/стопкой: contents
   убирает у неё собственную коробку, gap и центрирование ряда работают
   так, будто телефон и стопка — прямые дети ряда, как до правки. */
.hero-photo-slide{display:contents}
.hero-photo-hint{display:none}

/* На мобильном раньше телефон и стопка просто сжимались тем же рядом —
   при ширине колонки ~320px оба предмета мельчали почти до одного
   размера (72px телефон против ~115px карточки — визуально «одна и та
   же фотография», а не телефон рядом с фото, хотя в жизни телефон
   заметно выше). Настоящая причина не в размерах самих по себе, а в
   том, что двум предметам приходилось делить одну полосу. Решение —
   не втискивать оба туда же чуть крупнее, а отдать каждому свой экран:
   .hero-photo-row становится горизонтальным свайпом (тот же scroll-snap,
   что у film-track), один предмет виден за раз — и именно поэтому
   каждый может позволить себе вырасти обратно к настоящим пропорциям
   (см. .phone-mock/.photo-stack ниже), а не остаться мелким «раз места
   всё равно нет». */
@media(max-width:940px){
  /* justify-content:center наследуется с десктопного правила выше — там
     он центрирует два предмета, которые вместе УЖЕ помещаются в ряд.
     Тут же каждый слайд — flex:0 0 100%, то есть вдвоём они вдвое шире
     контейнера; center у переполненного flex-ряда центрирует весь
     излишек СИММЕТРИЧНО, а не просто позволяет проскроллить от начала
     — первый слайд оказывается сдвинут в минус (за левый край) ещё до
     какого-либо скролла. flex-start возвращает нормальную точку
     старта, с которой начинается сам свайп. */
  /* overflow-y:hidden нужен, чтобы у свайпа не было вертикального
     скролла/скроллбара — но он же режет по живому: рамка телефона
     повёрнута (rotate(7deg) у .phone-mock) и у обоих предметов есть
     drop-shadow/box-shadow, выходящие за собственный layout-бокс —
     transform и filter не меняют РАЗМЕР бокса для целей overflow, они
     просто рисуют за его пределами, и ровно это рисование обрезалось
     по верхнему/нижнему краю ряда (тень «выглядела порезанной»).
     Отступ асимметричный, а не padding-block поровну — у тени
     drop-shadow(0 16px 30px) смещение вниз (16px) плюс блюр (30px), то
     есть вниз ей нужно куда больше запаса, чем вверх (там только блюр
     от поворота рамки, единицы пикселей). */
  .hero-photo-row{max-width:340px;margin:var(--s6) auto 0;gap:0;
    padding:18px 0 58px;justify-content:flex-start;
    overflow-x:auto;overflow-y:hidden;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;
    scrollbar-width:none}
  .hero-photo-row::-webkit-scrollbar{display:none}
  /* Тут, а не на самом .phone-mock/.photo-stack — flex-basis:100% на
     них напрямую перебивала бы их собственный width (132/250px, ниже)
     и растягивала предмет на всю ширину слайда вместо центрирования
     внутри него (см. разбор в index_v1.php). */
  .hero-photo-slide{display:flex;flex:0 0 100%;align-items:center;justify-content:center;scroll-snap-align:center}
  /* .hero-text-slide — тот же слайд, что у телефона/стопки, но внутри
     не узкий предмет для центрирования, а текстовая колонка на всю
     ширину: center/center тут дали бы h1 и лиду сжаться до content-
     width вместо нормального блочного заполнения и переноса строк,
     как было до свайпа. flex-start по обеим осям — тот же эффект, что
     обычный блочный поток. */
  .hero-text-slide{align-items:flex-start;justify-content:flex-start}
  .hero-text-slide .hero-intro{width:100%}
  .hero-photo-hint{display:block;text-align:center;margin-top:10px;font-size:12.5px;color:var(--ink-soft)}
}

.photo-stack{position:relative;width:100%;aspect-ratio:4/5;max-width:300px;flex:none;z-index:1}
/* max-width подрос со 186 до 250px — раньше это число было подобрано
   под «делим полосу с телефоном», сейчас у стопки весь свой экран (см.
   .hero-photo-row выше), можно вернуться ближе к десктопному размеру. */
@media(max-width:940px){.photo-stack{max-width:250px;margin:0 auto}}

/* ---- макет телефона рядом со стопкой ----
   Рамка целиком на CSS — не картинка, поэтому не тянет лишний файл и
   не мылится на ретине. Наклон (7deg) — тот же непринуждённый приём,
   что у .slot-1..4: ничего на этой странице не стоит по линейке.
   drop-shadow, а не box-shadow: у рамки скруглённые углы и составной
   силуэт (плюс боковые кнопки), border-box-тень легла бы прямоугольником
   под скруглением. */
/* 148px держал телефон УЖЕ карточки полароида (186px, 62% от стопки в
   300px) — реальный телефон в руке заметно ВЫШЕ полароидного снимка,
   но у этой пары ширина read важнее на глаз, чем высота: узкий 148px
   телефон рядом с широкой карточкой читался мельче своего соседа,
   даже будучи выше. 180px — телефон теперь заметно весомее в паре, не
   только по высоте. */
.phone-mock{position:relative;width:180px;aspect-ratio:9/19.5;flex:none;
  margin-top:64px;z-index:0;transform:rotate(7deg);
  filter:drop-shadow(0 16px 30px rgba(19,33,50,.22))}
/* 72px делал телефон визуально таким же по высоте, как карточка
   полароида (156px против её 155px) — в жизни это не так, телефон
   заметно выше. 132px (высота ~286px) держит настоящую разницу и
   всё ещё укладывается в свой отдельный экран свайпа. margin-top
   уменьшен с 24 до 8px — свой запас сверху телефону больше не нужен
   (тень и наклон теперь ловит padding самого .hero-photo-row, см.
   выше), а меньший отступ ещё и слегка приподнимает сам телефон. */
@media(max-width:940px){.phone-mock{width:132px;margin:8px auto 0}}
.phone-frame{position:absolute;inset:0;background:linear-gradient(160deg,#3a3f47,#14161b);
  border-radius:26px;padding:6px;box-shadow:inset 0 0 0 1.5px rgba(255,255,255,.10)}
.phone-side{position:absolute;width:3px;background:#0f1013;border-radius:2px}
.phone-side.vol1{left:-3px;top:26%;height:22px}
.phone-side.vol2{left:-3px;top:38%;height:32px}
.phone-side.power{right:-3px;top:30%;height:40px}
.phone-screen{position:relative;width:100%;height:100%;border-radius:19px;overflow:hidden;background:var(--sky)}
.phone-screen video{width:100%;height:100%;object-fit:cover;display:block}
.phone-island{position:absolute;top:7px;left:50%;transform:translateX(-50%);
  width:38%;height:16px;background:#0b0c0f;border-radius:10px;z-index:3}
/* Плейсхолдер, пока ни одного файла нет — та же логика, что у .ph-empty
   в стопке: не пустой серый прямоугольник, а узнаваемый жест «здесь
   будет видео». */
.phone-placeholder{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  background:radial-gradient(120% 90% at 30% 0%,var(--sky-2) 0%,var(--sky) 100%);color:var(--ink-soft)}

/* ---- лента роликов в телефоне — свайп в духе шортов ----
   Один слайд — один экран целиком; следующий стоит ровно на одну высоту
   ниже. Формула transform у всех слайдов одна и та же и зависит только
   от --i (номер слайда, прибит в разметке PHP — не меняется) и --active
   (текущий слайд, меняет только JS): переключение — это правка одного
   числа на контейнере, а не пересчёт transform у каждого слайда
   отдельно. Тот же трюк, что у .step-card.lit ниже по файлу — состояние
   в CSS-переменной, а не в перебираемых классах. */
.phone-reel{position:absolute;inset:0}
.phone-slide{position:absolute;inset:0;transition:transform .5s var(--ease);
  transform:translateY(calc((var(--i) - var(--active,0)) * 100%))}
.phone-slide-veil{position:absolute;inset:0;background:linear-gradient(180deg,transparent 58%,rgba(10,18,28,.62) 100%);pointer-events:none}
.phone-slide-cap{position:absolute;left:10px;right:10px;bottom:8px;color:#fff;font-size:10.5px;font-weight:600;
  letter-spacing:.01em;text-shadow:0 1px 3px rgba(0,0,0,.35)}
@media(prefers-reduced-motion:reduce){.phone-slide{transition:none}}

.polaroid{position:absolute;left:50%;top:50%;width:62%;background:#fff;padding:8px 8px 28px;
  border-radius:3px;box-shadow:0 10px 26px rgba(19,33,50,.16),0 2px 6px rgba(19,33,50,.07);
  transition:transform .5s var(--ease),opacity .3s var(--ease)}
.polaroid img,.ph-empty{display:block;width:100%;aspect-ratio:4/5;border-radius:1px;object-fit:cover}
.ph-empty{background:var(--tint,var(--sky));display:flex;align-items:center;justify-content:center;color:var(--ink-soft)}
.ph-empty svg{width:32%;height:32%}
.polaroid figcaption{font-family:Literata,Georgia,serif;font-style:italic;font-size:12.5px;
  color:var(--ink-mid);text-align:center;margin-top:8px;white-space:nowrap}

/* Четыре места в стопке — JS переставляет карточкам эти классы по
   кругу при каждом «шаффле», а не пересчитывает transform на лету:
   один набор чисел, подобранный на глаз один раз, вместо четырёх
   генерируемых. slot-4 — верхняя, самая крупная и ровная карточка. */
.slot-1{transform:translate(-50%,-50%) translate(-55px,-19px) rotate(-10deg);z-index:1;opacity:.85}
.slot-2{transform:translate(-50%,-50%) translate(38px,-34px) rotate(7deg);z-index:2;opacity:.9}
.slot-3{transform:translate(-50%,-50%) translate(-26px,31px) rotate(-4deg);z-index:3;opacity:.95}
.slot-4{transform:translate(-50%,-50%) translate(17px,17px) rotate(2deg);z-index:4;opacity:1}
@media(prefers-reduced-motion:reduce){.polaroid{transition:none}}

/* ---- скролл-бегущая строка ----
   Один компонент, два места: под hero (факты архива, включая RAG —
   прямым именем, а не «ИИ») и ниже по странице (бренд-строка). */
.marquee{overflow:hidden;padding:var(--s7) 0;background:var(--ink);border-radius:var(--r-block)}
@media(max-width:760px){.marquee{border-radius:var(--r-card)}}
.marquee-track{display:flex;align-items:center;white-space:nowrap;will-change:transform}
/* line-height:1 явно, а не унаследованный 1.65 у body: на кегле 52px
   это разница между строкой высотой ~52px и ~86px — при overflow:hidden
   у .marquee лишние 34px наследованного межстрочного интервала на самом
   крупном экране откусывали верх и низ букв. */
.marquee-track span{font-family:Unbounded,Manrope,sans-serif;font-size:clamp(28px,4.6vw,52px);line-height:1;font-weight:600;color:#fff;padding:0 .5em;display:inline-flex;align-items:center;gap:.5em}
.marquee-track span i{font-style:normal;color:var(--dmint);font-weight:500}
.marquee-track span b{font-style:normal;color:rgba(255,255,255,.32);font-weight:500}
.marquee-track span em{font-style:normal;color:var(--dmint)}
/* Лента под hero раньше держала отдельный, куда более мелкий кегль
   (13.5–16px) — свой аргумент был в том, чтобы не вставить второй hero
   внутри hero (тёмный блок с текстом почти в экран смартфона). После
   явного запроса вернуть тот же масштаб, что у бренд-строки ниже по
   странице — .marquee-track span здесь больше НЕ переопределяется,
   кегль наследуется как есть (clamp(28px,4.6vw,52px), см. правило
   выше). Внутренний padding остался меньше (--s4, а не --s7 у бренд-
   строки) — панель всё ещё тоньше, весь компромисс теперь только в
   высоте самой полосы, а не в размере букв. */
.hero-marquee{margin-top:var(--s8)}
.hero-marquee .marquee{padding:var(--s5) 0}

/* =========================================================
   НЕ ТОЛЬКО ОДИН ПОВОД — киноплёнка.

   Первый заход после отказа от закреплённой сцены — обычная
   .grid-3/.card сетка — оказался слишком плоским: шесть карточек
   «повод + заголовок + строка текста» без единой фотографии выглядели
   как список, а не как архив. Пользователь отдельно указал: нет места
   под фото/видео, нет ощущения «вау». При этом три подряд попытки
   оживить именно ЭТУ секцию нитью/жгутом/драконом/орбитой уже были
   отклонены — новый эффект должен появиться не как повтор той же
   ошибки, а как что-то, что прямо вытекает из формы контента: шесть
   моментов жизни — это шесть кадров, естественная метафора — киноплёнка.

   Тёмная панель (первые три захода) была повторным использованием
   палитры --dbg/--dpanel из «Как это работает» — но там тёмный фон
   держит на себе орб и текст, а здесь на нём стоял тёмно-серый планшет
   и тёмная лента: почти чёрное на почти чёрном, тот же класс проблемы,
   что уже ловили на орбе в hero («мутное пятно», см. историю правок
   выше по файлу) — только на этот раз с целым устройством. Планшет
   специально тёмный (это его настоящий цвет), но контраст ему нужен
   от подложки, не от себя самого.

   Теперь подложка светлая — не белая страница один-в-один, а мягкий
   «стол фотостудии»: радиальный свет сверху-слева, чуть холоднее
   (--sky/--sky-2, те же токены, что у .tp-visual и у секций #temy/
   #privacy — опять не новая палитра) в тени справа-снизу, плюс мягкая
   растушёванная тень под самими предметами (.film-scene::before) —
   вместо тёмной панели на странице появляется предметный столик, на
   котором лежит настоящая тёмная плёнка и стоит настоящий тёмный
   планшет. Оба физических объекта наконец видно.

   Перфорация сперва шла по всей ширине панели, сверху и снизу — и
   планшет, стоящий в той же строке, что и лента, тоже оказывался
   между этими двумя дырчатыми полосами. На глаз это читалось как
   «планшет стоит внутри фотоплёнки», а не «плёнка подаёт кадры в
   планшет» — спутывало ровно ту метафору, ради которой всё
   затевалось. Перфорация теперь целиком принадлежит .film-ribbon —
   только у самой ленты, планшет стоит рядом с ней на подложке,
   как отдельный настоящий предмет. Сама лента при этом стала
   непрозрачной (раньше rgba(0,0,0,.28) — полупрозрачный дым, который
   держался только на тёмной панели позади; на светлой подложке та же
   прозрачность превращала бы плёнку в серую дымку вместо чёрной
   ленты), а .film-flicker — единственное, что осталось поверх всей
   сцены целиком, не только тёмных предметов, — не мешает: у него
   mix-blend-mode:overlay, и белое зерно на светлой подложке этим
   блендом почти гасится само, заметно оно ровно там, где под ним
   тёмный планшет или тёмная лента — то есть именно там, где и должно
   мигать, как свет старого проектора.

   Лента едет через прямой драг мышью и колесо (см. home_v1.js) — без
   стрелок и точек под лентой: первая версия с ними получилась
   маленьким отдельным пультом управления, лишней деталью интерфейса
   рядом с самой лентой. Плёнку и так тянут руками, а не через кнопки
   — так и оставили: только курсор-«рука» подсказывает, что тянуть
   можно, плюс текстовая подсказка под лентой на первый раз.

   Приглушение неактивных кадров сначала было через opacity:.5 — на
   тёмной подложке это гасило не только карточку, но и цвет самой
   фотографии/заглушки почти до серого, а весь смысл своего цвета на
   каждый повод (--art-fg) в том и был, чтобы отличать кадры друг от
   друга с одного взгляда. Приглушаем меньше (.82) — активный кадр всё
   равно крупнее и чётче, но остальные не превращаются в серые плашки.

   Фото/видео сначала стояло маленьким блоком 4:5 НАД текстом — на
   живом скрине читалось как «фото отдельно, подпись отдельно», а не
   как одна карточка-постер. Теперь снимок — это фон всей карточки
   целиком (.film-bg на весь кадр), текст лежит поверх, на затемнении
   снизу (::after) — тот же приём, что у постера фильма: работает и на
   настоящем фото, и на пастельной заглушке-градиенте, потому что
   затемнение просто накладывается сверху независимо от того, что под
   ним.

   Четвёртый заход на сцену: планшет + плёнка сбоку, которая как бы
   «утекает» в экран. Пользователь отдельно уточнил, что раньше не
   получалась не сама механика закреплённой прокрутки (scrollY), а
   именно реализация (не то фото, «одинокий блоб» при доскролле,
   разъехавшийся дизайн) — поэтому здесь сознательно НЕ берём scrollY
   вообще: активная карточка синхронизируется с экраном планшета через
   уже проверенный драг/колесо по ленте (см. filmSetActive в
   home_v1.js), просто теперь у переключения есть второй адресат —
   .tablet-slide рядом с .film-frame. Никакого пина, никакой новой
   прокрутки — тот же самый безопасный механизм, что уже был.

   «Утекание» ленты в планшет — не анимация, а геометрия: .film-ribbon
   заходит отрицательным margin-left под правый край .tablet-mock (тот
   выше по z-index), и та же mask-image прячет этот заход в прозрачность
   — раньше в тёмный фон .film, теперь в собственную тень планшета на
   светлой подложке (.tablet-mock отбрасывает настоящий drop-shadow —
   тень и служит «укрытием» для шва). Кадры физически выезжают из-под
   планшета, а не просто стоят рядом на подрагивающем краю. См.
   подробный разбор версии кадров и самой ленты чуть ниже, у .film-ribbon.

   Но геометрия — это где кадр появляется, а не как он туда попадает.
   Смена кадра в планшете — обычный opacity-кроссфейд
   (.tablet-slide.is-active). Ровно на этом месте было три подряд
   захода на «полноценный полёт»: летящий клон DOM, который едет от
   ленты до экрана и обратно — сперва по кривой offset-path, потом
   через честный transform-FLIP, с отдельным canvas-следом и ещё одним
   слоем-рамкой сверху, чтобы клон не летел НАД корпусом планшета (см.
   историю их всех — раньше здесь были ссылки на .film-ghost/
   filmFlyTransition/.tablet-bezel-ring в home_v1.js/CSS, сейчас всё
   это убрано). Каждый заход чинил проблему предыдущего и тут же ловил
   свою: падает сверху, застревает непропорциональной коробкой,
   дублируется из-за родного доскролла браузера — а когда починили и
   это, пользователь отдельно посмотрел на результат и сказал прямо:
   кроссфейд и без летящего объекта уже выглядит корректно, глазам не
   нужен предмет, пересекающий сцену, достаточно лёгкого сигнала.
   Объект убрали целиком, кроссфейд остался единственным, кто меняет
   содержимое планшета — тем самым, что был с самого начала. Даже
   последний, самый лёгкий след (абстрактная искра на canvas между
   кадром и экраном) в итоге тоже убран — на глаз он читался как
   декоративная стрелка «отсюда туда», лишняя деталь, которую никто
   не просил (.film-transit больше нет ни в разметке, ни здесь). */
/* Едва заметная перфорация по всей подложке, не только у .film-ribbon —
   раньше дырочки принадлежали только самой ленте (осознанно, см. разбор
   выше — иначе планшет читался «внутри плёнки»), и панель вокруг была
   просто мягким градиентом без своего рисунка. Точки здесь в 4-5 раз
   бледнее ленточных (.06 против .24) и не собраны в строку по краю, а
   рассеяны сеткой по всей поверхности — не «ещё одна перфорация», а
   текстура самой бумаги/стола, на которой лежит настоящая плёнка:
   весь прямоугольник читается как один кусок фотоплёнки, а не лента
   отдельно и нейтральный фон отдельно рядом с ней. */
.film{position:relative;overflow:hidden;border-radius:var(--r-block);border:1px solid var(--line-2);
  padding:var(--s7) 0;box-shadow:var(--sh-1);
  background:
    radial-gradient(circle, rgba(19,33,50,.06) 1px, transparent 1.4px) 0 0/26px 26px,
    radial-gradient(70% 100% at 14% 0%, #fff 0%, transparent 60%),
    radial-gradient(80% 90% at 100% 100%, var(--sky-2) 0%, transparent 65%),
    linear-gradient(175deg,#fff,var(--sky))}
/* ---- пустая светлая полоса над планшетом и лентой ----
   .film-scene — один flex-ряд (планшет + лента), высоту ряда задаёт
   самый высокий элемент — планшет (~480px). Лента рядом с ним всего
   ~154px, выравнивание по центру честно оставляет по ~220px пустой
   подложки сверху И снизу от неё.

   Пробовали закрыть это content'ом: планшет с лентой прижаты к низу
   сцены, а освободившийся верх — крупная курсивная подпись активного
   повода (тот же приём, что у .case-card .q+blockquote и
   .pull blockquote — Literata, класс "q" для кавычки). Идея была не
   в декоре, а в переиспользовании уже существующего текста —
   .tablet-cap активного слайда, тот же короткий caption, что и так
   есть в $moments, просто крупнее и в другой роли.

   На плейсхолдерах читалось нормально, на реальном контенте — нет:
   тот же самый .cap одновременно был виден дважды в одном кадре —
   один раз гигантским курсивом сверху, второй раз мелким текстом на
   самом планшете, буквально одна и та же строка на двух масштабах.
   На коротких тестовых фразах это терялось, с настоящими подписями
   сразу читалось как ошибка вёрстки, а не как приём. Заголовок или
   текст момента туда же не годились по той же причине — они тоже уже
   есть на планшете. Единственный источник текста, который не дублирует
   уже видимое, — писать новую копию для каждого повода специально под
   эту подпись, а это отдельная задача с реальным контентом, не
   косметическая правка отступов. Откатили; пустая подложка по бокам
   осталась как есть — лучше честный воздух, чем содержимое, которое
   спорит само с собой. */
.film-scene{position:relative;display:flex;align-items:center;gap:0;padding:var(--s6) var(--s7)}
.film-scene::before{content:"";position:absolute;left:10%;right:6%;bottom:8%;height:26px;z-index:0;
  pointer-events:none;filter:blur(7px);
  background:radial-gradient(ellipse at center, rgba(19,33,50,.16), transparent 72%)}

/* ---- планшет: тот же CSS-макет, что у .phone-mock в hero, только
   крупнее, с честной металлической рамкой и стеклянным бликом на
   экране — на тёмной панели этих деталей было не разглядеть, на
   светлой подложке (см. .film выше) наконец есть контраст, чтобы их
   вообще было видно, так что доработали заодно. z-index выше ленты:
   правый край экрана перекрывает начало ленты, чтобы кадры буквально
   выезжали из-под планшета, а не стояли рядом через пустой промежуток
   (см. .film-ribbon ниже).

   Ориентация — альбомная (4/3), не портретная (3/4): ширина та же
   (min(360px,46vw) не трогали — весь расчёт нахлёста ленты завязан
   именно на ширину планшета, менять её значило бы пересчитывать и
   .film-ribbon), просто высота теперь меньше, не больше. Камера при
   повороте не остаётся наверху — она сидит на одной и той же грани
   корпуса что в портрете, что в альбоме, а эта грань при повороте на
   90° становится боковой, не верхней. Раньше top:8px;left:50% (камера
   на короткой стороне), теперь left:8px;top:50% (та же камера, та же
   грань корпуса — просто сам корпус развёрнут). */
.tablet-mock{position:relative;z-index:2;width:min(360px,46vw);aspect-ratio:4/3;flex:none;
  filter:drop-shadow(0 28px 46px rgba(19,33,50,.24)) drop-shadow(0 6px 14px rgba(19,33,50,.14))}
.tablet-frame{position:absolute;inset:0;
  background:linear-gradient(155deg,#5b6169 0%,#33373d 42%,#131519 100%);
  border-radius:26px;padding:9px;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.16),inset 0 1.5px 0 rgba(255,255,255,.3),inset 0 -1px 0 rgba(0,0,0,.4)}
/* left:8px раньше почти совпадал с началом экрана (bezel — те же
   9px, что .tablet-frame padding) — камера пятном в 5px шириной на
   4/5 залезала НА .tablet-screen, а не сидела в металле рамки, отсюда
   и читалась как случайная нашлёпка на стыке, а не как деталь корпуса.
   Теперь диаметр и позиция подобраны так, чтобы кружок целиком
   помещался внутри тех же 9px бортика: (9-6)/2=1.5px с каждой стороны. */
.tablet-cam{position:absolute;top:50%;left:1.5px;transform:translateY(-50%);
  width:6px;height:6px;border-radius:50%;
  background:radial-gradient(circle at 35% 30%, #4a5c82 0%, #0a0d14 65%, #000 100%);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.2),0 0 3px 1px rgba(0,0,0,.4);z-index:4}
.tablet-screen{position:relative;width:100%;height:100%;border-radius:17px;overflow:hidden;background:var(--dbg)}
.tablet-screen::before{content:"";position:absolute;inset:0;z-index:5;pointer-events:none;
  background:linear-gradient(122deg,rgba(255,255,255,.14) 0%,rgba(255,255,255,0) 24%,rgba(255,255,255,0) 76%,rgba(255,255,255,.04) 100%)}
.tablet-slide{--tint:color-mix(in srgb, var(--art-fg) 55%, white);
  position:absolute;inset:0;opacity:0;transition:opacity .5s var(--ease)}
.tablet-slide.is-active{opacity:1}
.tablet-bg{position:absolute;inset:0}
.tablet-media{width:100%;height:100%;object-fit:cover;display:block}
.tablet-ico{position:absolute;inset:0;display:grid;place-items:center;color:var(--tint)}
.tablet-ico svg{width:52px;height:52px}
/* Текстовый блок мерился под портретный экран 480px высотой — заголовки
   в $moments писались длинными, на запас вертикального места. Альбомный
   экран — 270px, почти вдвое короче, и тот же блок (h4 19px + p 14px +
   тег + подпись, с запасом отступов) реально вылезал ЗА верхний край
   экрана — не на глаз, а буквально: 302px текста на 252px экрана,
   проверено через getBoundingClientRect. Длинный абзац (<p>) отсюда
   убран целиком — та же мысль дальше по странице всё равно повторяется
   мельче, а не единственное место, где она есть. Заголовок обрезан
   через line-clamp до двух строк с многоточием — это единственный
   способ дать ГАРАНТИРОВАННЫЙ потолок высоты независимо от того, какой
   длины окажется конкретный title, а не подбирать размер шрифта под
   самый длинный текст из шести и портить короткие. */
.tablet-slide::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,transparent 15%,rgba(6,12,20,.65) 55%,rgba(6,12,20,.95) 100%)}
.tablet-info{position:absolute;left:0;right:0;bottom:0;z-index:2;padding:var(--s4)}
.tablet-tag{display:block;font-size:10.5px;font-weight:700;letter-spacing:.03em;text-transform:uppercase;color:var(--tint)}
.tablet-info h4{margin-top:4px;font-size:15px;line-height:1.25;color:#fff;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.tablet-info p{display:none}
.tablet-cap{display:block;margin-top:6px;font-size:11px;font-weight:600;color:rgba(255,255,255,.6)}
@media(prefers-reduced-motion:reduce){.tablet-slide{transition:none}}

/* ---- лента: настоящая полоска плёнки, а не ряд маленьких планшетов.
   Первая версия кадров (104px, скруглённые углы, тень) визуально
   повторяла грамматику самого .tablet-mock — те же пропорции скругления
   и та же тень — и на глаз читалась как «ряд мини-планшетов», а не как
   другой физический объект. Плюс лента стояла ПОСЛЕ планшета через
   обычный flex-gap: между ними была пустая полоса, и «утекание» в тень
   было не видно — ничего никуда не «заходило», две карточки просто
   стояли рядом.

   Теперь .film-ribbon — сама полоска: тёмная подложка + своя перфорация
   по верхнему и нижнему краю — только у ленты, не у всей панели (см.
   разбор выше, у сводного комментария блока — там же объяснение, почему
   перфорацию убрали с .film целиком). Раньше подложка была полупрозрачной
   (rgba(0,0,0,.28)) — держалась на тёмном фоне .film позади неё, вместе
   с ним и давала чёрный цвет. Фон стал светлым (см. .film выше) —
   та же полупрозрачность превратила бы ленту в серую дымку, а не в
   чёрную плёнку, так что подложка теперь непрозрачная, свой настоящий
   тёмный цвет, а не заёмный у фона позади. Кадры внутри — плоские,
   почти без скругления, без тени: они врезаны В полоску, а не лежат
   отдельными карточками НА ней. И главное: ribbon отрицательным
   margin-left заходит ПОД правый край .tablet-mock (у планшета z-index
   выше), а маска растягивается на всю эту зашедшую часть — первые кадры
   физически прячутся под планшетом и проявляются из-под его тени, а не
   просто бледнеют на пустом фоне рядом.

   Размер кадра: первая версия (104px) была не меньше самого планшета,
   а стилистически им притворялась — свой физический язык лента получила
   только вместе с этой переработкой. Вторая версия (60px) перегнула в
   обратную сторону — кадр съёжился до нечитаемой точки. Обе версии
   вдобавок были portrait (4:5, выше, чем шире) — а настоящий кадр
   35-мм плёнки 36×24мм, то есть 3:2, ШИРЕ, чем выше: длинная сторона
   идёт вдоль ленты, короткая — поперёк, по ширине самой плёнки. Портрет
   был перепутанной ориентацией, а не просто пропорцией на глаз — кадр
   теперь 150×100px (тот же множитель 3:2), заметно шире прежних 88px,
   но высота (100px) осталась близкой к прежней (110px) — лента не
   вырастает по вертикали, только правильно ложится по горизонтали.

   Лента больше не кончается после шестого кадра — DOM трижды повторяет
   шесть кнопок (18 штук, см. index_v1.php), и filmWrapCheck в home_v1.js
   бесшовно подменяет scrollLeft на ширину одного комплекта, как только
   лента подъезжает к его краю: кадры одинаковые, подмена происходит
   ровно там, где они и так повторяются, — на глаз лента крутится
   бесконечно в обе стороны, хотя в DOM их всего 18. */
.film-ribbon{position:relative;z-index:1;flex:1 1 auto;min-width:0;
  margin-left:-158px;padding:6px 0 6px 170px;border-radius:9px;
  background:linear-gradient(180deg,#1c2430,#11151c);
  -webkit-mask-image:linear-gradient(90deg,transparent,transparent 158px,#000 210px);
  mask-image:linear-gradient(90deg,transparent,transparent 158px,#000 210px)}
.film-ribbon::before,.film-ribbon::after{content:"";position:absolute;left:0;right:0;height:7px;
  pointer-events:none;background-image:radial-gradient(circle,rgba(255,255,255,.24) 0 1.5px,transparent 1.5px);
  background-size:15px 100%;background-repeat:repeat-x;background-position:7.5px center}
.film-ribbon::before{top:0}
.film-ribbon::after{bottom:0}
.film-track{position:relative;display:flex;gap:8px;overflow-x:auto;scroll-snap-type:x proximity;
  padding:16px 18px;scrollbar-width:none;-ms-overflow-style:none;
  cursor:grab;-webkit-user-select:none;user-select:none}
.film-track::-webkit-scrollbar{display:none}
.film-track.is-dragging{cursor:grabbing;scroll-snap-type:none}
.film-track.is-auto-scrolling{scroll-snap-type:none}
/* Кадр ленты и активный слайд планшета одно время показывали одну и ту
   же фотографию один в один. Четыре подряд попытки чинили не ту
   проблему: цветная тонировка (невидима на синем фото), негатив
   (заметно другой кадр, но пользователь прямо сказал — не так), пустой
   кадр с цветной рамкой, и та же рамка вместе с автопрокруткой (мимо —
   рамка от «этой» фотографии не нужна вообще). Всё это чинило
   ОФОРМЛЕНИЕ активного кадра, но кадр оставался ВИДИМЫМ в ленте — а
   настоящая причина дубля в другом: filmUpdateActive (home_v1.js)
   выбирал «активным» кадр, стоящий у НАЧАЛА видимой части ленты, то
   есть уже вышедший из-под тени планшета почти полностью — он и не
   мог не быть на виду одновременно с планшетом, оформление тут ни при
   чём. Настоящий кадр 150px шире, чем был прежний заход планшета под
   ленту (70px, см. .film-ribbon ниже) — учетверение не хватало, чтобы
   спрятать кадр целиком. Заход теперь ровно один шаг ленты (150+8px
   зазор = 158px), и filmUpdateActive считает активным именно тот
   кадр, что сейчас целиком встал в эту зону — он физически скрыт под
   планшетом, а первый кадр, который видно в ленте, это уже следующее
   фото. Отдельного оформления активного кадра по-прежнему нет — весь
   смысл в геометрии захода, не в метке на кадре. */
.film-frame{--tint:color-mix(in srgb, var(--art-fg) 55%, white);
  position:relative;flex:0 0 auto;width:150px;aspect-ratio:3/2;scroll-snap-align:start;
  border:none;padding:0;margin:0;font:inherit;cursor:pointer;background:none;
  border-radius:4px;overflow:hidden;
  opacity:.7;transform:scale(.96);transition:opacity .35s var(--ease),transform .35s var(--ease)}
.film-frame.is-active{opacity:1;transform:scale(1)}
.film-bg{position:absolute;inset:0}
.film-media{width:100%;height:100%;object-fit:cover;display:block;-webkit-user-drag:none}
.film-ico{position:absolute;inset:0;display:grid;place-items:center;color:var(--tint)}
.film-ico svg{width:16px;height:16px}
.film-flicker{position:absolute;inset:0;pointer-events:none;mix-blend-mode:overlay;opacity:.9;z-index:2}
@media(prefers-reduced-motion:reduce){.film-frame{transition:none}}

/* ---- след при смене кадра ----
   Тут стояли четыре подряд захода на «фото заметно перемещается в
   планшет»: клон DOM (.film-ghost, filmFlyTransition, .tablet-bezel-
   ring), потом canvas-искра — растущий градиентный штрих со
   shadowBlur-свечением между кадром и экраном (.film-transit). Первые
   три чинили проблему предыдущего и ловили свою (падает сверху,
   застревает коробкой, дублируется). Четвёртый (искра) формально был
   «абстрактным, без предмета», но на практике всё равно читался как
   стрелка-указатель от ленты к планшету — лишняя деталь, которую не
   просили. Кроссфейда планшета (.tablet-slide.is-active, обычный
   opacity) достаточно как сигнала смены — весь блок и canvas убраны
   целиком, .film-transit в разметке (index_v1.php) больше нет. */

.film-hint{margin-top:var(--s3);text-align:center;font-size:12.5px;color:var(--ink-soft)}
.film-hint-mobile{display:none}
@media(max-width:760px){
  /* Второй заход на мобильную раскладку. Первый (лента листается по
     вертикали и заходит в планшет снизу) технически работал, но на
     маленьком экране это были два предмета ради одного действия —
     смена повода жестом по ленте ИЛИ по планшету, не пойми что
     главное. Решение проще, чем повторный трюк с геометрией: ленты на
     мобильном просто нет (.film-ribbon скрыт), остаётся один предмет —
     планшет, крупнее, сам меняет содержимое (автопрокрутка) или
     листается свайпом по экрану (см. filmMobileMode в home_v1.js). */
  .film-scene{padding:var(--s5) var(--s5) var(--s6);justify-content:center}
  .film-scene::before{display:none}
  .film-ribbon{display:none}
  /* touch-action:pan-y — без него браузер сам решает, что делать с
     горизонтальным движением пальца по планшету, и любая вертикальная
     примесь в жесте (почти неизбежная у живой руки) отдаёт жест под
     нативный скролл страницы вместо нашего touchend-свайпа (разбор в
     home_v1.js, рядом с обработчиком). pan-y явно оставляет вертикаль
     странице, горизонталь — нам. */
  .tablet-mock{width:min(340px,78vw);touch-action:pan-y}
  .film-hint-desktop{display:none}
  .film-hint-mobile{display:block}
}

/* ---- бесплатное семейное древо ----
   Раньше рост дерева считался от обычного, непинованного блока: у
   такой секции слишком мало собственной высоты, чтобы прокрутка через
   неё вообще ощущалась, и рост завершался ещё до того, как читатель
   успевал заметить начало — «параллакс идёт с конца». Теперь у блока
   есть своя закреплённая сцена (как у «Моментов»): прокрутка через
   .tree-pin даёт дереву честный, растянутый на весь экран отрезок
   скролла — 0 у самого начала, 1 у конца, без исключений. */
.tree-pin{position:relative}
/* top: var(--header-h) впритык — пока сцена держится (position:sticky),
   верх карточки идёт вровень с нижним краем шапки, без просвета между
   ними: две светлые панели одна над другой читаются слипшимися в одну,
   а не шапкой над отдельным блоком. Отступ возвращает шов. */
.tree-pin-inner{position:sticky;top:calc(var(--header-h) + var(--s5));min-height:600px;display:flex;align-items:center}
@media(max-width:760px){.tree-pin{height:auto!important}.tree-pin-inner{position:static;min-height:0}}

.tree-promo{background:linear-gradient(120deg,var(--blue-pale) 0%,#fff 46%);border:1px solid var(--line);border-radius:var(--r-block);padding:var(--s9) var(--s8);display:grid;grid-template-columns:1fr 1.15fr;gap:var(--s9);align-items:center;position:relative;overflow:hidden;width:100%;box-shadow:var(--sh-2)}
@media(max-width:900px){.tree-promo{grid-template-columns:1fr;padding:var(--s7) var(--s5)}}
.tree-promo .tag-free{display:inline-flex;height:28px;align-items:center;padding:0 14px;border-radius:8px;background:var(--mint);color:#fff;font-size:12.5px;font-weight:700;letter-spacing:.03em;text-transform:uppercase;margin-bottom:var(--s4)}
.tree-promo h2{max-width:16ch}
.tree-promo p{color:var(--ink-mid);margin-top:var(--s3);max-width:44ch}
.tree-promo .tp-list{margin-top:var(--s5);display:flex;flex-direction:column;gap:8px}
.tree-promo .tp-list li{font-size:14.5px;color:var(--ink-mid);display:flex;gap:8px;align-items:flex-start}
.tree-promo .tp-list svg{flex:none;margin-top:3px;color:var(--mint)}
.tree-promo .tp-actions{display:flex;gap:12px;flex-wrap:wrap;margin-top:var(--s6)}
/* ОКНО В ПРОДУКТ, А НЕ ИЛЛЮСТРАЦИЯ ПРО НЕГО.
   .tp-device — пустой контейнер (см. index_v1.php): всё, что в нём
   видно — заголовок, ярусы, имена, нить, фон, — рисует сам
   ehoai/assets/tree.js через EhoTree.mount() (см. assets/home_v1.js),
   тот же код, что и настоящее полноэкранное дерево. Задача этого
   правила — только форма и место под него в светлой карточке
   страницы, тем же приёмом, что у тёмного экрана в .phone-mock внутри
   hero чуть выше: страница остаётся светлой, а окно честно показывает
   тёмный продукт внутри рамки. Фон здесь — просто заглушка на случай,
   если JS ещё не успел домонтировать .sky (у него свой, из
   ehoai/assets/tree.css, — он и останется виден, .sky сверху непро-
   зрачен), не приближение настоящего цвета. */
.tp-visual{position:relative}
.tp-device{
  position:relative;aspect-ratio:1/1;border-radius:var(--r-card);overflow:hidden;
  background:#050b12;
  box-shadow:0 30px 70px -38px rgba(5,11,18,.55),inset 0 0 0 1px rgba(255,255,255,.07);
}
.tp-count{margin-top:var(--s4);text-align:center;font-size:12.5px;color:var(--ink-soft)}
/* Портретная панель на телефоне — тот же выбор, что у настоящего
   полноэкранного дерева на узком экране: род читается ярусами сверху
   вниз, и высоте там место нужнее, чем ширине. Внутри panel EhoTree сам
   вписывает дерево через свой this.fit — искажения нет ни при каком
   соотношении сторон. */
@media(max-width:760px){.tp-device{aspect-ratio:4/5}}

/* ---- как это работает (тёмная панель, палитра EhoAI) ---- */
/* overflow:hidden убран: он не подрезал ничего лишнего (фон и так не
   вылезает за border-radius), а вот sticky у шара (.story-orb-wrap)
   ломал напрочь — контейнер с overflow≠visible становится для sticky
   своим скролл-контекстом вместо окна, а сам он не прокручивается, и
   шар просто переставал куда-либо липнуть. */
.how-wrap{background:var(--dbg);color:var(--dink);border-radius:28px;padding:var(--s9) var(--s8);position:relative}
@media(max-width:760px){.how-wrap{padding:var(--s8) var(--s5);border-radius:var(--r-block)}}
.how-wrap .label{color:#7ec7ff}
.how-wrap .sec-head p{color:var(--dmid)}
/* align-items:center сажал шар точно посередине всей высоты ряда — а
   ряд считается по левой колонке (шаги + примечание про ИИ + четыре
   пункта закона + кнопка), которая заметно выше шара. Получалось: шар
   у верхней трети текста, а ниже — пустой тёмный участок панели на всю
   оставшуюся высоту, никак не заполненный. align-items:start плюс
   sticky у самого шара (см. .story-orb-wrap) держат его в поле зрения,
   пока читают весь левый столбец, вместо одной case точки по центру. */
.how-grid{display:grid;grid-template-columns:1fr 300px;gap:var(--s8);align-items:start}
@media(max-width:900px){.how-grid{grid-template-columns:1fr}.story-orb-wrap{position:static;max-width:220px;margin:0 auto}}
.how-steps{display:flex;flex-direction:column;gap:14px;margin-top:var(--s6)}
.how-step{display:flex;gap:14px;padding:16px 18px;border-radius:14px;background:var(--dpanel);border:1px solid rgba(255,255,255,.07)}
.how-n{flex:none;width:26px;height:26px;border-radius:50%;background:rgba(95,198,163,.16);color:var(--dmint);font-size:12.5px;font-weight:700;display:flex;align-items:center;justify-content:center}
.how-step b{display:block;color:var(--dink);font-size:15px}
.how-step p{margin:3px 0 0;color:var(--dmid);font-size:14px}
.ai-note{margin-top:var(--s6);padding-top:var(--s5);border-top:1px solid rgba(255,255,255,.1);font-size:14px;color:var(--dsoft)}
.ai-note b{color:var(--dink)}

/* Нулевой закон, коротко — четыре пункта в ряд внутри тёмной панели.
   Не карточки с рамкой (это уже панель внутри панели, лишний слой), а
   плотный список с номером — тот же приём, что у .parts на index.php,
   только суше и без подписи-абзаца под каждым: здесь она не нужна,
   абзац уже сказан в ai-note выше. */
.ans-parts{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-top:var(--s5)}
@media(max-width:640px){.ans-parts{grid-template-columns:1fr 1fr}}
.ans-part{display:flex;flex-direction:column;gap:2px}
.ans-n{font-family:Unbounded,Manrope,sans-serif;font-size:11px;color:var(--dmint);letter-spacing:.04em}
.ans-part b{font-size:14px;color:var(--dink)}
.ans-part span{font-size:12.5px;color:var(--dsoft);line-height:1.35}
.ans-cap{margin-top:var(--s4);font-size:12.5px;color:var(--dsoft)}
.ans-cap a{color:var(--dblue)}
.story-orb-wrap{position:sticky;top:calc(var(--header-h) + var(--s6));aspect-ratio:1/1;border-radius:50%;overflow:hidden}
.story-orb-wrap canvas{width:100%;height:100%}
.how-cta{margin-top:var(--s6)}

/* ---- сцена «Как это работает» ----
   Полноэкранный слой (.sky/.sky-c/.sky-top/.sky-x/.sky-tools/.sky-b)
   подключается настоящим файлом ehoai/assets/tree.css ($pageCssMore) —
   он самодостаточен и переменные объявляет на себе (см. комментарий в
   самом tree.css), поэтому не спорит с токенами этой страницы. Здесь —
   только специфичные для рассказа .story-* правила, перенесённые
   дословно из ehoai/assets/ehoai.css (var(--mint) заменён на локальный
   --dmint с тем же значением #5FC6A3, чтобы не тащить весь :root тёмной
   темы ehoai на светлую страницу). Саму сцену создаёт и показывает
   ehoai/assets/echo.js (window.EhoStory) — настоящий, не копия. */
.story-cap{position:absolute;left:26px;right:26px;bottom:96px;max-width:58ch;pointer-events:none}
.story-t{display:block;font-family:Literata,Georgia,serif;font-size:13px;letter-spacing:.10em;text-transform:uppercase;color:var(--dmint);margin-bottom:8px}
.story-p{font-family:Literata,Georgia,serif;font-size:19px;line-height:1.5;color:rgba(232,243,253,.92)}
.story-dots{position:absolute;left:26px;bottom:66px;display:flex;gap:7px;pointer-events:none}
.story-dots i{width:6px;height:6px;border-radius:50%;background:rgba(140,185,232,.22);transition:background .3s,transform .3s}
.story-dots i.was{background:rgba(95,214,176,.42)}
.story-dots i.now{background:var(--dmint);transform:scale(1.5)}
.story-orb{position:absolute;left:42%;top:50%;width:210px;height:210px;margin:-105px 0 0 -105px;pointer-events:none}
.story-orb canvas{width:100%;height:100%;display:block}
@media(max-width:760px){
  .story-cap{left:14px;right:14px;bottom:104px}
  .story-p{font-size:16px}
  .story-dots{left:14px;bottom:74px}
  .story-orb{left:46%;top:42%;width:150px;height:150px;margin:-75px 0 0 -75px}
}
@media(min-width:761px) and (max-height:820px){
  .story-orb{width:170px;height:170px;margin:-85px 0 0 -85px}
  .story-cap{bottom:82px;max-width:52ch}
  .story-p{font-size:17px}
  .story-dots{bottom:56px}
}
@media(min-width:561px) and (max-width:1024px) and (min-height:821px){
  .story-orb{width:230px;height:230px;margin:-115px 0 0 -115px}
  .story-cap{bottom:110px}
  .story-p{font-size:20px}
}
@media(max-width:560px){
  .story-orb{left:50%;top:36%;width:132px;height:132px;margin:-66px 0 0 -66px}
  .story-cap{left:12px;right:12px;bottom:96px}
  .story-t{font-size:12px}
  .story-p{font-size:15.5px;line-height:1.45}
  .story-dots{left:12px;bottom:68px}
  .story-dots i{width:5px;height:5px}
}

/* ---- материалы ----
   Были обычные .card — значок, заголовок, строка текста, все шесть
   одного и того же синего цвета: список фич из корпоративного сайта,
   а не оглавление архива. У каждого пункта уже был свой смысл (видео,
   звук, фото...) — не хватало только своего цвета, чтобы это было
   видно с одного взгляда, тем же приёмом, что уже есть у $moments в
   «Не только один повод» (color-mix от --art-fg на плашку значка).
   Номер в углу (01–06) — не декоративная деталь, а то же самое, что
   .film-num у плёнки: лёгкий намёк «это опись, а не случайный набор
   карточек».

   Раньше появление карточек вело .reveal — бинарный переключатель
   (вошла в кадр — сразу opacity:1, class .in), одинаковый для всей
   страницы. Здесь вместо него — updateMatParallax() в home_v1.js,
   тот же по духу приём, что уже проверен у updateSteps() («Порядок
   работы»): не пороговое появление, а плавная величина от позиции
   карточки в вьюпорте, пересчитываемая на каждый скролл. .reveal с
   карточек снят совсем — оба механизма одновременно писали бы в
   одни и те же opacity/transform и спорили бы друг с другом. */
.mat-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--gap)}
@media(max-width:760px){.mat-grid{grid-template-columns:1fr 1fr}}
@media(max-width:480px){.mat-grid{grid-template-columns:1fr}}
.mat-card{position:relative;will-change:transform,opacity}
.mat-card .ico{background:color-mix(in srgb, var(--art-fg) 14%, white);color:var(--art-fg)}
.mat-num{position:absolute;top:var(--s5);right:var(--s6);font-size:12px;font-weight:700;letter-spacing:.02em;color:color-mix(in srgb, var(--art-fg) 55%, var(--ink-soft))}
@media(prefers-reduced-motion:reduce){.mat-card{opacity:1!important;transform:none!important}}

/* ---- с чем приходят ---- */
.cases-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--gap)}
@media(max-width:900px){.cases-grid{grid-template-columns:1fr}}
.case-card{background:var(--sky);border-radius:var(--r-card);padding:var(--s6);display:flex;flex-direction:column;transition:transform .18s var(--ease),box-shadow .18s var(--ease);will-change:transform}
.case-card:hover{box-shadow:var(--sh-2)}
.case-card .q{font-family:Literata,Georgia,serif;font-style:italic;font-size:36px;line-height:1;color:var(--blue);opacity:.5;margin-bottom:var(--s2)}
.case-card blockquote{margin:0;font-size:15.5px;color:var(--ink);line-height:1.55}
.case-card cite{display:block;margin-top:var(--s4);font-style:normal}
.case-card cite b{display:block;font-size:14px;font-weight:600;color:var(--ink)}
.case-card cite span{display:block;font-size:12.5px;color:var(--ink-soft);margin-top:2px}

/* ---- методика (табы) ---- */
.tabs{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:var(--s5)}
.tab-b{padding:9px 16px;border-radius:999px;border:1px solid var(--line-2);background:#fff;font:inherit;font-size:14px;cursor:pointer;color:var(--ink-mid)}
.tab-b.on{background:var(--ink);color:#fff;border-color:var(--ink)}
/* 2 колонки на 3 вопроса (у каждой темы их ровно три, см. THEMES в
   home_v1.js) всегда оставляли одну пустую клетку в правом нижнем углу —
   ту самую «непонятную пустоту». Колонок теперь ровно три: столько же,
   сколько вопросов, — ни одна клетка не остаётся без пары. */
/* li был того же цвета (--sky), что и сама секция под ним (см.
   style="background:var(--sky)" у #temy в index_v1.php) — карточки
   вопросов не отделялись от подложки вообще, только чуть более тёмным
   текстом. Белый фон + едва заметная тень возвращают им форму
   карточки поверх цветного блока, а не сливаются с ним. */
.tab-qs{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
@media(max-width:900px){.tab-qs{grid-template-columns:1fr}}
.tab-qs li{padding:14px 16px;border-radius:12px;background:#fff;box-shadow:var(--sh-1);font-size:14.5px;color:var(--ink-mid)}

/* ---- кому это уже помогает ----
   Тот же приём, что у .mat-card выше: шесть карточек, у каждой был один
   и тот же мятный тег и один и тот же синий значок — на глаз ряд не
   читался как шесть разных аудиторий, только как шесть одинаковых
   карточек с разным текстом. Свой цвет на тег и значок (--art-fg,
   тот же color-mix, что у материалов и у $moments) возвращает то, что
   теряется в общем .card/.tag: «взрослым детям» и «музеям» — не одно
   и то же по интонации, и теперь это видно до чтения текста. */
.who-card{--tint:color-mix(in srgb, var(--art-fg) 14%, white)}
.who-card .ico{background:var(--tint);color:var(--art-fg)}
.who-card .tag{margin-bottom:var(--s3);display:inline-flex;height:26px;align-items:center;padding:0 12px;border-radius:8px;background:var(--tint);color:var(--art-fg);font-size:12.5px;font-weight:700;text-transform:uppercase}
.who-card h4{margin-bottom:6px}

/* ---- приватность и границы (объединённая сетка) ----
   Раньше появлялись через .reveal — все шесть пунктов одинаково
   всплывали при входе секции в кадр, ✓ и × не отличались по темпу.
   Теперь пункты «загораются» по одному при прокрутке — тот же самый
   механизм (позиция секции относительно вьюпорта → прогресс 0..1 →
   класс .lit при достижении своего порога), что уже отвечает за
   подсветку номеров в «Порядке работы» (.step-card.lit, updateSteps()
   в home_v1.js), только применённый не к номеру-кружку, а ко всей
   карточке: до включения — блёкло и обесцвечено (мы ещё не «дошли»
   до этого правила на глаз), после — обычный чёткий цвет. Читается
   как чек-лист, который заполняют по ходу чтения, а не как ещё один
   грид карточек, вошедший в кадр всем скопом. */
.priv-item{padding:18px;border-radius:12px;background:#fff;border:1px solid var(--line);font-size:14px;
  opacity:.35;filter:grayscale(.65);transform:translateY(10px);
  transition:opacity .4s var(--ease),filter .4s var(--ease),transform .4s var(--ease)}
.priv-item.lit{opacity:1;filter:none;transform:none}
.priv-item.no{background:var(--clay-pale)}
.priv-item b{display:block;margin-bottom:4px;font-size:14.5px}
.priv-item .mark{display:block;margin-bottom:8px;font-size:13px;font-weight:700;color:var(--mint)}
.priv-item.no .mark{color:var(--clay)}
@media(prefers-reduced-motion:reduce){.priv-item{transition:none;opacity:1;filter:none;transform:none}}

/* ---- порядок работы с прогресс-линией ---- */
.steps-wrap{position:relative}
.steps-track{position:absolute;left:0;right:0;top:37px;height:2px;background:var(--line)}
.steps-track i{position:absolute;left:0;top:0;height:100%;background:var(--blue);width:0;transition:width .25s var(--ease)}
.steps-row{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--gap);position:relative}
@media(max-width:900px){.steps-row{grid-template-columns:1fr 1fr}}
@media(max-width:560px){.steps-row{grid-template-columns:1fr}.steps-track{display:none}}
.step-card{background:#fff;border:1px solid var(--line);border-radius:var(--r-card);padding:var(--s5);transition:box-shadow .2s var(--ease),transform .2s var(--ease)}
.step-card:hover{box-shadow:var(--sh-1);transform:translateY(-2px)}
.step-card b.n{display:flex;width:26px;height:26px;border-radius:50%;background:var(--blue-pale);color:var(--blue-deep);align-items:center;justify-content:center;font-size:13px;font-weight:700;margin-bottom:14px}
.step-card.lit b.n{background:var(--blue);color:#fff}
.step-card h4{margin-bottom:4px}
.step-card .meta{font-size:12px;color:var(--blue);margin-bottom:6px;font-weight:600}
.step-card p{font-size:13.5px;color:var(--ink-mid);margin:0}

/* ---- вопросы ----
   Секция была уже остальных (inline max-width:820px на .wrap) — на
   странице, где ширина сознательно выровнена везде, это читалось
   поломкой. .wrap выровняли — но узкую колонку (--measure, 640px)
   под сами строки вопрос-ответ оставили как есть, и на широком экране
   это дало другой перекос: список стоит по левому краю секции, а
   справа от него — сотни лишних пикселей пустоты, почти половина
   ширины. Причина сузить строки была правильной (длинная строка
   тяжело читается), но одноколоночный список этого не учитывал —
   ужать МОЖНО было только по счастливой случайности, если бы вопросов
   было мало и секция заканчивалась раньше, чем становится заметно.
   Решение — не убирать сужение, а взять его тем же, чем оно и было
   задумано (для читаемости), только колонок теперь две: CSS
   column-count держит ту же узкую меру на строку, но использует всю
   ширину секции, а не только половину. break-inside:avoid не даёт
   вопросу с ответом разорваться на стыке колонок. */
#faqList{column-count:2;column-gap:var(--s9)}
@media(max-width:760px){#faqList{column-count:1}}
.faq-item{border-bottom:1px solid var(--line);break-inside:avoid;-webkit-column-break-inside:avoid}
.faq-q{width:100%;text-align:left;background:none;border:0;padding:18px 0;font:inherit;font-size:16px;font-weight:600;display:flex;align-items:center;justify-content:space-between;gap:var(--s5);cursor:pointer;color:var(--ink);transition:color .18s}
.faq-q:hover{color:var(--blue-deep)}
.faq-ic{position:relative;flex:none;width:18px;height:18px}
.faq-ic i{position:absolute;left:50%;top:50%;background:var(--ink-soft);border-radius:2px;transform-origin:center;transition:transform .3s var(--ease),background .2s}
.faq-ic i:first-child{width:14px;height:2px;margin:-1px 0 0 -7px}
.faq-ic i:last-child{width:2px;height:14px;margin:-7px 0 0 -1px}
.faq-item.on .faq-ic i{background:var(--blue)}
.faq-item.on .faq-ic i:last-child{transform:rotate(90deg) scale(0)}
.faq-a{max-height:0;overflow:hidden;transition:max-height .4s var(--ease)}
.faq-a p{color:var(--ink-mid);font-size:14.5px;padding-bottom:20px;margin:0}
.faq-item.on .faq-a{max-height:240px}

/* ---- финальный CTA — тёмный, переопределяет светлый .pull из app.css ---- */
.pull{background:linear-gradient(160deg,#0e1b2b,#132a3f);color:#fff;border-radius:var(--r-block);padding:var(--s10) var(--s8);text-align:center;position:relative;overflow:hidden}
@media(max-width:760px){.pull{padding:var(--s9) var(--s5)}}
.pull blockquote{color:#fff}
.pull cite{color:var(--dmid)}
.pull .cta-actions{display:flex;gap:12px;justify-content:center;flex-wrap:wrap;margin-top:var(--s6);position:relative;z-index:2}
.pull canvas{position:absolute;inset:0;width:100%;height:100%;opacity:.5}
