/* ============================================================
   OZMA PERFORMANCE, лендинг витрины (редизайн Ф4, 21.07).
   0 CDN, всё со своего хоста. Hero и шрифты self-contained (base64);
   встроенный блок образов (вшивка 21.07) живёт файлами /site-assets —
   осознанно: каталог в base64 не влезает. Канон вкуса Жени:
   - холст-крем, не белоснежный; тёмного гламура нет вовсе;
   - один сквозной мотив: ПОЯВЛЕНИЕ ИЗ НИЧЕГО (буквы и блоки
     проступают из холста), никакого мельтешения;
   - медиа всегда в окне и видно целиком, fullscreen запрещён;
   - текст никогда не лежит поверх фото;
   - живое фото: рандомный параллакс (принцип b58f1a6) — наведение
     оживляет кадр, дальше он блуждает сам, курсор-слежки нет.
   Токены в :root: перешить айдентику = поменять один блок.
   ============================================================ */

:root{
  /* --- палитра бренда (дека + канон): крем / почти-чёрный / красный --- */
  --paper:#F6F2EC;        /* крем бренда, НЕ #FFFFFF (её слова, дважды) */
  --paper-deep:#EFEAE1;   /* фон уходит в глубину по скроллу (Ausra) */
  --paper-settled:#EEE6D9; /* холст после сборки ленты: теплее и глубже
                              (её просьба 23.07 «чтобы цвет фона поменялся»);
                              тёплый песочный, не белый и не тёмный */
  --ink:#16130F;
  --ink-soft:#3D3A34;
  --muted:#79726A;
  --line:#E3DCD0;
  --line-strong:#D3CABB;
  --red:#C8102E;          /* её «оттенок бордового» — это он */
  --red-deep:#A20C25;
  --on-red:#FFFFFF;

  /* --- типографика: Jost на всём сайте (Jacquemus-скин, принят 18.07) --- */
  --serif:'Jost', sans-serif;   /* имя историческое: дисплейная роль */
  --sans:'Jost', system-ui, sans-serif;

  /* --- ритм --- */
  --radius:2px;
  --edge: clamp(1.2rem, 5vw, 5rem);
  --maxw:1280px;
  --sect: clamp(2.8rem, 7vh, 5rem);  /* ужато умеренно по слову Андрея 21.07 */

  --ease:cubic-bezier(.16,1,.3,1);
  color-scheme: light;
}

*{box-sizing:border-box; margin:0; padding:0}
html{-webkit-text-size-adjust:100%; scroll-behavior:smooth; overflow-x:clip}
@media (prefers-reduced-motion: reduce){ html{scroll-behavior:auto} }
body{
  font-family:var(--sans);
  background:var(--paper);
  /* Фон живёт: холст участник. Градиент вынесен в body::before (LANE_CSS),
     чтобы его можно было ПЛАВНО погасить, когда лента встала: сокращённое
     `background` сбрасывало бы картинку разом, а transition умеет только цвет. */
  color:var(--ink);
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow-x:clip;
}
img,video{max-width:100%; display:block}
a{color:inherit; text-decoration:none}
::selection{background:var(--red); color:var(--on-red)}

.wrap{max-width:var(--maxw); margin:0 auto; padding-inline:var(--edge)}

/* ---------- типографика ---------- */
.display{
  font-family:var(--serif); font-weight:300;
  line-height:1.15; letter-spacing:.1em; text-transform:uppercase;
}
h2.display{ font-size:clamp(1.4rem,3.4vw,2.4rem) }
.eyebrow{
  display:block; margin-bottom:1rem;
  font-family:var(--sans); font-size:.7rem; font-weight:600;
  letter-spacing:.26em; text-transform:uppercase; color:var(--red);
}
.lead{ font-size:clamp(1.02rem,1.5vw,1.22rem); color:var(--ink-soft);
  max-width:52ch; line-height:1.6; margin-top:1.1rem }
.muted{ color:var(--muted) }

/* ---------- мотив «появление из ничего» ----------
   Единственный сквозной эффект сайта (её одобренный приём Immersive:
   «нравится, что появляются буквы»). Заголовки режутся на буквы, буквы
   проступают из холста в случайном порядке; блоки проявляются blur-fade.
   Никакого мельтешения: один раз, медленно, спокойно. */
[data-letters] .lw{ display:inline-block; white-space:nowrap }
[data-letters] .lt{
  display:inline-block; opacity:0; filter:blur(9px);
  transition:opacity 1.1s var(--ease), filter 1.1s var(--ease);
}
[data-letters].lit .lt{ opacity:1; filter:blur(0) }
.reveal{ opacity:0; filter:blur(6px); transform:translateY(12px);
  transition:opacity .9s var(--ease), filter .9s var(--ease), transform .9s var(--ease) }
.reveal.in{ opacity:1; filter:none; transform:none }
.reveal.d1{ transition-delay:.12s } .reveal.d2{ transition-delay:.24s }
.reveal.d3{ transition-delay:.36s }

/* ---------- кнопки ---------- */
.btn{
  display:inline-flex; align-items:center; gap:.55rem;
  font-family:var(--sans); font-size:.92rem; font-weight:500; letter-spacing:.01em;
  padding:.85rem 1.5rem; border-radius:var(--radius); cursor:pointer;
  border:1px solid transparent; white-space:nowrap;
  transition:background .22s var(--ease), color .22s var(--ease),
             border-color .22s var(--ease), transform .12s var(--ease);
}
.btn:active{ transform:translateY(1px) }
.btn-primary{ background:var(--red); color:var(--on-red); border-color:var(--red) }
.btn-primary:hover{ background:var(--red-deep); border-color:var(--red-deep) }
.btn-ghost{ background:transparent; color:var(--ink); border-color:var(--line-strong) }
.btn-ghost:hover{ border-color:var(--ink) }
.btn .arrow{ transition:transform .22s var(--ease) }
.btn:hover .arrow{ transform:translateX(3px) }
.cta-line{ display:inline-block; margin-top:1.6rem; color:var(--red);
  border-bottom:1px solid currentColor; padding-bottom:2px; font-size:.95rem }
.cta-line .arrow{ display:inline-block; transition:transform .22s var(--ease) }
.cta-line:hover .arrow{ transform:translateX(3px) }

/* ---------- nav: минимум меню («очень много меню» — отказ) ---------- */
.nav{
  position:sticky; top:0; z-index:50;
  display:flex; align-items:center; justify-content:space-between; gap:1rem;
  height:64px; padding-inline:var(--edge);
  border-bottom:1px solid transparent;
  transition:background .3s var(--ease), border-color .3s var(--ease);
}
.nav.scrolled{
  background:color-mix(in srgb, var(--paper) 85%, transparent);
  backdrop-filter:saturate(140%) blur(12px);
  -webkit-backdrop-filter:saturate(140%) blur(12px);
  border-bottom-color:var(--line);
}
.brand{ font-family:var(--serif); font-size:1.1rem; letter-spacing:.34em; text-indent:.34em }
.brand b{ font-weight:400 }
.brand .dot{ color:var(--red) }
.nav-links{ display:flex; align-items:center; gap:clamp(.9rem,3vw,1.9rem);
  font-size:.84rem; color:var(--ink-soft) }
.nav-links a{ position:relative; padding:.2rem 0; letter-spacing:.02em; white-space:nowrap }
.nav-links a::after{
  content:""; position:absolute; left:0; right:100%; bottom:-2px; height:1px;
  background:var(--red); transition:right .25s var(--ease);
}
.nav-links a:hover{ color:var(--ink) }
.nav-links a:hover::after{ right:0 }
/* Узкий экран: бренд плюс четыре пункта в 375px не влезали и делали всю
   страницу шире вьюпорта (замер 28.07: scrollWidth 382 при 375 — «Контакт»
   срезало краем, а вместе с ним съезжал весь макет). Пунктов не убираем,
   поджимаем шрифт, разрядку и зазор. */
@media (max-width:430px){
  .brand{ font-size:1rem; letter-spacing:.2em; text-indent:.2em }
  .nav-links{ gap:.7rem; font-size:.74rem }
  .nav-links a{ letter-spacing:0 }
}

/* ---------- hero: холст-крем, буквы проявляются ----------
   Медиа в окне-контейнере и видно целиком: fullscreen-обложка запрещена
   («большую главную картинку не видно целиком» — отказ Lemaire).
   Текст на холсте, НЕ поверх фото. Hero влезает в экран и на 375x812. */
.hero{ display:flex; align-items:flex-start;
  min-height:min(88svh, 860px); padding:clamp(2rem,5vh,3.5rem) 0 clamp(1.6rem,4vh,3rem) }
.hero-inner{ width:100%; max-width:var(--maxw); margin:0 auto;
  padding-inline:var(--edge);
  display:grid; gap:clamp(.9rem,2.2vh,1.4rem); justify-items:start }
.brandline{
  font-family:var(--serif); font-weight:300; color:var(--ink);
  font-size:clamp(1.55rem, 4.4vw, 2.8rem); line-height:1.25;
  letter-spacing:.32em; text-transform:uppercase; text-wrap:balance;
}
.hero .hook{
  font-size:clamp(1.08rem, 1.9vw, 1.4rem); color:var(--ink);
  letter-spacing:.02em;
}
.hero .sub{ font-size:clamp(.98rem,1.4vw,1.15rem); color:var(--ink-soft);
  max-width:52ch; line-height:1.55 }
/* Что умеет творческая мастерская: тот же ряд с бордовой нумерацией,
   что у событий и форматов (Андрею она понравилась в событиях, 22.07). */
.shop-list{ display:grid; grid-template-columns:repeat(2,1fr);
  gap:clamp(1rem,2.4vw,1.8rem); margin-top:1.8rem }
.srow{ display:flex; gap:.9rem; align-items:baseline;
  border-top:1px solid var(--line); padding-top:1rem }
.srow .idx{ font-family:var(--sans); font-size:.72rem; font-weight:600;
  letter-spacing:.14em; color:var(--red); font-variant-numeric:tabular-nums }
.srow h3{ margin:0; font-family:var(--serif); font-weight:400;
  font-size:clamp(1rem,1.9vw,1.25rem); line-height:1.2 }
.srow p{ margin:.35rem 0 0; color:var(--ink-soft); font-size:.92rem; line-height:1.5 }
@media (max-width:640px){ .shop-list{ grid-template-columns:1fr } }

/* Ссылка на мастерскую Евгении Озма: тихое подчёркивание, как у контактов. */
.hero .sub a{ border-bottom:1px solid var(--line-strong); padding-bottom:1px;
  transition:border-color .2s var(--ease) }
.hero .sub a:hover{ border-color:var(--red) }
.actions{ display:flex; flex-wrap:wrap; gap:.9rem; align-items:center }
/* Рамы-паспарту с видео здесь больше нет: Женя 22.07 отказалась от hero-видео
   и попросила перенести ролик в ленту, где он запускается по наведению.
   Лента встала на его место, стили ленты живут в collections_build.py. */

/* ---------- встроенный блок образов (вшивка 21.07) ----------
   ПОЛНЫЙ блок со страницы /site/collections: лента-попурри, блок
   «Коллекции» (фильтр тем, поиск), окно коллекции, остров «Подборка».
   Один источник кода: site/collections_build.py::build_fragment().
   Свой HTML не пишем — разойдётся с standalone-страницей. */

/* Фон участник, а не подложка (её канон): пока лента собирается, холст один,
   а как встала в линию — меняется. Идея Жени 22.07, усилена 23.07: «хотелось,
   чтобы после того, как лента соберётся, цвет фона поменялся».
   Прежде смена была почти невидима (F6F2EC → EFEAE1, семь единиц) и вдобавок
   мгновенна: сокращённое `background` сбрасывало градиент разом, а transition
   умеет только цвет. Теперь градиент живёт отдельным слоем и гаснет плавно,
   а холст уходит в тёплый песочный — заметно, но без переключения света. */
body{ transition:background-color 1.8s var(--ease) }
body::before{ content:""; position:fixed; inset:0; z-index:-1; pointer-events:none;
  background:linear-gradient(180deg, var(--paper) 0%, var(--paper-deep) 100%);
  transition:opacity 1.8s var(--ease) }
html.lane-settled body{ background-color:var(--paper-settled) }
html.lane-settled body::before{ opacity:0 }
@media (prefers-reduced-motion: reduce){
  body, body::before{ transition:none }
}

/* Сплошная лента-попурри: без полей, сшивок и подписей (её слова про Jacquemus).
   НЕ плитка: ни сетки, ни фикс-пропорции карточек — «квадратики» она отвергла. */
/* Высота: лента стоит ПЕРВОЙ на странице (фидбек Жени 22.07 через Андрея),
   поэтому экран целиком не занимает — под ней сразу должно читаться начало
   текста, иначе первый экран выглядит как заставка без входа. Кадры растут
   до 46vh вместо прежних 62: её слово «собирается и увеличивается, но не
   так сильно». */
.lane{
  display:flex; align-items:center; gap:0;
  overflow:hidden;                 /* прокрутки нет: всё движение transform'ом */
  height:64vh;
  scrollbar-width:none;
  touch-action:pan-y;              /* вертикальный скролл страницы не отбираем */
}
/* Ряд. МЕХАНИКА ДОНОРА (ausrababiedaite.com, вынута из их бандла 25.07 и
   принята Андреем): ряд стартует сжатым так, что ВСЯ лента влезает в экран,
   затем растёт до 1. Двигаем только transform'ом — нативную прокрутку
   браузеры (особенно Safari) обрезают у масштабированного содержимого, из-за
   чего лента уезжала за экран. flex:0 0 auto обязателен: без него ряд как
   flex-элемент ужимался до ширины экрана, а кадры вываливались из него. */
.lane-row{ display:flex; align-items:center; gap:2px; flex:0 0 auto;
  transform-origin:0 0; will-change:transform }
.lane-row.anim{ transition:transform 1s cubic-bezier(.215,.61,.355,1) }
.lane::-webkit-scrollbar{display:none}
/* Кадр донора: фикс-ширина по брейкпоинту, пропорция 3/4, разлёт по X от
   центрального (--ax из JS) и схождение за 2с их изингом. Ни высоты, ни
   --sx/--sy: вертикального разлёта у донора нет, а высоту диктует пропорция.

   ⚠️ Женин фидбек на прежнюю сборку: «похоже, что комп тупит» — он был про
   ТЕМП, кадры выезжали по одному две секунды. Здесь stagger донорский:
   0.1с НА ВСЮ пачку, кадры летят почти разом. */
/* ⚠️ Всё, что про РАЗМЕР и РАЗЛЁТ кадра, живёт под .lane и только под ней.
   Класс .shot носят ещё обложки блока «Коллекции» и кадры окна коллекции —
   у них своя высота (--cover-h) и свои пропорции. Общее правило с фикс-
   шириной 18vw ловило и их: на телефоне обложка становилась 68px и фото
   ужималось — ровно то, за что Андрей уже правил 25.07 («не обрезал, а
   уменьшил»). Нашлось замером 28.07 при разборе оверфлоу на 375px. */
.shot{ position:relative; overflow:hidden; background:var(--paper-deep) }
.lane .shot{
  flex:0 0 var(--shot-w,18vw); width:var(--shot-w,18vw);
  aspect-ratio:3/4;                /* донорская пропорция кадра */
  opacity:0;
  transform:translateX(var(--ax,0px));
  transition: opacity 2s cubic-bezier(.215,.61,.355,1), transform 2s cubic-bezier(.215,.61,.355,1),
    width .5s var(--ease), flex-basis .5s var(--ease);
}
.lane.assemble .shot{ opacity:1; transform:none }
/* Резиновость (донорская): ширина кадра по брейкпоинтам; S/M/L переключает
   класс на ленте, а не инлайн-переменная — инлайн перебивал бы медиа. */
.lane.sz-s{--shot-w:13vw} .lane.sz-m{--shot-w:18vw} .lane.sz-l{--shot-w:25vw}
/* Согласованный вход: лента после сборки на 30% крупнее обычного M.
   Это только её первая подача; первый ручной S/M/L возвращает шкалу. */
#lane.lane-start-larger{--shot-w:23.4vw}
@media (max-width:1024px){ .lane{--shot-w:30vw}
  .lane.sz-s{--shot-w:22vw} .lane.sz-m{--shot-w:30vw} .lane.sz-l{--shot-w:44vw}
  #lane.lane-start-larger{--shot-w:39vw} }
@media (max-width:640px){ .lane{--shot-w:38vw}
  .lane.sz-s{--shot-w:26vw} .lane.sz-m{--shot-w:38vw} .lane.sz-l{--shot-w:56vw}
  #lane.lane-start-larger{--shot-w:49.4vw} }
/* На телефоне лента остаётся входом в витрину, но не должна выталкивать
   название и первое действие за пределы экрана. Высоты 30svh достаточно
   для портретных кадров и оставляет кнопку «Обсудить событие» в первом
   сценарии прокрутки. */
@media (max-width:640px){ .lane{height:30svh} }
@media (max-width:480px){ .lane{--shot-w:44vw}
  .lane.sz-s{--shot-w:30vw} .lane.sz-m{--shot-w:44vw} .lane.sz-l{--shot-w:64vw}
  #lane.lane-start-larger{--shot-w:57.2vw} }
.lane .shot img,.lane .shot video{height:100%; width:100%; object-fit:cover}
.covers .shot img,.covers .shot video{height:100%; width:100%; object-fit:cover}

/* Защита кадров от «сохранить как» (Андрей 29.07). Полностью закрыть
   картинку в вебе нельзя — скриншот не отменить, — но убираем всё, что
   даёт утащить оригинал одним движением: контекстное меню, перетаскивание
   и долгое нажатие на iOS, которое предлагает «Сохранить фото». */
.shot img, .shot video, .cover img, .cover video, .cwin-lane img{
  -webkit-user-select:none; user-select:none;
  -webkit-touch-callout:none;   /* iOS:долгое нажатие без «Сохранить фото» */
  -webkit-user-drag:none; pointer-events:none;
}
/* Клик по кадру нужен самим фигурам (окно коллекции, сердечки), поэтому
   события гасим только у картинки, а не у контейнера. Фигуру окна тут не
   трогаем: у неё своё правило с position:relative, и второе правило на тот
   же селектор путает и людей, и стражей. */
.shot, .cover{ -webkit-touch-callout:none }

/* Живое фото (видео): её определение — «при наведении курсора фото начинает
   двигаться; девочки сами передают через фото танец». ЗУМ ЗАПРЕЩЁН, никаких scale(). */
.shot video{
  position:absolute; inset:0; height:100%; width:100%; object-fit:cover;
  opacity:0; transition:opacity .8s var(--ease);
}
.shot img{transition:opacity .8s var(--ease)}
.shot.live:hover video, .shot.live.awake video{opacity:1}
.shot.live:hover img, .shot.live.awake img{opacity:0}
@media (hover: none){
  .shot.live:hover video{opacity:0}
  .shot.live:hover img{opacity:1}
  .shot.live.awake video{opacity:1}
  .shot.live.awake img{opacity:0}
}

/* Живое фото (глубина): общий WebGL-канвас-«линза» накрывает кадр под курсором
   и рендерит его с параллаксом по карте глубины. Пространственность, не зум. */
.lens{position:absolute; inset:0; width:100%; height:100%;
  opacity:0; transition:opacity .45s var(--ease); pointer-events:none}
.lens.on{opacity:1}

/* Плотность решает смотрящий: просила дважды. Контрол скромный. */
.density{
  position:fixed; right:var(--edge); bottom:var(--edge); z-index:10;
  display:inline-flex; border:1px solid var(--line); border-radius:2px;
  background:color-mix(in srgb,var(--paper) 88%,transparent); backdrop-filter:blur(8px);
}
.density button{
  border:0; background:transparent; color:var(--muted); cursor:pointer;
  font:600 .78rem var(--sans); padding:.4rem .7rem;
  transition:background .2s var(--ease), color .2s var(--ease);
}
.density button.on{background:var(--red); color:var(--paper)}

/* Окно образа (387db94): её механика словами (Ausra). НЕ на весь экран —
   сказано дважды. Медиа помещается в экран целиком. */
.scrim{position:fixed;inset:0;background:rgba(26,22,19,.45);opacity:0;
  pointer-events:none;transition:opacity .4s var(--ease);z-index:20}
.scrim.on{opacity:1;pointer-events:auto}
.cwin{
  position:fixed; z-index:21; top:50%; left:50%; transform:translate(-50%,-50%) scale(.98);
  width:min(78vw, 980px); max-height:78vh; background:var(--paper);
  border:1px solid var(--line); border-radius:2px;
  /* Прокрутка внутри окна, а не обрезка. Пока в окне была одна лента кадров,
     всё влезало; с блоком номера и ссылкой «все номера» ленте перестало
     хватать высоты — кадры ужимались и обрезались, а S/M/L будто переставал
     работать (Андрей 29.07). Окно теперь прокручивается, лента держит
     заданную высоту. */
  overflow-y:auto; overscroll-behavior:contain;
  display:none; flex-direction:column; opacity:0;
  transition:opacity .4s var(--ease), transform .4s var(--ease);
}
.cwin.on{display:flex; opacity:1; transform:translate(-50%,-50%) scale(1)}
.cwin-head{display:flex;align-items:center;gap:.8rem;padding:.9rem 1.1rem;
  border-bottom:1px solid var(--line)}
.cwin-name{font-family:var(--serif);font-size:1.15rem}
.cwin-lane{display:flex;gap:.5rem;overflow-x:auto;padding:1rem;align-items:center;
  flex:0 0 auto}   /* не ужимаемся под остальные блоки окна */
/* position:relative обязателен: сердечко подборки позиционируется от фигуры;
   без него все сердечки окна съезжали в угол окна на крестик закрытия. */
/* Размер кадра в окне ставит JS прямо на элемент. Через CSS не вышло:
   и переменная, и класс матчились, значения доходили, а computed height
   оставался прежним — проверено на живом проде 29.07 всеми способами.
   Инлайновая высота применяется сразу и предсказуемо, а объяснение того,
   почему так, дороже красоты правила. */
.cwin-lane figure{flex:0 0 auto;position:relative;min-width:6rem}
/* ⛔ БЕЗ transition на height. Именно она и ломала S/M/L в окне: с анимацией
   высота залипала на первом применённом значении — inline менялся, а кадр
   оставался прежним. Проверено подряд обоими способами: с анимацией
   325→325→325, без неё 325→504→179 (29.07). Смена размера мгновенная,
   и это нормально: переключатель не анимация, а выбор. */
.cwin-lane img{height:40vh;width:auto;object-fit:cover}
/* Видео в окне коллекции: постер со знаком, по клику на его месте плеер
   Диска. Ширину даём фиксированную — у iframe своей пропорции нет. */
.cwin-lane figure.has-video{cursor:pointer}
.cwin-lane .play{position:absolute;inset:0;display:grid;place-items:center;
  color:#fff;font-size:1.6rem;text-shadow:0 1px 6px rgba(0,0,0,.5);pointer-events:none}
.cwin-lane iframe,.cwin-lane video{border:0;display:block;background:#000}
.cwin-x{margin-left:auto;border:1px solid var(--line);background:transparent;
  color:var(--ink);cursor:pointer;width:32px;height:32px;border-radius:2px}
.cwin-x:hover{border-color:var(--ink)}

/* Остров «Подборка» (React): курация + подборка, НЕ корзина. Сердечки на
   кадрах + панель. Стиль скромный: контролы не спорят с костюмом. */
/* Сердечко видно ВСЕГДА (правка Андрея 21.07: прятать до ховера
   неинтуитивно, а на таче ховера нет вовсе). Приглушено, на ховере кадра
   или самого сердечка — в полную силу. */
.wish-heart{position:absolute; top:.6rem; right:.6rem; z-index:2;
  width:32px; height:32px; display:grid; place-items:center;
  border:0; border-radius:100px; cursor:pointer;
  background:color-mix(in srgb, var(--ink) 38%, transparent);
  color:#fff; backdrop-filter:blur(4px);
  opacity:.55; transition:opacity .25s var(--ease), background .2s}
.shot:hover .wish-heart, .cwin-lane figure:hover .wish-heart,
.wish-heart:hover, .wish-heart.on{opacity:1}
.wish-heart.on{background:var(--red)}
@media (hover: none){ .wish-heart{opacity:.9} }
/* Номер по мотивам коллекции — внутри окна, под кадрами. Появляется только
   там, где номер есть: пустого заголовка «а номера нет» быть не должно. */
.cwin-acts{display:none}
.cwin-acts.has{display:flex; flex-wrap:wrap; gap:1rem; padding:0 1rem 1.2rem;
  border-top:1px solid var(--line); margin-top:.2rem; padding-top:1.1rem}
.cwin-acts::before{content:"Номера в этом костюме"; display:block; width:100%;
  font-size:.72rem; letter-spacing:.22em; text-transform:uppercase;
  color:var(--red); margin-bottom:.2rem}
.cwin-acts .act{margin:0; cursor:pointer; max-width:min(100%, 22rem);
  display:flex; gap:.9rem; align-items:flex-start}
.cwin-acts .act-shot{position:relative; flex:0 0 auto; width:8.5rem;
  aspect-ratio:16/10; overflow:hidden; background:var(--paper-deep)}
/* Играющий номер занимает всю ширину окна: ролик в превью с ладонь
   бесполезен, а его собственные кнопки в такой размер не помещаются. */
.cwin-acts .act.playing{max-width:100%; width:100%; flex-direction:column;
  gap:.6rem; cursor:default}
.cwin-acts .act.playing .act-shot{width:100%; aspect-ratio:16/9}
.cwin-acts .act-shot img{width:100%; height:100%; object-fit:cover; display:block}
.cwin-acts .act-shot iframe{width:100%; height:100%; border:0; display:block}
.cwin-acts .play{position:absolute; inset:0; display:grid; place-items:center;
  color:#fff; font-size:1.4rem; text-shadow:0 1px 6px rgba(0,0,0,.55);
  width:100%; padding:0; border:0; background:transparent; cursor:pointer}
.cwin-acts .play:focus-visible{outline:2px solid var(--red); outline-offset:-3px}
.cwin-acts figcaption{display:flex; flex-direction:column; gap:.25rem}
.cwin-acts figcaption b{font-weight:500; letter-spacing:.1em; text-transform:uppercase;
  font-size:.8rem}
.cwin-acts figcaption span{color:var(--ink-soft); font-size:.85rem; line-height:1.45}
@media (max-width:640px){ .cwin-acts .act{max-width:100%} }

/* Кнопка «остановить» поверх плеера. Без неё выйти из просмотра можно было
   только закрыв окно, то есть потеряв коллекцию, которую смотришь. */
.vstop{position:absolute;top:.4rem;right:.4rem;z-index:3;width:1.8rem;height:1.8rem;
  border:0;border-radius:999px;background:rgba(26,23,18,.72);color:#fff;
  font-size:.95rem;line-height:1;cursor:pointer}
.vstop:hover{background:var(--red)}
.cwin-lane figure,.cwin-acts .act-shot{position:relative}

.cwin-all{display:none}
.cwin-all.has{display:block; padding:0 1rem 1.2rem}
.cwin-all a{display:inline-flex; align-items:center; gap:.5rem;
  font-size:.78rem; letter-spacing:.16em; text-transform:uppercase;
  color:var(--red); border-bottom:1px solid transparent;
  transition:border-color .2s var(--ease)}
.cwin-all a:hover{border-bottom-color:var(--red)}

.wish-panel{position:fixed; left:var(--edge); bottom:var(--edge); z-index:10;
  max-width:min(320px, 86vw)}
.wish-toggle{border:1px solid var(--line); border-radius:2px; cursor:pointer;
  background:color-mix(in srgb,var(--paper) 88%,transparent); backdrop-filter:blur(8px);
  color:var(--ink); font:600 .78rem var(--sans); padding:.45rem .8rem}
.wish-panel.open .wish-toggle{background:var(--ink); color:var(--paper)}
.wish-body{margin-top:.5rem; padding:.8rem; border:1px solid var(--line);
  border-radius:2px; background:var(--paper)}
.wish-empty{font-size:.82rem; color:var(--muted); max-width:24ch}
.wish-grid{display:flex; flex-wrap:wrap; gap:.4rem; max-height:38vh; overflow-y:auto}
.wish-thumb{position:relative; width:56px; height:72px}
.wish-thumb img{width:100%; height:100%; object-fit:cover; border-radius:2px}
.wish-thumb button{position:absolute; top:-6px; right:-6px; width:18px; height:18px;
  border:0; border-radius:100px; background:var(--ink); color:var(--paper);
  font-size:.6rem; cursor:pointer; line-height:1}
.wish-cta{display:block; margin-top:.7rem; text-align:center; padding:.6rem;
  background:var(--red); color:#fff; border-radius:2px; text-decoration:none;
  font:500 .85rem var(--sans)}
/* Выбранные форматы в панели (чекер, Андрей 23.07). Стоят ПЕРЕД кадрами:
   Жене важнее, что нужно на событии, чем какие кадры понравились. Живут и
   на /site/collections, где самой секции форматов нет: выбор общий. */
.wish-fmts{display:flex; flex-wrap:wrap; gap:.3rem; margin-bottom:.6rem}
.wish-chip{display:inline-flex; align-items:center; gap:.35rem; cursor:pointer;
  border:1px solid var(--line); border-radius:2px; background:transparent;
  color:var(--ink); font:500 .72rem var(--sans); padding:.28rem .5rem}
.wish-chip span{color:var(--muted); font-size:.66rem}
.wish-chip:hover{border-color:var(--red)}

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

/* Блок «Коллекции» (выбор Жени 21.07 на демо 4 видов: механика Сборка,
   вид B из site/look.html; правки Андрея 21.07: подписи, фильтр, поиск).
   Отдельная секция ПОСЛЕ ленты-попурри: по одной обложке на коллекцию
   (первый кадр её первого появления в FEATURED), под обложкой подпись
   тихой капителью. Сборка: обложка рождается маленькой и смещённой
   (--sx/--sy), при входе секции в экран встаёт в линию СТРОГОЙ ОЧЕРЕДЬЮ
   слева направо (фаза 1, .assemble) и растёт до ЕДИНОЙ высоты ряда
   (фаза 2, .grown) — осознанный контраст с лентой, которая слетается
   вразнобой. После сборки ряд статичен: дрейфует только лента.
   Переполнение уходит в горизонтальный скролл, скроллбар спрятан как
   у ленты. */
.covers-block{padding:clamp(2.5rem,8vh,4.5rem) 0 clamp(2.5rem,9vh,5rem)}
.covers-head{padding:0 var(--edge) 1rem}
/* Ширина как у .sec-head остальных блоков (Андрей 22.07: заголовок висел
   иначе, чем соседние). Ограничение на ОБЁРТКЕ с базовым кеглем, а не на
   самом заголовке: 56ch считаются от собственного шрифта, и у крупного
   дисплейного они дают полторы тысячи пикселей вместо пятисот. */
.covers-head-inner{max-width:56ch}
/* Шапка как у остальных блоков лендинга (Андрей 22.07: «везде под бордовыми
   названиями идёт большим шрифтом текст, кроме коллекций — туда пишем тоже»).
   Капитель бордовая, под ней крупная строка. Токены .eyebrow и .display
   объявлены здесь же: фрагмент едет и на standalone-страницу, своих стилей
   лендинга у неё нет. */
.covers-head .eyebrow{display:block; margin-bottom:1rem;
  font-family:var(--sans); font-size:.7rem; font-weight:600;
  letter-spacing:.26em; text-transform:uppercase; color:var(--red)}
.covers-head h2.display{font-family:var(--serif); font-weight:300;
  font-size:clamp(1.4rem,3.4vw,2.4rem); line-height:1.15;
  letter-spacing:.1em; text-transform:uppercase; color:var(--ink)}
/* Два предложения под крупной строкой (текст Андрея 22.07): тот же кегль
   и ширина, что у лидов остальных блоков лендинга. */
.covers-lead{font-size:clamp(1.02rem,1.5vw,1.22rem); color:var(--ink-soft);
  max-width:52ch; line-height:1.6; margin-top:1.1rem}
/* Пилюли тем + поиск: тон скромный, контролы не спорят с костюмом. */
.covers-nav{display:flex; align-items:center; gap:.6rem; flex-wrap:wrap;
  padding:0 var(--edge) 1.1rem}
.covers-reset{display:none; margin:0 var(--edge) 1rem; border:0; padding:0;
  background:transparent; color:var(--red); font:500 .8rem var(--sans);
  cursor:pointer; border-bottom:1px solid currentColor}
.covers-block.filters-active .covers-reset{display:inline-flex}
.covers-chips{display:flex; gap:.4rem; flex-wrap:wrap; min-width:0}
.chip{border:1px solid var(--line); background:transparent; color:var(--ink-soft);
  border-radius:100px; padding:.4rem .9rem; cursor:pointer;
  font:500 .8rem var(--sans); white-space:nowrap;
  transition:background .2s var(--ease), color .2s var(--ease),
    border-color .2s var(--ease)}
.chip:hover{border-color:var(--ink)}
.chip.on{background:var(--ink); color:var(--paper); border-color:var(--ink)}
/* Пилюля, ведущая в пустоту при выбранном другом измерении: видна, но тиха.
   Не блокируем — клик даст честное «ничего не нашлось» и путь назад. */
.chip.dim{opacity:.35}
.covers-search{border:1px solid var(--line); border-radius:2px;
  background:color-mix(in srgb,var(--paper) 92%,transparent); color:var(--ink);
  font:400 .85rem var(--sans); padding:.45rem .7rem; width:200px; margin-left:auto}
.covers-search:focus{outline:none; border-color:var(--ink)}
.covers-search::placeholder{color:var(--muted)}
/* ⭐ СЕТКА, а не ряд (выбор Жени 29.07 из трёх видов на смотровой).
   Коллекций стало за сотню, и «мотать влево-вправо неудобно» (Андрей).
   Её правки к выбранному виду: кадров в ряду меньше — крупнее, и имена
   подписаны всегда, потому что «наведение красиво, но так отбор делать
   сложно». Горизонтальная лента осталась выше — она про настроение. */
.covers{
  display:grid; gap:clamp(.6rem,1.2vw,1.1rem); padding:0 var(--edge);
  grid-template-columns:repeat(auto-fill,minmax(190px,1fr));
}
@media (max-width:700px){ .covers{grid-template-columns:repeat(2,1fr)} }
/* Размер обложек слушает тот же S/M/L, что и лента. */
html.sz-s .covers{grid-template-columns:repeat(auto-fill,minmax(130px,1fr))}
html.sz-m .covers{grid-template-columns:repeat(auto-fill,minmax(190px,1fr))}
html.sz-l .covers{grid-template-columns:repeat(auto-fill,minmax(290px,1fr))}
@media (max-width:700px){
  html.sz-s .covers{grid-template-columns:repeat(3,1fr)}
  html.sz-m .covers{grid-template-columns:repeat(2,1fr)}
  html.sz-l .covers{grid-template-columns:1fr}
}
/* Сборка живёт на фигуре (кадр + подпись летят вместе), живое фото —
   на внутреннем .shot тем же кодом, что у ленты. Высота обложек своя
   (--cover-h) и от переключателя S/M/L ленты не зависит. */
/* overflow прячем только у схлопнутой обложки (.hid): постоянный hidden
   резал длинные подписи (Бал Маргариты, Антуанетта) по краю кадра. */
.covers .cover{position:relative; margin:0; opacity:0;
  transform:translate(var(--sx,0vw), var(--sy,0vh));
  transition:opacity 1.1s var(--ease), transform 1.4s var(--ease)}
.covers.assemble .cover{opacity:1; transform:none}
/* Обложка держит высоту ряда, ширина по кадру — но не шире полутора высот.
   Кадры коллекций приходят из каталога, где рядом с портретными съёмками
   лежат горизонтальные афиши: без потолка такая обложка занимает пол-экрана
   и тянет на себя весь блок (поймано 28.07 при переезде витрины на базу).
   Уменьшать её нельзя — ряд держится на единой высоте, поэтому лишнее
   подрезается по краям. */
/* В сетке кадр держит ячейку целиком и общую пропорцию: разнобой ширин был
   уместен в ряду, а в сетке он рвёт колонки. Лишнее подрезается по краям —
   портретные съёмки и горизонтальные афиши иначе не уживаются. */
.covers .shot{width:100%; aspect-ratio:3/4; cursor:pointer; opacity:1;
  transform:none; overflow:hidden}
/* Поправка Андрея 21.07: обложки сразу по умолчанию в М — слетаются уже
   конечного размера, фазы «маленькие → выросли» у блока Коллекций нет. */
/* Фильтр и поиск прячут несовпавшие обложки плавно, сборка не переигрывается. */
/* В сетке несовпавшую обложку прячем совсем: схлопывание по ширине было
   приёмом ряда, в колонках оно оставляло дыры. */
.covers .cover.hid{display:none}
.cover-name{margin-top:.5rem;
  font-size:.66rem; font-weight:500; letter-spacing:.14em;
  text-transform:uppercase; color:var(--muted); cursor:pointer;
  opacity:0; transition:opacity 1.1s var(--ease)}
.covers.grown .cover-name{opacity:1}
/* Длинный хвост: сотня обложек сразу — стена, за которой не видно, что
   ниже есть текст и контакты. Открывается надписью, и обратно не сворачивается:
   свернуть то, что человек только что попросил показать, значит спорить с ним. */
.covers .cover.tail{display:none}
/* :not(.hid) обязателен. Правило раскрытия хвоста на класс длиннее правила
   фильтра, поэтому без него оно перебивает .hid — и поиск фильтровал только
   первые тридцать обложек, а хвост показывал целиком (проверено на живом:
   «мулен» давал 71 коллекцию вместо одной). */
.covers.all .cover.tail:not(.hid){display:block}
.covers-more{display:block; margin:1.4rem auto 0; padding:.7rem 1.6rem;
  border:1px solid var(--line); background:transparent; color:var(--ink);
  font-family:inherit; font-size:.82rem; letter-spacing:.14em;
  text-transform:uppercase; cursor:pointer; border-radius:2px;
  transition:border-color .2s var(--ease), color .2s var(--ease)}
.covers-more:hover{border-color:var(--red); color:var(--red)}
.covers-more.gone{display:none}
.covers-empty{display:none; align-self:center; margin:0 auto;
  color:var(--muted); font-size:.85rem; letter-spacing:.08em; padding:1rem 0}
.covers.empty .covers-empty{display:block}

/* Мини-подсказки (Андрей 22.07: «посетителю непонятно, что он может»).
   Отменяют его же правку 17.07 «подсказки не нужны, всё интуитивно», но
   не целиком: жестовых императивов по-прежнему нет, их список держит страж
   test_hints_name_the_possibility_not_the_gesture. Подсказка называет
   ВОЗМОЖНОСТЬ, а не командует: «коллекция открывается по клику».
   Ненавязчиво: тихий кегль, приглушённый цвет, одна на действие.
   ⚠️ Запрещённые слова в комментарии НЕ перечислять: комментарий уезжает
   в выдачу, и страж ловит собственный же список (поймано дважды 22.07). */
.hint{padding:0 var(--edge) .9rem; color:var(--ink-soft);
  font-size:.9rem; letter-spacing:.01em; max-width:60ch}
/* Бордовая метка перед подсказкой: без неё строка сливалась с текстом блока
   и Андрей 22.07 сказал «не вижу подсказок». Цвет бренда работает указателем,
   сама строка остаётся спокойной. */
.hint::before{content:"→"; color:var(--red); margin-right:.5rem;
  font-weight:600; display:inline-block}
.cwin-hint{padding:.7rem 1rem .1rem}

/* Номера: тот же блок обложек («бери прямо полностью код» — Андрей 22.07),
   но со СВОЕЙ сборкой. Коллекции слетаются вразнобой и встают очередью
   слева направо; номера поднимаются снизу, каждый следующий чуть позже —
   ровный подъём вместо разлёта, чтобы блоки не читались одинаково. */
.covers.rise .cover{ transform:translateY(26px) }
.covers.rise.assemble .cover{ transform:none }
@media (prefers-reduced-motion: reduce){
  .covers.rise .cover{ transform:none }
}
/* Телефон: пилюли листаются пальцем строкой, поиск во всю ширину, секция
   снизу отступает от плавающих контролов (Подборка и S/M/L). */
@media (max-width:640px){
  .covers-block{padding-bottom:7.5rem}
  .covers-nav{padding-bottom:.9rem}
  .covers-chips{flex-wrap:nowrap; overflow-x:auto; scrollbar-width:none;
    margin:0 calc(-1 * var(--edge)); padding:0 var(--edge) .2rem}
  .covers-chips::-webkit-scrollbar{display:none}
  .chip{padding:.5rem 1rem}
  .covers-search{width:100%; margin-left:0}
}
/* Тихий режим: сборку не играем, блок показываем сразу собранным. */
@media (prefers-reduced-motion: reduce){
  .covers .cover{opacity:1; transform:none; transition:none}
  .covers .shot{transition:none}
  .cover-name{opacity:1; transition:none}
}


/* Лендинг поверх фрагмента: шапке секции дать воздух до ленты. */
#collections .sec-head{ margin-bottom:2.2rem }
/* Фикс-контрол S/M/L не смеет висеть поверх hero: виден только когда
   блок образов в вьюпорте (скрипт ниже). «Подборка» остаётся всегда —
   она про всю страницу. */
#density{ opacity:0; pointer-events:none; transition:opacity .4s var(--ease) }
#density.vis{ opacity:1; pointer-events:auto }
/* «Подборка» появляется только когда в ней уже есть выбор. До этого не
   перекрывает вводную ленту; положение справа оставляет свободным текст hero. */
.wish-panel{left:auto; right:var(--edge)}
.wish-panel:not(.has-choice){display:none}
/* После первого выбора рядом появляются два фиксированных инструмента.
   S/M/L остаётся в углу, а «Подборка» поднимается ровно над ним: иначе
   панели занимают один прямоугольник и один из контролов не нажимается. */
.wish-panel.has-choice{bottom:calc(var(--edge) + 2.8rem)}
@media (max-width:640px){
  .covers-nav #density{position:static; right:auto; bottom:auto; margin-left:0}
  .covers-nav .covers-search{flex:1 1 12rem; width:auto; margin-left:0}
}

/* ---------- мастерская ---------- */
.addr{ margin-top:1.4rem; font-size:.88rem; color:var(--muted); letter-spacing:.02em }

/* ---------- числа бренда ---------- */
/* События: где мы выступаем. Раньше блок назывался «Форматы»,
   но так теперь называется блок выступлений; два бордовых «Форматы» на одной
   странице спорили бы друг с другом. Без баннера с текстом поверх фото —
   «текст, вылезающий на картинку» у неё в отказах. */
.events-list{ display:grid; grid-template-columns:repeat(2,1fr);
  gap:clamp(1.4rem,3vw,2.6rem); margin-top:1.6rem }
.erow{ display:flex; gap:.9rem; align-items:baseline;
  border-top:1px solid var(--line); padding-top:1rem }
.erow .idx{ font-family:var(--sans); font-size:.72rem; font-weight:600;
  letter-spacing:.14em; color:var(--red); font-variant-numeric:tabular-nums }
.erow h3{ margin:0; font-family:var(--serif); font-weight:400;
  font-size:clamp(1rem,1.9vw,1.25rem); line-height:1.2 }
.erow p{ margin:.35rem 0 0; color:var(--ink-soft); font-size:.92rem; line-height:1.5 }
@media (max-width:640px){ .events-list{ grid-template-columns:1fr; gap:1.4rem } }
/* Плашек с числами (15 / 60 / 500) на витрине нет: сняты Андреем 22.07 как
   «устаревший, немодный формат лендинга». Опыт живёт словами в открывающем
   тексте. Числа остаются каноном бренда (опросник 04), просто не витриной. */

/* ---------- контакт ---------- */
.contact .actions{ margin-top:1.8rem }
.tg-handle{ font-family:var(--serif); font-size:1rem; letter-spacing:.04em;
  color:var(--ink); border-bottom:1px solid var(--line-strong);
  padding-bottom:2px; transition:border-color .2s var(--ease) }
.tg-handle:hover{ border-color:var(--red) }

/* ---------- footer ----------
   Доработан 22.07: была одна строка с почтой, теперь подвал отвечает на три
   вопроса, с которыми туда доскроливают — как написать, где мы, куда вернуться.
   Регистр тихий: подвал закрывает страницу, а не начинает второй разговор. */
.foot{ padding-block:clamp(2.4rem,5vh,3.6rem); border-top:1px solid var(--line) }
.foot-top{ display:grid; grid-template-columns:repeat(3, minmax(0,1fr));
  gap:clamp(1.4rem,4vw,3rem); align-items:start }
.foot h3{ font-family:var(--sans); font-size:.7rem; font-weight:600;
  letter-spacing:.26em; text-transform:uppercase; color:var(--red); margin-bottom:.7rem }
.foot .brand{ font-size:1rem; display:inline-block; margin-bottom:.5rem }
.foot p, .foot li{ font-size:.86rem; color:var(--ink-soft); line-height:1.6 }
.foot ul{ list-style:none }
.foot a{ border-bottom:1px solid transparent; transition:border-color .2s var(--ease) }
.foot a:hover{ border-color:var(--red) }
.foot-bottom{ margin-top:clamp(1.8rem,4vh,2.6rem); padding-top:1.2rem;
  border-top:1px solid var(--line); display:flex; justify-content:space-between;
  gap:1rem; flex-wrap:wrap; font-size:.78rem; color:var(--muted) }
@media (max-width:760px){ .foot-top{ grid-template-columns:1fr; gap:1.8rem } }

/* Отдельного блока о команде нет: 22.07 он расформирован и слит в открывающий
   текст hero, стили вместе с ним. */

/* Форматы выступлений. Раньше блок назывался иначе и читался как перечень
   того, что мы продаём; правка Андрея 22.07: это просто форматы, а всё, что мы
   умеем, живёт в мастерской. Лаконично: без кадров.
   Бордовая нумерация вернулась 22.07 (понравилась Андрею в событиях). Она
   больше не «закрытый список»: там же, где нумерация, стоит открытая строка
   про другие форматы — счёт идёт видимым, а не итоговым. */
.fmt-grid{ display:grid; grid-template-columns:repeat(2,1fr);
  gap:clamp(1rem,2.4vw,1.8rem); margin-top:1.6rem }
.fmt{ display:flex; gap:.9rem; align-items:baseline;
  border-top:1px solid var(--line); padding-top:1rem }
.fmt .idx{ font-family:var(--sans); font-size:.72rem; font-weight:600;
  letter-spacing:.14em; color:var(--red); font-variant-numeric:tabular-nums }
.fmt h3{ margin:0; font-family:var(--serif); font-weight:400;
  font-size:clamp(1rem,1.9vw,1.25rem); line-height:1.2 }
.fmt p{ margin:.35rem 0 0; color:var(--ink-soft); font-size:.92rem; line-height:1.5 }
@media (max-width:640px){ .fmt-grid{ grid-template-columns:1fr } }

/* Чекер форматов (идея 13, Андрей 23.07). Классы навешивает остров
   «Подборка», поэтому без острова секция остаётся прежним текстом и ничего
   не ломается. Знак выбора тихий: линия верхней границы наливается бордовым,
   галочка появляется на месте кружка. Никакой заливки и рамок — порог
   перегруза у Жени низкий, декор не спорит с содержимым. */
.fmt-pick{ cursor:pointer; position:relative; padding-right:1.9rem;
  transition:border-color .25s ease }
.fmt-pick:hover{ border-top-color:var(--ink-soft) }
.fmt.fmt-on{ border-top-color:var(--red) }
.fmt-check{ position:absolute; top:1rem; right:0; line-height:0;
  color:color-mix(in srgb, var(--muted) 55%, transparent);
  transition:color .25s ease }
.fmt-pick:hover .fmt-check{ color:var(--ink-soft) }
/* Отмеченное держит бордовый и под курсором: правило hover выше имеет ту же
   специфичность, поэтому селектор здесь такой же длины и стоит после него.
   С коротким «.fmt-check.on» галочка под мышью выцветала в серый. */
.fmt-pick .fmt-check.on{ color:var(--red) }
/* Подсказка к секции: сама по себе галочка не объясняет, что выбор куда-то
   уедет. Женя 22.07 сняла запрет на подсказки везде, кроме ленты.
   Показывается только когда чекер живой (класс ставит остров): без острова
   карточки не кликаются, и обещание выбора было бы враньём. */
.fmt-note{ display:none; margin:.7rem 0 0; font-family:var(--sans);
  font-size:.8rem; color:var(--muted) }
#formats.fmt-live .fmt-note{ display:block }
@media (prefers-reduced-motion: reduce){
  .fmt-pick, .fmt-check{ transition:none }
}

/* ---------- section shell ---------- */
section{ padding-block:var(--sect) }
/* «Готовые номера»: карточки кураторских кадров, включается наполнением
   curated.NUMBERS (реестр развилок §8). */
.acts-row{ display:flex; gap:1rem; overflow-x:auto; margin-top:1.4rem;
  scrollbar-width:none; padding-bottom:.4rem }
.acts-row::-webkit-scrollbar{ display:none }
.act{ flex:0 0 auto; width:min(46vw, 300px) }
.act img{ width:100%; aspect-ratio:3/4; object-fit:cover; display:block;
  background:var(--paper-deep) }
.act-name{ display:block; margin-top:.55rem; font-family:var(--sans);
  font-size:.72rem; font-weight:500; letter-spacing:.16em;
  text-transform:uppercase; color:var(--muted) }
.act-lead{ margin-top:.3rem; font-size:.86rem; color:var(--ink-soft);
  line-height:1.45 }
.hero{ padding-block:clamp(1.6rem,4vh,3rem) }
#collections{ padding-top:clamp(2rem,5vh,3.5rem) }
.sec-head{ max-width:56ch }

/* ---------- тихий режим: всё видно сразу, без анимаций ---------- */
@media (prefers-reduced-motion: reduce){
  [data-letters] .lt{ opacity:1; filter:none; transition:none }
  .reveal{ opacity:1; filter:none; transform:none; transition:none }
  .btn .arrow, .cta-line .arrow{ transition:none }
  #density{ transition:none }
}
