/* ────────────────────────────────────────────────────────────
   ОБОЛОЧКА СТРАНИЦЫ КЕЙСА

   Раскладка, общая для ВСЕХ кейсов. Подключается после design-system.css
   и ничего в ней не переопределяет — только достраивает своё: рельсу,
   стопку карточек, ленту кадров, пагинацию.

   Вынесено из вёрстки кейса, когда страниц кейсов стало пять. До этого
   оболочка жила прямо в файле кейса, и это работало ровно пока кейс был
   один: 626 строк на пять копий — это 3130 строк, в которых любая правка
   раскладки делается пять раз, а расхождение между копиями замечается
   не сразу.

   Содержимое кейса — заголовок, текст карточек, кадры — остаётся
   в его собственном index.html. Здесь только форма.
   ──────────────────────────────────────────────────────────── */

/* ────────────────────────────────────────────────────────────
   КЕЙС «OH MY GADGET!»

   Раскладка: слева рельса, справа только картинки. Рельса делится
   на две части — верх постоянный (аватар, язык, возврат), низ
   меняется по мере прокрутки: каждой группе картинок соответствует
   своя карточка текста.

   Текст и картинки перенесены со старого сайта bogutvictor.ru/omg.
   Деление на карточки — оттуда же: где на старом сайте новый блок
   текста, здесь новая карточка.
   ──────────────────────────────────────────────────────────── */

/* Рельса ровно четверть ширины экрана — как на главной, где рельса тоже 25vw.
   Раньше стоял clamp(280px, 25vw, 420px): на широком мониторе он упирался
   в потолок 420, и доля переставала быть долей. Ни пола, ни потолка теперь
   нет, деление одинаковое на любой ширине. */
:root { --case-rail: 25vw; }

.case {
  display: grid;
  grid-template-columns: var(--case-rail) minmax(0, 1fr);
  gap: var(--gap);
  padding: var(--edge);
  align-items: start;
}

.rail {
  position: sticky;
  top: var(--edge);
  height: calc(100dvh - var(--edge) * 2);
  display: grid;
  /* Три ряда: постоянный верх, меняющийся текст, постоянные контакты.
     Соцсети в ряду auto — они прибиты к низу рельсы и не уезжают
     вместе с текстом. */
  grid-template-rows: auto minmax(0, 1fr) auto;
  gap: var(--gap);
  min-width: 0;
}

/* Постоянный верх: аватар и возврат. Переключателя языка здесь нет —
   смена языка живёт только на главной, и внутри кейса ей делать нечего.
   Освободившееся место забрала кнопка возврата. */
.idrow {
  display: grid;
  /* Колонка ровно под аватар, высота ряда — от него же.

     Была пропорция 410/100 от ширины рельсы, и аватар получался её
     следствием: на кейсе рельса шире, чем колонка главной, и один и тот же
     аватар выходил 95 против 77 на планшете. Теперь наоборот — размер
     задан аватару, а ряд подстраивается. */
  grid-template-columns: var(--ava) minmax(0, 1fr);
  grid-auto-rows: var(--ava);
  gap: var(--gap);
  min-height: 0;
}

/* Кнопка возврата: уголок и подпись в одну строку, вместе по центру блока.
   .tile--sm из системы центрует единственного ребёнка через place-items,
   а здесь их двое — нужен flex со своим зазором.
   Селектор из двух классов, чтобы не зависеть от порядка подключения. */
.tile--sm.tile--back {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
}

/* Высота уголка привязана к кеглю подписи, а не задана в пикселях: кегль
   растёт вместе с экраном, фиксированная иконка от него отставала бы.
   flex: none — иначе уголок сожмётся первым, когда подписи не хватит места. */
.chev { height: 0.7em; width: auto; flex: none; transition: transform var(--t-fast) ease; }
.chev--right { transform: scaleX(-1); }

/* Под курсором уголок отъезжает в ту сторону, куда ведёт кнопка.
   Три пикселя — намёк, а не переезд: движение должно читаться боковым
   зрением и не отвлекать от подписи.

   У правого уголка порядок множителей важен. transform читается справа
   налево: сдвиг на −3 считается в СВОИХ координатах, уже перевёрнутых
   через scaleX(−1), и на экране получается +3. Если поменять местами,
   уголок поедет влево — в сторону, обратную кнопке. */
@media (hover: hover) {
  .tile--back:hover .chev,
  .pager .prev:hover .chev  { transform: translateX(-3px); }
  .pager .next:hover .chev  { transform: scaleX(-1) translateX(-3px); }
}

/* ── Динамический низ ───────────────────────────────────────
   Панель стоит на месте, меняется только текст внутри. Это принципиально:
   если бы уезжала вся панель, на каждой смене дёргалась бы вся рельса,
   и глаз ловил бы движение вместо чтения. Пропадает и появляется текст,
   рамка не шевелится.

   flex-колонка: шапка и подвал по своей высоте, карточки забирают остаток. */
.brief {
  display: flex;
  flex-direction: column;
  padding: calc(var(--gap) * 2.4);
  min-height: 0;
}

.brief-head { flex: 0 0 auto; }
.case-title {
  margin: 0 0 0.9em;
  font-size: var(--fs-section);
  font-weight: 300;
  line-height: 1.1;
  letter-spacing: -0.03em;
}

/* Стопка карточек. Все лежат друг на друге, видна одна.
   min-height: 0 обязателен — без него flex-элемент отказывается
   становиться ниже своего содержимого, и панель распирает рельсу.

   Обрезка по краям панели — на ней держится весь переход: текст уезжает
   за край, а не растворяется.

   clip, а НЕ hidden. Разница решающая: hidden создаёт полноценный контейнер
   прокрутки. Пользователь его не крутит, но браузер крутит сам — семь карточек,
   припаркованных под панелью, растягивают область прокрутки, и якорение
   прокрутки сдвигает scrollTop контейнера на всю их высоту. Тогда активная
   карточка уезжает вверх за край, а на её место встаёт последняя из
   припаркованных. Поймано замером: контейнер стоял прокрученным на 627,
   активная показывала −627, а на нуле висела карточка, которой там быть
   не должно.

   clip обрезает так же, но контейнера прокрутки не создаёт — и крутить
   становится нечего. Строка с hidden оставлена выше как запасная для
   браузеров, которые clip ещё не знают.

   Маска убирает жёсткий край обрезки. Без неё текст на ходу упирался
   в невидимую прямую линию и срезался по ней на середине буквы — «стеклянный
   потолок». Градиентная маска делает эту границу мягкой: у самого края
   прозрачность падает до нуля, и строка не обрывается, а растворяется.

   Полоса растворения задана в долях кегля, а не в пикселях: она должна быть
   примерно в полторы строки, а строка растёт вместе с кеглем. */
.cards {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  overflow: clip;

  /* Кегль объявлен и здесь, и на самой карточке — намеренно.

     --растворение задано в em, и em считается от кегля ТОГО элемента, где
     используется. Маска живёт на контейнере, отступ — на карточке, и пока
     кегли различались, один токен разрешался в два числа: 27.2 против 29.
     Разница безобидная, но это ровно тот сорт молчаливого расхождения,
     который потом ищешь полдня. Один кегль на оба — одно значение. */
  font-size: max(15px, calc(var(--fs-role) * 1.05));

  --растворение: 1.7em;
  -webkit-mask-image: linear-gradient(to bottom,
      transparent 0, #000 var(--растворение),
      #000 calc(100% - var(--растворение)), transparent 100%);
          mask-image: linear-gradient(to bottom,
      transparent 0, #000 var(--растворение),
      #000 calc(100% - var(--растворение)), transparent 100%);
}

/* Смена карточек сдвигом, а не растворением.

   Растворение читалось плохо: на середине перехода видны ДВА полупрозрачных
   текста сразу, и глаз не понимает, какой из них читать. При сдвиге текст
   всё время непрозрачный — он просто уезжает, а на его место приходит другой.

   Направление берётся из порядка карточек, отдельного состояния «уходит»
   не нужно. Карточки выше активной припаркованы НАД панелью, ниже активной —
   ПОД ней. Когда активной становится следующая, предыдущая автоматически
   попадает в разряд «выше» и уезжает вверх, а новая приходит снизу. При
   прокрутке назад всё разворачивается само собой, без единой строки на это. */
/* Отступы сверху и снизу равны полосе растворения: в покое текст обязан
   стоять НИЖЕ неё, иначе первая строка окажется приглушённой просто так.
   Растворение должно работать только на ходу. */
.card {
  position: absolute;
  inset: 0;
  padding-block: var(--растворение);
  overflow: auto;
  visibility: hidden;
  transform: translateY(110%);          /* по умолчанию — под панелью */
  transition: transform var(--t-swap) var(--e-soft), visibility var(--t-swap);
}
.card.is-above { transform: translateY(-110%); }
.card.is-active {
  visibility: visible;
  transform: none;
}

.card p { margin: 0 0 0.9em; }
.card p:last-child { margin-bottom: 0; }
.card ol {
  margin: 0 0 0.9em;
  padding-left: 1.2em;
}
.card li { margin-bottom: 0.35em; }

/* Мера строки от кегля, не от ширины панели. max с 15 — нижний предел
   для телефона, где --fs-role падает до 12. */
.card {
  font-size: max(15px, calc(var(--fs-role) * 1.05));
  font-weight: 200;
  line-height: 1.55;
}


/* ── Правая колонка: только картинки ────────────────────────
   Кадр здесь — сама картинка со скруглением, без подложки и полей.

   Обратный вариант — объект НА панели, с полями — в системе тоже есть,
   и выбор между ними делается по содержимому, а не по вкусу. Фотографии,
   интерьеры и снимки экрана заполняют кадр целиком, и панель вокруг них
   была бы лишней рамкой в рамке. Панель нужна предметам с прозрачностью
   и мокапам на весу — им нужен воздух по краям.

   Разбор обоих видов — в design-system.md, «Кадр: на подложке или во всю
   рамку». */
.shots {
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  min-width: 0;
}
.group {
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  min-width: 0;
}
.pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gap);
  min-width: 0;
}

.shot {
  border-radius: var(--radius);
  overflow: hidden;
  min-width: 0;
  background: var(--panel);   /* видно, пока картинка не пришла */
}
.shot img {
  display: block;
  width: 100%;
  height: auto;
}
/* Кадр, который не встаёт встык по контейнеру.

   По умолчанию высота кадра выходит из пропорции самой картинки, и она садится
   в слот вплотную — подрезать нечего. Но если пропорция картинки со слотом
   не сходится, кадр НЕ сужается и не ложится на подложку с полями: контейнер
   берёт свою пропорцию, а картинка заполняет его целиком и подрезается.

   Раньше здесь стояло сужение до 46% — по бокам оставались полосы фона,
   и лента переставала быть лентой. Потом — объект на подложке с полями:
   просветов не стало, но внутри кадра появилась пустота. Заполнение убирает
   и то, и другое: колонка сплошная, кадр сплошной.

   Пропорция контейнера разная по ширине экрана. 16/10 на десктопе — при 1170
   в ширину это 731 в высоту, вменяемый кадр. На узком экране контейнер выше:
   там ширины мало, и горизонтальный кадр съедал бы почти всё изображение. */
.shot--fill { aspect-ratio: 16 / 10; }
.shot--fill img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Плашка-уведомление ростом с полосу контактов — и здесь это НЕ --ava.

   В двухколонной раскладке полоса лежит в рельсе, и высоту ей даёт пропорция
   300/63 от ширины рельсы, а не токен. Система такого знать не может: --case-rail
   объявлен здесь, на странице. Поэтому пересчёт живёт тоже здесь — системный
   компонент остаётся общим, а страница уточняет его своей величиной.

   Формула ровно та же, что у кнопок пагинации ниже: совпасть с полосой они
   могут только через общий источник — рельсу. */
.toast { height: calc(var(--case-rail) * 63 / 300); }

.pager {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gap);
  margin-top: calc(var(--gap) * 4);
}
/* Высота считается от рельсы, а не подбирается отступами: у полосы контактов
   она выходит из ширины рельсы через пропорцию 300/63, и здесь берётся ровно
   та же формула. Кнопки стоят в другой колонке и другой ширины, поэтому
   совпасть по высоте они могут только через общий источник — рельсу. */
.pager .tile {
  height: calc(var(--case-rail) * 63 / 300);
  padding: 0 calc(var(--gap) * 2);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6em;
}

/* ══════════════════════════════════════════════════════════════
   ГОРИЗОНТАЛЬНЫЙ ПЛАНШЕТ

   Диапазон 901–1100 в альбомной: две колонки ещё держатся, но десктопные
   пропорции здесь врут, и врут дважды.

   Первое: рельса. 25vw на 1024 это 256, упирается в нижнюю границу 280,
   и на текст остаётся 194 — двадцать пять знаков в строке. Читать нельзя.
   Доля увеличена до 38%: рельса становится 389, галерея 581 — картинкам
   этого хватает с запасом.

   Второе, и это важнее: отступы панели считаются от --gap, а компактный
   --gap РАВЕН 18 против десктопных 10. Множитель 2.4 давал 43 пикселя
   с каждой стороны вместо 24 — панель съедала текст собственными полями.
   Множитель здесь свой, чтобы отступ в пикселях остался прежним.

   Итог обеих правок: две первые карточки перестают быть обрезанными.
   До правки им не хватало 288 и 313 пикселей по высоте — то есть половина
   текста кейса на планшете была недоступна.
   ══════════════════════════════════════════════════════════════ */
@media (orientation: landscape) and (min-width: 901px) and (max-width: 1100px) {
  :root { --case-rail: clamp(340px, 38vw, 420px); }

  /* 1.3 вместо 2.4: при --gap в 18 это те же ~24 пикселя, что на десктопе. */
  .brief { padding: calc(var(--gap) * 1.3); }

  /* Заголовок отдаёт часть своего отступа карточкам — высоты здесь мало. */
  .case-title { margin-bottom: 0.5em; }

  /* Полоса растворения тоже ужимается: она съедает высоту дважды,
     сверху и снизу, а строк тут дефицит. */
  .cards { --растворение: 1.3em; }

  /* Интерлиньяж и отступ между абзацами чуть плотнее десктопных.

     После правки рельсы самая длинная карточка влезала с запасом в 15
     пикселей — меньше одной строки. Любая правка текста или другой
     рендеринг шрифта ломали бы раскладку. 1.5 вместо 1.55 и 0.7em вместо
     0.9em дают тридцать с лишним пикселей запаса, а на глаз разница
     в плотности не читается. */
  .card { line-height: 1.5; }
  .card p { margin-bottom: 0.7em; }
}

/* ══════════════════════════════════════════════════════════════
   ОДНА КОЛОНКА: узкий экран и любая портретная раскладка

   Стопка карточек здесь не нужна и вредна: текст отрывается от своих
   картинок. Поэтому карточки перестают быть стопкой и раскладываются
   по местам — каждая над своей группой кадров. Переносит их скрипт
   внизу страницы, копия текста одна.

   Условие не только по ширине. Раньше стоял голый max-width: 900px,
   и вертикальный планшет в него не попадал: у iPad Pro в портрете
   1024 по ширине — формально «широкий экран». Страница отдавала ему
   двухколоночную десктопную раскладку с липкой рельсой, где текст
   стоит отдельно от кадров. Портретная ориентация теперь включает
   одну колонку независимо от ширины.

   Шапка и контакты в этой раскладке липкие: страница кейса длинная,
   и возврат с контактами должны быть под рукой на любой её высоте.
   ══════════════════════════════════════════════════════════════ */
@media (max-width: 900px), (orientation: portrait) {
  /* fixed, а не sticky, и это вынужденно.

     Рельса здесь раскрыта через display: contents, поэтому шапка и контакты
     стали самостоятельными ячейками грида. Липкий блок ездит только внутри
     СВОЕЙ ячейки, а ячейка ровно по высоте блока — ехать некуда, и sticky
     молча не работает. Проверено прокруткой: на 3894 пикселях ни шапки,
     ни контактов на экране не было.

     Цена fixed — блоки уходят из потока, и место под них надо занять руками.
     Обе полосы ростом с аватар, поэтому и резерв под них одинаковый.

     Слагаемых ровно три, и каждое отвечает за своё: --edge отодвигает блок
     от края экрана, --ava это сам блок, --gap — зазор до содержимого.
     Отступ здесь ОДИН, а не два: панели шапки кончаются на --edge + --ava,
     и второй --edge был лишним. Из-за него разрыв между шапкой и первым
     блоком выходил 32 при ритме ленты в 16 — вдвое больше, чем везде. */
  .case {
    grid-template-columns: minmax(0, 1fr);
    padding-top:    calc(var(--edge) + var(--ava) + var(--gap));
    padding-bottom: calc(var(--edge) + var(--ava) + var(--gap));
  }

  /* Рельса перестаёт быть блоком: её содержимое становится рядами страницы.

     display: contents, а не просто static — иначе контакты остаются внутри
     рельсы, а рельса идёт до ленты кадров, и полоса соцсетей оказывается
     в начале длинной страницы, сразу под заголовком. Раскрыв рельсу, можно
     отправить контакты в самый низ обычным order. */
  .rail { display: contents; }

  /* Название переехало в шапку, стопка не нужна — в панели не осталось
     ничего. Прячем её целиком, а не оставляем пустую рамку. */
  .brief { display: none; }

  /* ШАПКА: аватар, возврат, название. Липкая.

     Третья колонка добавляется под название, которое скрипт переносит
     сюда из панели. minmax(0, 1fr) — чтобы длинное название сжимало
     себя, а не разрывало ряд.

     Подложки у самой шапки НЕТ намеренно: три блока просто висят над
     содержимым, и между ними видно, как оно проезжает. Поэтому фон нужен
     каждому блоку отдельно — иначе название легло бы прямо на фотографию.
     Аватар непрозрачен сам, кнопке и названию фон возвращён ниже. */
  .idrow {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 5;
    grid-template-columns: var(--ava) auto minmax(0, 1fr);
    padding: var(--edge) var(--edge) var(--gap);
  }

  /* Кнопка возврата стоит в колонке auto, ровно по содержимому,
     и подпись упиралась в края. Отступ по бокам от --gap, а не числом. */
  /* Блоки шапки непрозрачные. Подложки у ряда нет, содержимое проезжает
     прямо под ними, и на 70% прозрачности оно просвечивало сквозь панель.

     Тот же приём, что у контактов: сверху слой цвета панели, под ним
     непрозрачный фон страницы. Выглядит ровно как обычная панель, но
     сквозь неё уже ничего не видно. Цвет обязан идти картинкой —
     в шорткоде background он допустим только в последнем слое. */
  .idrow > .tile--back,
  .idrow > .case-title {
    background-image: linear-gradient(var(--panel), var(--panel)), var(--page-bg);
    background-attachment: scroll, fixed;
  }

  /* Ширина считается от --ava, как и высота, — а не от длины подписи.

     Колонка у кнопки `auto`, то есть ровно по содержимому, и ширину ей давал
     текст: величина от КЕГЛЯ. Высота при этом приходит из --ava, а та в портрете
     считается от ВЫСОТЫ ЭКРАНА. Два источника растут с разной скоростью, и на
     высоком планшете высота догоняла ширину: 110×76 на телефоне, 140×113 на Air,
     140×130 на iPad Pro — отношение падало с 1.45 до 1.08, и кнопка становилась
     квадратом. Заодно это мина под перевод: «Проекты» короче, чем «Projects»,
     и на русской версии квадрат наступил бы раньше.

     Один источник на обе стороны это чинит: отношение держится 1.6 на любом
     экране (проверено на 375, 834 и 1024). Название отдаёт под это 12 пикселей
     на телефоне и 68 на iPad Pro — при 622 остатка незаметно.

     min-width, а не width: правило только поднимает ширину и никогда не режет
     подпись, если та окажется длиннее вычисленного минимума. */
  .idrow > .tile--back {
    padding-inline: calc(var(--gap) * 1.6);
    min-width: calc(var(--ava) * 1.6);
  }

  /* Название крупнее кнопки — чтобы читалось как заголовок страницы,
     а не как ещё одна плитка в ряду.

     Кегль привязан к высоте самой шапки, а не задан своим clamp: шапка
     ростом с аватар, аватар считается от высоты экрана, и название растёт
     вместе с ними. Отдельный clamp пришлось бы согласовывать с ними руками
     при каждой правке.

     Перенос разрешён: на телефоне колонка узкая, и две строки лучше,
     чем название, вылезающее за экран. */
  .idrow > .case-title {
    margin: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 calc(var(--gap) * 2);
    min-width: 0;
    /* Фона здесь нет намеренно: он задан выше слоями, вместе с кнопкой.
       Шорткод background сбросил бы background-image в none, и название
       снова стало бы прозрачным — что и случилось при первой правке. */
    border-radius: var(--radius);
    font-size: calc(var(--ava) * 0.28);
    line-height: 1.1;
    text-align: center;
  }

  /* Карточка переехала внутрь группы: она снова обычный блок в потоке. */
  .group > .card {
    position: static;
    opacity: 1;
    visibility: visible;
    transform: none;
    transition: none;
    overflow: visible;
    background: var(--panel);
    border-radius: var(--radius);
    padding: calc(var(--gap) * 2.4);
  }

  /* Контакты прибиты к низу экрана. Панель остаётся плавающей и круглой,
     как на главной, — поэтому подложка не растягивается на всю ширину,
     а подкладывается ПОД саму панель вторым слоем фона.

     Два слоя: сверху полупрозрачный --panel, под ним непрозрачный фон
     страницы. Выглядит ровно так же, как раньше, но содержимое больше
     не просвечивает сквозь контакты на прокрутке.

     Цвет завёрнут в linear-gradient намеренно. В шорткоде background
     цвет допустим ТОЛЬКО в последнем слое, и запись «цвет, картинка»
     браузер бракует целиком — вместе с ней отваливается и подложка.
     Градиент из одного цвета в себя же — это уже картинка, и слоем
     она встаёт куда угодно. */
  .socials {
    position: fixed;
    /* По центру, а не во всю ширину: left: 50% ставит левый край блока
       в середину экрана, translateX(-50%) сдвигает его на половину
       собственной ширины обратно. right: auto обязателен — иначе пара
       left/right продолжила бы растягивать блок на всю ширину. */
    left: 50%;
    right: auto;
    transform: translateX(-50%);
    bottom: var(--edge);
    z-index: 5;
    /* Ширина ВЫВОДИТСЯ из квадратных ячеек, а не задаётся отдельно.

       Высота блока равна --ava, значит сторона квадратной ячейки это
       --ava минус два отступа. Четыре такие ячейки плюс три зазора между
       ними плюс два отступа по краям дают

         2·gap + 4·(ava − 2·gap) + 3·gap  =  4·ava − 3·gap

       Из этого выходит приятное свойство: ширина падает вместе с высотой,
       а высота считается от высоты экрана. Значит на любом телефоне полоса
       заведомо уже экрана и подпирать её потолком не нужно. */
    width: calc(var(--ava) * 4 - var(--gap) * 3);

    /* Ростом с шапку. Пропорция 300/63 из системы задаёт высоту от ШИРИНЫ,
       и на планшете полоса выходила 168 против шапки в 112 — низ экрана
       перевешивал верх. Здесь высота задана прямо, а пропорция отключена,
       иначе она продолжила бы спорить за тот же размер. */
    height: var(--ava);
    aspect-ratio: auto;

    /* Подложки нет: полоса полупрозрачная, как на главной, и содержимое
       под ней просвечивает. Это осознанный выбор в пользу единообразия
       с главной — там сквозь соцсети виден портрет.

       Блоки шапки при этом остаются непрозрачными: там под панелью
       оказывается НАЗВАНИЕ КЕЙСА, и фотография сквозь него мешала бы
       читать. У соцсетей читать нечего — только иконки, и у каждой своя
       сплошная плашка. */
  }

  /* Ячейки снова квадратные. В полосе система отключает им пропорцию —
     там ячейка вытянутая, — но здесь высота блока задана явно, и квадрат
     из неё получается сам. */
  .socials a { aspect-ratio: 1; }

  .pair { grid-template-columns: minmax(0, 1fr); }
  /* Контейнер выше: на 352 в ширину пропорция 16/10 дала бы 220 в высоту,
     и от вертикальной картинки осталась бы узкая полоса поперёк. */
  .shot--fill { aspect-ratio: 4 / 5; }

  /* Кнопки остаются в один ряд — колонки берутся из базового правила,
     переопределять их здесь не нужно.

     А вот высота от рельсы тут не работает: рельса раскрыта и своей
     ширины больше не имеет. Возвращаем отступы. */
  /* Ростом с шапку и с полосой соцсетей — ровно --ava.

     Стояла высота ЯЧЕЙКИ соцсетей, --ava минус два отступа: на ступень мельче
     полосы. Довод был в том, что кнопки во всю ширину, и при высоте шапки
     внутри окажется много пустоты вокруг короткой подписи. На планшете это
     не подтвердилось: кнопка широкая, подпись по центру, и блок читается как
     ещё одна панель того же ряда, а не как раздутая кнопка. Зато разница
     в 32 пикселя (ровно два --gap) была видна сразу — три горизонтали
     страницы шли тремя разными высотами.

     Теперь шапка, кнопки и соцсети берут высоту из одного --ava: на 834 это
     112.5, на 1024 — 129.9. Одна полоса на всю страницу. */
  /* В одну колонку рельса раскрыта, своей ширины у неё нет, и полоса контактов
     получает высоту прямо — var(--ava). Плашка возвращается к тому же источнику. */
  .toast { height: var(--ava); }

  .pager { margin-top: var(--gap); }
  .pager .tile {
    height: var(--ava);
    padding: 0 calc(var(--gap) * 2);
  }
}

/* ══════════════════════════════════════════════════════════════
   ТЕЛЕФОН: название уходит из ряда шапки на свою полосу

   В одну колонку шапка держит три блока в ряд — аватар, возврат, название.
   На планшете места хватает, на телефоне нет: название получало 130 пикселей
   при 375 в ширину и ломалось на две строки. На 430 то же самое — 149 и снова
   две строки, то есть весь телефонный диапазон, а не только узкие модели.

   Название уходит из шапки в НАЧАЛО ЛЕНТЫ и прокручивается вместе с ней.
   Прибитым оно быть не должно: на телефоне и так прибиты шапка сверху
   и контакты снизу, третья несменяемая полоса делает верх экрана нагромождением.
   Название — это то, что читают один раз в начале, держать его перед глазами
   всю страницу незачем.

   Из-за этого одним CSS не обойтись. Ребёнок фиксированного блока фиксирован
   вместе с ним, и «расфиксировать» его на месте нечем — название обязано
   уйти из .idrow в поток. Переносит его тот же скрипт, что раскладывает
   карточки, третьим случаем к двум имеющимся.

   Освободившееся место в шапке забирает кнопка возврата: она растягивается
   на весь остаток, как «About» и «CV» в шапке главной. min-width от --ava
   никуда не девается — он просто перестаёт быть связывающим, потому что
   доля больше него.

   Резерв под шапку не трогаем: рядов в ней по-прежнему один, и формула
   из раскладки в одну колонку остаётся верной.

   594 — та же граница, на которой в портрете вступают потолки кеглей
   (26/0.04375 и 19/0.032). Одна граница на две темы лучше двух близких:
   реальных устройств между 430 и 744 всё равно нет.
   ══════════════════════════════════════════════════════════════ */
@media (max-width: 594px) {
  /* Шапка снова в один ряд: аватар и возврат. Третья колонка не нужна —
     название в ней больше не стоит. */
  .idrow { grid-template-columns: var(--ava) minmax(0, 1fr); }

  /* Название — обычная панель в начале ленты, первым элементом колонки кадров.
     Правила приходится писать заново, а не наследовать от .idrow > .case-title:
     тот селектор перестаёт совпадать, как только узел уезжает из шапки.

     Подложка здесь простая, в один слой. Двухслойная непрозрачная нужна была
     в шапке, потому что под ней проезжало содержимое; в потоке под названием
     не проезжает ничего. */
  .shots > .case-title {
    margin: 0;
    height: calc(var(--ava) * 0.62);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 calc(var(--gap) * 2);
    background: var(--panel);
    border-radius: var(--radius);
    font-size: calc(var(--ava) * 0.3);
    line-height: 1.1;
    text-align: center;
  }
}

@media (prefers-reduced-motion: reduce) {
  .card { transition: none; }
}
