/* =================================================================
   Свадебное приглашение — Елисей & Анна
   Mobile-first. Основной вьюпорт 380–430px, десктоп — та же колонка.
   ================================================================= */

/* ---------- Шрифты (локально, без CDN) ---------- */

/* Каллиграфия заголовков — шрифт заказчика, кириллица родная.
   Один файл на все алфавиты: в шрифте 173 глифа, делить на сабсеты нечего. */
@font-face {
  font-family: 'Florisel Script';
  src: url('assets/fonts/florisel-script.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* Переменный файл: один woff2 покрывает все начертания 300–700. */
@font-face {
  font-family: 'Cormorant Garamond';
  src: url('assets/fonts/cormorant-garamond-cyrillic.woff2') format('woff2');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Cormorant Garamond';
  src: url('assets/fonts/cormorant-garamond-latin.woff2') format('woff2');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+20AC, U+2122, U+2212, U+FEFF, U+FFFD;
}

/* Польские буквы с диакритикой. Стандартный latin-ext весит 33 КБ ради
   сотен глифов, из которых нужны шестнадцать, — сабсет ровно под них.
   Ó и ó лежат в Latin-1 и уже есть в наборе выше. */
@font-face {
  font-family: 'Cormorant Garamond';
  src: url('assets/fonts/cormorant-garamond-polish.woff2') format('woff2');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0104-0107, U+0118-0119, U+0141-0144, U+015A-015B, U+0179-017C;
}

/* Заголовки на польском.

   В Florisel польских букв нет вообще — ни ó, ни ś, ни ę: в файле 173 глифа,
   латиница базовая плюс кириллица. Без своего шрифта каждая буква с
   диакритикой падала в системный, и «Ślub» набиралось двумя гарнитурами
   сразу. Pinyon Script — та же английская пропись с тем же контрастом и
   росчерками, и лицензия у него ясная (OFL), в отличие от Florisel.

   Сабсет: базовая латиница + польские буквы + типографские кавычки и тире,
   с запасом на правку текстов. Русский гость этот файл не качает — браузер
   тянет шрифт, только когда он кому-то понадобился. */
@font-face {
  font-family: 'Pinyon Script';
  src: url('assets/fonts/pinyon-script-polish.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ---------- Токены ---------- */

:root {
  --bg: #faf5ee;
  --ink: #1a1a1a;
  --ink-soft: #4a453e;
  --ink-faint: #8b8377;
  --rule: #c6b99f;
  --rule-soft: #e2d8c6;
  --accent: #6e7748;

  --font-script: 'Florisel Script', 'Segoe Script', cursive;
  /* Множитель кегля заголовков: у разных прописей разный рост строчных
     при одном и том же font-size. Для русского Florisel — единица. */
  --script-scale: 1;
  --font-serif: 'Cormorant Garamond', 'Times New Roman', Georgia, serif;

  --col: 500px;      /* максимальная ширина колонки */
  /* Боковые отступы. По ТЗ было 24px, но заказчик просил ровнять текст
     по краям фотографии пары, а у неё отступы заметно шире. Теперь
     значение одно на всю страницу, и колонка везде одной ширины. */
  --pad: clamp(30px, 12.5vw, 60px);
  --gap-section: 64px;

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);

  /* Фиксированная «шапка»: переключатель языка слева, музыка справа.
     --chrome — от края экрана до дальнего края более широкой из них
     (переключатель: 12px отступа + 50px ширины; кнопка музыки уже —
     12 + 38). Текст держится от этой границы подальше, чтобы не уезжать
     под кнопки при скролле. */
  --chrome-gap: 12px;
  --chrome: 62px;
}

/* У Pinyon строчные заметно крупнее относительно кегля, чем у Florisel
   (x-height 0.37 против 0.21 em), поэтому польские заголовки при том же
   font-size выглядели бы больше русских. Уравниваем множителем. */
html:lang(pl) {
  --font-script: 'Pinyon Script', 'Segoe Script', cursive;
  --script-scale: 0.82;
}

/* ---------- База ---------- */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-serif);
  font-size: 18px;
  line-height: 1.6;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
  /* У Cormorant по умолчанию минускульные цифры: «12» читается как «I2».
     Везде нужны прописные (lining). */
  font-variant-numeric: lining-nums;
  font-feature-settings: 'lnum' 1;
}

/* До нажатия «Открыть приглашение» страница не скроллится.
   position: fixed, а не overflow: hidden — Safari на iOS одним overflow
   скролл не блокирует. Блокируем всегда в позиции 0, восстанавливать нечего. */
body.is-locked {
  position: fixed;
  inset: 0;
  width: 100%;
  overflow: hidden;
}

/* Атрибут hidden должен побеждать любой display в наших же правилах:
   UA-стиль [hidden]{display:none} слабее селектора по классу, и элемент,
   которому мы задали display: grid/flex, через .hidden = true не спрячется. */
[hidden] { display: none !important; }

img, picture, video, svg { display: block; max-width: 100%; }
img { height: auto; }

button { font: inherit; color: inherit; }

#content {
  max-width: var(--col);
  margin: 0 auto;
  padding-bottom: 8px;
}

.noscript {
  margin: 0;
  padding: 16px var(--pad);
  text-align: center;
  background: var(--rule-soft);
}

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

.script-title {
  margin: 0 0 20px;
  font-family: var(--font-script);
  font-weight: 400;
  font-size: calc(clamp(28px, 9vw, 38px) * var(--script-scale));
  /* Florisel — роундхенд с росчерками вверх и вниз: тесный интерлиньяж их режет. */
  line-height: 1.4;
  text-align: center;
  letter-spacing: 0.01em;
  /* Длинные заголовки переносим до того, как строка дойдёт до кнопок в
     шапке. Заголовок центрирован, поэтому вычитаем зазор с обеих сторон. */
  max-width: min(290px, calc(100vw - 2 * (var(--chrome) + 8px)));
  margin-left: auto;
  margin-right: auto;
}

.kicker {
  margin: 0 0 28px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-align: center;
  color: var(--ink-faint);
  /* Тот же зазор до кнопок в шапке, что и у заголовков. */
  max-width: calc(100vw - 2 * (var(--chrome) + 8px));
  margin-left: auto;
  margin-right: auto;
}

.prose {
  margin: 0;
  color: var(--ink-soft);
}
.prose p { margin: 0 0 1em; }
.prose p:last-child { margin-bottom: 0; }

/* Выключка по обоим краям — весь текст на странице, включая дресс-код и
   раздел про цветы. Колонка ровно по ширине фотографии, и рваный правый
   край рядом с её ровной кромкой бросался в глаза.

   Переносы обязательны: на 292px без них между словами вставали бы дыры.
   Язык для словаря браузер берёт из html[lang], который мы и так
   проставляем до первой отрисовки. Словари есть не везде — проверить
   на живом телефоне, в первую очередь во встроенном браузере Telegram. */
.prose,
.program__note {
  text-align: justify;
  -webkit-hyphens: auto;
  hyphens: auto;
}

.prose--small { font-size: 16px; }

.section {
  padding: var(--gap-section) var(--pad);
}

/* ---------- Разделитель ---------- */

.divider {
  height: 22px;
  margin: 0 auto;
  background: center / 240px 22px no-repeat
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 240 22' fill='none' stroke='%23c6b99f' stroke-width='1' stroke-linecap='round'%3E%3Cpath d='M8 11h84'/%3E%3Cpath d='M148 11h84'/%3E%3Cpath d='M98 11c6-7 13-7 16 0-3 7-10 7-16 0z'/%3E%3Cpath d='M142 11c-6-7-13-7-16 0 3 7 10 7 16 0z'/%3E%3Ccircle cx='120' cy='11' r='1.6' fill='%23c6b99f' stroke='none'/%3E%3C/svg%3E");
}

/* ---------- 3.1 Обложка ---------- */

.cover {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;   /* без прыжков адресной строки в Safari */
  display: grid;
  grid-template-rows: 1fr auto;
  align-items: end;
  overflow: hidden;
  color: #fff;
  background: #2a2620;
}

.cover__photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
  /* Наезд. alternate — кадр возвращается назад, без рывка на перезапуске
     цикла. Точка отсчёта чуть ниже центра, там пара. Прежние 12% за 28 с
     давали 0.4% в секунду — движение было почти незаметным; теперь 24% за
     20 с, это больше процента в секунду и уже читается как наезд. */
  transform-origin: 50% 58%;
  animation: kenburns 20s ease-in-out infinite alternate;
}

@keyframes kenburns {
  from { transform: scale(1); }
  to   { transform: scale(1.24); }
}

.cover__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(180deg, rgba(0, 0, 0, 0.32) 0%, rgba(0, 0, 0, 0.16) 46%, rgba(0, 0, 0, 0.46) 100%);
}

.cover__body {
  position: relative;
  z-index: 2;
  grid-row: 1;
  align-self: center;
  padding: 0 var(--pad);
  text-align: center;
}

.cover__names {
  margin: 0;
  font-family: var(--font-script);
  font-weight: 400;
  font-size: calc(clamp(38px, 12vw, 54px) * var(--script-scale));
  line-height: 1.15;
  text-shadow: 0 2px 24px rgba(0, 0, 0, 0.4);
}

.cover__date {
  /* Дата стоит над именами, поэтому отступ снизу, а не сверху. */
  margin: 0 0 20px;
  font-size: 13px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  opacity: 0.9;
}

.open-btn {
  position: relative;
  z-index: 2;
  grid-row: 2;
  justify-self: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  margin: 0 0 calc(env(safe-area-inset-bottom, 0px) + 56px);
  padding: 8px 16px;
  background: none;
  border: 0;
  color: #fff;
  cursor: pointer;
  transition: opacity 0.4s var(--ease), transform 0.4s var(--ease);
  -webkit-tap-highlight-color: transparent;
}

/* Графика заказчика: вензель «Е & А» и ряд управления плеером.
   Вензель шире ряда стрелок в 2.2 раза, поэтому масштабируем их порознь
   и приводим к одной ширине. */
.open-btn__art {
  display: grid;
  justify-items: center;
  gap: 12px;
  --art: min(150px, 40vw);
}
.open-btn__mono,
.open-btn__controls {
  width: var(--art);
}
.open-btn__art svg {
  height: auto;
  fill: #fff;
  /* Вензель нарисован волосяными линиями. Широкая мягкая тень их не держит —
     нужна узкая и плотная, иначе на цветах штрихи пропадают. */
  filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.75));
  animation: breathe 3.2s var(--ease) infinite;
}

.open-btn__label {
  font-size: 12px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

.open-btn.is-hidden {
  opacity: 0;
  transform: translateY(8px);
  pointer-events: none;
}

/* Кружка с расходящейся волной больше нет — вместо неё мягкое дыхание,
   чтобы графика читалась как кнопка, а не как декор. */
@keyframes breathe {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.72; }
}

/* ---------- Переключатель языка ---------- */

/* Зеркало кнопки музыки: та же высота и та же посадка от края, только
   слева. Виден с самого начала, в отличие от музыки: гость должен
   переключить язык ещё на обложке, не открывая приглашение. */
.lang {
  position: fixed;
  z-index: 50;
  top: calc(env(safe-area-inset-top, 0px) + var(--chrome-gap));
  left: var(--chrome-gap);
  display: flex;
  overflow: hidden;
  height: 38px;
  border: 1px solid var(--rule);
  border-radius: 19px;
  background: rgba(250, 245, 238, 0.82);
  backdrop-filter: blur(6px);
  animation: fade-in 0.5s var(--ease) both;
}

.lang__btn {
  width: 24px;
  border: 0;
  padding: 0;
  background: none;
  font-family: var(--font-serif);
  font-size: 12px;
  font-weight: 600;
  line-height: 36px;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
  cursor: pointer;
  transition: color 0.2s var(--ease), background-color 0.2s var(--ease);
  -webkit-tap-highlight-color: transparent;
}

/* Волосяная линия между языками — вместо рамки на каждой кнопке. */
.lang__btn + .lang__btn {
  box-shadow: inset 1px 0 0 var(--rule-soft);
}

.lang__btn[aria-pressed='true'] {
  color: var(--ink);
  background: rgba(198, 185, 159, 0.28);
}

/* На самых узких экранах (320px — iPhone SE первых поколений) имена
   с обложки при скролле проходили под переключателем. Ужимаем обоих:
   имена на шаг, переключатель до 46px. */
@media (max-width: 340px) {
  :root { --chrome: 56px; }
  .lang__btn { width: 21px; }
  .cover__names { font-size: calc(36px * var(--script-scale)); }
}

/* ---------- Кнопка музыки ---------- */

.music-toggle {
  position: fixed;
  z-index: 50;
  top: calc(env(safe-area-inset-top, 0px) + var(--chrome-gap));
  right: var(--chrome-gap);
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: 50%;
  background: rgba(250, 245, 238, 0.82);
  backdrop-filter: blur(6px);
  cursor: pointer;
  animation: fade-in 0.5s var(--ease) both;
  -webkit-tap-highlight-color: transparent;
}

.music-toggle__icon {
  width: 16px;
  height: 15px;
  fill: var(--ink);
}

/* Кнопка показывает действие, а не состояние: играет — значок паузы,
   выключено — значок play. */
.music-toggle[aria-pressed='true'] .music-toggle__play,
.music-toggle[aria-pressed='false'] .music-toggle__pause {
  display: none;
}

  50%      { opacity: 1; }
}
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

/* ---------- 3.3 Фото пары ---------- */

/* Отступы вокруг фото пары задаём здесь целиком, а не складываем с нижним
   отступом приветствия: сверху выходило 80px, снизу ноль, и завиток
   прилипал к фотографии. Теперь сверху и снизу поровну — на строку текста
   (около 29px) меньше межсекционных 64px. По бокам — общий --pad: по этим
   краям выравнивается весь текст на странице. */
.couple {
  --gap: 51px;
  margin: 0;
  padding: var(--gap) var(--pad);
}
#greeting { padding-bottom: 0; }
.couple img {
  width: 100%;
  border-radius: 2px;   /* по ТЗ — скругление 2px */
}

/* ---------- 3.4 Обратный отсчёт ---------- */

.countdown {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 4px;
}

.countdown__cell {
  text-align: center;
  position: relative;
}
.countdown__cell + .countdown__cell::before {
  content: '';
  position: absolute;
  left: 0;
  top: 12%;
  height: 46%;
  border-left: 1px solid var(--rule-soft);
}

.countdown__value {
  display: block;
  font-size: clamp(30px, 9vw, 38px);
  font-weight: 300;
  line-height: 1.1;
  font-variant-numeric: lining-nums tabular-nums;
  font-feature-settings: 'lnum' 1, 'tnum' 1;
  letter-spacing: 0.02em;
}

.countdown__unit {
  display: block;
  margin-top: 8px;
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.countdown__today { margin: 8px 0 0; }

/* ---------- 3.5 Программа дня ---------- */

.program {
  margin: 0;
  padding: 0;
  list-style: none;
}

.program__item + .program__item {
  margin-top: 28px;
  padding-top: 28px;
  border-top: 1px solid var(--rule-soft);
}

.program__head {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: baseline;
  gap: 16px;
}

.program__title {
  font-family: var(--font-script);
  font-size: calc(38px * var(--script-scale));
  line-height: 1.15;
}

.program__rule {
  align-self: stretch;
  border-left: 1px solid var(--rule);
}

.program__time {
  font-size: 22px;
  font-weight: 500;
  font-variant-numeric: lining-nums tabular-nums;
  font-feature-settings: 'lnum' 1, 'tnum' 1;
  letter-spacing: 0.04em;
}

.program__note {
  margin: 10px 0 0;
  font-size: 16px;
  color: var(--ink-soft);
}

/* ---------- 3.6 Дресс-код ---------- */

.palette {
  display: flex;
  justify-content: center;
  margin: 36px 0 0;
  padding: 0;
  list-style: none;
}

/* Цветов шесть, и в фиксированном размере они не влезают в колонку на 320px.
   Ширина ряда = n*S - (n-1)*0.28*S = 4.6*S, отсюда предел размера круга. */
.palette {
  --swatch: min(72px, calc((100vw - 2 * var(--pad)) / 4.6));
}
.palette__swatch {
  width: var(--swatch);
  height: var(--swatch);
  border-radius: 50%;
  /* круги накладываются внахлёст, каждый следующий поверх предыдущего */
  margin-left: calc(var(--swatch) * -0.28);
  box-shadow: 0 0 0 1px rgba(26, 26, 26, 0.06);
}
.palette__swatch:first-child { margin-left: 0; }

/* Просьба ответить до срока: стоит между заголовком и формой, поэтому
   отступ снизу больше, чем у обычного абзаца. */
.rsvp__deadline {
  margin: 0 0 34px;
}

/* ---------- Цветы и подарки ---------- */

.flowers__art {
  width: min(112px, 28vw);
  height: auto;
  margin: 6px auto 26px;
  color: var(--ink);
  opacity: 0.85;
}

/* ---------- 3.7 Место проведения ---------- */

.venue__address {
  margin: 0 0 28px;
  font-style: normal;
  font-size: 19px;
  text-align: center;
  color: var(--ink-soft);
}
.venue__address p { margin: 0 0 4px; }
.venue__address p:last-child { margin-bottom: 0; }

.venue__photo {
  width: 100%;
  border-radius: 2px;
  filter: grayscale(1);   /* фото здания — ч/б */
}

/* ---------- Кнопки ---------- */

.btn {
  display: block;
  width: 100%;
  margin-top: 24px;
  padding: 15px 20px;
  border-radius: 2px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.25s var(--ease), color 0.25s var(--ease),
    opacity 0.25s var(--ease);
  -webkit-tap-highlight-color: transparent;
}

.btn--outline {
  border: 1px solid var(--ink);
  background: transparent;
  color: var(--ink);
}
.btn--outline:active { background: var(--ink); color: var(--bg); }

.btn--solid {
  border: 1px solid var(--ink);
  background: var(--ink);
  color: var(--bg);
}
.btn--solid:active { opacity: 0.75; }
.btn[disabled] { opacity: 0.5; pointer-events: none; }

/* ---------- 3.8 Форма ---------- */

.form { margin-top: 32px; }

.field {
  margin: 0 0 28px;
  padding: 0;
  border: 0;
}

.field__label {
  display: block;
  margin: 0 0 12px;
  padding: 0;
  font-size: 16px;
  font-weight: 500;
}

.field__hint {
  margin: 8px 0 0;
  font-size: 14px;
  line-height: 1.45;
  color: var(--ink-faint);
}

.field__input {
  width: 100%;
  padding: 12px 2px;
  border: 0;
  border-bottom: 1px solid var(--rule);
  border-radius: 0;              /* iOS Safari скругляет по умолчанию */
  background: transparent;
  color: var(--ink);
  font-family: var(--font-serif);
  font-size: 17px;               /* < 16px вызывает зум на iOS */
  /* UA-стили полей сбрасывают font-variant, поэтому цифры задаём заново. */
  font-variant-numeric: lining-nums;
  font-feature-settings: 'lnum' 1;
  -webkit-appearance: none;
  appearance: none;
  transition: border-color 0.2s var(--ease);
}
.field__input:focus {
  outline: none;
  border-bottom-color: var(--ink);
}
.field__input--number { width: 96px; text-align: center; }

.field.has-error .field__input { border-bottom-color: #a2483c; }

.field__error {
  margin: 8px 0 0;
  font-size: 14px;
  color: #a2483c;
}
.field__error--form { text-align: center; }

.field.is-hidden { display: none; }

/* ---------- Список гостей ---------- */

.guests {
  display: grid;
  gap: 14px;
}

.guest {
  display: flex;
  align-items: center;
  gap: 10px;
}
.guest .field__input { flex: 1 1 auto; min-width: 0; }

.guest__remove {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: 50%;
  background: transparent;
  color: var(--ink-faint);
  font-size: 19px;
  line-height: 1;
  cursor: pointer;
  transition: color 0.2s var(--ease), border-color 0.2s var(--ease);
  -webkit-tap-highlight-color: transparent;
}
.guest__remove:active { color: var(--ink); border-color: var(--ink); }

.add-guest {
  margin-top: 16px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent);
  font-family: var(--font-serif);
  font-size: 16px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.add-guest:active { opacity: 0.6; }

.radios { display: grid; gap: 12px; }

.radio {
  display: flex;
  align-items: center;
  gap: 12px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
/* Невидимая, но настоящая радиокнопка поверх нарисованного кружка:
   сохраняются нативный фокус, тап и работа скринридера. */
.radio input {
  position: absolute;
  width: 20px;
  height: 20px;
  margin: 0;
  opacity: 0;
  -webkit-appearance: none;
  appearance: none;
}
.radio__mark {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  border: 1px solid var(--rule);
  border-radius: 50%;
  transition: border-color 0.2s, box-shadow 0.2s;
}
.radio input:checked + .radio__mark {
  border-color: var(--ink);
  box-shadow: inset 0 0 0 5px var(--ink);
}
.radio input:focus-visible + .radio__mark {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.radio__text { font-size: 17px; }

/* honeypot — вне экрана, но не display:none (боты такое пропускают) */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Строка «спасибо» не влезала в 290px и вылезала из блока вправо — оттого
   и казалась сдвинутой. Ограничение по кнопке музыки оставляем, но пошире:
   текст помещается целиком и встаёт ровно по центру. */
.thanks {
  margin: 40px auto 0;
  max-width: min(330px, calc(100vw - 116px));
}

/* ---------- 3.9 Футер ---------- */

.footer {
  padding: 56px var(--pad) calc(env(safe-area-inset-bottom, 0px) + 56px);
  text-align: center;
  border-top: 1px solid var(--rule-soft);
}
.footer__monogram {
  width: 64px;
  height: 64px;
  margin: 0 auto 18px;
  opacity: 0.6;
}
.footer__names {
  margin: 0;
  font-family: var(--font-script);
  font-size: calc(36px * var(--script-scale));
  line-height: 1.3;
}
.footer__date {
  margin: 10px 0 0;
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* ---------- Появление секций при скролле ---------- */

.reveal {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.6s var(--ease), transform 0.6s var(--ease);
  will-change: opacity, transform;
}
.reveal.is-visible {
  opacity: 1;
  transform: none;
  will-change: auto;
}

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
  .open-btn__art svg,
  .cover__photo,
  .music-toggle,
  .lang { animation: none; }
  * { scroll-behavior: auto !important; }
}
