/* Maison Rouge · главная страница как журнал
   Этап 1: статичная вёрстка 12 разворотов, десктоп. Движения нет.

   Как устроен масштаб
   ───────────────────
   Макет нарисован в 1440×900. Все числа в разметке — это координаты и кегли
   из макета, в «единицах макета». Единица считается один раз:

       --u = min(ширина экрана / 1440, высота полосы / 900)

   меньшее из того, что позволяют ширина и высота, — поэтому разворот целиком
   влезает в экран на любом мониторе и ничего не обрезается. Высота полосы
   зажата в 720…1000 px, как просили в ТЗ.

   В разметке координаты живут как custom properties (--l --t --w --h --fs).
   Если свойство не задано, calc(var(--l) * var(--u)) становится невалидным
   на этапе вычисления — и браузер берёт начальное значение (left: auto).
   Это штатное поведение CSS, на нём и держится вся раскладка: пишем только
   те координаты, которые есть в макете.

   Одна оговорка, на которой легко обжечься: custom properties наследуются.
   Колонка с --gap:40 передала бы свой отступ вложенной колонке, а разворот —
   свой фон плашкам внутри. Поэтому каждый класс, который читает переменную,
   сначала гасит её у себя: `--gap: initial`. Значение из разметки (инлайн)
   сильнее правила и переживает сброс, а унаследованное — нет.

   Межбуквенное (em) и интерлиньяж (без единиц) не масштабируются — они и так
   привязаны к кеглю, поэтому стоят прямо в разметке. */

/* ── DRUZHOK ────────────────────────────────────────────────────────── */

/* Шрифт логотипа дома. Директор прислал файл 28.09, и он совпал с вывеской
   в зале буква в букву: та же «M» с тонкой левой стойкой, та же «A» с
   вылетающим навершием, та же «S», пересекающая саму себя. До этого я
   считал знак рисованным — ошибался.

   Автор — Влада Олейник, Школа дизайна ВШЭ. Начертание одно, знаков 184,
   строчных нет: строчные дублируют прописные. Поэтому он стоит только на
   имени дома и больше нигде — в тексте он нечитаем.

   ВНИМАНИЕ: в файле нет ни слова о лицензии, скачан с агрегатора. До
   письменного разрешения автора это макетная подстановка, а не готовое
   решение. На живой сайт так выпускать нельзя. */
@font-face {
  font-family: "Druzhok";
  src: url("media/font/druzhok.otf") format("opentype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ── HK Grotesk ─────────────────────────────────────────────────────── */

/* Свой файл, а не Google Fonts: гротеск прислал директор (27.09). Латиница
   Альфредо Марко Прадиля, кириллица Стефана Пеева, лицензия OFL — текст
   лежит рядом в media/font/OFL.txt. Три начертания из четырёх: Light в
   вёрстке не нужен. Каждое около 46 КБ, кириллица полная.

   swap — чтобы страница не ждала шрифт и рисовала текст сразу. */
@font-face {
  font-family: "HK Grotesk";
  src: url("media/font/hkgrotesk-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "HK Grotesk";
  src: url("media/font/hkgrotesk-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "HK Grotesk";
  src: url("media/font/hkgrotesk-700.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* ── Переменные ─────────────────────────────────────────────────────── */

:root {
  --paper: #FFFFFF;
  --ink: #141110;
  --muted: #6B635C;
  --red: #A51C1F;
  --night: #0E0B0A;
  --on-dark: #FAF8F4;   /* текст поверх фото и видео */
  --cap-dark: #E6D8C6;  /* подписи на тёмном */

  /* Золото в этой версии не используется — вопрос в листе согласования.
     Чтобы включить, достаточно подставить var(--gold) там, где нужен акцент. */
  --gold: #C4A15E;

  /* Голос главы подставляется классом .voice-* на развороте. Здесь —
     запасной вариант на случай, если класс забыли. */
  --font-display: "Cormorant Garamond", Georgia, serif;
  --font-text: "PT Serif", Georgia, serif;
  /* Капсы раньше набирал Inter — 197 КБ ради одних мелких строчек. Теперь
     их и шапки «ночи» держит HK Grotesk, который лежит у нас своим файлом.
     Одна гарнитура вместо двух, и ни одного запроса на сторону. */
  --font-ui: "HK Grotesk", system-ui, sans-serif;

  /* Разворот занимает ровно один экран — и по высоте тоже. Потолок в 1000 px
     из ТЗ пришлось снять: на 2560×1440 он давал разворот ростом 1000 в окне
     1440, зазор 440 px, и попасть скроллом в границы было физически нельзя —
     страница меньше экрана. Теперь единица считается от самого экрана.

     Из экрана сразу вычитается полоса меню: лист никогда под неё не заезжает,
     поэтому шапке нечего перекрывать. Это поле страницы, как в журнале. */
  --screen-h: 100vh;
  --strip: 56px;
  --u: min(calc(100vw / 1440), calc((var(--screen-h) - var(--strip)) / 900));
}

@supports (height: 100svh) {
  :root { --screen-h: 100svh; }
}

/* Лист всегда встаёт в границы экрана. Здесь mandatory, хотя в ТЗ он запрещён:
   с proximity движение ровно на пол-экрана оставляло страницу посередине —
   браузер не дотягивал до ближайшей границы, и разворот так и висел стыком.
   Шаговой прокрутки это не даёт: scroll-snap-stop оставлен normal, поэтому
   одним махом трекпада можно пролететь несколько разворотов подряд. Опасности
   «недостижимого контента» тут нет — каждый разворот ровно в экран. */
html {
  scroll-snap-type: y mandatory;
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

/* ── База ───────────────────────────────────────────────────────────── */

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-text);
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; }

img, video { display: block; }

.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ── Разворот и полоса ──────────────────────────────────────────────── */

.spread {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: var(--screen-h);
  padding-top: var(--strip);
  scroll-snap-align: start;
  scroll-snap-stop: normal;
  background: var(--sheet-bg, var(--paper));
  color: var(--ink);
  overflow: hidden;
}

.sheet {
  position: relative;
  width: calc(1440 * var(--u));
  height: calc(900 * var(--u));
}

/* ── Раскладка по координатам макета ────────────────────────────────── */

.p {
  --l: initial; --t: initial; --r: initial; --b: initial; --w: initial; --h: initial;
  position: absolute;
  left: calc(var(--l) * var(--u));
  top: calc(var(--t) * var(--u));
  right: calc(var(--r) * var(--u));
  bottom: calc(var(--b) * var(--u));
  width: calc(var(--w) * var(--u));
  height: calc(var(--h) * var(--u));
}

/* Блок во всю ширину разворота: для центрованных заголовков и подвалов. */
.p.x { left: 0; right: 0; width: auto; }

.col,
.row {
  --gap: initial;
  display: flex;
  gap: calc(var(--gap) * var(--u));
}

.col { flex-direction: column; }
.row { flex-direction: row; }

.grid {
  --gap: initial;
  --cols: initial;
  display: grid;
  grid-template-columns: var(--cols, repeat(2, minmax(0, 1fr)));
  gap: calc(var(--gap) * var(--u));
}

.w { --w: initial; width: calc(var(--w) * var(--u)); }
.h { --h: initial; height: calc(var(--h) * var(--u)); }
.fs { --fs: initial; font-size: calc(var(--fs) * var(--u)); }
.mt { --mt: initial; margin-top: calc(var(--mt) * var(--u)); }
.pt { --pt: initial; padding-top: calc(var(--pt) * var(--u)); }
.center { text-align: center; align-items: center; }
.right { text-align: right; }
.end { align-items: flex-end; }
.baseline { align-items: baseline; }

/* Линейки макета: толщина в пикселях экрана, а не в единицах, — волосяная
   линия должна оставаться волосяной и на 2560. */
.rule-t { border-top: 1px solid currentColor; }
.rule-b { border-bottom: 1px solid currentColor; }

/* ── Типографика ────────────────────────────────────────────────────── */

.pf { font-family: var(--font-display); font-weight: 400; }
.sr { font-family: var(--font-text); }
.it { font-style: italic; }

.cap {
  font-family: var(--font-ui);
  font-size: calc(10 * var(--u));
  font-weight: 500;
  letter-spacing: 0.16em;
}

.cr {
  font-family: var(--font-ui);
  font-size: calc(10 * var(--u));
  letter-spacing: 0.04em;
  color: var(--muted);
}

/* Кегль из макета всегда сильнее кегля класса. */
.cap.fs,
.cr.fs { --fs: initial; font-size: calc(var(--fs) * var(--u)); }

/* Буквица. В макете это float с отрицательной визуальной компенсацией. */
.drop {
  --fs: initial;
  float: left;
  font-family: var(--font-display);
  font-size: calc(var(--fs) * var(--u));
  line-height: 0.8;
  padding: calc(4 * var(--u)) calc(8 * var(--u)) 0 0;
  color: var(--red);
}

/* Колонки редакционной полосы: текст выключен влево, как просили. */
.cols {
  --cgap: initial;
  column-count: 2;
  column-gap: calc(var(--cgap, 32) * var(--u));
  text-align: left;
}

.cols p { margin: 0; }

/* ── Ссылки вместо кнопок ───────────────────────────────────────────── */

/* Подчёркивание есть всегда (это единственный признак действия), но при
   наведении прорисовывается ярче и ближе к тексту. Зона нажатия — от 44 px
   по высоте, поэтому у ссылки-строки вертикальные поля. */
.link {
  display: inline-block;
  color: var(--red);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: calc(6 * var(--u));
  /* Строка капсом высотой ~12 px; поля добирают зону нажатия до 44 px и
     съедаются отрицательным полем, чтобы ритм макета не поехал. */
  padding: max(17px, calc(17 * var(--u))) 0;
  margin: max(-17px, calc(-17 * var(--u))) 0;
  transition: text-underline-offset 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

.link:hover { text-underline-offset: calc(3 * var(--u)); }
.link.on-dark { color: var(--on-dark); }

/* Строки афиши — вся строка кликабельна, подчёркивания нет. */
.event {
  display: grid;
  grid-template-columns: calc(96 * var(--u)) minmax(0, 1fr) calc(70 * var(--u));
  gap: calc(20 * var(--u));
  align-items: baseline;
  padding: calc(20 * var(--u)) 0;
  border-top: 1px solid var(--ink);
  text-decoration: none;
  transition: background-color 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

.event:hover { background: rgba(165, 28, 31, 0.05); }

/* ── Слоты под медиа ────────────────────────────────────────────────── */

/* Заглушка фото: тёмная плашка нужного тона, подпись снизу слева —
   как в макете. Когда в media.json появится путь, main.js положит внутрь
   картинку, а подпись уедет в alt. */
.slot {
  /* --cap-* задаются на самой плашке и читаются подписью внутри — гасим их
     здесь, чтобы соседняя плашка не подхватила чужие поля. */
  --bg: initial;
  --fg: initial;
  --cap-x: initial;
  --cap-y: initial;
  --cap-fs: initial;
  --justify: initial;
  --pb: initial;
  position: relative;
  margin: 0;
  overflow: hidden;
  background: var(--bg, #3B2E26);
  color: var(--fg, #C9B8A5);
}

/* Плашка сама по себе — точка отсчёта для своей подписи, поэтому relative.
   Но плашка на всю полосу стоит по координатам макета, и тогда .p должен
   победить: специфичность у обоих классов одинаковая, а .slot ниже по файлу. */
.slot.p { position: absolute; }

/* Промо-ролик из соцсетей приходит вертикальным 9:16 и свёрстан заранее:
   дата и телефон сверху, «le restaurant · le salon · le club» снизу. Если
   обрезать его по нашей полосе 720×900, эти строки уедут за край. Поэтому
   вписываем целиком, а поля по бокам уходят в чёрный фон полосы. */
.slot.slot--fit > video,
.slot.slot--fit > img { object-fit: contain; }

.slot > img,
.slot > video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Какой срез кадра брать, когда пропорция плашки не совпадает с
     пропорцией снимка. По умолчанию середина. */
  object-position: var(--pos, 50% 50%);
}

.slot--photo .slot__cap {
  position: absolute;
  left: calc(var(--cap-x, 14) * var(--u));
  right: calc(var(--cap-x, 14) * var(--u));
  bottom: calc(var(--cap-y, 12) * var(--u));
  font-family: var(--font-ui);
  font-size: calc(var(--cap-fs, 10) * var(--u));
  letter-spacing: 0.12em;
}

/* Заглушка видео: знак воспроизведения и описание нужного кадра по центру. */
.slot--video {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: var(--justify, center);
  gap: calc(12 * var(--u));
  text-align: center;
  font-family: var(--font-ui);
  font-size: calc(11 * var(--u));
  letter-spacing: 0.14em;
  padding-bottom: calc(var(--pb, 0) * var(--u));
}

.slot--video svg { width: calc(40 * var(--u)); height: calc(40 * var(--u)); }

/* Когда слот заполнен, вся служебная разметка заглушки уходит. */
.slot[data-filled] {
  display: block;
  background: var(--night);
  padding: 0;
}

.slot[data-filled] .slot__cap,
.slot[data-filled] .slot__play { display: none; }

/* Шов между полосами разворота — тонкая светлая линия, как в макете. */
.seam { background: var(--on-dark); }

/* ── Стрекоза ───────────────────────────────────────────────────────── */

.fly {
  --fly: initial;
  width: calc(var(--fly, 40) * var(--u));
  height: auto;
  color: var(--red);
}

/* ── Тонкое меню ────────────────────────────────────────────────────── */

/* Меню живёт в своей полосе над листом — той самой, что вычтена из экрана.
   Фона у полосы нет: под ней виден фон разворота, поэтому меню само берёт
   тон от страницы — светлое на тёмном, тёмное на кремовом. Перекрывать ему
   нечего: лист под полосу не заезжает. */
.menu {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  z-index: 10;
  height: var(--strip);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(28 * var(--u));
  padding: 0 calc(40 * var(--u));
  font-family: var(--font-ui);
  font-size: calc(12 * var(--u));
  color: var(--on-dark);
  transition: color 0.9s cubic-bezier(0.22, 1, 0.36, 1);
}

.menu[data-chrome="paper"] { color: var(--ink); }

.menu a {
  text-decoration: none;
  padding: max(15px, calc(15 * var(--u))) 0;
  margin: max(-15px, calc(-15 * var(--u))) 0;
}

.menu a[data-booking] {
  text-decoration: underline;
  text-underline-offset: calc(5 * var(--u));
}

.menu a:hover { opacity: 0.75; }

/* ── Пока без мобильной раскладки ───────────────────────────────────── */

/* Мобильную версию директор отложил. Чтобы на телефоне не показывать
   нечитаемый разворот в 0,27 масштаба, ниже 1100 px стоит заглушка. */
.narrow {
  display: none;
  min-height: 100vh;
  align-items: center;
  justify-content: center;
  padding: 32px;
  text-align: center;
}

.narrow p { max-width: 30em; font-size: 16px; line-height: 1.6; color: var(--muted); }

@media (max-width: 1099px) {
  .narrow { display: flex; }
  .menu, main { display: none; }
}

/* ── Подпись основателя ─────────────────────────────────────────────── */

/* Росчерк нарисован вектором: заглавная петля, несколько связных букв,
   выносной элемент вниз и концевая петля с длинным подчерком. Имени в нём
   нет — читать нечего, это закорючка, а не автограф Владимира. Настоящую
   можно отсканировать и заменить svg на картинку.

   Абзац растянут на обе колонки: в колонку шириной 288 единиц росчерк не
   влезает. column-span работает только на блочном боксе, поэтому наклон
   живёт на вложенном svg. */
.sign,
.sign-credit {
  column-span: all;
  -webkit-column-span: all;
  margin: 0;
}

.sign { line-height: 0; }

/* Подпись — картинка, а не рисунок. Задаём высоту, а не ширину: росчерк
   вертикальный, и по ширине он занял бы полполосы. Наклон снят — у живой
   подписи свой, придуманный ей не нужен. */
.sign__mark {
  width: auto;
  height: calc(130 * var(--u));
  margin: calc(6 * var(--u)) 0 calc(4 * var(--u));
}

/* ── Значки соцсетей ────────────────────────────────────────────────── */

/* Значки прислал директор: чёрные силуэты со знаком, вырезанным насквозь.
   Перекрашены в красный дома, знак внутри остаётся цветом бумаги. Телеграм
   пришёл без круга, одним самолётиком, — вложен в такой же круг, иначе он
   выпадал из ряда. Зона нажатия добирается полями до 44 px. */
.social {
  display: flex;
  gap: calc(18 * var(--u));
  align-items: center;
}

.social a {
  display: inline-flex;
  padding: max(11px, calc(11 * var(--u))) calc(2 * var(--u));
  transition: opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

.social a:hover { opacity: 0.68; }

.social img {
  width: calc(22 * var(--u));
  height: calc(22 * var(--u));
  display: block;
}

.social--big { gap: calc(30 * var(--u)); }
.social--big img { width: calc(52 * var(--u)); height: calc(52 * var(--u)); }

/* ── Обложка: дуэт день/ночь ────────────────────────────────────────── */

/* Полосы работают по очереди: живая идёт в цвете и в движении, вторая
   замерла, обесцвечена и притушена. Между тактами вспышка, и смена
   происходит на её пике — стыка не видно, виден удар (директор, 26.09).

   Фильтр ложится и на постер, поэтому до загрузки ролика полоса уже серая:
   первый кадр не вспыхивает цветом. */
.duet { filter: grayscale(1) brightness(0.4) contrast(0.82); }
.duet[data-live] { filter: none; }

/* Вспышка. Кремовая, а не белая: белого в палитре нет. Лежит поверх кадров,
   но под именем дома — буквы сквозь неё остаются резкими. */
.flash {
  position: absolute;
  inset: 0;
  z-index: 2;
  background: var(--paper);
  opacity: 0;
  pointer-events: none;
}

.flash[data-fire] { animation: mr-flash 280ms cubic-bezier(0.22, 1, 0.36, 1) both; }

@keyframes mr-flash {
  0% { opacity: 0; }
  30% { opacity: 0.62; }
  100% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .duet,
  .duet[data-live] { filter: none; }
  .flash[data-fire] { animation: none; }
}

/* ── Имя дома на обложке ────────────────────────────────────────────── */

/* Две колонки по половине разворота: слово прижато к шву со своей стороны,
   просвет между ними делится швом ровно пополам. */
.logo {
  --fs: initial;
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: baseline;
  margin: 0;
  font-size: calc(var(--fs) * var(--u));
  line-height: 1;
  letter-spacing: 0.02em;
  color: var(--on-dark);
  white-space: nowrap;
}

.logo > span:first-child { justify-self: end; padding-right: calc(23 * var(--u)); }

/* «ROUGE» на красной плашке, со стрекозой на конце. Красный — наш, не
   алый: на обложке рядом с кремовым он и так кричит.

   Селектор нарочно на класс длиннее правила ниже: то задаёт этой же
   ячейке отступ слева, и при равном приоритете выигрывало бы оно. */
.logo > span.pf.lg-red {
  display: inline-flex;
  align-items: center;
  gap: calc(16 * var(--u));
  /* Справа поле меньше: стрекоза добирает разницу в длине слов, чтобы
     плашка встала зеркально «MAISON» относительно шва. */
  padding: calc(4 * var(--u)) calc(14 * var(--u)) calc(12 * var(--u)) calc(22 * var(--u));
  background: var(--red);
  line-height: .9;
}

.logo .lg-red .fly {
  width: calc(var(--fs) * 0.34 * var(--u));
  height: auto;
  color: var(--on-dark);
}
.logo > span:last-child { justify-self: start; padding-left: calc(23 * var(--u)); }

/* ── Кликабельная карта ─────────────────────────────────────────────── */

/* Ссылка лежит поверх карты целиком. Подсказка внизу слева — напротив
   кредита OpenStreetMap, который стоит внизу справа и убирать который
   нельзя по лицензии. */
.map-link {
  z-index: 2;
  display: block;
  text-decoration: none;
  transition: background-color 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

.map-link .cap {
  position: absolute;
  left: calc(28 * var(--u));
  bottom: calc(20 * var(--u));
  color: var(--on-dark);
  opacity: 0.72;
  transition: opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

.map-link:hover { background: rgba(250, 248, 244, 0.06); }
.map-link:hover .cap { opacity: 1; }

/* ── Аккордеон ──────────────────────────────────────────────────────── */

/* Карточки лежат в строке и делят её ширину: активная забирает почти всё,
   остальные сжимаются в полоски, но остаются видимыми — из полоски виден
   край кадра, и понятно, что там ещё что-то есть.

   Ширину меняем через flex, а не через width: сумма всегда равна строке,
   и при любом числе карточек ничего не переполняется. */
.accordion {
  display: flex;
  gap: calc(8 * var(--u));
  height: calc(var(--h, 620) * var(--u));
}

.card {
  position: relative;
  /* figure по умолчанию несёт поля в 40 px с каждой стороны. Пять карточек
     съедали 400 px из 580, места на раздачу не оставалось, и все садились
     на min-width. */
  margin: 0;
  flex: 1 1 0;
  min-width: calc(76 * var(--u));
  overflow: hidden;
  border-radius: calc(44 * var(--u));
  background: #1A1210;
  cursor: pointer;
  transition: flex-grow 0.9s cubic-bezier(0.22, 1, 0.36, 1);
}

.card[data-open] { flex-grow: 4.2; }

.card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--pos, 50% 35%);
  /* Сжатые уходят в тень и теряют цвет: в цвете всегда одна, как на обложке. */
  filter: grayscale(1) brightness(0.68);
  transform: scale(1.04);
  transition:
    filter 0.9s cubic-bezier(0.22, 1, 0.36, 1),
    transform 1.4s cubic-bezier(0.22, 1, 0.36, 1);
}

.card[data-open] img { filter: none; transform: scale(1); }

/* Подпись ложится на светлые места кадра, поэтому под ней своя тень —
   иначе строка состава пропадает на бликах бокала. */
.card::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 52%;
  background: linear-gradient(to bottom, transparent, rgba(14, 11, 10, 0.88));
  opacity: 0;
  transition: opacity 0.9s cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
}

.card[data-open]::after { opacity: 1; }

.card figcaption {
  position: absolute;
  z-index: 2;
  left: calc(34 * var(--u));
  right: calc(34 * var(--u));
  bottom: calc(38 * var(--u));
  color: var(--on-dark);
  opacity: 0;
  transform: translateY(calc(10 * var(--u)));
  transition:
    opacity 0.7s 0.15s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.7s 0.15s cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
}

.card[data-open] figcaption { opacity: 1; transform: none; }

.card .nm {
  display: block;
  font-family: var(--font-display);
  font-size: calc(32 * var(--u));
  line-height: 1.06;
}

.card .rl {
  display: block;
  margin-top: calc(12 * var(--u));
  padding-top: calc(12 * var(--u));
  border-top: 1px solid rgba(250, 248, 244, 0.42);
  font-family: var(--font-text);
  font-size: calc(14 * var(--u));
  line-height: 1.5;
  color: var(--cap-dark);
}

/* На кремовой полосе подпись живёт не в карточке, а под ней, на бумаге:
   кадр остаётся чистым, а текст читается без теней и подложек. */
.accordion--plain .card {
  border-radius: calc(10 * var(--u));
  /* На бумажной полосе строка всего 580 px на пять кадров. С прежним
     порогом в 44 px три полоски из четырёх упирались в него и выходили
     одной ширины — веер не читался. */
  min-width: calc(24 * var(--u));
}

.accordion--plain .card::after,
.accordion--plain .card figcaption { display: none; }

/* На чёрных страницах сжатый кадр можно топить в тень — он и так лежит на
   тёмном. На бумаге тот же кадр шириной в 30 px превращается в чёрную
   палку: соседство с кремом съедает последние полутона. Здесь притеняем
   вдвое слабее — полоска остаётся фотографией. */
.accordion--plain .card img { filter: grayscale(1) brightness(0.86); }
.accordion--plain .card[data-open] img { filter: none; }

.dots { display: flex; gap: calc(10 * var(--u)); justify-content: center; }

.dots button {
  width: calc(7 * var(--u));
  height: calc(7 * var(--u));
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(250, 248, 244, 0.28);
  cursor: pointer;
  transition:
    background-color 0.6s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}

.dots button[data-on] { background: var(--red); transform: scale(1.6); }

/* Подпись под аккордеоном: гаснет и зажигается при смене карточки. */
.acc-caption { transition: opacity 0.22s linear; }
.acc-caption[data-fading] { opacity: 0; }

/* Съёмки вина пока нет. Пустая карточка — не серая дыра, а помеченное
   место: тон бумаги на тон темнее, тонкая штриховка и слово [кадр],
   которое видно только у раскрытой. Ряд держит композицию, и сразу
   понятно, чего ждём от фотографа. */
.card--empty {
  background: #ECE5DC;
  box-shadow: inset 0 0 0 1px #D8CEC1;
}

.card--empty::before {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    135deg,
    transparent 0 calc(7 * var(--u)),
    rgba(58, 52, 48, 0.055) calc(7 * var(--u)) calc(8 * var(--u))
  );
}

.card--empty .ph {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-family: var(--font-cap, var(--font-text));
  font-size: calc(12 * var(--u));
  letter-spacing: 0.14em;
  color: #9A8F84;
  opacity: 0;
  transition: opacity 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}

.card--empty[data-open] .ph { opacity: 1; }

/* Обводка фокуса — только с клавиатуры: под мышью карточка и так
   раскрывается, рамка была бы шумом. */
.card:focus { outline: none; }

.card:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: calc(3 * var(--u));
}

/* ── Полоса перехода на внутреннюю страницу ─────────────────────────── */

/* Прежние ссылки были строкой капсом в 12 px с подчёркиванием. На
   тринадцатидюймовом макбуке масштаб падает до 0,79, строка садится до
   девяти пикселей и теряется в бумаге — директор смотрел с Air и не нашёл
   их вовсе (27.09). Поэтому переход стал полосой во всю ширину колонки,
   внизу листа, со стрекозой дома слева и стрелкой справа. */
.btn {
  display: flex;
  align-items: center;
  gap: calc(18 * var(--u));
  /* 46 px по макету, но не ниже 44 настоящих: это нижняя граница зоны
     нажатия, ниже неё в кнопку не попасть пальцем. */
  min-height: max(44px, calc(46 * var(--u)));
  padding: 0 calc(18 * var(--u));
  border-top: 1px solid var(--red);
  border-bottom: 1px solid var(--red);
  color: var(--red);
  text-decoration: none;
  transition:
    background-color 0.5s cubic-bezier(0.22, 1, 0.36, 1),
    color 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Стрекоза на полосе берёт цвет самой полосы: на залитой она кремовая,
   на контурной красная. Класс .fly красит её в красный жёстко — здесь
   это надо снять. */
.btn .fly { flex: none; color: inherit; }

.btn__t {
  flex: 1;
  /* Надпись не переносим: полоса невысокая, вторая строка в ней не
     помещается и уезжает под нижнюю границу. */
  white-space: nowrap;
  font-family: var(--font-cap, var(--font-text));
  font-size: max(11px, calc(13 * var(--u)));
  letter-spacing: 0.2em;
  line-height: 1;
}

.btn__a {
  flex: none;
  font-size: max(13px, calc(15 * var(--u)));
  line-height: 1;
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

.btn:hover { background: var(--red); color: #FAF8F4; }
.btn:hover .btn__a { transform: translateX(calc(8 * var(--u))); }

/* Залитый вариант: полоса видна сразу, без наведения. */
.btn--solid {
  background: var(--red);
  color: #FAF8F4;
  border-color: var(--red);
}

.btn--solid:hover { background: #8E1619; border-color: #8E1619; color: #FAF8F4; }

/* Полоса по ширине слова, а не колонки: нужна там, где переход стоит
   внутри вёрстки, а не в подвале листа. */
.btn--inline { width: calc(var(--w, 300) * var(--u)); }

.btn:focus { outline: none; }
.btn:focus-visible { outline: 2px solid var(--red); outline-offset: calc(3 * var(--u)); }

/* ── Появления и паузы-главы ────────────────────────────────────────── */

/* Пометку data-reveal ставит скрипт. Без него правила не срабатывают
   вовсе, и страница просто видна — это защита от пустого листа. */
@media (prefers-reduced-motion: no-preference) {
  .spread[data-reveal] [data-rv] {
    opacity: 0;
    transform: translateY(calc(12 * var(--u)));
    transition:
      opacity 0.6s cubic-bezier(0.22, 1, 0.36, 1),
      transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
    /* Очередь сверху вниз. 55 мс — столько, чтобы читалось как перелистывание,
       а не как поочерёдная загрузка блоков. Вся очередь из шести частей
       отыгрывает за 0,9 с, и почти вся успевает до приземления разворота. */
    transition-delay: calc(var(--i, 0) * 55ms);
  }

  /* Кадр во всю полосу не едет, а только проявляется: сдвиг у фотографии
     на пол-листа виден как подскок вёрстки. */
  .spread[data-reveal] [data-rv].slot { transform: none; }

  .spread[data-reveal][data-in] [data-rv] { opacity: 1; transform: none; }
}

/* Границы глав: обложка, ночь и аренда. Через них колесо не перемахивает
   разом — разворот обязан остановиться. */
.spread[data-chapter] { scroll-snap-stop: always; }

/* ── Голоса глав ────────────────────────────────────────────────────── */

/* В глянце шапка меняет гарнитуру от темы к теме, а держат номер общие
   вещи: текст, капсы, колонтитул, сетка, красная полоса перехода.
   Здесь меняется только крупный набор — всё остальное одно на все листы.

   Множитель кегля сидит не на развороте, а на самих заголовках: поставь
   его выше — и вместе с шапкой поедет основной текст. */

/* Дом: тонкая антиква. Очко мелкое, поэтому кегль поднят на четверть,
   иначе шапка в прежнем размере теряется на листе. */
.voice-house { --font-display: "Cormorant Garamond", Georgia, serif; }
.voice-house .pf.fs { font-size: calc(var(--fs) * 1.26 * var(--u)); }

/* Имя дома живёт по своим правилам: его кегль подобран под ширину полосы,
   и множитель голоса его выбивает — на обложке буквы уезжали за край,
   на Ж12 строка ломалась надвое. */
.voice-house .pf.fs.wm,
.voice-house .logo { font-size: calc(var(--fs) * var(--u)); }
.voice-house h2.pf { letter-spacing: -0.004em; }

/* Еда: плотный дидон. Курсива у Prata нет вовсе, поэтому вторую фразу
   выделяем не наклоном, а цветом дома. */
.voice-food { --font-display: Prata, Georgia, serif; }
.voice-food .pf.fs { font-size: calc(var(--fs) * 0.94 * var(--u)); }
.voice-food h2.pf { letter-spacing: -0.012em; }
.voice-food .it { font-style: normal; color: var(--red); }
.voice-food h2.pf .it { color: var(--red); }

/* Ночь: тяжёлый гротеск. Курсива нет и не нужно — контраст держит вес. */
.voice-night { --font-display: "HK Grotesk", system-ui, sans-serif; }
.voice-night .pf.fs { font-size: calc(var(--fs) * 0.88 * var(--u)); font-weight: 500; }
.voice-night h2.pf.fs { font-weight: 700; letter-spacing: -0.026em; }
/* Курсива у гротеска нет вовсе, и браузер наклоняет прямое начертание сам —
   получается не курсив, а покосившиеся буквы. Поэтому на «ночных» листах
   наклон снят везде, а в шапках разницу держит вес. */
.voice-night .it { font-style: normal; }
.voice-night h2.pf .it { font-weight: 400; letter-spacing: -0.01em; }

/* ── Согласие на куки ───────────────────────────────────────────────── */

/* Полоса внизу листа, в языке журнала: бумага, волосяная красная линейка
   сверху, капсы. Обе кнопки одного размера — отказ не должен быть тише
   согласия. */
.consent {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 11;
  display: flex;
  align-items: center;
  gap: calc(28 * var(--u));
  padding: calc(14 * var(--u)) calc(40 * var(--u));
  background: #FAF8F4;
  border-top: 1px solid var(--red);
  font-family: var(--font-ui);
  font-size: max(11px, calc(12 * var(--u)));
  line-height: 1.45;
  color: #3A3430;
}

.consent[hidden] { display: none; }

.consent__t { flex: 1; margin: 0; max-width: calc(760 * var(--u)); }

.consent__l {
  flex: none;
  color: var(--red);
  text-decoration: underline;
  text-underline-offset: calc(4 * var(--u));
}

.consent__b { flex: none; display: flex; gap: calc(10 * var(--u)); }

.consent__b button {
  min-height: max(38px, calc(38 * var(--u)));
  padding: 0 calc(20 * var(--u));
  border: 1px solid var(--red);
  background: transparent;
  color: var(--red);
  font: inherit;
  letter-spacing: 0.06em;
  cursor: pointer;
  transition:
    background-color 0.4s cubic-bezier(0.22, 1, 0.36, 1),
    color 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}

.consent__b button:hover { background: var(--red); color: #FAF8F4; }

/* Селектор нарочно длиннее, чем у правила выше: короткий проигрывал ему
   по приоритету, и залитая кнопка выходила такой же контурной, как отказ. */
.consent__b .consent__y { background: var(--red); color: #FAF8F4; }
.consent__b .consent__y:hover { background: #8E1619; border-color: #8E1619; }

/* ── Приглашение на обложке ─────────────────────────────────────────── */

/* Плашки ближайших вечеров и бронь стоят справа на обложке, столбиком.
   Язык — язык самой обложки: тёмное поле, волосяная красная линейка,
   наши капсы, наша красная кнопка. */
/* Плашки стоят на левой половине, вверху. Правая занята роликом вечера,
   а у него своя вёрстка — дата, состав, «LE SALON»; всё, что кладётся
   поверх, с ней спорит. Левая половина тиха в обоих состояниях: живая
   она мягкая и расфокусированная, замершая — серая. */
.invite {
  position: fixed;
  z-index: 12;
  left: calc(56 * var(--u));
  top: calc(116 * var(--u));
  width: calc(348 * var(--u));
  display: flex;
  flex-direction: column;
  gap: calc(12 * var(--u));
}

.invite[hidden] { display: none; }

.invite__k { align-self: flex-start; color: rgba(250, 248, 244, 0.72); }

.invite__list { display: flex; flex-direction: column; gap: calc(12 * var(--u)); }

.invite__row {
  display: flex;
  flex-direction: column;
  gap: calc(4 * var(--u));
  padding: calc(16 * var(--u)) calc(20 * var(--u));
  background: #110E0D;
  border-left: 2px solid var(--red);
  color: var(--on-dark);
}

.invite__d {
  font-family: var(--font-ui);
  font-weight: 500;
  font-size: calc(10 * var(--u));
  letter-spacing: 0.12em;
  color: var(--red);
}

.invite__n {
  font-family: var(--font-display);
  font-size: calc(22 * var(--u));
  line-height: 1.1;
  color: #FAF8F4;
}

.invite__t {
  font-family: var(--font-ui);
  font-size: calc(11 * var(--u));
  letter-spacing: 0.06em;
  color: #9A8F84;
}

.invite__x {
  align-self: flex-start;
  order: -1;
  margin-bottom: calc(-4 * var(--u));
  padding: calc(4 * var(--u)) calc(6 * var(--u));
  border: 0;
  background: none;
  color: rgba(250, 248, 244, 0.55);
  font-size: calc(20 * var(--u));
  line-height: 1;
  cursor: pointer;
}

/* Выезд. Ход короткий — глаз должен зафиксировать положение, а не путь.
   Очередь сверху вниз по --i, кнопка идёт последней с лишним тактом:
   она вывод фразы, а не её часть. */
@media (prefers-reduced-motion: no-preference) {
  .invite__row,
  .invite__b,
  .invite__x,
  .invite__k {
    opacity: 0;
    transform: translateX(calc(-28 * var(--u)));
    transition:
      opacity 0.62s cubic-bezier(0.22, 1, 0.36, 1),
      transform 0.62s cubic-bezier(0.22, 1, 0.36, 1);
    transition-delay: calc(var(--i, 0) * 80ms);
  }

  .invite[data-in] .invite__row,
  .invite[data-in] .invite__b,
  .invite[data-in] .invite__x,
  .invite[data-in] .invite__k { opacity: 1; transform: none; }

  /* Уход не зеркалит приход: все разом и вдвое быстрее. */
  .invite[data-closing] .invite__row,
  .invite[data-closing] .invite__b,
  .invite[data-closing] .invite__x,
  .invite[data-closing] .invite__k {
    transition-duration: 0.3s;
    transition-delay: 0s;
  }
}

/* Пока плашки открыты, правая нижняя подпись обложки прячется: она
   говорит про пятницу с субботой, плашки её замещают. */
#zh01[data-invite] .p.cr:last-of-type { opacity: 0; }

/* Имя дома вернулось на нашу антикву (директор, 28.09): DRUZHOK снят до
   согласования лицензии. Файл и объявление шрифта остались на месте —
   чтобы включить его обратно, достаточно раскомментировать правило ниже
   и вернуть кегли: обложка 134 вместо 158, Ж12 — 46, Ж03 — 23.

.logo,
.logo .pf,
.pf.fs.wm { font-family: "Druzhok", var(--font-display); }
*/

/* ── Ярлык афиши на обложке ─────────────────────────────────────────── */

.afisha {
  display: inline-flex;
  align-items: center;
  gap: calc(14 * var(--u));
  min-height: max(38px, calc(40 * var(--u)));
  padding: 0 calc(18 * var(--u));
  background: #FAF8F4;
  color: var(--red);
  text-decoration: none;
  font-family: var(--font-ui);
  font-weight: 500;
  font-size: max(11px, calc(12 * var(--u)));
  letter-spacing: 0.14em;
  transition:
    background-color 0.4s cubic-bezier(0.22, 1, 0.36, 1),
    color 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}

.afisha__a { font-size: max(15px, calc(17 * var(--u))); line-height: 1; }

.afisha:hover { background: var(--red); color: #FAF8F4; }

/* Вектор времени на полосе салона: svg тянется по тем же единицам, что
   и всё остальное, поэтому задаём ему ширину и высоту через --w и --h. */
.vec { display: block; overflow: visible; }

/* Вертикальная строка выходных данных у корешка. */
.vert { writing-mode: vertical-rl; letter-spacing: 0.18em; }

/* Текст фича-полосы выключен по формату, как в журнале. */
.just { text-align: justify; hyphens: auto; }
