@charset "UTF-8";
/* Обязательно первая строка файла, без пробела перед ней и без BOM —
   иначе браузер её не признает и вернётся к угадыванию кодировки
   (сейчас работает только потому, что таблица наследует UTF-8 самой
   страницы — умолчание, не явное указание, см. README). Классы в этом
   файле кириллические (.лист, .трек-лист, .люди-инфо__блок и т.д.) —
   при ошибке кодировки селекторы просто перестанут совпадать, и стили
   молча не применятся по всему сайту разом. @charset сильнее и
   HTTP-заголовка Content-Type, и унаследованной кодировки документа —
   не зависит от настроек хостинга. */

/* Точная копия механики и оформления odrodok.ru — стопка листов, бумага,
   чернила, жёсткие тени, зерно. Разница — своё содержимое (собирает
   scripts/собрать.py из данных) и вложенные книги «Видео», «Устроить
   сэйшен», «Люди», плюс свой шрифт (Basis Grotesque Pro). Прокрутка внутри
   тела листа разрешена — только между листами её нет. */

/* ── ШРИФТ: одна переменная, заменить — поменять только этот блок ── */
@font-face{ font-family:"Basis Grotesque Pro"; font-weight:400; font-style:normal; font-display:swap;
  src:url('шрифты/BasisGrotesquePro-Regular.woff2') format('woff2'),
      url('шрифты/BasisGrotesquePro-Regular.woff') format('woff'); }
@font-face{ font-family:"Basis Grotesque Pro"; font-weight:500; font-style:normal; font-display:swap;
  src:url('шрифты/BasisGrotesquePro-Medium.woff2') format('woff2'),
      url('шрифты/BasisGrotesquePro-Medium.woff') format('woff'); }
@font-face{ font-family:"Basis Grotesque Pro"; font-weight:700; font-style:normal; font-display:swap;
  src:url('шрифты/BasisGrotesquePro-Bold.woff2') format('woff2'),
      url('шрифты/BasisGrotesquePro-Bold.woff') format('woff'); }
@font-face{ font-family:"Basis Grotesque Pro"; font-weight:400; font-style:italic; font-display:swap;
  src:url('шрифты/BasisGrotesquePro-Italic.woff2') format('woff2'),
      url('шрифты/BasisGrotesquePro-Italic.woff') format('woff'); }
:root{ --шрифт:"Basis Grotesque Pro", -apple-system, Helvetica, Arial, sans-serif; }

/* ── ТОКЕНЫ (палитра бумаги и чернил — как у odrodok) ── */
html{
  --mobile-font-size-min:11; --mobile-font-size-max:16;
  --desktop-font-size-min:10.5; --desktop-font-size-max:15;
  --mobile-viewport-min:320; --mobile-desktop-breakpoint:768; --desktop-viewport-max:1500;
  font-size:calc(var(--mobile-font-size-min) * 1px);
}
@media screen and (min-width:320px){html{font-size:calc(var(--mobile-font-size-min) * 1px + (var(--mobile-font-size-max) - var(--mobile-font-size-min)) * ((100vw - var(--mobile-viewport-min) * 1px) / (var(--mobile-desktop-breakpoint) - var(--mobile-viewport-min))))}}
@media screen and (min-width:768px){html{font-size:calc(var(--desktop-font-size-min) * 1px + (var(--desktop-font-size-max) - var(--desktop-font-size-min)) * ((100vw - var(--mobile-desktop-breakpoint) * 1px) / (var(--desktop-viewport-max) - var(--mobile-desktop-breakpoint))))}}
@media screen and (min-width:1500px){html{font-size:calc(var(--desktop-font-size-max) * 1px)}}

:root{
  --бумага:rgb(242,236,224); --бумага2:rgb(233,226,211); --карточка:rgb(253,252,250);
  --чернила:rgb(23,21,18); --тихий:rgb(112,105,92);
  --кирпич:rgb(216,66,32); --охра:rgb(247,216,110);
  --линия:color-mix(in srgb, var(--чернила) 20%, transparent);

  --поле-s:.5rem; --поле-m:1rem; --поле-l:1.5rem;
  --рамка-s:1px; --рамка-m:2px;
  --обводка:1px; --обводка-h:2px;

  --тень:3px 3px 0 var(--чернила);
  --тень2:2px 2px 0 var(--чернила);
  --тень-подъём:7px 7px 0 var(--чернила);
  --переход:cubic-bezier(.2,.7,.3,1);
}

*{ box-sizing:border-box; }
html,body{ margin:0; padding:0; height:100%; overflow:hidden; }

body{
  font-family:var(--шрифт);
  color:var(--чернила);
  background-color:var(--бумага);
  background-image:
    radial-gradient(120% 80% at 12% 6%, rgba(120,95,55,.055), transparent 62%),
    radial-gradient(100% 70% at 88% 94%, rgba(120,95,55,.05), transparent 60%),
    radial-gradient(70% 50% at 60% 40%, rgba(255,255,255,.5), transparent 70%);
  -webkit-font-smoothing:antialiased;
  overscroll-behavior:none;
}

body::before, body::after{
  content:""; position:fixed; inset:0; pointer-events:none;
  mix-blend-mode:multiply; z-index:60;
}
body::before{ opacity:.075;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.22' numOctaves='5' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E"); }
body::after{ opacity:.11;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); }

img{ display:block; max-width:100%; }
button{ font:inherit; color:inherit; background:none; border:none; cursor:pointer; }
a{ color:inherit; text-decoration:none; }

/* ── СЦЕНА: стопка листов текущей книги ── */
/* Находка Виктора с айфона: «Люди» (и потенциально другие листы) впритык
   прокручивались в мобильном Safari. vh считается от «большого»
   вьюпорта — как если бы панели адресной строки/таб-бара были свёрнуты,
   а не от того, что реально видно (там их ~150px). dvh — от видимой
   высоты прямо сейчас, пересчитывается сама при сворачивании панелей.
   Пишу vh ПЕРВОЙ строкой (откат для браузеров без dvh — их там мало, но
   правило не должно пропадать целиком), dvh — второй, тем же значением:
   валидный dvh в каскаде перебивает vh, невалидный (старый браузер) —
   игнорируется, остаётся vh. */
.сцена{
  position:fixed; inset:0;
  padding:clamp(.6rem, 2.2vh, 1.6rem);
  padding:clamp(.6rem, 2.2dvh, 1.6rem);
  z-index:1;
}

/* Листы не активной книги не показываются вовсе — но остаются в HTML,
   поисковик и мессенджер видят их без выполнения скрипта. */
/* inset:0 + margin:auto — единственный источник центрирования листа.
   Раньше центрировал place-items:center у .сцена, а у абсолютного листа
   не было ни inset, ни margin: Safari при рефлоу (его запускает transform
   у .enter:hover) терял грид-выравнивание и ронял лист в static position —
   в левый верхний угол сцены. Размеры листа заданы явно, так что
   margin:auto центрирует его сам, без участия родителя. */
.лист{
  position:absolute;
  inset:0; margin:auto;
  width:min(92vw, 62rem);
  height:min(88vh, 46rem);
  height:min(88dvh, 46rem);
  background:var(--карточка);
  border:var(--рамка-s) solid var(--чернила);
  box-shadow:var(--тень);
  display:flex; flex-direction:column;
  overflow:hidden;
  will-change:transform;
  touch-action:pan-y;
  user-select:none;
}
.лист[hidden]{ display:none; }
.лист.активна{ cursor:grab; }
.лист.активна.тянется{ cursor:grabbing; }
.лист.приподнят{ box-shadow:var(--тень-подъём); }

.лист__шапка{
  display:flex; align-items:center; justify-content:space-between;
  gap:var(--поле-m);
  padding:var(--поле-m) var(--поле-l);
  border-bottom:var(--рамка-m) solid var(--чернила);
  flex:0 0 auto;
}
.знак-мал{ display:block; height:1.15em; width:auto; flex:0 0 auto; -webkit-text-stroke:0; }
.лист__номер{
  font-size:.72em; letter-spacing:.14em; color:var(--тихий);
  -webkit-text-stroke:var(--обводка) currentColor; paint-order:stroke fill;
  white-space:nowrap;
}

/* ── ТЕЛО ЛИСТА: прокрутка разрешена, только здесь ── */
.лист__тело{
  flex:1 1 auto; min-height:0;
  overflow-y:auto; overflow-x:hidden; overscroll-behavior:contain;
  padding:var(--поле-l);
  scrollbar-width:thin;
}
.лист__тело::-webkit-scrollbar{ width:6px; }
.лист__тело::-webkit-scrollbar-thumb{ background:var(--линия); }
.лист__тело.соло{ display:flex; flex-direction:column; justify-content:center; align-items:center; text-align:center; }
.лист__тело.текст{ display:flex; flex-direction:column; justify-content:flex-start; gap:.9em; }
/* Лист с одиночным крупным роликом и текстом под ним (§16 дизайн.md,
   сейчас только «что такое сэйшен»; имя общее — не завязано на этот
   один лист, ещё пригодится). Не текст сверху вниз, а две зоны: зона
   ролика забирает всё свободное место (flex:1) и центрирует его в себе
   по обеим осям; зона текста — своего размера (flex:0), поэтому
   фактически прижата к нижнему краю тела. Всё по центру. */
/* Срочная находка Виктора (скриншот с домена, Safari, широкое окно):
   заголовок наезжал на «подпись под роликом» — это не отдельный текст, а
   .лид-подпись, которую видео_медиа() всегда дописывает внутрь <a
   class="видео"> (название клипа, здесь — «что такое сэйшен?», дословный
   дубль заголовка листа). .видео-центр__ролик .media--отдельно >
   .видео{height:100%} ниже принудительно ограничивает <a> высотой
   letterbox-обёртки, а .лид-подпись — обычный поточный <p> ПОСЛЕ .media
   внутри него: на contentwidth `<a>` без overflow:hidden эта подпись
   просто вылезала за нижний край ролика прямо на текстовый блок под ним.
   display:none — тот же приём, что уже прячет .лид-подпись в
   .видео-ряд (там подпись тоже дублирует заголовок карточки на узком
   экране). Зазор — не меньше var(--поле-m) (было .7em, Виктор явно
   попросил не меньше этого токена). */
/* находка kort (прогон по всем 45 листам): .lead на 1440×900 стоял на
   −94px от центра тела — единственное отклонение по выравниванию во всей
   книге. Причина — без align-items контейнер по умолчанию stretch: h1
   (без своего max-width) стретчится во всю ширину тела и потому выглядит
   центрированным случайно, а .lead (max-width:46rem у общего .lead,
   страница.css) стретчится, упирается в свой max-width и, как обычный
   блочный бокс без margin-inline:auto, прижимается к левому краю
   контейнера, а не центрируется. align-items:center — тот же приём, что
   уже стоит у соседнего .лист__тело.плеер: оба ребёнка центрируются по
   ширине сами по себе, а не растягиваются до стены с последующим
   left-прижатием у того, что упёрся в потолок. */
.лист__тело.видео-центр{ display:flex; flex-direction:column; align-items:center; text-align:center; gap:var(--поле-m); }
/* §2/§23 решения-дизайн.md: класс переиспользован для 20 листов
   видео-выпусков (книга_видео() в собрать.py) — там, кроме внутренней
   подписи видео_медиа() (дубль заголовка, гасим её), есть ЕЩЁ один
   .лид-подпись — «состав» под заголовком (сиблинг h1, а не потомок
   ролика), его прятать нельзя, это и есть нужный текст. Поэтому
   селектор специфичнее — только внутри .видео-центр__ролик, не по
   всему .лист__тело. */
.лист__тело.видео-центр .видео-центр__ролик .лид-подпись{ display:none; }
.видео-центр__ролик{
  flex:1 1 auto; min-height:0; width:100%;
  display:flex; align-items:center; justify-content:center;
}
/* Размер .media--отдельно здесь считает JS (вписатьВидеоЦентр() в
   странице.js), не чистый CSS: пробовала честную CSS-раскладку из
   макета (width:auto;height:auto;max-width:100%;max-height:100%;
   aspect-ratio:16/9 — и на flex, и на grid-контейнере) — у пустого
   div-обёртки без собственного контента (внутри — <img
   position:absolute>, в сайзинге бокса не участвует) оба «auto»
   одновременно схлопывались в 0×0/крошечный размер, браузеру не от
   чего оттолкнуться. Тот же класс задачи, что уже решала JS-разметка
   афиши (расположитьАфишу) — тут то же самое для ролика, только с
   пересчётом на resize и при заходе на лист (обновитьХад).
   Специфичность выше, чем у общего .media--отдельно/.media--отдельно
   .media (video-выпуски, свой — vh-based — потолок, не трогаю): без
   лишних классов та пара ниже по файлу молча выигрывала каскад. */
.лист__тело.видео-центр .видео-центр__ролик .media--отдельно{
  display:block; margin-inline:auto; max-width:100%; max-height:100%;
}
.лист__тело.видео-центр .видео-центр__ролик .media--отдельно > .видео{
  display:block; width:100%; height:100%; position:relative;
}
/* находка VRX (замер 1440×900 после video-tekst-pod): .ещё — обычная
   ссылка в потоке ПОСЛЕ .media внутри <a class="видео"> (видео_медиа()
   в собрать.py, тот же узел держит и .лид-подпись выше) — у выпусков с
   двумя источниками (вк+ютуб) она добавляла высоту сверх letterbox-
   рамки той же природы, что уже чинили для подписи: <a> зажат в 100%
   высоты ролика, а .ещё в обычном потоке эту высоту не уважает и
   вылезает на h1 под роликом (15 из 20 выпусков — у остальных пяти
   источник один, кнопки нет вовсе). Не прятать (как подпись) — это
   рабочая кнопка «смотреть на ютубе», не дубль текста. Вместо этого —
   оверлей поверх кадра, тем же приёмом, что уже даёт .время (правый
   нижний угол .media): левый нижний, чтобы не спорить с ней. */
.лист__тело.видео-центр .видео-центр__ролик .ещё{
  position:absolute; left:.5em; bottom:.5em; z-index:2; margin-top:0;
  padding:.15em .45em; border-radius:2px;
  background:rgba(23,21,18,.82); color:var(--карточка);
  text-decoration:none;
}
.лист__тело.видео-центр .видео-центр__ролик .ещё:hover{ text-decoration:underline; }
.лист__тело.видео-центр .видео-центр__ролик .media{
  width:100%; height:100%; max-width:none; aspect-ratio:auto; margin-inline:0;
}
.лист__тело.видео-центр h1,
.лист__тело.видео-центр .lead,
.лист__тело.видео-центр > .лид-подпись{ flex:0 0 auto; }
/* лист с плеером альбома: сам лист (тело) никогда не прокручивается —
   иначе перетаскивание для перелистывания на этом листе перехватывается
   как прокрутка тела (см. страница.js, изТела в pointerdown). Вместо
   этого прокручивается только список треков внутри — заголовок, пульт и
   площадки всегда на виду, лист помещается целиком. */
.лист__тело.плеер{
  display:flex; flex-direction:column; align-items:center; text-align:center;
  overflow:hidden; gap:.5em;
}
.лист__тело.плеер h1{ flex:0 0 auto; }
/* .lead и .плеер (обложка+пульт, список треков, площадки) — одна ширина,
   одно число (44rem, как у .плеер): без этого оба — блоки без width,
   каждый сам по себе ужимается до предпочтительной ширины своего
   содержимого (алгоритм shrink-to-fit при align-items:center), и на
   части экранов текст .lead и плеер расходятся по краю на глаз (Виктор,
   04/07: «что с выравниванием? заполнить весь лист шириной»). */
/* пресс-релиз (альбом-описание.json) пришёл от Виктора длинным абзацем —
   куда длиннее прежнего плейсхолдера, для которого писался .лист__тело.
   плеер{overflow:hidden} (тело листа никогда не прокручивается — иначе
   перетаскивание для перелистывания перехватывается как скролл тела, см.
   страница.js/изТела). Без ограничения абзац съедал всю высоту, и
   .трек-лист (flex:1 1 auto;min-height:0) схлопывался до 0 — список
   треков пропадал целиком на 375×812. line-clamp — тот же приём, что уже
   держит подписи видео-превью (.видео-превью__название) — текст, не
   решение слоя прокрутки: обрезаю ВИЗУАЛЬНО, слова Виктора не меняю,
   только не даю абзацу вытеснить список треков. 4 строки — с запасом
   хватает и на 375×812, и на 1440×900 (проверено с этим самым
   пресс-релизом: список из десяти треков и площадки видны целиком на
   обоих экранах). */
.лист__тело.плеер .lead{
  flex:0 0 auto; width:100%; max-width:44rem;
  overflow:hidden; display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:4;
}
.лист__тело.плеер .плеер{ flex:1 1 auto; min-height:0; display:flex; flex-direction:column; }

h1{
  margin:0 0 .5em;
  font-size:min(1.5em, 5.2vw); line-height:1.08;
  letter-spacing:.03em; text-transform:uppercase;
  -webkit-text-stroke:var(--обводка-h) currentColor; paint-order:stroke fill;
  overflow-wrap:anywhere;
}
.col{ min-width:0; }
.lead{
  font-size:.95em; line-height:1.6; letter-spacing:.04em; text-transform:uppercase;
  -webkit-text-stroke:var(--обводка) currentColor; paint-order:stroke fill;
  max-width:46rem;
}
.lead p{ margin:0 0 1em; }
.lead p:last-child{ margin-bottom:0; }
.lead h2{ margin:1.1em 0 .35em; font-size:1em; letter-spacing:.1em; text-transform:uppercase; color:var(--тихий); -webkit-text-stroke:0; }
.lead h2:first-child{ margin-top:0; }
.lead ul{ margin:0 0 1em; padding-left:1.2em; }
.lead li{ margin-bottom:.3em; }
.лид-подпись{ margin:.5em 0 0; font-size:.8em; color:var(--тихий); }

/* два отзыва в карточках на открывашке «Устроить сэйшен» — третий заход
   (docs/дизайн.md §19, отменяет сетку-ссылок второго захода). Два в ряд
   на десктопе, одна колонка на мобильном (карточка с воздухом внутри и
   так не сожмётся вдвое без потери приёма). */
.отзывы-сетка{
  display:grid; grid-template-columns:repeat(2, 1fr);
  gap:var(--поле-s); margin:1em 0 0;
}
/* тот же бордюр/тень/hover, что .люди-инфо__блок — решение 19 прямо
   называет этот приём, — но внутреннее устройство другое: текст прижат
   к низу карточки, в центре воздух, не обтягивает текст плотно. Карточка
   не ссылка (в отличие от прошлой сетки), поэтому нет a.-hover. */
.отзыв-карточка{
  display:flex; flex-direction:column; justify-content:flex-end;
  min-height:11em; padding:.9em 1em; text-align:left;
  background:var(--карточка); border:var(--рамка-s) solid var(--чернила); box-shadow:var(--тень2);
}
.отзыв-карточка blockquote{ margin:0 0 .4em; font-size:.95em; line-height:1.55; letter-spacing:.02em; }
.отзыв-карточка .лид-подпись{ margin:0; }

@media (max-width:560px){
  .отзывы-сетка{ grid-template-columns:1fr; }
}
/* Виктор, с айфона (docs/дизайн.md §21): на настоящей высоте мобильного
   Safari (~660px видимых, не 812 — панели адресной строки/таб-бара)
   .лист__тело этого листа переполнялось на 117px. max-height в паре с
   max-width, не одна ширина — иначе то же самое сжатие карточек
   применилось бы и на честных высоких экранах (812px и выше), где место
   и так есть и теснота не нужна. */
@media (max-width:560px) and (max-height:700px){
  .отзыв-карточка{ min-height:4.5em; padding:.55em .75em; }
  .отзыв-карточка blockquote{ font-size:.82em; line-height:1.35; }
  .отзыв-карточка .лид-подпись{ font-size:.72em; }
  .отзывы-сетка{ margin-top:.5em; gap:.35em; }
}


/* ── МЕДИА (обложка/видео) ── */
/* max-height рядом с aspect-ratio и width:100% — в WebKit конфликт: при
   упоре в потолок по высоте бокс не пересчитывает ширину под пропорцию
   обратно, а остаётся широким — 16:9 расходится (у Виктора в Safari
   вышло ~2.7:1, кадр обрезан сверху и снизу). Тот же предельный размер
   без конфликта — через max-width, посчитанный из желаемой предельной
   высоты и той же пропорции 16:9: тогда высота всегда следует из
   aspect-ratio у уже готовой ширины, а не спорит со вторым потолком. */
.media{
  position:relative; width:100%; aspect-ratio:16/9;
  /* dvh, не vh — см. .сцена выше: тот же откат-потом-перебивание */
  max-width:calc(min(46vh, 22rem) * 16 / 9);
  max-width:calc(min(46dvh, 22rem) * 16 / 9);
  margin-inline:auto;
  border:var(--рамка-s) solid var(--чернила);
  box-shadow:var(--тень2);
  margin-bottom:var(--поле-m);
  background:var(--бумага2);
  overflow:hidden;
}
.media img, .media iframe{
  position:absolute; inset:0; width:100%; height:100%; border:0;
  object-fit:cover; display:block;
}
/* заглушка обложки — у видео без ютуба (главное видео-объяснение и т.п.),
   не пустой прямоугольник: знак, лёгкий фон и подпись */
.media .кадр-пустой{
  position:absolute; inset:0;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:.5em;
  background:
    radial-gradient(120% 100% at 50% 0%, rgba(23,21,18,.05), transparent 60%),
    var(--бумага2);
}
/* лого теперь широкий логотип (не квадратный знак), масштабируем по
   ширине контейнера, а не по высоте строки — иначе размер зависит от
   пропорции файла и обрезается краями .media */
/* .media img уже задаёт всем картинкам внутри media position:absolute и
   100%×100% — специфичность выше одного класса, без переопределения по
   селектору с .media эта картинка тоже растягивалась на весь бокс */
.media .кадр-пустой__знак{ position:static; width:40%; max-width:12rem; height:auto; opacity:.55; }
.кадр-пустой__текст{
  font-size:.68em; letter-spacing:.1em; text-transform:uppercase; color:var(--тихий);
}
.media .плей{
  position:absolute; inset:0; margin:auto; width:0; height:0; z-index:1;
  border-style:solid; border-width:.9em 0 .9em 1.5em;
  border-color:transparent transparent transparent var(--карточка);
  filter:drop-shadow(0 1px 3px rgba(0,0,0,.5));
}
.media .время{
  position:absolute; right:.5em; bottom:.5em; z-index:1;
  padding:.15em .45em; border-radius:2px;
  background:rgba(23,21,18,.82); color:var(--карточка);
  font-size:.68em; letter-spacing:.05em;
}
.видео{ display:block; }
.ещё{
  position:relative; z-index:1; display:inline-block;
  margin-top:.4em; padding:0;
  font-size:.78em; letter-spacing:.08em; text-transform:uppercase;
  color:var(--тихий); text-decoration:underline; text-underline-offset:3px;
}
.ещё:hover{ color:var(--чернила); }
/* без явной ширины .media--отдельно (обёртка вокруг ссылки-карточки
   .видео) в центрированной колонке (align-items:center у .лист__тело.соло
   не растягивает детей) сама сжималась под свой контент по ширине —
   а контент это подпись-название, у каждого выпуска своей длины. .media
   внутри честно берёт width:100% от НЕЁ, так что 100% от разного давало
   разный размер ролика на каждом из 20 листов. Ширина листа одна и та
   же везде — просто задаём её явно, вместо того чтобы обёртка гадала. */
.media--отдельно{ width:100%; }
.media--отдельно .media{
  max-width:calc(min(50vh, 26rem) * 16 / 9);
  max-width:calc(min(50dvh, 26rem) * 16 / 9);
}

/* три маленьких видео в ряд */
.видео-ряд{ display:flex; gap:var(--поле-s); width:100%; }
.видео-ряд .media{ flex:1; min-width:0; margin-bottom:0; margin-inline:0; aspect-ratio:16/9; max-width:none; }
.видео-ряд .лид-подпись{ display:none; }
.видео-ряд--фото .media{ aspect-ratio:4/3; }
@media (min-width:900px){
  .видео-ряд{ gap:var(--поле-m); }
  /* 1 1 (не 0 0) — ширина сжимается, если в листе тесно, и не даёт
     горизонтальную прокрутку на узких десктопных окнах */
  .видео-ряд .media{ flex:1 1 13rem; min-width:0; }
  .видео-ряд .лид-подпись{ display:block; }
}

/* ── превью на открывашке книги «Видео» ──
   Раньше открывашка показывала только заголовок и счётчик «20 шт.» —
   сетка маленьких карточек даёт заглянуть внутрь книги, не открывая её.
   Восемь по выбору (поле в_превью в видео.json, ПРЕВЬЮ_ЛИМИТ в
   собрать.py — предохранитель; сама книга остаётся полной, 20 листов),
   в порядке json — колонки фиксированные, не auto-fill: делитель
   восьми, последний ряд не бывает рваным. */
.видео-превью{
  display:grid; grid-template-columns:repeat(4, 1fr);
  gap:var(--поле-s);
}
/* Виктор, после выкладки: текст сверху, сетка — у нижней границы тела,
   не сразу под текстом. .лист__тело.текст — flex-колонка, margin-top:auto
   у последнего элемента забирает всё свободное место сверху себя. */
.лист__тело.текст > .видео-превью{ margin-top:auto; }
.видео-превью__карточка{ display:block; }
.видео-превью__кадр{
  aspect-ratio:16/9; margin-bottom:0; transition:box-shadow .15s var(--переход), transform .15s var(--переход);
}
.видео-превью__карточка:hover .видео-превью__кадр{ box-shadow:var(--тень); transform:translate(-1px,-1px); }
.видео-превью__название{
  margin-top:.35em; font-size:.72em; line-height:1.3; color:var(--тихий);
  overflow:hidden; display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2;
}
.видео-превью__карточка:hover .видео-превью__название{ color:var(--чернила); }

@media (max-width:560px){
  /* Виктор, §22 решения-дизайн.md, уточнено §23 («третий заход» —
     шесть, не четыре): на мобильном не восемь мелких, а шесть крупных —
     первые шесть из в_превью (тот же порядок json), 2×3, лист
     по-прежнему в экран (§21 — состав листа на мобильном может
     отличаться от десктопного, это тот случай). Карточки 7–8 скрыты, не
     удалены — на десктоп это не влияет, а не восстанавливать их для
     мобильного не пришлось: разметка одна на оба экрана. */
  .видео-превью{ grid-template-columns:repeat(2, 1fr); gap:var(--поле-m); }
  .видео-превью__карточка:nth-child(n+7){ display:none; }
  .видео-превью__название{ font-size:.82em; margin-top:.5em; }
  /* §25 решения-дизайн.md: «ленту превью прижать к нижнему краю листа,
     и на мобильном тоже» — отменяет мобильный override отсюда (был
     margin-top:1em, обычный поток сразу под текстом): тогда лист был
     заметно ниже (82vh на глаз), и margin-top:auto с шестью крупными
     карточками оставлял бы большой разрыв. После list-vyshe/§23-25 лист
     занимает максимум высоты экрана — то же margin-top:auto, что на
     десктопе (.лист__тело.текст > .видео-превью выше), работает и тут:
     сетка внизу листа на обоих экранах, одно правило без исключения. */
}

/* ── КНОПКИ (как odrodok: .enter) ── */
.enter{
  display:inline-flex; align-items:center; gap:.5em;
  padding:.45em .9em;
  background:var(--карточка); color:var(--чернила);
  border:var(--рамка-s) solid var(--чернила);
  box-shadow:var(--тень2);
  font-size:1em; letter-spacing:.14em; text-transform:uppercase;
  -webkit-text-stroke:var(--обводка) currentColor; paint-order:stroke fill;
  transition:background .15s var(--переход), box-shadow .15s var(--переход), transform .15s var(--переход);
}
.enter:hover{ background:var(--охра); box-shadow:var(--тень); transform:translate(-1px,-1px); }
.enter:active{ box-shadow:none; transform:translate(2px,2px); }
/* кнопка занята (сейчас так грузится касса qtickets, ~170 КБ чужого
   скрипта): видно, что нажатие приняли, и второе нажатие не уходит */
.enter[aria-busy="true"]{ opacity:.55; pointer-events:none; cursor:progress; }
/* главное действие сайта — купить билет; единственное применение
   --кирпич как «горячего» акцента, не раскраски книг */
.enter.главная{ background:var(--кирпич); color:var(--карточка); border-color:var(--кирпич); }
.enter.главная:hover{ background:var(--чернила); }

/* фокус с клавиатуры — везде одинаково: кнопки, ссылки, поля формы,
   точки пагинации. :focus-visible, не :focus — рамка не мешает клику
   мышью, только табу и стрелкам */
:focus-visible{ outline:2px solid var(--чернила); outline-offset:2px; }

/* ── ПОДВАЛ ЛИСТА (тема слева, действия справа) ── */
.лист__подвал{
  flex:0 0 auto;
  display:flex; align-items:center; justify-content:space-between; gap:var(--поле-m);
  /* нижнее поле было нулевым, пока под подвалом шла мелкая строка
     соцсетей: без неё подвал упирался бы в край листа */
  padding:var(--поле-s) var(--поле-l);
  border-top:var(--рамка-s) solid var(--линия);
  font-size:.72em; letter-spacing:.14em; text-transform:uppercase; color:var(--тихий);
}
.лист__подвал .acts{ display:flex; align-items:center; gap:var(--поле-s); flex:0 0 auto; flex-wrap:wrap; justify-content:flex-end; }

/* ── лист «здарова, музыканты»: плеер альбома ──
   Всё выравнивание внутри плеера левое: тело листа у этого листа «соло»
   (центрирует блок и текст), но список из десяти строк по центру не
   читается. Ширина ограничена — на десктопе лист шире 60rem, а строка
   трека длиной во весь лист распадается на «номер … далеко … время». */
.плеер{ width:100%; max-width:44rem; margin-inline:auto; text-align:left; }

/* пульт: обложка слева, управление справа. На телефоне колонка — но
   обложка там ужимается до 7rem, чтобы список влез без прокрутки.
   §18 дизайн.md «компактнее»: шаг отступов вниз (поле-m → поле-s) и
   обложка на четверть меньше по обеим границам clamp — пульт занимает
   меньше высоты, под текст об альбоме и список остаётся больше места.
   Блок центрируется по горизонтали в рамках .плеер (как заголовок и лид
   над ним), текст внутри — «сейчас играет»/время — остаётся у своего
   края, не по центру (см. margin-inline:auto ниже, не text-align). */
.плеер__пульт{
  display:flex; gap:var(--поле-s); align-items:stretch; margin-bottom:.25em;
  width:fit-content; max-width:100%; margin-inline:auto;
}
/* §24 решения-дизайн.md: обложка — строго квадрат на всех размерах.
   align-items:stretch у .плеер__пульт (нужен «правой» колонке — она
   должна тянуться на всю высоту пульта) заодно растягивал и обложку по
   высоте вслед за более высоким соседом; width — фиксированный clamp, а
   aspect-ratio:1 при таком конфликте (ширина задана, высота растянута)
   не может удержать квадрат — object-fit:cover просто обрезает уже
   не-квадратную рамку. align-self:flex-start возвращает обложке
   собственную высоту, aspect-ratio держит квадрат чисто по ширине. */
.плеер__обложка{
  flex:0 0 auto; align-self:flex-start;
  width:clamp(5rem, 18vw, 8rem); height:auto; aspect-ratio:1;
  object-fit:cover;
  border:var(--рамка-s) solid var(--чернила); box-shadow:var(--тень2);
  background:var(--бумага2);
}
.плеер__правая{ flex:1 1 auto; min-width:0; display:flex; flex-direction:column; justify-content:center; gap:.5em; }
.плеер__сейчас{
  margin:0; font-size:.8em; letter-spacing:.1em; text-transform:uppercase;
  color:var(--тихий); overflow-wrap:anywhere;
}
.плеер__сейчас b{ font-weight:500; color:var(--чернила); }

/* полоса — кнопка во всю ширину: и нажатие, и протяжка считаются от её
   границ, а листалка кнопки не перетаскивает */
.плеер__полоса{
  display:block; width:100%; height:.9em; padding:0;
  border:var(--рамка-s) solid var(--чернила); background:var(--бумага2);
  box-shadow:var(--тень2); cursor:pointer; touch-action:none;
}
.плеер__прошло{ display:block; height:100%; width:0; background:var(--чернила); }
.плеер__время{
  display:flex; justify-content:space-between; margin:0;
  font-size:.72em; letter-spacing:.1em; color:var(--тихий);
  font-variant-numeric:tabular-nums;
}
.плеер__кнопки{ display:flex; gap:var(--поле-s); }
.плеер__кн{
  display:grid; place-items:center; width:2.4em; height:2.4em; padding:0;
  border:var(--рамка-s) solid var(--чернила); background:var(--карточка);
  box-shadow:var(--тень2);
  transition:background .15s var(--переход), box-shadow .15s var(--переход), transform .15s var(--переход);
}
.плеер__кн:hover{ background:var(--охра); box-shadow:var(--тень); transform:translate(-1px,-1px); }
.плеер__кн:active{ box-shadow:none; transform:translate(2px,2px); }
.плеер__кн--главная{ width:3em; height:3em; }
.значок{ width:1em; height:1em; fill:currentColor; display:block; }
/* пауза показывается вместо треугольника, только пока звук идёт */
.значок--пауза{ display:none; }
/* иконки площадок (инлайн-SVG из public/иконки/*.svg, значок_площадки() в
   собрать.py) — та же система currentColor, что и .значок выше, крупнее:
   это самостоятельная кнопка (.плеер__кн — общий класс с иконками на
   «на связи», §20/§24, не копия стилей), а не строка мелких кнопок пульта.
   Единственное объявление размера на весь сайт — раньше было два
   (здесь и у .площадки ниже), второе тем же селектором молча выигрывало
   каскад по порядку файла, первое было мёртвым кодом. */
.значок-площадки{ width:1.3em; height:1.3em; display:block; }
.плеер[data-играет] .плеер__кн--главная .значок--играть{ display:none; }
.плеер[data-играет] .плеер__кн--главная .значок--пауза{ display:block; }

/* §25 решения-дизайн.md: список и площадки разделяла пустая треть листа
   — flex:1 1 auto растягивал список на весь остаток .плеер (flex-
   колонка), а десять строк не заполняли эту высоту (лист теперь заметно
   выше — list-vyshe/§23), пустое место оставалось МЕЖДУ последней
   строкой и площадками. flex-grow:0 — список берёт свою настоящую
   высоту содержимого, площадки идут сразу следом; flex-shrink:1 и
   min-height:0 остаются — на низком экране, где десять строк не влезают
   целиком, список всё ещё сжимается и честно скроллится сам (штатное
   исключение §21), просто больше не тянется ВВЕРХ сверх своего
   содержимого, когда места и так достаточно. */
.трек-лист{ list-style:none; margin:0; padding:0; flex:0 1 auto; min-height:0; overflow-y:auto; scrollbar-width:thin; }
.трек{ border-bottom:1px solid var(--линия); }
.трек:first-child{ border-top:1px solid var(--линия); }
/* вся строка — кнопка: попасть в неё пальцем проще, чем в название, и
   листалка не принимает нажатие по списку за перетаскивание листа */
.трек__кнопка{
  /* §18 дизайн.md: строка трека «не влезает» на мобильном — разбор
     показал, что перенос имени работает (нет nowrap/ellipsis), но
     align-items:baseline выравнивал только первую строку многострочного
     имени по номеру/времени, и на глаз это читалось как обрезку.
     flex-start — номер и время у верхнего края строки, а не случайной
     базовой линии. */
  display:flex; align-items:flex-start; gap:.6em; width:100%;
  /* левое поле шире правого — в нём стоит метка играющего трека, и от неё
     строки не прыгают: место занято всегда */
  padding:.28em .3em .28em 1.2em; text-align:left; font-size:.85em; color:var(--тихий);
}
.трек__кнопка:hover{ background:var(--бумага2); color:var(--чернила); }
.трек__номер{ flex:0 0 auto; font-variant-numeric:tabular-nums; }
.трек__имя{ flex:1 1 auto; min-width:0; overflow-wrap:anywhere; }
.трек__кто{ text-transform:uppercase; letter-spacing:.06em; }
.трек__кто::after{ content:" — "; }
.трек__время{ flex:0 0 auto; font-variant-numeric:tabular-nums; }
/* играющий трек виден без цвета — жирным и меткой слева, чтобы читалось
   и в чёрно-белой печати, и при дальтонизме */
.трек--играет .трек__кнопка{ color:var(--чернила); font-weight:500; background:var(--бумага2); }
.трек--играет .трек__номер{ position:relative; }
.трек--играет .трек__номер::before{
  content:"▶"; position:absolute; left:-1em; top:0; font-size:.7em;
}

/* площадки — под списком, а не в подвале: четыре кнопки в подвал не лезут,
   а здесь это строчка иконок вроде контактов (§18: «вместо надписей
   площадок — иконки», подпись остаётся в aria-label, не исчезает совсем).
   Строка центрируется блоком, как пульт выше — justify-content вместо
   margin-inline:auto: она и так flex, а gap уже держит промежутки.
   §24: сами кнопки — класс .плеер__кн (см. собрать.py), тот же квадрат
   с рамкой/тенью/hover, что на «на связи» — своих стилей у .площадки a
   больше нет, всё несёт общий класс.
   Находка VRX: кнопки того же роста, что .плеер__кн (2.4em), заметно
   выше прежних мелких иконок — на 1440×900 .трек-лист (flex:1,
   min-height:0) недосчитался высоты и десятая строка обрезалась
   (241/233, 8px). Не трогаю сами кнопки (Виктор просил «того же
   размера», что на «на связи» — общий класс) — отступ сверху сузила
   вместе с margin-bottom пульта ниже, вдвоём хватает вернуть трек-лист
   к точному фиту. */
.площадки{
  list-style:none; margin:.25em 0 0; padding:0;
  display:flex; flex-wrap:wrap; justify-content:center; gap:.7em; color:var(--тихий);
}

@media (max-width:560px){
  /* §23 решения-дизайн.md: обложка и пульт — в две колонки даже на
     мобильном (не в колонку друг под другом, как раньше), чтобы
     выиграть высоту для списка треков. Обложка мельче, чем на
     десктопе/раньше на мобильном (была min(9rem,45vw) в колонку) —
     здесь она в строке рядом с управлением, а не над ним.
     §24: width:100% убран — Виктор прямо попросил пульт не растягивать
     на всю ширину листа шире обложки; fit-content (общее правило выше)
     держит его собственной ширины и на мобильном тоже. */
  .плеер__обложка{ width:min(5.5rem, 26vw); }
  /* §18: «компактнее», раз всё равно уменьшаем — на ступень мельче кегль
     строки трека, чтобы двухстрочных имён на мобильном стало меньше (не
     чтобы перенос совсем исчез — это было бы обратным решению) */
  .трек__кнопка{ font-size:.78em; }
}

/* ── форма заявки (§6 дизайн.md) ──
   Поля в теле листа (не в подвале — подвал везде на сайте держит только
   тему слева и действие справа, для textarea там места нет). Не <form>:
   подвал листа — отдельный от тела элемент, страница.js собирает поля
   по клику на кнопку через .closest('.лист'), а не нативной отправкой. */
.заявка{ display:flex; flex-direction:column; gap:.8em; max-width:40rem; }
.поле{ display:flex; flex-direction:column; gap:.3em; }
.поле__метка{
  font-size:.72em; letter-spacing:.14em; text-transform:uppercase; color:var(--тихий);
  -webkit-text-stroke:var(--обводка) currentColor; paint-order:stroke fill;
}
.поле input, .поле textarea{
  font:inherit; color:var(--чернила); background:var(--бумага2);
  border:var(--рамка-s) solid var(--чернила); padding:.5em .6em; resize:vertical;
  /* без тени — тень язык поднятых объектов (кнопка/медиа/лист), поле
     утоплено в бумагу, а не лежит на ней */
}
.поле input.поле--ошибка, .поле textarea.поле--ошибка{ border-color:var(--кирпич); }
.поле__ошибка{ font-size:.78em; color:var(--кирпич); }
/* ловушка для ботов: спрятана визуально, не display:none — простой бот
   заполняет всё подряд, а человек её никогда не видит и не находит табом */
.поле--ловушка{ position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0,0,0,0); }
.заявка__статус{ font-size:.82em; color:var(--кирпич); }
.заявка__успех{
  font-size:.72em; letter-spacing:.14em; text-transform:uppercase; color:var(--тихий);
  -webkit-text-stroke:var(--обводка) currentColor; paint-order:stroke fill;
}

/* ── согласие на обработку данных (152-ФЗ) ── */
.согласие{
  display:flex; align-items:flex-start; gap:.5em; margin-top:1.2em;
  font-size:.82em; line-height:1.4; max-width:40rem;
}
.согласие input{ margin-top:.2em; flex:0 0 auto; width:1.1em; height:1.1em; accent-color:var(--чернила); }
.согласие a{ border-bottom:1px solid var(--чернила); }
.enter[data-требует-согласия]{ opacity:.4; pointer-events:none; transition:opacity .15s var(--переход); }
.enter[data-требует-согласия].доступна{ opacity:1; pointer-events:auto; }

/* ── отзывы ── */
.отзыв{ margin:0 0 1.1em; max-width:44rem; }
.отзыв blockquote{
  margin:0 0 .4em; font-size:.95em; line-height:1.55; letter-spacing:.02em;
  font-style:italic;
}

/* ── люди ── */
/* Сетка, а не колонка: в «вокале» 20 имён, в «съёмочной команде» 16 с
   ролями — в один столбец лист приходилось прокручивать. minmax с max()
   даёт три колонки на десктопе и одну на телефоне, без брейкпоинтов. */
.человек-список{
  list-style:none; margin:0; padding:0; display:grid;
  grid-template-columns:repeat(auto-fill, minmax(max(18rem, 30%), 1fr));
  gap:.35em var(--поле-l);
}
.человек{
  display:flex; flex-direction:column; gap:.1em; padding:.3em 0;
  border-bottom:1px solid var(--линия); min-width:0;
}
/* длинные ники («полина маркина-тимофеева») рвутся внутри ячейки, а не
   растягивают колонку */
.человек__имя{ font-weight:500; text-transform:uppercase; letter-spacing:.03em; overflow-wrap:anywhere; }
.человек__роль{ font-size:.82em; color:var(--тихий); }

/* ── инфографика «Люди» на открывашке книги (§7 дизайн.md) ──
   Заменяет прежний плоский список «группа — число»: три яруса —
   создатели (именованные, без пропорций), «на сцене» (артисты и
   музыканты по инструментам), «за кадром». Блоки внутри строки — все
   одной ширины (решение Виктора, docs/решения-дизайн.md §3: ширина по
   числу людей отменена — она делала из мелких групп обрубки); пропорция
   группы читается по самому числу в блоке, не по его площади. */
.люди-инфо{ display:flex; flex-direction:column; gap:.7em; }
.люди-инфо h2{
  margin:.3em 0 0; font-size:.72em; letter-spacing:.14em; text-transform:uppercase;
  color:var(--тихий); -webkit-text-stroke:var(--обводка) currentColor; paint-order:stroke fill;
}
.люди-инфо__создатели{
  display:flex; align-items:center; gap:var(--поле-m); flex-wrap:wrap;
  padding-bottom:.6em; border-bottom:1px solid var(--линия);
}
.люди-инфо__создатели ul{
  list-style:none; margin:0; padding:0; display:flex; flex-wrap:wrap;
  gap:.3em 1.2em; font-size:.85em; color:var(--тихий);
}
.люди-инфо__создатели b{ color:var(--чернила); font-weight:500; text-transform:uppercase; }

.люди-инфо__строка{ display:flex; gap:var(--поле-s); align-items:stretch; }

.люди-инфо__блок{
  display:flex; flex-direction:column; gap:.15em;
  flex:1 1 0; min-width:5.5em;
  padding:.6em .7em; text-align:left;
  background:var(--карточка); border:var(--рамка-s) solid var(--чернила); box-shadow:var(--тень2);
  transition:background .15s var(--переход), box-shadow .15s var(--переход), transform .15s var(--переход);
}
a.люди-инфо__блок:hover{ background:var(--охра); box-shadow:var(--тень); transform:translate(-1px,-1px); }
a.люди-инфо__блок:active{ box-shadow:none; transform:translate(2px,2px); }
/* число — главный герой листа, не подпись к нему: крупно, одно
   начертание (жирным, tabular-nums — разряды выравниваются между
   соседними блоками разной длины числа) */
.люди-инфо__число{
  font-size:2.1em; font-weight:700; font-variant-numeric:tabular-nums; line-height:1;
}
.люди-инфо__подпись{
  font-size:.72em; letter-spacing:.1em; text-transform:uppercase; color:var(--тихий);
}

@media (max-width:560px){
  /* Правило «мобильный без прокрутки» (docs/решения-дизайн.md §12):
     сплошная колонка (один блок в ряд) на 375×812 переполняла тело на
     317px — не кегль и не скролл, а два блока в ряд вместо одного:
     ширина внутри пары по-прежнему общая (пропорция читается числом,
     имён в блоке нет), просто пар вдвое меньше, чем блоков в колонку. */
  .люди-инфо__строка{ display:grid; grid-template-columns:repeat(2, 1fr); gap:var(--поле-s); }
  /* §23 решения-дизайн.md: три яруса плотнее, блоки ниже — общее
     уплотнение на мобильном, не только на низких экранах (там своя,
     более глубокая правка ниже, в max-height:700px). */
  .люди-инфо{ gap:.4em; }
  .люди-инфо__блок{ padding:.3em .5em; }
  /* Расширенная проверка (докс/решения-дизайн.md §14 — любой потомок
     листа с внутренней прокруткой, не только тело): списки на «вокале»
     (20 имён) и «съёмочной команде» (16) на 375px переполняли тело на
     17–18px каждый — список в один столбец, .человек берёт вертикальный
     отступ построчно, и на двух самых длинных списках это набегает
     заметно. Не кегль (имена того же размера) — построчный отступ. */
  .человек{ padding:.18em 0; }
  /* §23 решения-дизайн.md: создатели одной строкой на мобильном — с
     ролями (полными предложениями) это физически не влезает ни при
     каком кегле, роль прячется (человек остаётся с именем, роль — на
     листе группы, не здесь), имена в ряд без переноса. */
  .люди-инфо__создатели ul{ flex-wrap:nowrap; }
  .люди-инфо__роль{ display:none; }
}
/* Виктор, с айфона (докс/дизайн.md §21): на настоящей высоте мобильного
   Safari (~660px видимых, а не 812 — панели адресной строки/таб-бара
   съедают часть экрана, см. .лист/dvh выше) три листа книги «Люди»
   переполнялись, хотя на «бумажных» 375×812 умещались впритык:
   открывашка (инфографика групп) на 108px, «вокал» (20 имён) на 85px,
   «съёмочная команда» (16, у части — роль второй строкой) на 26px.
   Большие группы (сама «вокал»/«съёмочная команда») не превращаю в
   сетку — читаемость построчного списка важнее, только плотнее отступ.
   max-height в паре с max-width, не одна ширина: на честных высоких
   375-экранах (812px) это уплотнение не нужно и не применяется. */
@media (max-width:560px) and (max-height:700px){
  .люди-инфо{ gap:.25em; }
  .люди-инфо__блок{ padding:.22em .4em; min-width:4.2em; gap:.05em; }
  .люди-инфо__число{ font-size:1.45em; }
  .люди-инфо__подпись{ font-size:.6em; }
  .люди-инфо__создатели{ padding-bottom:.25em; }
  .люди-инфо__строка{ gap:.35em; }
  .люди-инфо h2{ margin-top:.1em; font-size:.66em; }
  .человек{ padding:.03em 0; gap:0; }
  .человек-список{ gap:.1em; }
  .человек__роль{ font-size:.76em; }
}

/* ── лист 7: контакты ──
   тело листа — «соло» (центрировано по обеим осям, как «что такое
   сэйшен»): при «текст» (верх, левый край) под коротким содержимым
   оставалась пустая нижняя треть листа (находка kort). margin-bottom
   здесь — .соло не даёт flex-gap между своими детьми, а без отступа
   заголовок формы садится вплотную под последней ссылкой соцсетей. */
.контакты__шапка{ align-self:center; text-align:center; margin-bottom:1.4em; }
/* §20 дизайн.md «больше воздуха»: кнопки-иконки вместо строки подчёркнутых
   надписей — та же кнопка, что .плеер__кн (квадрат, рамка, box-shadow,
   тот же hover), плюс собственный зазор между иконками внутри строки. */
.контакты{
  list-style:none; margin:0; padding:0;
  display:flex; flex-wrap:wrap; justify-content:center; gap:var(--поле-m) var(--поле-l);
}
/* §24 решения-дизайн.md: больше расстояния между знаком и строкой иконок
   (было 1.2em, тот же шаг, что уже отделяет кнопку телеграма ниже — 1.4em,
   этого показалось мало, взяла заметно больше) */
.знак-крупный{ height:3.4em; width:auto; margin:0 auto 2.2em; }
/* кнопка «написать в телеграм» отделена от строки иконок тем же шагом
   воздуха, что и шапка выше (1.4em — на ступень больше var(--поле-m)) */
.контакты + .enter{ margin-top:1.4em; }

/* афиша: заполняет рамку целиком, без полей вокруг (находка Виктора,
   §12 решения-дизайн.md — было заметно меньше своей рамки: aspect-ratio
   16:9 + max-height в vh давали кадр меньше доступного места в .соло,
   центрирование только подчёркивало пустые поля по бокам/сверху-снизу).
   Ширина/высота — 100% того, что реально даёт .лист__тело.соло; картинка
   внутри (object-fit:cover, из базового .media img) обрезается под этот
   размер, а не наоборот — кадр никогда не остаётся меньше рамки. */
/* margin-bottom:var(--поле-m) у базового .media (отступ перед подписью
   на обычных карточках) здесь ни от чего не отделяет афишу — только
   раздвигал центрирование в .соло и оставлял снизу больше поля, чем
   сверху/по бокам (находка kort, ~12px). Обнулила — кадр вровень с
   рамкой на всех четырёх сторонах. */
#афиша-media{ width:100%; height:100%; max-width:none; margin-bottom:0; }

/* ── края экрана для клика (десктоп) ── */
.край{
  position:fixed; top:0; bottom:0; width:clamp(48px, 7vw, 110px);
  z-index:40; border:none; background:transparent;
  display:grid; place-items:center;
  opacity:0; transition:opacity .2s var(--переход);
}
.край:hover{ opacity:1; }
.край--назад{ left:0; cursor:w-resize; }
.край--вперёд{ right:0; cursor:e-resize; }
/* невидимая полоса (opacity:0) всё равно ловит клики, если явно не
   выключить: на узком экране лист заметно ближе к краю, и что угодно
   слева в теле листа (например, галочка согласия) может физически
   оказаться под .край--назад. На курсорных устройствах эта полоса и
   задумана — hover-раскрытие работает только через pointer-events,
   выключать нельзя; выключаем только там, где по дизайну она и так не
   нужна — на тач-устройствах без hover, где листают свайпом. */
@media (hover:none), (pointer:coarse){
  .край{ pointer-events:none; }
}
.край span{ font-size:1.4rem; color:var(--тихий); -webkit-text-stroke:.5px currentColor; paint-order:stroke fill; }

/* ── СЧЁТЧИК И ТОЧКИ ── */
.хад{
  position:fixed; left:0; right:0; bottom:0;
  display:flex; align-items:center; justify-content:center; gap:var(--поле-m);
  padding:.7rem;
  font-size:.7rem; letter-spacing:.14em; text-transform:uppercase; color:var(--тихий);
  z-index:50; pointer-events:none;
}
@media (max-width:768px){
  /* Виктор, с айфона (dqp/list-vyshe): просит ещё высоты листу — резерв
     не только в самом листе, но и в соседях. .хад компактнее — та же
     подпись/точки, тоньше внутренний отступ. */
  .хад{ padding:.35rem .7rem; }
}
.точки{ display:flex; gap:.4rem; pointer-events:auto; }
.точка{
  width:.5rem; height:.5rem; border:1px solid var(--чернила); background:transparent;
  padding:0; transition:background .15s var(--переход);
}
.точка[aria-current="true"]{ background:var(--чернила); }

/* ── оглавление: вне .лист и вне .сцена, тот же слой, что край/хад ──
   Строка семи разделов, всегда на виду, без панели и без подпунктов
   (Виктор, §10 решения-дизайн.md — раньше была выезжающая панель).
   Одна строка всегда (nowrap), но правило разное по экрану (§14,
   поправка к §13): на десктопе строка умещается без прокрутки — короткие
   подписи из словаря сайта (см. собрать.py, КОРОТКО) уже этого
   добиваются; на мобильном, если всё равно не влезает, строка
   прокручивается пальцем вбок, а не переносится и не ужимается кеглем
   до нечитаемого — горизонтальная прокрутка здесь разрешена явно
   (навигационная строка, не тело листа, на которое действует §21). */
.оглавление{
  position:fixed; top:var(--поле-m); left:50%; transform:translateX(-50%); z-index:50;
  display:flex; flex-wrap:nowrap; justify-content:center;
  gap:.9em; max-width:96vw;
  overflow-x:auto; overscroll-behavior-x:contain; scrollbar-width:none;
}
.оглавление::-webkit-scrollbar{ display:none; }
.оглавление__пункт{
  padding:.3em .05em; white-space:nowrap; flex:0 0 auto;
  font-size:.72em; letter-spacing:.08em; text-transform:uppercase; color:var(--тихий);
  border-bottom:var(--рамка-s) solid transparent;
  transition:color .15s var(--переход), border-color .15s var(--переход);
}
.оглавление__пункт:hover{ color:var(--чернила); }
.оглавление__пункт[aria-current="page"]{ color:var(--чернила); border-bottom-color:var(--чернила); }

@media (max-width:768px){
  /* §23 решения-дизайн.md, предложение Виктора: лист на мобильном
     занимает МАКСИМУМ высоты — прижат к строке оглавления сверху и к
     точкам снизу, зазоры минимальные. Готовое число (82vh/82dvh) было
     приблизительным запасом «сверху», не расчётом от реальных соседей —
     JS (вписатьЛист() в странице.js) меряет фактический низ оглавления
     и верх .хад (счётчик+точки) и подставляет --лист-верх/--лист-высота
     как честные px, тем же приёмом, что уже решает letterbox ролика
     (вписатьВидеоЦентр) и афишу (расположитьАфишу) — тут негде взять
     число из чистого CSS, соседи сами по себе не фиксированной высоты
     (шрифт по vw через clamp). inset:auto плюс отдельные top/height —
     не inset:0+margin:auto, как на десктопе: там вертикаль тоже
     авто-центрируется, а тут её явно даёт JS; горизонталь остаётся
     прежней (left/right:0+margin-inline:auto — без transform, чтобы не
     спорить с инлайновым transform, которым разложить() двигает лист). */
  .лист{
    width:94vw; inset:auto 0 auto 0; margin-inline:auto; margin-block:0;
    top:var(--лист-верх, 9vh); height:var(--лист-высота, 82vh);
  }
  .лист{ height:var(--лист-высота, 82dvh); }
  .край{ width:44px; }
  /* Виктор, со скриншота: строка оглавления прижата к самому краю
     экрана, а лист под ней стоит с полем (лист — width:94vw, тоже
     центрирован) — на глаз строка и лист не выровнены по левому краю.
     Тот же приём центрирования, что у .лист (left:50%+translateX(-50%),
     94vw), плюс justify-content:safe center — строка центрируется
     ВНУТРИ этой же 94vw-полосы, когда влезает целиком; когда не влезает
     и включается горизонтальная прокрутка (см. overflow-x:auto у
     базового .оглавление выше) — safe откатывает на выравнивание от
     начала, и левый край первого пункта совпадает с левым краем листа
     ровно потому, что это один и тот же левый край одной и той же
     94vw-полосы. Один расчёт двух требований разом. */
  .оглавление{
    top:3px; left:50%; transform:translateX(-50%);
    width:94vw; max-width:94vw; padding:0; justify-content:safe center;
  }
  /* тоньше вертикальный отступ строки — та же причина, что у .хад выше:
     резерв высоты листу за счёт соседей, не только самого листа */
  .оглавление__пункт{ padding:.15em .05em; }
}
/* §15 дизайн.md: подсказка на первом листе при заходе на сайт — коротко
   уходит на 12px влево и возвращается, один раз (страница.js добавляет
   класс после первого перейтиНаМесте(), снимает по animationend). Полный
   transform в кейфреймах, не только translateX: у активного листа на
   глубине 0 разложить() всегда даёт translate3d(0,0,0) scale(1) — это и
   есть состояние покоя, кейфреймы просто отклоняют его и возвращают
   обратно, не спорят с инлайновым transform листалки. var(--переход) —
   тот же токен, что держит остальные переходы сайта, не новая кривая
   ради одной анимации. */
@keyframes интро-подсказка{
  0%, 100%{ transform:translate3d(0, 0, 0) scale(1); }
  50%{ transform:translate3d(-12px, 0, 0) scale(1); }
}
.лист.интро-подсказка{ animation:интро-подсказка .42s var(--переход); }

@media (prefers-reduced-motion: reduce){
  .лист{ transition:none !important; }
  .лист.интро-подсказка{ animation:none; }
}
