/* ═══════════════════════════════════════════════════════════════════
   sections.css — все секции сайта «Слёзы Ангелов Кутюр»
   Владелец: агент B. Токены :root объявляет base.css — здесь только
   использование переменных. Разметка index.html не меняется.
   ═══════════════════════════════════════════════════════════════════ */

/* ─── Общий ритм секций ───
   Много чёрного воздуха: секции дышат, hero живёт по своим правилам. */
.s-manifest,
.s-catalog,
.s-custom,
.s-shop,
.s-order{
  padding-block:clamp(6rem,14vh,10rem);
  padding-inline:clamp(1.25rem,5vw,4rem);
}

/* Общая шапка секции: используется в каталоге, магазине, заказе.
   В .s-custom те же классы живут БЕЗ обёртки .sec-head — поэтому
   центрирование навешано на .sec-head, а не на сами элементы. */
.sec-head{
  max-width:760px;
  margin-inline:auto;
  text-align:center;
  margin-bottom:clamp(2.5rem,6vh,4rem);
}
.sec-over{
  margin:0 0 1rem;
  font-size:12px;
  letter-spacing:.32em;
  text-transform:uppercase;
  color:var(--muted);
}
/* Фрактур-латиница крупнее и без разрядки: в 12px с letter-spacing
   готический шрифт разваливается на нечитаемые палочки */
.sec-over[data-latin]{
  text-transform:none;
  letter-spacing:.08em;
  font-size:1.1rem;
  color:var(--chrome-mid);
}
.sec-title{
  margin:0;
  font-family:var(--font-display),sans-serif;
  font-weight:800;
  font-size:clamp(3rem,9vw,7rem);
  line-height:.95;
  letter-spacing:-.02em;
}
.sec-note{
  max-width:46ch;
  margin:1.5rem auto 0;
  color:var(--muted);
  line-height:1.65;
}

/* Смена фильтра каталога: catalog.js вешает .is-switching на 220мс —
   сетка мягко гаснет и проявляется с новым набором (аудит, п.5) */
.catalog-grid{transition:opacity .18s ease;}
.catalog-grid.is-switching{opacity:0;}

/* Защитная заглушка пустого каталога */
.grid-empty{
  grid-column:1/-1;
  padding:3rem 1rem;
  text-align:center;
  color:var(--muted);
}
.grid-empty a{color:var(--ink);}

/* ═══════════════════════════════════════════════════════════════════
   СЦЕНА 1. НЕБО. СЛЕЗА (.s-hero) — пин-сцена, высоту пину даёт JS
   ═══════════════════════════════════════════════════════════════════ */
.s-hero{
  position:relative;
  min-height:100vh;
  overflow:hidden;
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  background:var(--bg);
}

/* ─── Небо: луна, звёзды, зерно ─── */
.hero-sky{
  position:absolute;
  inset:0;
  z-index:0;
  overflow:hidden;
  pointer-events:none;
}

/* Луна: серебряный диск с тёмными «морями» из наложенных radial-gradient,
   лёгкая кольцевая текстура conic-градиентом. Свечение — статичный
   box-shadow с большим blur (рисуется один раз, кадровый цикл не трогает). */
.hero-moon{
  position:absolute;
  left:50%;
  top:40%;
  z-index:1;
  width:min(62vw,640px);
  aspect-ratio:1;
  transform:translate(-50%,-50%);
  border-radius:50%;
  background:
    repeating-conic-gradient(from 12deg,
      rgba(255,255,255,.022) 0deg 5deg,
      rgba(0,0,0,0) 5deg 11deg),
    radial-gradient(circle at 63% 34%, rgba(58,58,74,.32) 0 3%, rgba(58,58,74,.14) 7%, rgba(0,0,0,0) 12%),
    radial-gradient(circle at 44% 56%, rgba(52,52,68,.28) 0 5%, rgba(52,52,68,.12) 10%, rgba(0,0,0,0) 16%),
    radial-gradient(ellipse at 68% 66%, rgba(48,48,62,.24) 0 4%, rgba(48,48,62,.10) 8%, rgba(0,0,0,0) 14%),
    radial-gradient(circle at 30% 72%, rgba(60,60,76,.16) 0 2%, rgba(0,0,0,0) 7%),
    radial-gradient(circle at 34% 30%,
      #eaeaf2 0%, #c9c9da 26%, #8d8da2 58%, #4c4c60 88%, #3a3a4c 100%);
  box-shadow:
    0 0 90px 22px rgba(201,201,218,.16),
    0 0 260px 70px rgba(150,150,185,.10),
    inset -34px -48px 110px rgba(5,5,8,.55);
  transition:box-shadow .45s var(--ease-out);
}
/* Вспышка в момент удара слезы (класс вешает motion.js на пике пина):
   луна коротко разгорается — кульминация вместо пустой паузы */
.s-hero.is-impact .hero-moon{
  box-shadow:
    0 0 130px 40px rgba(220,220,240,.30),
    0 0 360px 110px rgba(170,170,205,.16),
    inset -34px -48px 110px rgba(5,5,8,.45);
}
body.is-demon .s-hero.is-impact .hero-moon{
  box-shadow:
    0 0 130px 40px rgba(255,80,90,.30),
    0 0 360px 110px rgba(160,20,30,.22),
    inset -34px -48px 110px rgba(5,5,8,.45);
}

/* Фолбэк без WebGL: класс no-webgl вешает tear.js. Вместо канваса под
   луной висит маленькая статичная хром-капля из чистого CSS. */
body.no-webgl .hero-moon::after{
  content:'';
  position:absolute;
  left:50%;
  bottom:-14%;
  width:5.2%;
  aspect-ratio:.62;
  transform:translateX(-50%);
  border-radius:50% 50% 50% 50% / 24% 24% 76% 76%;
  background:linear-gradient(165deg,
    var(--chrome-hi) 0%, var(--chrome-mid) 42%, var(--chrome-lo) 78%, #3c3c4e 100%);
  box-shadow:0 0 22px rgba(220,220,235,.45);
}

/* Звёзды: два слоя точек из radial-gradient с разным шагом повторения.
   Дрейф — только transform (композитор), слои с запасом -160px,
   чтобы при сдвиге не оголялись края. */
.hero-stars{position:absolute; inset:0; z-index:0;}
.hero-stars::before,
.hero-stars::after{
  content:'';
  position:absolute;
  inset:-160px;
  background-repeat:repeat;
}
.hero-stars::before{
  background-image:
    radial-gradient(1px 1px at 25px 35px,  rgba(242,242,247,.85), rgba(0,0,0,0) 45%),
    radial-gradient(1px 1px at 168px 92px, rgba(201,201,218,.6),  rgba(0,0,0,0) 45%),
    radial-gradient(1.5px 1.5px at 226px 214px, rgba(255,255,255,.75), rgba(0,0,0,0) 45%),
    radial-gradient(1px 1px at 84px 252px, rgba(154,154,173,.55), rgba(0,0,0,0) 45%);
  background-size:300px 300px;
  animation:stars-drift-a 160s linear infinite;
}
.hero-stars::after{
  background-image:
    radial-gradient(2px 2px at 120px 180px, rgba(255,255,255,.7), rgba(0,0,0,0) 45%),
    radial-gradient(1.5px 1.5px at 480px 90px, rgba(201,201,218,.5), rgba(0,0,0,0) 45%),
    radial-gradient(2px 2px at 340px 520px, rgba(242,242,247,.45), rgba(0,0,0,0) 45%),
    radial-gradient(1px 1px at 620px 340px, rgba(154,154,173,.5), rgba(0,0,0,0) 45%);
  background-size:700px 700px;
  animation:stars-drift-b 260s linear infinite;
}
@keyframes stars-drift-a{ to{ transform:translate3d(-120px,-60px,0); } }
@keyframes stars-drift-b{ to{ transform:translate3d(90px,-110px,0);  } }

/* Зерно: SVG-шум data-uri. Дёргается сдвигом transform со steps() —
   никакого blur/filter, слой с запасом 50% под сдвиги. */
.hero-grain{
  position:absolute;
  inset:-50%;
  z-index:2;
  opacity:.05;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%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");
  animation:grain-shift 1.6s steps(1,end) infinite;
}
@keyframes grain-shift{
  0%  { transform:translate3d(0,0,0); }
  20% { transform:translate3d(-2%,1.5%,0); }
  40% { transform:translate3d(1.5%,-2%,0); }
  60% { transform:translate3d(-1%,-1%,0); }
  80% { transform:translate3d(2%,1%,0); }
  100%{ transform:translate3d(0,0,0); }
}

/* Канвас слезы: поверх неба, под текстом, клики сквозь */
#tear-canvas{
  position:absolute;
  inset:0;
  z-index:2;
  width:100%;
  height:100%;
  pointer-events:none;
}
body.no-webgl #tear-canvas{display:none;}

/* ─── Копирайт hero: центр, чуть ниже середины ─── */
.hero-copy{
  position:relative;
  z-index:3;
  margin-top:8vh;
  text-align:center;
  padding-inline:1.25rem;
}
/* Тёмная вуаль под копирайтом: серебряный заголовок ложится на светлый диск
   луны и теряет контраст. Мягкий эллипс возвращает читаемость, луна остаётся
   видна по краям. Статичный градиент — композитору бесплатно. */
.hero-copy::before{
  content:'';
  position:absolute;
  left:50%; top:50%;
  width:min(1240px,116%); height:150%;
  transform:translate(-50%,-50%);
  z-index:-1;
  pointer-events:none;
  /* closest-side обязателен. По умолчанию эллипс считается farthest-corner:
     верхняя грань блока лежит на нормированном радиусе ~70.7%, поэтому альфа
     на стопе 78% обрывалась гранью — поперёк луны шёл прямой шов. При
     closest-side радиус = половине высоты блока, ноль альфы приходится ровно
     на грань, ступеньки нет. Стопы пересчитаны от 70.7%, чтобы плотность
     вуали осталась прежней. */
  background:radial-gradient(ellipse closest-side at center,
    rgba(5,5,8,.82) 0%, rgba(5,5,8,.66) 54%, rgba(5,5,8,.3) 88%, rgba(5,5,8,0) 100%);
}
body.is-demon .hero-copy::before{
  background:radial-gradient(ellipse closest-side at center,
    rgba(10,4,6,.84) 0%, rgba(10,4,6,.68) 54%, rgba(10,4,6,.32) 88%, rgba(10,4,6,0) 100%);
}
/* Слаган-фрактура — над сценой, под шапкой: на тёмном небе читается,
   с каплей не спорит. Живёт вне .hero-copy и не участвует в его уходе. */
.hero-over{
  position:absolute;
  left:0; right:0;
  max-width:none;   /* базовая типографика ограничивает p в 65ch — здесь это ломает центровку */
  top:calc(var(--nav-h) + 10px); /* выше острия капли — не пересекаются */
  z-index:3;
  margin:0;
  text-align:center;
  font-size:clamp(1.1rem,2.6vw,1.5rem);
  color:var(--chrome-mid);
  text-shadow:0 2px 18px rgba(5,5,8,.8);
}
.hero-title{
  margin:0;
  font-family:var(--font-display),sans-serif;
  font-weight:800;
  font-size:clamp(3rem,14vw,9rem);
  line-height:.92;
  letter-spacing:-.02em;
}
.hero-title .line{display:block; position:relative;}
/* Управляемая асимметрия: строки съезжают лесенкой. Сдвиг через
   relative left, а НЕ transform — transform строк принадлежит GSAP */
.hero-title .line:nth-child(1){left:.35em;}
.hero-title .line:nth-child(2){left:-.22em;}
.hero-sub{
  margin:1.6rem 0 0;
  font-size:12px;
  text-transform:uppercase;
  letter-spacing:.35em;
  /* строка лежит на светлом диске луны и на бликах капли —
     серый --muted там тонул, нужен полный ink + тёмная подложка-тень */
  color:var(--ink);
  text-shadow:0 2px 14px rgba(5,5,8,.85), 0 0 4px rgba(5,5,8,.6);
}
.hero-actions{
  display:flex;
  justify-content:center;
  gap:1rem;
  margin-top:2.4rem;
}

/* ─── Подсказка внизу: текст + линия, по которой стекает «капля» ─── */
.hero-hint{
  position:absolute;
  left:50%;
  bottom:calc(1.5rem + env(safe-area-inset-bottom,0px));
  z-index:3;
  transform:translateX(-50%);
  margin:0;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:.8rem;
  font-size:11px;
  letter-spacing:.28em;
  text-transform:uppercase;
  color:var(--muted);
  white-space:nowrap;
}
.hint-line{
  position:relative;
  display:block;
  width:1px;
  height:48px;
  background:var(--line);
  overflow:hidden;
}
.hint-line::after{
  content:'';
  position:absolute;
  left:0;
  top:0;
  width:100%;
  height:14px;
  background:linear-gradient(180deg, rgba(0,0,0,0), var(--chrome-hi), rgba(0,0,0,0));
  animation:hint-drop 2.4s cubic-bezier(.5,0,.9,.6) infinite;
}
@keyframes hint-drop{
  from{ transform:translateY(-16px); }
  to  { transform:translateY(52px); }
}

/* ═══════════════════════════════════════════════════════════════════
   СЦЕНА 2. МАНИФЕСТ — экран тишины после разбитой слезы
   ═══════════════════════════════════════════════════════════════════ */
.s-manifest{
  padding-block:max(8rem,30vh);
  padding-inline:1.25rem;
  text-align:center;
}
.manifest-line{
  max-width:28ch;
  margin:0 auto;
  font-family:var(--font-display),sans-serif;
  font-weight:300;
  font-size:clamp(1.6rem,4vw,3rem);
  line-height:1.3;
  color:var(--ink);
}
.manifest-line + .manifest-line{
  margin-top:2.2rem;
  font-size:clamp(1.15rem,2.6vw,1.9rem);
  color:var(--muted);
  max-width:34ch;
}

/* Три цифры, разделённые тонкими вертикалями */
.manifest-stats{
  list-style:none;
  margin:clamp(4rem,10vh,7rem) auto 0;
  padding:0;
  display:flex;
  justify-content:center;
  align-items:stretch;
}
.manifest-stats li{
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:.7rem;
  padding-inline:clamp(1.5rem,4vw,3.5rem);
}
.manifest-stats li + li{border-left:1px solid var(--line);}
.stat-num{
  font-family:var(--font-display),sans-serif;
  font-weight:600;
  font-size:clamp(2.5rem,6vw,4rem);
  line-height:1;
  font-variant-numeric:tabular-nums;
  color:var(--chrome-mid);
}
.manifest-stats span{
  font-size:11px;
  text-transform:uppercase;
  letter-spacing:.18em;
  color:var(--muted);
  max-width:20ch;
  line-height:1.5;
}

/* ═══════════════════════════════════════════════════════════════════
   СЦЕНА 3. КАТАЛОГ
   ═══════════════════════════════════════════════════════════════════ */

/* ─── Табы ─── */
.catalog-tabs{
  display:flex;
  flex-wrap:wrap;
  justify-content:center;
  gap:.25rem 1rem;
  margin:0 auto clamp(2.5rem,6vh,3.5rem);
}
.tab{
  position:relative;
  min-height:44px;                 /* честная зона нажатия на таче */
  padding:.7rem 1rem;
  background:none;
  border:0;
  font:inherit;
  font-size:12px;
  text-transform:uppercase;
  letter-spacing:.22em;
  color:var(--muted);
  cursor:pointer;
  transition:color .3s;
}
.tab::after{
  content:'';
  position:absolute;
  inset-inline:.9rem;
  bottom:6px;
  height:1px;
  background:linear-gradient(90deg, rgba(0,0,0,0), var(--chrome-mid), rgba(0,0,0,0));
  transform:scaleX(0);
  transition:transform .4s var(--ease-out);
}
.tab:hover{color:var(--ink);}
.tab.is-active{color:var(--ink);}
.tab.is-active::after{transform:scaleX(1);}
.tab:focus-visible{outline:2px solid var(--chrome-mid); outline-offset:3px;}

/* ─── Сетка: журнальная, чётные карточки ниже ───
   Мобайл-первым: 2 колонки с тесным гэпом, дальше 2/3/4. */
.catalog-grid{
  max-width:1360px;
  margin-inline:auto;
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:1rem .6rem;
  align-items:start;
}
@media (min-width:560px){
  .catalog-grid{gap:1.5rem 1rem;}
}
@media (min-width:900px){
  .catalog-grid{grid-template-columns:repeat(3,minmax(0,1fr));}
  /* Сдвиг чётных — margin-top, а не transform: transform карточек
     занят анимацией появления в motion.js, конфликт запрещён */
  .catalog-grid .card:nth-child(even){margin-top:2.5rem;}
}
@media (min-width:1200px){
  .catalog-grid{grid-template-columns:repeat(4,minmax(0,1fr));}
}

/* ─── Карточка ─── */
.card{
  position:relative;
  cursor:pointer;
}
.card:focus-visible{outline:2px solid var(--chrome-mid); outline-offset:4px;}

/* .card-media НЕ позиционирован намеренно: его overflow:hidden режет
   только картинку (она в потоке), а абсолютные дети (нимб, блик)
   считаются от .card и НЕ обрезаются — так нимб может висеть НАД
   верхом карточки. Не добавлять сюда position:relative. */
.card-media{
  aspect-ratio:3/4;
  overflow:hidden;
  background:var(--bg-2);
  border:1px solid var(--line);
  transition:border-color .45s;
}
/* Виньетка поверх фото: белофонные товарные снимки «усаживаются» в тёмную
   сетку и не вспыхивают прямоугольниками. Псевдоэлемент позиционируется
   от .card (media не позиционирован — см. комментарий выше), геометрия
   повторяет медиа-область тем же приёмом, что и блик ::after. */
.card-media::before{
  content:'';
  position:absolute;
  left:0; top:0;
  width:100%;
  aspect-ratio:3/4;
  pointer-events:none;
  z-index:1;
  box-shadow:inset 0 0 0 1px rgba(5,5,8,.18), inset 0 -52px 74px rgba(5,5,8,.24), inset 0 30px 60px rgba(5,5,8,.10);
}
.card-media img{
  display:block;
  width:100%;
  height:100%;
  object-fit:cover;
  transition:transform .6s var(--ease-out);
}
.card:hover .card-media,
.card:focus-visible .card-media{border-color:rgba(201,201,218,.5);}
.card:hover .card-media img,
.card:focus-visible .card-media img{transform:scale(1.06);}

/* Блик сверху при ховере. Геометрия повторяет медиа-область
   (width 100% + тот же aspect-ratio), потому что позиционируется от .card */
.card-media::after{
  content:'';
  position:absolute;
  left:0;
  top:0;
  width:100%;
  aspect-ratio:3/4;
  background:linear-gradient(180deg, rgba(255,255,255,.14), rgba(255,255,255,0) 38%);
  opacity:0;
  transition:opacity .45s;
  pointer-events:none;
}
.card:hover .card-media::after,
.card:focus-visible .card-media::after{opacity:1;}

/* Нимб: светящееся кольцо-эллипс, всплывает над верхом карточки */
.card-halo{
  position:absolute;
  left:50%;
  top:0;
  width:70%;
  aspect-ratio:4.2/1;
  border:1px solid var(--chrome-mid);
  border-radius:50%;
  opacity:0;
  transform:translate(-50%,calc(-52% + 8px));
  transition:opacity .45s var(--ease-out), transform .45s var(--ease-out), box-shadow .45s;
  pointer-events:none;
}
.card:hover .card-halo,
.card:focus-visible .card-halo{
  opacity:1;
  transform:translate(-50%,-52%);
  box-shadow:
    0 0 18px rgba(201,201,218,.35),
    inset 0 0 14px rgba(255,255,255,.14);
}

.card-meta{padding-top:.9rem;}
.card-title{
  margin:0;
  font-size:.95rem;
  font-weight:600;
  line-height:1.35;
  color:var(--ink);
}
.card-info{
  margin:.4rem 0 0;
  display:flex;
  justify-content:space-between;
  align-items:baseline;
  gap:.75rem;
}
.card-size{
  min-height:1em;                  /* пустой размер не роняет строку */
  font-size:11px;
  text-transform:uppercase;
  letter-spacing:.14em;
  color:var(--muted);
}
.card-price{
  font-variant-numeric:tabular-nums;
  font-weight:600;
  color:var(--chrome-mid);
  white-space:nowrap;
}

/* ─── «Показать ещё» ─── */
.catalog-more{
  display:flex;
  justify-content:center;
  gap:1rem;
  margin-top:3rem;
}

/* ─── Quick-view ─── */
.qv{
  position:fixed;
  inset:0;
  z-index:90;
  display:grid;
  place-items:center;
  padding:1.25rem;
}
.qv-backdrop{
  position:absolute;
  inset:0;
  background:rgba(5,5,8,.8);
  -webkit-backdrop-filter:blur(8px);
  backdrop-filter:blur(8px);        /* статичный, не в кадровом цикле */
  opacity:0;
  transition:opacity .4s;
}
.qv.is-open .qv-backdrop{opacity:1;}
.qv-panel{
  position:relative;
  z-index:1;
  width:min(920px,94vw);
  /* height:auto, а не фиксированные 620px: жёсткая высота растягивала
     правую колонку и оставляла ~140px пустоты между ценой и кнопками
     (кнопки прижаты margin-top:auto). Теперь панель по содержимому,
     потолок остаётся прежним. */
  height:auto;
  max-height:min(620px,90vh);
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  /* Строка minmax(0,1fr), а не auto: при height:auto она равна содержимому
     (панель по контенту, дыры нет), а когда max-height упирается в низкий
     экран — сжимается до потолка, и правая колонка прокручивается сама,
     вместо того чтобы уехать под overflow:hidden вместе с кнопками. */
  grid-template-rows:minmax(0,1fr);
  background:var(--bg-2);
  border:1px solid var(--line);
  overflow:hidden;
  transform:translateY(24px);
  opacity:0;
  transition:transform .4s var(--ease-out), opacity .4s var(--ease-out);
}
.qv.is-open .qv-panel{transform:none; opacity:1;}
.qv-img{
  width:100%;
  height:100%;
  object-fit:cover;
  background:var(--bg);
}
.qv-info{
  display:flex;
  flex-direction:column;
  gap:1rem;
  padding:2rem;
  overflow-y:auto;
}
.qv-cat{
  margin:0;
  font-size:11px;
  text-transform:uppercase;
  letter-spacing:.24em;
  color:var(--muted);
}
.qv-title{
  margin:0;
  font-family:var(--font-display),sans-serif;
  font-weight:600;
  font-size:1.6rem;
  line-height:1.2;
}
.qv-row{
  margin:0;
  display:flex;
  gap:2rem;
  align-items:baseline;
  font-family:var(--font-display),sans-serif;
  font-size:1.35rem;
  font-variant-numeric:tabular-nums;
  color:var(--ink);
}
.qv-size{color:var(--muted);}
.qv-size:empty{display:none;}
/* Цена — первое, что должно прочитаться в окне. До правки она шла тем же
   кеглем и весом, что «размер M», и отличалась только цветом. */
.qv-price{
  font-size:2.2rem;
  font-weight:600;
  line-height:1;
  letter-spacing:-.01em;
  color:var(--ink);
  white-space:nowrap;
}
.qv-actions{
  margin-top:auto;
  display:flex;
  flex-wrap:wrap;
  gap:.75rem;
}
.qv-actions .btn{flex:1 1 auto; text-align:center;}
.qv-close{
  position:absolute;
  top:1rem;
  right:1rem;
  z-index:2;
  width:44px;
  height:44px;
  display:grid;
  place-items:center;
  border:1px solid var(--line);
  border-radius:50%;
  background:rgba(5,5,8,.6);
  color:var(--ink);
  font-size:1rem;
  cursor:pointer;
  transition:color .3s, border-color .3s;
}
.qv-close:hover{color:var(--blood); border-color:var(--blood);}
.qv-close:focus-visible{outline:2px solid var(--chrome-mid); outline-offset:3px;}

/* Мобильный quick-view: шторка снизу, одна колонка */
@media (max-width:859px){
  .qv{
    display:flex;
    align-items:flex-end;
    justify-content:center;
    padding:0;
  }
  .qv-panel{
    width:100vw;
    height:auto;
    /* svh, а не vh: в Safari vh считается по свёрнутой панели браузера,
       и низ шторки (кнопка «Хочу») уезжает под адресную строку */
    max-height:92svh;
    grid-template-columns:1fr;
    /* Явная раскладка нужна крестику: он живёт в ячейке кадра и потому
       не отъедает отдельную полосу сверху (см. .qv-close ниже) */
    grid-template-rows:auto auto;
    border-radius:20px 20px 0 0;
    border-inline:0;
    border-bottom:0;
    overflow-y:auto;
    transform:translateY(100%);
  }
  .qv-img{aspect-ratio:4/5; height:auto; grid-column:1; grid-row:1;}
  /* «размер S/M» и цена в одну строку: при 1.35rem и зазоре 2rem подпись
     переносилась, и хвост «S/M» уезжал под полосу кнопок. 1rem — это 16px,
     нижняя граница читаемого текста, и заодно честная иерархия: цена 35px
     против подписи 16px. */
  .qv-row{gap:1rem; font-size:1rem;}
  .qv-info{
    grid-column:1;
    grid-row:2;
    /* верх и межстрочные зазоры плотнее десктопных: липкая полоса кнопок
       занимает низ шторки, и на прежних отступах цена приходилась ровно
       на её кромку — резалась пополам на всех карточках с двухстрочным
       названием. 22px экономии поднимают цену над полосой. */
    padding:.75rem 1.25rem 2rem;
    gap:.7rem;
    /* overflow:visible обязателен. С overflow-y:auto сам .qv-info становится
       скролл-контейнером, и sticky-кнопки прилипали бы к его собственному
       низу, то есть никуда. Прокрутка на мобильном принадлежит .qv-panel. */
    overflow:visible;
  }
  /* Кнопка «Хочу — написать» всегда на экране: без этого она уходила
     на 277px ниже сгиба, и главное действие приходилось искать прокруткой.
     Фото при этом не ужимается — панель по-прежнему прокручивается. */
  .qv-actions{
    position:sticky;
    bottom:0;
    z-index:1;
    background:var(--bg-2);
    padding-block:.75rem;
    margin-inline:-1.25rem;
    padding-inline:1.25rem;
    /* волосяная линия и мягкая тень: под полосой проезжает текст, и без
       границы обрез строки читался как сбой отрисовки, а не как док */
    border-top:1px solid var(--line);
    box-shadow:0 -14px 18px -10px rgba(5,5,8,.95);
  }
  /* Крестик: absolute ехал вместе с содержимым, потому что скролл-контейнером
     стала сама панель. sticky держит его в кадре. Ячейка 1/2 строки — это
     весь столбец панели, поэтому липкости есть куда двигаться, а кадр
     крестик не сдвигает: он лежит поверх фото. */
  .qv-close{
    position:sticky;
    top:1rem;
    right:auto;
    grid-column:1;
    grid-row:1 / span 2;
    align-self:start;
    justify-self:end;
    margin:1rem 1rem 0 auto;
    z-index:3;
  }
}

/* ═══════════════════════════════════════════════════════════════════
   СЦЕНА 4. КАСТОМ — пин-сцена: три вещи крупным планом, текст сбоку
   ═══════════════════════════════════════════════════════════════════ */
.s-custom{
  position:relative;
  min-height:100vh;
  display:grid;
  grid-template-columns:minmax(0,1fr);
  gap:clamp(2.5rem,6vw,5rem);
  align-items:center;
  max-width:1360px;
  margin-inline:auto;
}
@media (min-width:900px){
  .s-custom{grid-template-columns:minmax(0,1fr) minmax(0,1fr);}
}

.custom-stage{
  position:relative;
  width:100%;
  aspect-ratio:3/4;
  max-height:78vh;
  /* держим пропорцию, когда упёрлись в 78vh по высоте */
  max-width:calc(78vh * 3 / 4);
  margin-inline:auto;
}
/* Угловые метки-фоторамки — на стейдже, а не на кадрах:
   при кроссфейде кадров рамка стоит неподвижно */
.custom-stage::before,
.custom-stage::after{
  content:'';
  position:absolute;
  width:22px;
  height:22px;
  pointer-events:none;
}
.custom-stage::before{
  top:-8px; left:-8px;
  border-top:1px solid var(--chrome-mid);
  border-left:1px solid var(--chrome-mid);
}
.custom-stage::after{
  bottom:-8px; right:-8px;
  border-bottom:1px solid var(--chrome-mid);
  border-right:1px solid var(--chrome-mid);
}
.custom-shot{
  position:absolute;
  inset:0;
  margin:0;
  opacity:0;
  transform:scale(.96);
  transition:none;                  /* кроссфейдом управляет GSAP */
}
/* Фолбэк без JS: первый кадр помечен is-active в разметке и виден */
.custom-shot.is-active{opacity:1; transform:none;}
.custom-shot img{
  display:block;
  width:100%;
  height:100%;
  object-fit:cover;
  border:1px solid var(--line);
}
/* Виньетка поверх кадра — тем же приёмом, что у карточек каталога
   (.card-media::before): белый студийный фон пробивал в чёрной странице
   светлый прямоугольник. Затемняем края и низ, кроп и насыщенность самого
   снимка не трогаем. Тень статичная, в кадровый цикл не попадает;
   pointer-events:none — клики и ховер идут насквозь. */
.custom-shot::after{
  content:'';
  position:absolute;
  inset:0;
  pointer-events:none;
  z-index:1;
  box-shadow:
    inset 0 0 0 1px rgba(5,5,8,.20),
    inset 0 -78px 96px rgba(5,5,8,.30),
    inset 0 44px 76px rgba(5,5,8,.16),
    inset 70px 0 90px rgba(5,5,8,.18),
    inset -70px 0 90px rgba(5,5,8,.18);
}

.custom-copy{
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:1.5rem;
}
.custom-copy .sec-title{font-size:clamp(2.6rem,6vw,5rem);}
.custom-copy .sec-over{margin-bottom:0;}
.custom-text{
  margin:0;
  max-width:44ch;
  font-size:1.05rem;
  line-height:1.7;
  color:var(--muted);
}

/* Шаги кастома: свои номера, активный подсвечивается серебряной чертой */
.custom-steps{
  list-style:none;
  counter-reset:cstep;
  margin:0;
  padding:0;
  align-self:stretch;
}
.custom-steps li{
  counter-increment:cstep;
  position:relative;
  padding:.85rem 0 .85rem 1.4rem;
  color:var(--muted);
  line-height:1.5;
  transition:color .4s;
}
.custom-steps li::before{
  content:counter(cstep,decimal-leading-zero);
  /* Пропорциональные цифры давали разную ширину номера, и текст шагов
     начинался с трёх разных краёв. Табличные цифры + фиксированная
     колонка выравнивают старт строки. */
  display:inline-block;
  min-width:2.4ch;
  font-variant-numeric:tabular-nums;
  margin-right:.75em;
  font-family:var(--font-display),sans-serif;
  font-size:.7rem;
  letter-spacing:.08em;
  /* --chrome-lo давал 4.16:1 (а в демоне 1.86:1) — мелкому тексту нужен muted */
  color:var(--muted);
}
/* Черта слева рисуется transform-ом (scaleY), а не border —
   border не анимируется без перерисовки макета */
.custom-steps li::after{
  content:'';
  position:absolute;
  left:0;
  top:18%;
  bottom:18%;
  width:1px;
  background:linear-gradient(180deg, var(--chrome-hi), var(--chrome-lo));
  transform:scaleY(0);
  transform-origin:top;
  transition:transform .45s var(--ease-out);
}
.custom-steps li.is-on{color:var(--ink);}
.custom-steps li.is-on::after{transform:scaleY(1);}

/* ═══════════════════════════════════════════════════════════════════
   СЦЕНА 5. ЧЁРНЫЙ ХОД (.s-shop) — темнее, неон, маршрут
   ═══════════════════════════════════════════════════════════════════ */
.s-shop{
  background:linear-gradient(180deg,
    var(--bg) 0%, var(--bg-2) 22%, var(--bg-2) 78%, var(--bg) 100%);
}

/* Неоновая вывеска: единственное место, где алый горит в полную силу.
   Свечение — многослойный статичный text-shadow, мерцание — opacity
   шагами (steps), без filter. */
.shop-neon{text-align:center; margin-bottom:.75rem;}
.neon-sign{
  display:inline-block;
  font-size:clamp(1.4rem,4vw,2.6rem);
  color:var(--blood);
  text-shadow:
    0 0 6px  rgba(255,46,60,.9),
    0 0 18px rgba(255,46,60,.55),
    0 0 46px rgba(255,46,60,.35),
    0 0 90px rgba(255,46,60,.2);
  animation:neon-flicker 5s steps(1,end) infinite;
}
@keyframes neon-flicker{
  0%   {opacity:1;}
  7%   {opacity:.62;}
  8%   {opacity:1;}
  9.5% {opacity:.7;}
  10.5%{opacity:1;}
  46%  {opacity:1;}
  47%  {opacity:.55;}
  48.5%{opacity:1;}
  81%  {opacity:1;}
  82%  {opacity:.8;}
  83%  {opacity:1;}
  100% {opacity:1;}
}

/* Маршрут: вертикальная нить с остановками */
.shop-route{
  max-width:560px;
  margin:clamp(3rem,7vh,4.5rem) auto 0;
  display:flex;
  flex-direction:column;
}
.route-step{
  display:grid;
  grid-template-columns:56px minmax(0,1fr);
  gap:1.25rem;
  align-items:center;
}
.route-step b{
  width:56px;
  height:56px;
  display:grid;
  place-items:center;
  border:1px solid var(--line);
  border-radius:50%;
  background:rgba(255,255,255,.02);
  font-family:var(--font-display),sans-serif;
  font-weight:600;
  font-size:.8rem;
  letter-spacing:.02em;
  color:var(--chrome-mid);
}
.route-step p{
  margin:0;
  color:var(--muted);
  line-height:1.55;
}
.route-step p strong{
  color:var(--ink);
  font-weight:600;
}
/* Нить между остановками; scaleY рисует motion.js, дефолт — видимая */
.route-line{
  width:1px;
  height:64px;
  margin-left:27.5px;               /* центр колонки иконок 56px */
  background:linear-gradient(180deg, var(--chrome-mid), var(--chrome-lo));
  transform-origin:top;
}
/* Финальная остановка — залитый серебром круг */
.route-step.is-final b{
  background:linear-gradient(160deg,
    var(--chrome-hi) 0%, var(--chrome-mid) 55%, var(--chrome-lo) 100%);
  border-color:transparent;
  color:#0b0b12;
  box-shadow:0 0 24px rgba(201,201,218,.35);
}

/* Часы работы */
.shop-hours{
  display:flex;
  justify-content:center;
  margin:clamp(3rem,7vh,4.5rem) auto 0;
}
.shop-hours > div{
  padding-inline:clamp(1.5rem,5vw,3rem);
  text-align:center;
}
.shop-hours > div + div{border-left:1px solid var(--line);}
.shop-hours dt{
  font-size:11px;
  text-transform:uppercase;
  letter-spacing:.24em;
  color:var(--muted);
}
.shop-hours dd{
  margin:.5rem 0 0;
  font-family:var(--font-display),sans-serif;
  font-weight:500;
  font-size:clamp(1.25rem,3vw,1.85rem);
  font-variant-numeric:tabular-nums;
  color:var(--ink);
  white-space:nowrap;
}

/* ═══════════════════════════════════════════════════════════════════
   СЦЕНА 6. ЗАКАЗ
   ═══════════════════════════════════════════════════════════════════ */
.s-order{text-align:center;}
.order-steps{
  list-style:none;
  max-width:640px;
  margin:0 auto;
  padding:0;
  text-align:left;
}
.order-steps li{
  display:flex;
  align-items:baseline;
  gap:1.5rem;
  padding:1.5rem .5rem;
  font-size:1.1rem;
  line-height:1.55;
  color:var(--ink);
  border-top:1px solid var(--line);
}
.order-steps li:last-child{border-bottom:1px solid var(--line);}
.order-steps li span{
  /* Фиксированная колонка номера + табличные цифры: с flex:0 0 auto и
     пропорциональными цифрами текст трёх шагов стартовал с разных краёв
     (разброс 5px) */
  flex:0 0 2.25rem;
  font-variant-numeric:tabular-nums;
  font-family:var(--font-display),sans-serif;
  font-size:.9rem;
  letter-spacing:.1em;
  color:var(--chrome-mid);
}
.order-cta{
  margin-top:3rem;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:1rem;
}
.order-note{
  margin:0;
  font-size:12px;
  letter-spacing:.06em;
  color:var(--muted);
}

/* ═══════════════════════════════════════════════════════════════════
   АДАПТИВ: узкие экраны
   ═══════════════════════════════════════════════════════════════════ */
@media (max-width:700px){
  /* Луна крупнее и выше: узкий диск целиком прятался за каплей,
     кадр терял контровой свет (арт-критика, mob-1) */
  .hero-moon{
    width:88vw;
    top:32%;
  }

  /* Hero: кнопки столбиком по центру, заголовок теснее */
  .hero-actions{
    flex-direction:column;
    align-items:center;
    gap:.85rem;
  }
  .hero-actions .btn{min-width:230px; text-align:center;}
  .hero-title .line:nth-child(1){left:.2em;}
  .hero-title .line:nth-child(2){left:-.12em;}

  /* Манифест: цифры столбиком, разделители — горизонтальные */
  .manifest-stats{flex-direction:column; align-items:center;}
  .manifest-stats li{padding:1.6rem 0;}
  .manifest-stats li + li{
    border-left:0;
    border-top:1px solid var(--line);
  }

  /* Часы работы: в строку два блока сжимались, и «14:00» обрезалось до
     «4:00». Столбиком, разделитель — горизонтальный (тот же приём, что
     у .manifest-stats выше) */
  .shop-hours{
    flex-direction:column;
    gap:1.5rem;
  }
  .shop-hours > div + div{
    border-left:0;
    border-top:1px solid var(--line);
    padding-top:1.5rem;
  }

  /* «Показать ещё» столбиком */
  .catalog-more{flex-direction:column; align-items:center;}
  .catalog-more .btn{min-width:250px; text-align:center;}

  /* Кастом: сцена компактнее, кнопка на всю ширину не нужна */
  .custom-stage{max-height:62vh; max-width:calc(62vh * 3 / 4);}

  /* Маршрут: круги мельче, нить короче */
  .route-step{grid-template-columns:48px minmax(0,1fr); gap:1rem;}
  .route-step b{width:48px; height:48px; font-size:.72rem;}
  .route-line{height:48px; margin-left:23.5px;}

  /* Заказ: номера над текстом не переносим, только теснее */
  .order-steps li{gap:1rem; padding:1.25rem .25rem; font-size:1rem;}
}

/* ═══════════════════════════════════════════════════════════════════
   Сниженная анимация: гасим все фоновые циклы, статика остаётся
   ═══════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion:reduce){
  .hero-stars::before,
  .hero-stars::after,
  .hero-grain,
  .hint-line::after,
  .neon-sign{animation:none;}
  .card-media img{transition:none;}
  .card:hover .card-media img,
  .card:focus-visible .card-media img{transform:none;}
  .card-halo{transition:opacity .2s;}
  .qv-panel,
  .qv-backdrop{transition:opacity .2s;}
  .qv-panel{transform:none;}
}
