/* ==========================================================================
   Вариант A — «a-cinematic»: тёмный зал.

   Идея: сайт как один непрерывный проезд камеры. Палитра «Песок и море»
   пере-взвешена в тёмную сторону — чернила прототипа (--ink) становятся
   фоном, песок (--bg) становится текстом. Фотографии — единственные
   источники света. Хром минимальный: тонкая шапка, HUD только на время
   киносцены.

   Контраст проверен: python3 scripts/contrast.py
     песочный текст #f2e6cc на #16211f — 13.34:1
     приглушённый  #c2cdc4 на #16211f — 10.09:1
     тёплый акцент #ffce7a на #16211f — 11.30:1
     белый текст под пеленой .82 над белым небом — 10.72:1
   --deep (#0f6e84) на тёмном даёт 2.82:1 → в этом варианте служит только
   заливкой, никогда цветом текста.
   ========================================================================== */

.a {
  --page: #16211f;
  --page2: #1c2a27;
  --page3: #22322e;
  --text: #f2e6cc;
  --muted: #c2cdc4;
  --hair: rgba(242, 230, 204, 0.16);
  --dock-h: 0px;

  background: var(--page);
  color: var(--text);
}

/* Крупный текст в этом варианте — светлый песок, а не чернила. */
.a h1, .a h2, .a h3, .a h4 { color: var(--text); }
.a em { font-style: italic; color: var(--heroem); }
.a a { color: var(--heroem); }
.a a:hover { color: var(--accent); }

/* Тонкая зернистость поверх плоских тёмных плоскостей: атмосфера
   киноплёнки, ноль байт (SVG-шум в data-URI). */
.a::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 0.05;
  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='3'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ==== Общие мелочи варианта ============================================== */

.eyebrow {
  font-size: var(--t-micro);
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 var(--s-3);
}
.eyebrow--warm { color: var(--heroem); }
.eyebrow--photo { color: var(--onphoto-soft); }

.sec__head { max-width: 46ch; margin: 0 auto var(--s-7); text-align: center; }
.sec__head h2 { font-size: var(--t-h2); }
.sec__hint { color: var(--muted); font-size: var(--t-small); margin-top: var(--s-3); }

.lead { font-size: var(--t-lead); color: var(--text); }

.btn--ghost-dark { border-color: var(--hair); color: var(--text); }
.btn--ghost-dark:hover { background: var(--text); color: var(--page); border-color: var(--text); }
.btn--ghost-warm { border-color: var(--heroem); color: var(--heroem); }
.btn--ghost-warm:hover { background: var(--heroem); color: var(--onaccent); }

/* Появление секций. Класс на <body> ставит script.js — без JS содержимое
   просто видно сразу, ничего не прячется навсегда. */
.has-reveal .reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
}
.has-reveal .reveal.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .has-reveal .reveal { opacity: 1; transform: none; }
}

/* ==== Шапка ==============================================================
   Требование оси 3: не выше 64px на 390px. Здесь — одна строка,
   flex-wrap запрещён, поэтому переноса в три строки (дефект прототипа)
   структурно не может произойти.
   ========================================================================= */

.hdr {
  /* sticky, не fixed: шапка растёт на второй ряд при увеличенном тексте
     (см. margin-left: auto у .hdr__cta ниже), а margin-top баннера-
     поздравления держал ЗАФИКСИРОВАННЫЕ 56px независимо от реального роста —
     на 200% масштабе шапка становилась ~130px, а баннер начинался на 56px
     и первая строка поздравления пряталась под шапкой (наложение). sticky
     сама резервирует место под себя в потоке документа, каким бы ни было
     реальное число строк — компенсирующий отступ у .bday больше не нужен
     ни при каком масштабе. Визуально неотличимо от fixed: шапка первый же
     дочерний элемент body, поэтому её natural-flow позиция и так y=0, а
     .a::before/.cine__stage sticky уже требуют body{overflow-x:clip} вместо
     hidden именно для того, чтобы sticky здесь работала (см. tokens.css). */
  position: sticky;
  inset: 0 0 auto 0;
  z-index: 60;
  min-height: var(--header-h);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  row-gap: var(--s-2);
  column-gap: var(--s-4);
  padding: 0 var(--gut);
  background: rgba(18, 27, 26, 0.86);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--hair);
}

.hdr__brand {
  font-family: var(--serif);
  font-size: 1.22rem;
  letter-spacing: 0.04em;
  color: var(--text);
  white-space: nowrap;
  margin-right: auto;
  /* min-height ради тап-таргета 44px внутри 56-пиксельной шапки. */
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
}
.hdr__brand em { color: var(--heroem); }

.hdr__nav {
  display: flex;
  align-items: center;
  gap: clamp(0.9rem, 2vw, 1.8rem);
  font-size: var(--t-micro);
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  white-space: nowrap;
}
.hdr__nav a { color: var(--muted); padding: var(--s-2) 0; }
.hdr__nav a:hover { color: var(--heroem); }

.hdr__cta {
  font-size: var(--t-micro);
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  color: var(--heroem);
  border: 1px solid var(--heroem);
  border-radius: var(--rad-pill);
  padding: 0 var(--s-4);
  min-height: var(--tap);
  white-space: nowrap;
  /* Держит cta+menu прижатыми к правому краю их собственной строки, если
     шапка переносится на вторую строку при увеличенном тексте (см. .hdr
     flex-wrap): без этого margin-right:auto у .hdr__brand работает только
     пока всё в одну строку — на второй строке бренда уже нет, толкать
     cta/menu вправо больше нечему, и .menu__panel (right:0 от .menu)
     уезжает якорем в середину экрана, а не к правому краю. */
  margin-left: auto;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.hdr__cta:hover { background: var(--heroem); color: var(--onaccent); }

/* Мобильное меню на <details> — работает без JS и с клавиатуры. */
.menu { display: none; position: relative; }
.menu__btn {
  list-style: none;
  cursor: pointer;
  border-radius: var(--rad-pill);
  border: 1px solid var(--hair);
}
.menu__btn::-webkit-details-marker { display: none; }
.menu__bars,
.menu__bars::before,
.menu__bars::after {
  display: block;
  width: 18px;
  height: 1.5px;
  background: var(--text);
  content: "";
}
.menu__bars { position: relative; }
.menu__bars::before { position: absolute; top: -6px; }
.menu__bars::after { position: absolute; top: 6px; }
.menu[open] .menu__bars { background: var(--heroem); }

/* .menu — <details>: браузер нативно прячет всё, кроме <summary>, пока нет
   [open]. display: grid без привязки к [open] перебивал это нативное
   скрытие — закрытая панель получала реальную геометрию и хит-тестировалась
   (тот же дефект, что чинили для .ctab__panel в D, коммит 0939e4f, не
   распространили на этот структурно идентичный компонент). */
/* Явное скрытие обязательно, одного ограничения правила [open] мало: замерено
   при закрытом меню — display оставался block, а прямоугольник 44x881, почти
   во всю высоту страницы. Причина: элементу когда-либо задавали явный display,
   и браузер выводит такой элемент из-под родного скрытия закрытого <details>
   насовсем, даже когда правило с этим значением уже не совпадает. */
.menu__panel { display: none; }
.menu[open] .menu__panel {
  position: absolute;
  right: 0;
  top: calc(100% + 10px);
  /* 12rem удваивается вместе с текстом при увеличении шрифта до 200%, но
     .menu сидит у самого правого края шапки — без предела панель толкает
     свой левый край за пределы экрана на узких вьюпортах (было видно как
     обрезанные слева пункты меню). min-width обычной формы здесь не
     годится: если 12rem (после удвоения — 24rem) окажется БОЛЬШЕ этого
     предела, спецификация отдаёт приоритет min-width и max-width
     полностью игнорируется — поэтому оба предела в одном width: min(). */
  width: min(12rem, calc(100vw - 2 * var(--gut)));
  display: grid;
  background: rgba(20, 30, 28, 0.98);
  border: 1px solid var(--hair);
  border-radius: var(--rad);
  box-shadow: var(--shadow-lift);
  overflow: hidden;
}
.menu__panel a {
  padding: 0 var(--s-5);
  min-height: var(--tap);
  display: flex;
  align-items: center;
  color: var(--text);
  font-size: var(--t-small);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--hair);
}
.menu__panel a:last-child { border-bottom: 0; color: var(--heroem); }
.menu__panel a:hover { background: var(--page3); }

@media (max-width: 860px) {
  .hdr__nav { display: none; }
  .menu { display: block; }
}
@media (max-width: 420px) {
  /* На самых узких — оставляем бренд, «Связаться» и меню; всё в одну строку. */
  .hdr { gap: var(--s-2); padding: 0 var(--s-4); }
  .hdr__brand { font-size: 1.05rem; }
  .hdr__cta { padding: 0 var(--s-3); font-size: 0.66rem; }
}

/* ==== Киносцена ==========================================================
   По умолчанию — обычный статичный герой: один кадр, без высокого трека
   и HUD, ровно то же самое, что раньше жило только под
   prefers-reduced-motion. Скролл-скрабинг (липкая сцена, высокий трек,
   шесть кадров, HUD) включает СКРИПТ при инициализации, добавляя класс
   .cine--scroll на секцию — тот же приём, что .has-reveal для появления
   блоков (см. выше). Раньше было наоборот: CSS безусловно резервировал
   420vh прокрутки, а кадры переключал только скрипт — без JS страница
   зависала на ~3780px (4.2 экрана) визуально мёртвой прокрутки, прежде
   чем секция отпускала. Теперь без скрипта (или при reduced-motion, JS
   намеренно не добавляет класс) секция — обычная 100svh-высотой шапка,
   прокрутка сразу уходит к следующему разделу.
   ========================================================================= */

.cine { position: relative; }
.cine__stage {
  position: relative;
  /* min-height, не height: — то же самое 100svh «полотно» при обычном
     кегле (контент короче полотна, min-height и есть итоговая высота), но
     без жёсткого потолка. При увеличении текста до 200% .cine__copy
     (заголовок + лид + две кнопки, втрое выше себя же) раньше физически
     не помещался в фиксированные 100svh: копия была position: absolute с
     bottom-отступом, поэтому росла ВВЕРХ за пределы сцены, а overflow:
     hidden просто обрезал всё, что вылезло — заголовок исчезал целиком,
     а видимый обрубок текста геометрически перекрывался с шапкой/скип-
     линком (та самая «фантомная» находка sweep-инструмента: оба участника
     невидимы, но их геометрия всё равно пересекается). Теперь .cine__copy
     ниже — обычный (не абсолютный) флекс-элемент, его высота участвует в
     высоте сцены: сцена растёт вместе с текстом, ничего не обрезается и
     нечему становиться invisible-но-геометрически-пересекающимся.
  */
  min-height: max(520px, 100svh);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  overflow: hidden;
  isolation: isolate;
}
.cine__track { height: 0; }

.cine--scroll .cine__stage { position: sticky; top: 0; }
.cine--scroll .cine__track { height: 420vh; }

.cine__frames { position: absolute; inset: 0; }
.cine__frame {
  position: absolute;
  inset: 0;
  opacity: 0;
  will-change: opacity, transform;
  display: none;
}
.cine__frame[data-frame="0"] { display: block; }
.cine--scroll .cine__frame { display: block; }
.cine__frame.is-on { opacity: 1; }
.cine__frame picture { display: block; height: 100%; }
.cine__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 45%;
}

/* Пелена — ДВА полноэкранных слоя, без локальных подложек: любая коробка
   меньше кадра оставляет видимый шов (проверено скриншотом).
   Вертикальный слой ведёт кадр к тёмному низу, диагональный притемняет
   левую нижнюю четверть, где живут заголовок и CTA. В сумме там ≥ 0.85
   плотности → белый текст держит ≥ 10:1 даже над белым небом.
   Счёт: python3 scripts/contrast.py --stack '#ffffff' '#ffffff' 0e1516:0.66 0c1314:0.56 */
.cine__veil {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(102deg,
      rgba(12, 19, 20, 0.56) 0%,
      rgba(12, 19, 20, 0.34) 38%,
      rgba(12, 19, 20, 0.08) 62%,
      rgba(12, 19, 20, 0) 78%),
    linear-gradient(180deg,
      rgba(14, 21, 22, 0.44) 0%,
      rgba(14, 21, 22, 0.14) 26%,
      rgba(14, 21, 22, 0.3) 46%,
      rgba(14, 21, 22, 0.66) 74%,
      rgba(14, 21, 22, 0.86) 100%);
}

.cine__copy {
  /* relative, не absolute: см. комментарий у .cine__stage — обычный флекс-
     элемент растягивает сцену под свою реальную высоту вместо того, чтобы
     вылезать за её пределы. position: relative оставлена ради z-index (сама
     по себе .cine__stage — flex, выравнивание copy к низу даёт
     justify-content: flex-end на сцене, а прежний bottom-отступ живёт
     теперь в margin-bottom — то же расстояние от низа полотна). */
  position: relative;
  z-index: 3;
  margin-bottom: calc(var(--dock-h) + 2.5rem);
  padding: 0 var(--gut);
  max-width: 60rem;
  color: var(--onphoto);
}
.cine--scroll .cine__copy { margin-bottom: calc(var(--dock-h) + 5.5rem); }
.cine__copy .eyebrow { margin-bottom: var(--s-4); }

.cine__h1 {
  font-size: var(--t-h1);
  line-height: var(--lh-tight);
  color: var(--onphoto);
  margin: 0;
  text-shadow: 0 2px 26px rgba(10, 16, 17, 0.5);
}
.cine__h1 span { display: block; }
.cine__h1 em { color: var(--heroem); }

.cine__sub {
  margin: var(--s-5) 0 0;
  max-width: 40ch;
  font-size: var(--t-lead);
  color: var(--onphoto);
  text-shadow: 0 1px 18px rgba(10, 16, 17, 0.6);
}

.cine__actions {
  display: flex;
  gap: var(--s-4);
  flex-wrap: wrap;
  margin-top: var(--s-6);
}

/* Подпись к кадру: живёт в правом нижнем углу, над HUD. Видна только со
   скролл-скрабингом — без него меняющейся подписи нет, показывать нечего. */
.cine__cap {
  display: none;
  position: absolute;
  right: var(--gut);
  bottom: calc(var(--dock-h) + 4.6rem);
  z-index: 3;
  max-width: 22ch;
  text-align: right;
  font-family: var(--serif);
  font-size: var(--t-h4);
  line-height: 1.25;
  color: var(--onphoto-soft);
  text-shadow: 0 1px 16px rgba(10, 16, 17, 0.75);
  transition: opacity var(--dur) var(--ease);
}
.cine--scroll .cine__cap { display: block; }

/* HUD прокрутки — управляет кадрами, которых без скрипта не существует
   (сами кадры 1-5 достраивает hydrate() в script.js), поэтому без
   .cine--scroll HUD не просто визуально ни к чему, а ведёт себя мёртво:
   точки и «Экскурсия» ничего не переключают. Скрыт по умолчанию целиком. */
.cine__hud {
  display: none;
  position: absolute;
  left: 0;
  right: 0;
  bottom: var(--dock-h);
  z-index: 4;
  align-items: center;
  gap: var(--s-4);
  padding: var(--s-1) var(--gut);
  background: linear-gradient(to top, rgba(10, 16, 17, 0.6), transparent);
}
.cine--scroll .cine__hud { display: flex; }
/* flex-wrap: 6 точек по фиксированным var(--tap)=44px (тап-таргет, ему
   специально запрещено сжиматься зумом) + 5 зазоров по 6px = 294px —
   это уже впритык к 320-390px экрану на обычном кегле (умещается) и
   перестаёт умещаться, как только --gut в .cine__hud подрастает на 200%
   масштабе: последняя точка вылезает за край всего документа, а не
   только за паддинг родителя. wrap — тот же приём, что уже применён к
   самому .cine__hud на ≤720px (перенос точек отдельной строкой): лишние
   точки уходят на вторую строку внутри своего собственного ряда, ни один
   тап-таргет не уменьшается и не пропадает за экран. На обычном кегле
   все 6 умещаются в одну строку — перенос не срабатывает, раскладка не
   меняется. */
.hud__dots { display: flex; flex-wrap: wrap; gap: 6px; }
.hud__dot {
  width: var(--tap);
  height: var(--tap);
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  display: grid;
  place-items: center;
}
.hud__dot::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.34);
  transition: background var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.hud__dot[aria-current="true"]::before { background: var(--heroem); transform: scale(1.5); }

.hud__bar {
  flex: 1;
  height: 2px;
  background: rgba(255, 255, 255, 0.22);
  border-radius: 2px;
  overflow: hidden;
}
.hud__fill {
  display: block;
  height: 100%;
  width: 0;
  background: var(--heroem);
}

.hud__tour {
  min-height: var(--tap);
  flex-shrink: 0;                         /* никогда не сжимать подпись меньше её текста */
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.28);
  color: var(--onphoto);
  border-radius: var(--rad-pill);
  padding: 0 var(--s-4);
  font-size: var(--t-micro);
  letter-spacing: var(--tr-wide);
  text-transform: uppercase;
  cursor: pointer;
  white-space: nowrap;
  backdrop-filter: blur(8px);
}
.hud__tour[aria-pressed="true"] { background: var(--heroem); color: var(--onaccent); border-color: var(--heroem); }

/* Отдельный prefers-reduced-motion блок здесь больше не нужен: статичный
   герой — теперь и есть база по умолчанию (см. комментарий у .cine__stage
   выше), а script.js сам не добавляет .cine--scroll, когда matchMedia
   считает reduced-motion включённым — тот же результат без дублирования
   значений в двух местах. */

@media (max-width: 720px) {
  /* .cine--scroll .cine__cap перевешивает голый .cine__cap по
     специфичности (два класса против одного) независимо от порядка в
     файле — на мобильном нужно перебить его явно тем же селектором,
     иначе на узких экранах со скролл-скрабингом подпись снова появится
     и будет спорить с CTA. */
  .cine__cap,
  .cine--scroll .cine__cap { display: none; }          /* на мобильном не спорим с CTA */
  .cine__actions .btn { flex: 1 1 100%; }

  /* Точки + полоса + кнопка в один ряд не помещаются на узких экранах:
     6 тач-таргетов по 44px уже съедают весь гут. Переносим точки на
     отдельную строку, чтобы полоса и «Экскурсия» не сжимали друг друга
     и подпись кнопки не резалась о край экрана. */
  .cine__hud { flex-wrap: wrap; row-gap: var(--s-1); }
  .hud__dots { flex: 1 0 100%; justify-content: center; }

  /* margin-bottom здесь и раньше был константой (dock-h + 4.2rem), сама
     подобранной под HUD в ОДНУ строку (padding-top + ряд + padding-bottom
     ≈ 2 * var(--s-1) + var(--tap)). Правило .cine__hud{flex-wrap} прямо
     над этим блоком переносит точки на СВОЮ строку — HUD стал в две
     строки, а резерв под ним остался старым: замерено, что кнопка «Прайс
     и форматы» тонет под выросшим HUD (пересечение 33px) и под нижним
     доком (48px), document.elementFromPoint в центре кнопки не возвращал
     саму кнопку ни на scrollY=0, ни в середине сцены. Реальная высота HUD
     в две строки = padding-top + ряд точек + row-gap + ряд полосы/кнопки +
     padding-bottom = 3 * var(--s-1) + 2 * var(--tap) — считаем её явно,
     вместо того чтобы держать отдельную константу, которая может снова
     разойтись с разметкой HUD при следующей правке. var(--s-4) сверху —
     видимый зазор между кнопкой и HUD, а не часть его высоты. */
  .cine__copy,
  .cine--scroll .cine__copy {
    margin-bottom: calc(var(--dock-h) + 3 * var(--s-1) + 2 * var(--tap) + var(--s-4));
  }
}

/* ==== Обо мне ============================================================ */

.about {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1fr);
  gap: clamp(2rem, 6vw, 5rem);
  align-items: center;
  padding: var(--sec-y) var(--gut);
  background: var(--page2);
}
.about__media { position: relative; max-width: 30rem; width: 100%; justify-self: end; }
.about__img { width: 100%; border-radius: var(--rad); }
/* Смещённая рамка прототипа переполняла узкие экраны, потому что уходила
   за левую границу. Здесь она внутри контейнера — inset только положительный. */
.about__media::after {
  content: "";
  position: absolute;
  inset: 0.9rem;
  border: 1px solid var(--accent);
  border-radius: var(--rad);
  pointer-events: none;
  mix-blend-mode: screen;
}
.about__text { max-width: var(--measure); }
.about__text h2 { font-size: var(--t-h2); margin-bottom: var(--s-4); }
.about__text p { color: var(--muted); margin-bottom: var(--s-4); }
.about__text .lead { color: var(--text); }

.about__facets {
  display: flex;
  gap: var(--s-6);
  flex-wrap: wrap;
  margin: var(--s-5) 0 var(--s-6);
}
.about__facets em {
  font-family: var(--serif);
  font-size: 1.3rem;
  color: var(--heroem);
  font-style: italic;
}
.about__facets span { display: block; font-size: var(--t-small); color: var(--muted); }

@media (max-width: 900px) {
  .about { grid-template-columns: 1fr; }
  .about__media { justify-self: center; }
}

/* ==== Прайс ============================================================== */

.price {
  position: relative;
  z-index: 2;
  padding: var(--sec-y) var(--gut);
  background:
    radial-gradient(120% 80% at 50% 0%, rgba(15, 110, 132, 0.35), transparent 70%),
    var(--page);
}
/* Мера 44ch стоит на самом h2, а не на обёртке: `ch` считается в шрифте того
   элемента, где записан, а у обёртки своего font-size нет — она наследует
   ~1rem от body, и 44ch резолвились примерно в 480px вместо меры заголовка,
   набранного var(--t-h2) (до 3.1rem). Заголовок ломался на две строки с
   висящим «и» в конце первой, хотя вокруг было свободно. Та же болезнь и то же
   лечение, что в c-gallery. */
.price__head { text-align: center; margin: 0 auto var(--s-7); }
.price__head h2 { font-size: var(--t-h2); max-width: 44ch; margin: 0 auto; }

.price__tiers {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  gap: var(--s-5);
  max-width: 60rem;
  margin: 0 auto var(--s-8);
}
.tier {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s-3);
  padding: var(--s-6);
  border: 1px solid var(--hair);
  border-radius: calc(var(--rad) + 4px);
  background: rgba(242, 230, 204, 0.04);
}
.tier--main { border-color: var(--accent); background: rgba(224, 123, 47, 0.1); }
.tier__name { font-size: var(--t-h3); }
.tier__sum {
  font-family: var(--serif);
  font-size: clamp(2rem, 4vw, 2.8rem);
  line-height: 1;
  color: var(--heroem);
}
.tier__sum strong { font-weight: 600; }
.tier__note { color: var(--muted); font-size: var(--t-small); flex: 1; }
.tier .btn { margin-top: var(--s-2); }

.price__lists {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
  gap: clamp(2rem, 5vw, 4rem);
  max-width: 60rem;
  margin: 0 auto;
}
.price__sub {
  font-size: var(--t-h4);
  font-weight: 600;
  padding-bottom: var(--s-2);
  margin-bottom: var(--s-4);
  border-bottom: 2px solid var(--heroem);
}
.price__list li {
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--hair);
  color: var(--text);
  display: flex;
  gap: var(--s-3);
}
.price__list li::before { content: "·"; color: var(--heroem); font-weight: 600; }
.price__fine { margin-top: var(--s-4); font-size: var(--t-small); color: var(--muted); font-style: italic; }

/* ==== Манифест =========================================================== */

.manifesto {
  position: relative;
  z-index: 2;
  padding: clamp(4.5rem, 12vh, 8rem) var(--gut);
  display: flex;
  justify-content: center;
  background: linear-gradient(180deg, var(--page), var(--page3));
  border-top: 1px solid var(--hair);
  border-bottom: 1px solid var(--hair);
}
/* Прототип ломал строки жёсткими <br>. Здесь текст течёт сам, а ритм задаёт
   ограниченная мера и balance. */
.manifesto__text {
  font-family: var(--serif);
  font-size: clamp(1.45rem, 3vw, 2.2rem);
  line-height: 1.45;
  max-width: 34ch;
  text-align: center;
  text-wrap: balance;
}

/* ==== Виды съёмок ======================================================== */

.services {
  position: relative;
  z-index: 2;
  padding: var(--sec-y) var(--gut);
  background: var(--page2);
}
/* Было repeat(auto-fit, minmax(min(100%, 16rem), 1fr)): на 1440 в 80rem-
   контейнере помещается 4 колонки по ширине, а карточек 6 — последний ряд
   рвётся на 4+2, и правая половина второго ряда пустует во всю ширину двух
   карточек. Явные счётные колонки по брейкпоинтам (вместо auto-fit) делят
   шесть карточек ровно на целые ряды: 3×2 на широких, 2×3 на средних
   (брейкпоинт 900px — тот же, что уже держит переход .about в одну колонку
   выше по файлу), 1×6 на узких (520px — тот же, что уже переключает размер
   .bday__text). aspect-ratio у .svc — от ширины колонки (см. комментарий у
   .svc), поэтому карточки увеличивают и высоту, и ширину пропорционально;
   жёсткой высоты нет, пересчитывать нечего. */
/* minmax(0, 1fr), не голый 1fr: у грид-трека тот же защитный дефолт
   minmax(auto, 1fr), что у флекс-айтема min-width: auto — колонка не сжимается
   ниже min-content своего содержимого. Замерено на 320px при 200% масштабе
   текста: подпись карточки требовала 288px, колонка раздувалась до них при
   доступных 240, и документ получал 8px горизонтальной прокрутки (нарушение
   WCAG 1.4.10). Тот же приём уже применён к нижнему доку в b-editorial. */
.svc__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s-4);
  max-width: 80rem;
  margin: 0 auto;
}
@media (max-width: 900px) {
  .svc__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 520px) {
  .svc__grid { grid-template-columns: minmax(0, 1fr); }
}
.svc {
  position: relative;
  /* flex-колонка вместо самостоятельных .svc__title/.svc__sub с
     собственными bottom-отступами в rem: на 200% масштабе оба текста
     растут (и сам шрифт, и rem-отступ вместе с ним), а карточка держит
     ВЫСОТУ через aspect-ratio (от ширины колонки, с зумом почти не
     меняется) — два независимых bottom-якоря наезжали друг на друга
     («Семейная» накрывала свою же подпись). flex-колонка складывает их
     в обычный поток, прижатый к низу карточки: сколько бы текст ни
     вырос, заголовок и подпись просто раздвигают друг друга, а не
     перекрываются.
     overflow здесь больше НЕ hidden (см. .svc picture / .svc::after
     ниже, куда переехало обрезание): раньше overflow:hidden на самой
     .svc не давало карточке вырасти выше aspect-ratio ни при каких
     обстоятельствах — при удлинившемся на 200% масштабе заголовке
     («Лавандовое поле» и т.п., переносится на вторую строку) блок
     title+sub физически не помещался в те же 320px и обрезанный низ
     подписи всё равно оставался в геометрии (getBoundingClientRect не
     знает про visual clipping) и ложно засчитывался как наложение со
     СЛЕДУЮЩЕЙ карточкой сеткой ниже. aspect-ratio теперь работает как
     МИНИМУМ высоты (используется, пока текст помещается), а не потолок:
     если тексту нужно больше места, карточка вырастает по-настоящему,
     и ничего никуда не заезжает. На обычном кегле все заголовки
     умещаются в одну строку и card ровно = aspect-ratio, как раньше. */
  display: flex;
  flex-direction: column;
  aspect-ratio: 3 / 4;
  border-radius: var(--rad);
  color: var(--onphoto);
  isolation: isolate;
}
/* picture поднят в absolute: без этого он стал бы обычным flex-элементом
   и делил бы высоту карточки с заголовком/подписью вместо того, чтобы
   заполнять её целиком фоном. overflow/border-radius, что раньше стояли
   на .svc, теперь здесь — обрезают только фото (и его hover-приближение),
   не мешая самой .svc расти вслед за текстом. */
.svc picture { position: absolute; inset: 0; border-radius: inherit; overflow: hidden; }
.svc__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-slow) var(--ease);
}
.svc:hover .svc__img,
.svc:focus-visible .svc__img { transform: scale(1.06); }
.svc::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(180deg, transparent 35%, rgba(10, 16, 17, 0.86) 100%);
}
.svc__num,
.svc__title,
.svc__sub { position: relative; z-index: 2; }
/* .svc__num раньше было position: absolute (top/left: var(--s-4)) —
   висело над карточкой независимо от того, сколько места ниже занял
   .svc__title/.svc__sub. На 200% масштабе более длинные заголовки
   («Лавандовое поле», «Закат у моря», «Старый Несебр») переносятся на
   вторую строку, блок title+sub (прижатый к низу) вырастает и его
   верхний край поднимается ВЫШЕ нижнего края бейджа с номером —
   абсолютное позиционирование ничего об этом не знает и оба текста
   просто накладывались. Бейдж возвращён в обычный поток первым flex-
   элементом (align-self: flex-start, чтобы не растягиваться на всю
   ширину, margin вместо top/left — та же визуальная позиция), а
   `margin-top: auto` на .svc__title забирает себе всё свободное место
   НАД собой, прижимая (title+sub) к низу лишь настолько, насколько
   реально осталось места. Отрицательным auto-margin не бывает — блок
   заголовка физически не может начаться раньше, чем закончится бейдж,
   при любой длине текста и любом масштабе; на обычном кегле свободного
   места с избытком, поэтому видимая раскладка не меняется. */
.svc__num {
  align-self: flex-start;
  margin: var(--s-4) 0 0 var(--s-4);
  font-size: var(--t-micro);
  letter-spacing: var(--tr-caps);
  color: var(--onphoto-soft);
}
.svc__title {
  padding: 0 var(--s-4);
  margin: auto 0 0.25rem;
  font-size: var(--t-h3);
  /* 600, а не 500: у Cormorant 500 своя пара subset-файлов (~50 КБ), а
     разницы на этом размере нет. Экономия — в шрифтовом бюджете. */
  font-weight: 600;
  color: var(--onphoto);
}
.svc__sub {
  padding: 0 var(--s-4) var(--s-4);
  font-size: var(--t-small);
  color: var(--onphoto-soft);
}

/* ==== Галерея ============================================================ */

.gallery {
  position: relative;
  z-index: 2;
  padding: var(--sec-y) var(--gut);
  background: var(--page);
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  justify-content: center;
  margin-bottom: var(--s-6);
}
.chip {
  min-height: var(--tap);
  padding: 0 var(--s-5);
  border: 1px solid var(--hair);
  border-radius: var(--rad-pill);
  background: transparent;
  color: var(--muted);
  font-size: var(--t-small);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
.chip:hover { color: var(--text); border-color: var(--text); }
.chip[aria-pressed="true"] {
  background: var(--heroem);
  border-color: var(--heroem);
  color: var(--onaccent);
}

.shots {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr));
  gap: var(--s-3);
  max-width: 80rem;
  margin: 0 auto;
}
.shot {
  position: relative;
  display: block;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  border-radius: var(--rad);
  overflow: hidden;
  aspect-ratio: 3 / 4;
  isolation: isolate;
}
.shot[hidden] { display: none; }
.shot__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-slow) var(--ease), filter var(--dur) var(--ease);
}
.shot:hover .shot__img,
.shot:focus-visible .shot__img { transform: scale(1.05); }
.shot__cap {
  position: absolute;
  inset: auto 0 0 0;
  padding: 2.4rem var(--s-3) var(--s-3);
  font-family: var(--serif);
  font-size: 1rem;
  line-height: 1.2;
  text-align: left;
  color: var(--onphoto);
  background: linear-gradient(180deg, transparent, rgba(10, 16, 17, 0.85));
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
}
.shot:hover .shot__cap,
.shot:focus-visible .shot__cap { opacity: 1; }

/* На тач-устройствах наведения нет — подпись показываем всегда. */
@media (hover: none) {
  .shot__cap { opacity: 1; }
}

/* ==== Призыв к действию ================================================== */

.cta {
  position: relative;
  z-index: 2;
  min-height: 60svh;
  display: grid;
  place-items: center;
  overflow: hidden;
  text-align: center;
  padding: var(--sec-y) var(--gut);
}
.cta picture { position: absolute; inset: 0; }
.cta__bg { width: 100%; height: 100%; object-fit: cover; object-position: 50% 40%; }
.cta__veil {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(12, 19, 20, 0.62), rgba(12, 19, 20, 0.82));
}
.cta__inner { position: relative; z-index: 2; max-width: 48rem; color: var(--onphoto); }
.cta__inner h2 { font-size: var(--t-h2); color: var(--onphoto); margin-bottom: var(--s-4); }
.cta__inner p { color: var(--onphoto-soft); margin-bottom: var(--s-6); }
.cta__channels {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  justify-content: center;
}

/* ==== FAQ ================================================================ */

.faq {
  position: relative;
  z-index: 2;
  padding: var(--sec-y) var(--gut);
  background: var(--page2);
}
.faq__list { max-width: 46rem; margin: 0 auto; }
.faq__item { border-bottom: 1px solid var(--hair); }
.faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  min-height: var(--tap);
  padding: var(--s-4) 0;
  font-family: var(--serif);
  font-size: var(--t-h4);
  cursor: pointer;
  list-style: none;
}
.faq__q::-webkit-details-marker { display: none; }
.faq__q::after {
  content: "+";
  color: var(--heroem);
  font-size: 1.4rem;
  line-height: 1;
  transition: transform var(--dur) var(--ease);
}
.faq__item[open] .faq__q::after { transform: rotate(45deg); }
.faq__a { padding: 0 0 var(--s-5); color: var(--muted); max-width: 62ch; }

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

.foot {
  position: relative;
  z-index: 2;
  text-align: center;
  padding: var(--s-8) var(--gut) calc(var(--s-8) + var(--dock-h));
  background: #101a19;
  border-top: 1px solid var(--hair);
}
.foot__brand { font-family: var(--serif); font-size: 1.5rem; color: var(--text); }
.foot__brand em { color: var(--accent); }
.foot__where { color: var(--muted); font-size: var(--t-small); margin: var(--s-2) 0 var(--s-5); }
.foot__links { display: flex; gap: var(--s-5); justify-content: center; flex-wrap: wrap; }
.foot__links a {
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
  font-size: var(--t-small);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* ==== Док связи ==========================================================
   Ось 7: три канала в пределах одного экрана с любой точки прокрутки —
   ноль взаимодействий, чтобы их увидеть.
   ========================================================================= */

.dock {
  position: fixed;
  right: var(--s-4);
  top: 50%;
  transform: translateY(-50%);
  z-index: 65;
  display: grid;
  gap: var(--s-2);
}
.dock__link {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  /* Симметричный padding без gap: свёрнутая пилюля (только иконка) должна
     получиться КРУГОМ, а не таблеткой со свободным хвостом справа — gap
     между иконкой и подписью убран отсюда и перенесён в padding-left самой
     .dock__label (см. ниже), чтобы он схлопывался вместе с ней и не
     оставлял пустого места, когда подпись скрыта. */
  padding: 0 var(--s-3);
  border-radius: var(--rad-pill);
  border: 1px solid var(--hair);
  background: rgba(18, 27, 26, 0.9);
  backdrop-filter: blur(10px);
  color: var(--text);
  font-size: var(--t-small);
  letter-spacing: 0.06em;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              color var(--dur) var(--ease);
}
.dock__link:hover { background: var(--heroem); color: var(--onaccent); border-color: var(--heroem); }
.dock__ico {
  width: 22px;
  height: 22px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linejoin: round;
}

/* Замерено скриптом (пересечение прямоугольников по горизонтали, элементы
   p/li/h1/h2/h3/img/.btn/a): полная пилюля 126px, левый край на 142px от
   правого края экрана — на 1280/1440 заезжает на абзац «Обо мне» (обрезает
   концы строк) и на четвёртую карточку «Что снимаем?» (27-29 пересечений).
   На десктопе схлопываем пилюлю до круга ~44px с одной иконкой; подпись
   остаётся в DOM (она же accessible name ссылки — не display:none и не
   visibility:hidden) и раскрывается только по наведению/фокусу. Мобильный
   брейкпоинт ниже не участвует — там подписи нужны всегда. */
@media (min-width: 861px) {
  .dock__link { gap: 0; }
  .dock__label {
    display: inline-block;
    max-width: 0;
    padding-left: 0;
    overflow: hidden;
    white-space: nowrap;
    opacity: 0;
    transition: max-width var(--dur) var(--ease), opacity var(--dur) var(--ease),
                padding-left var(--dur) var(--ease);
  }
  .dock:hover .dock__label,
  .dock:focus-within .dock__label {
    max-width: 12rem;
    padding-left: var(--s-3);
    opacity: 1;
  }
}

@media (max-width: 860px) {
  /* На мобильном док становится нижней панелью: пальцем достаётся всегда. */
  .a { --dock-h: 58px; }
  .dock {
    right: 0;
    left: 0;
    top: auto;
    bottom: 0;
    transform: none;
    grid-template-columns: repeat(3, 1fr);
    gap: 0;
    background: rgba(16, 26, 25, 0.96);
    backdrop-filter: blur(14px);
    border-top: 1px solid var(--hair);
    padding: 0;
  }
  .dock__link {
    flex-direction: column;
    gap: 2px;
    justify-content: center;
    min-height: var(--dock-h);
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
    backdrop-filter: none;
    /* Зафиксировано в px, не rem: --dock-h выше (58px) резервирует место
       под этот fixed-нижний-бар в остальной раскладке (.cine__copy,
       .hud__bar, .foot — везде calc(var(--dock-h) + ...)). На 200% масштабе
       rem-подпись росла вместе с текстом, реальная высота дока (иконка +
       две строки подписи) уходила далеко за 58px, и содержимое сцены,
       рассчитанное на 58px, накладывалось на реальный, более высокий док.
       Тот же приём, что уже применён для .tab__link на десктопе в B —
       здесь просто не был перенесён в мобильный брейкпоинт. */
    font-size: 10.88px;
    letter-spacing: 0.04em;
  }
  .dock__ico { width: 20px; height: 20px; }
}

/* ==== Баннер-поздравление ================================================
   В потоке документа сразу под шапкой — раздвигает киносцену вниз вместо
   того, чтобы лечь fixed-пилюлей поверх её заголовка и CTA, как было раньше.
   Отдельного отступа под шапку здесь больше не нужно: .hdr сама sticky и
   резервирует под себя ровно свою реальную высоту, в один ряд или в два
   (см. комментарий у .hdr) — раньше здесь был margin-top: var(--header-h),
   и на 200% масштабе, где шапка переносится на второй ряд, фиксированные
   56px не поспевали за её реальным ростом, и баннер лез под шапку. Никогда
   не перекрывает лайтбокс (z-index 100 у .lb, у баннера обычный поток,
   z-index не нужен) и не участвует в HUD/доке — те не в потоке документа.
   ========================================================================= */

.bday {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-3);
  padding: var(--s-3) var(--gut);
  background: var(--page2);
  border-bottom: 1px solid var(--accent);
  text-align: center;
}
.bday[hidden] { display: none; }
.bday__text {
  font-family: var(--serif);
  font-size: 1rem;
  line-height: 1.25;
  color: var(--text);
}
.bday__text em { color: var(--heroem); }
.bday__heart { color: var(--accent); }
.bday__heart svg { width: 0.85em; height: 0.85em; vertical-align: -0.08em; fill: currentColor; }
.bday__close {
  flex: none;
  background: none;
  border: 0;
  color: var(--muted);
  font-size: 1rem;
  cursor: pointer;
  border-radius: 50%;
}
.bday__close svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 2; display: block; }
.bday__close:hover { color: var(--text); }

@media (max-width: 520px) {
  .bday__text { font-size: 0.9rem; }
}
