/* ───────── Шкала отступов ─────────
   Все расстояния берутся отсюда, чтобы воздух был одинаковый по всей странице. */
:root {
  --gut:   clamp(24px, 5vw, 80px);   /* боковые поля страницы      */
  --sec:   clamp(80px, 11vw, 180px); /* между большими разделами   */
  --col:   clamp(32px, 6vw, 96px);   /* между колонками            */
  --row:   clamp(28px, 3.5vw, 48px); /* между строками опыта       */
  --tile:  clamp(20px, 2.5vw, 32px); /* между карточками кейсов    */
  --block: clamp(56px, 8vw, 110px);  /* между блоками внутри раздела */
  --text:  20px;                     /* между абзацами             */
}

* { box-sizing: border-box; }

/* Плавной прокрутки здесь намеренно нет.
   С ней ссылка «← Все работы» (portfolio.html#projects) не срабатывала:
   браузер начинал анимацию на 4500px, но пока догружались шрифты и картинки,
   она срывалась, и человек оставался в самом верху страницы вместо раздела.
   Без неё переход мгновенный и всегда попадает в нужный блок. */

body {
  margin: 0;
  background: #1a1a1a;
}

.p {
  background: #1a1a1a;
  /* своя система слоёв: без неё фоновые пятна (слой -1) ушли бы
     под заливку страницы и их не было бы видно вовсе */
  position: relative;
  isolation: isolate;
  color: #e8e8e8;
  font-family: 'Montserrat', Arial, sans-serif;
  font-size: 17px;
  line-height: 1.35;
}

.w {
  max-width: 1280px;
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--gut);
  padding-right: var(--gut);
}

.p a { color: #e8e8e8; text-decoration: none; }
.p a:hover { color: #9a9a9a; }

.p p { margin: 0 0 var(--text); }
.p p:last-child { margin-bottom: 0; }

.nav {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px;
  padding: 28px 0;
  font-size: 15px;
}
.nav div { display: flex; gap: 28px; flex-wrap: wrap; }
.nav--top { padding-bottom: 0; }
.nav-brand { font-weight: 500; font-size: 15px; }

/* ───────── Живой фон первого экрана ─────────
   Разметка и сам фильтр — в portfolio.html, там расписано,
   как считается общее поле. Здесь только размеры, движение
   кругов и зерно.

   Круги ходят навстречу друг другу с разными периодами (34 и 43
   секунды) и большим размахом: к середине цикла они сходятся
   настолько, что между пятнами вырастает перемычка, а к концу
   снова расходятся. Периоды не кратны, поэтому сходятся они
   каждый раз по-разному.

   Слой выше первого экрана на 24vh и к низу сходит на нет: если
   обрезать его ровно по краю экрана, на стыке со следующим разделом
   осталась бы видимая горизонтальная линия. */
.hero-bg {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: calc(100svh + 24vh);
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  /* заливка цветом страницы: зерно наложено режимом «перекрытие»,
     и смешиваться ему надо с чёрным, иначе оно выбелит весь экран */
  background: #1a1a1a;
  isolation: isolate;
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 24vh), transparent 100%);
          mask-image: linear-gradient(to bottom, #000 calc(100% - 24vh), transparent 100%);
}
.hero-field {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}
/* Движутся сами координаты центров, и заданы они в процентах экрана,
   а не сдвигом на столько-то пикселей. Это принципиально: исходные
   места кругов тоже в процентах, поэтому на узком экране фиксированный
   сдвиг уводил круги не навстречу друг другу, а врозь.

   К середине цикла оба идут к центру и перекрываются — поле
   складывается, фигура становится одной. К концу расходятся обратно.
   Периоды 34 и 43 секунды не кратны, поэтому сходятся они каждый раз
   по-разному и повтор не читается. */
.hero-field .f1 { animation: field-a 34s ease-in-out infinite; }
.hero-field .f2 { animation: field-b 43s ease-in-out infinite; }
/* Глубина захода подобрана замером: в середине цикла края
   перекрываются примерно на 140 px при сумме радиусов около 680.
   Глубже нельзя — шары сливаются в один ровный круг и перемычка
   пропадает; мельче — они просто касаются и слияния не видно.
   Пути намеренно разной формы, чтобы перешеек каждый раз
   вырастал в стороне, а не строго по диагонали. */
@keyframes field-a {
  0%   { cx: 19%; cy: 15%; }
  30%  { cx: 27%; cy: 23%; }
  50%  { cx: 32%; cy: 29%; }
  72%  { cx: 24%; cy: 19%; }
  100% { cx: 19%; cy: 15%; }
}
@keyframes field-b {
  0%   { cx: 81%; cy: 77%; }
  30%  { cx: 73%; cy: 70%; }
  50%  { cx: 68%; cy: 64%; }
  72%  { cx: 77%; cy: 73%; }
  100% { cx: 81%; cy: 77%; }
}
@media (prefers-reduced-motion: reduce) {
  .hero-field .f1, .hero-field .f2 { animation: none; }
}

/* Зерно. Режим «перекрытие» почти не трогает чёрное и проявляется
   на светлых местах — поэтому пыль видна только там, где есть свет. */
.hero-bg .grain {
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 200px 200px;
  opacity: 0.5;
  mix-blend-mode: overlay;
}

/* ───────── Первый экран ─────────
   Титул занимает всю высоту окна: меню сверху, «Portfolio» по центру,
   контакты прижаты к низу. Кегль и стрелка заданы в vw, поэтому
   строка держит одну и ту же долю экрана на любом мониторе.
   Ограничение по vh нужно для низких окон: на ноутбуке с короткой
   высотой заголовок не должен выталкивать контакты за край экрана. */
.screen {
  max-width: none;          /* обложка во всю ширину окна, а не в колонку 1280 */
  /* поля тоже доля экрана, иначе на широком мониторе справа копится пустота */
  padding-left: max(24px, 5vw);
  padding-right: max(24px, 5vw);
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  padding-bottom: clamp(24px, 4vh, 56px);
}
.screen .hero { margin-top: auto; margin-bottom: auto; padding-top: clamp(24px, 4vh, 56px); }

.hero {
  padding-top: clamp(24px, 5vw, 64px);
  display: flex;
  align-items: flex-end;
  gap: 3vw;
}
.hero svg { width: min(13.5vw, 26vh); min-width: 44px; flex: none; margin-bottom: 1.2vw; }
/* 18.9vw подобрано по замеру: стрелка 13.5vw + отступ 3vw + слово = ровно 90vw,
   то есть правый край «Portfolio» садится на правое поле страницы.
   Ограничение 35vh — для низких окон: в ноутбуке 1440×700 заголовок
   иначе выталкивает контакты за нижний край первого экрана. */
.hero h1 { font-size: min(18.9vw, 35vh); }
.hero-meta { margin-top: clamp(40px, 6vw, 80px); font-size: clamp(17px, 1.8vw, 22px); }
/* Контакты на первом экране: значок + адрес, строки друг под другом.
   Расстояние между строками задано отступом сетки, а не межстрочным
   интервалом: иначе значок и текст в строке разъезжались бы по высоте. */
.hero-contacts {
  font-size: 14px;
  margin-top: 16px;
  line-height: 1.4;
  display: grid;
  gap: 14px;
  justify-items: start;
}
.hero-contacts a { display: inline-flex; align-items: center; gap: 10px; }
/* значок повторяет цвет текста, поэтому гаснет вместе с ним при наведении */
.hero-contacts svg { width: 17px; height: 17px; flex: none; display: block; }

/* Телефон в портретной ориентации: 100svh минус адресная строка оставляет
   мало места, поэтому заголовок ограничиваем только по ширине */
/* Уже 520px боковые поля перестают быть долей экрана и фиксируются на 24px,
   поэтому доля под заголовок уменьшается */
@media (max-width: 520px) {
  .hero svg { width: 13.5vw; }
  /* поля здесь уже не доля экрана, а 24px, поэтому вычитаем их отдельно,
     иначе на телефоне справа от слова остаётся пустая полоса */
  .hero h1 { font-size: calc(21.3vw - 12px); }
}

.h { margin: 0; font-weight: 500; letter-spacing: -0.055em; line-height: 0.88; }
.m { color: #9a9a9a; font-size: 14px; letter-spacing: 0.02em; line-height: 1.5; }

/* Раздел: воздух сверху и снизу + запас под якорную прокрутку */
/* Только padding-top: шорткат обнулил бы боковые поля из .w */
.sec {
  padding-top: var(--sec);
  scroll-margin-top: 32px;
}

.sec-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 24px;
  font-size: 15px;
  font-weight: 500;
}
.sec-num { text-align: right; font-weight: 400; }
.sec-kicker { color: #e8e8e8; }
.sec-num b {
  display: block;
  margin-top: 4px;
  font-size: 30px;
  font-weight: 400;
  letter-spacing: -0.02em;
}

.sec-title {
  /* нижняя граница 46px, а не 56: при 320px «Портфолио» в 56px не влезает
     в колонку и страница начинает ездить вбок */
  font-size: clamp(46px, 11vw, 150px);
  margin: clamp(20px, 2.5vw, 36px) 0 clamp(40px, 5vw, 72px);
  letter-spacing: -0.06em;
}

/* Подпись в конце раздела — отбита сверху и отделяет раздел от следующего */
.sign {
  display: flex;
  justify-content: space-between;
  gap: 24px;
  font-size: 15px;
  margin-top: clamp(56px, 7vw, 100px);
  padding-top: 24px;
  border-top: 1px solid #3a3a3a;
}
.sign b { font-weight: 600; }

.g2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr)); gap: var(--col); }
.g3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); gap: var(--col); }
/* 320px, чтобы пять кейсов вставали 3 + 2, а не 4 + одинокая плитка.
   min(...) обязателен: без него колонка не сжимается и на узком экране вылезает за край. */
.gw { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); gap: var(--tile); }

.ph {
  background: #2a2a2a;
  color: #9a9a9a;
  font-size: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 300px;
  padding: 24px;
  text-align: center;
}
/* Обложки проектов */
.shot {
  display: block;
  width: 100%;
  /* height: auto обязателен: у <img> есть атрибуты width/height, и без него
     высота берётся из атрибута, а aspect-ratio просто игнорируется */
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  background: #2a2a2a;
}
/* Слайд презентации показываем в его пропорции 16:9, а не режем под 4:3 */
.shot--wide { aspect-ratio: 16 / 9; }
/* Кадры AI-образов вертикальные, 4:5 */
.shot--tall { aspect-ratio: 4 / 5; }
/* auto-fill, а не auto-fit: одинокая плитка занимает одну колонку,
   а не растягивается на всю ширину раздела */
.gw--fill { grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr)); }

.tile .shot { transition: opacity .2s ease; }
.tile:hover .shot { opacity: .78; }

.ln { border-top: 1px solid #3a3a3a; padding-top: 18px; }

.stat {
  font-size: clamp(48px, 7vw, 96px);
  letter-spacing: -0.05em;
  font-weight: 500;
  /* цифры одной ширины: разряд не ёрзает, пока барабан крутится */
  font-variant-numeric: tabular-nums;
  /* разряды стоят рядом и выравниваются по нижнему краю */
  display: flex;
  align-items: flex-end;
  /* Высота ячейки барабана = высота строки числа. Обе величины берутся
     отсюда, поэтому цифры стоят ровно там же, где стояли бы обычным
     текстом, и подпись под числом не сдвигается. */
  --cell: 0.9em;
  line-height: 0.9;
  position: relative;
}
/* Знаки «~» и «+»: та же высота, что у барабана, чтобы всё стояло на одной линии */
.stat-fix { display: block; height: var(--cell); }
/* Окошко в одну цифру: всё, что выше и ниже, обрезано */
.stat-reel {
  display: block;
  width: 1ch;
  height: var(--cell);
  overflow: hidden;
  /* повторяем трекинг числа: ширина разряда задана жёстко,
     и без этого «~10» стало бы чуть шире обычного */
  margin-right: -0.05em;
}
/* Столбик цифр, который едет вверх за окошком */
.stat-col { display: block; will-change: transform; }
.stat-col > span { display: block; height: var(--cell); }
/* Барабан целиком не выделяется: иначе при копировании страницы
   вместо «5+» в буфер попадёт весь столбик, 01234567890 */
.stat-reel, .stat-fix { user-select: none; -webkit-user-select: none; }
/* Настоящее число для копирования, поиска по странице и экранных читалок:
   лежит рядом с барабаном, но не видно и места не занимает */
.stat-real {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.stats { margin-bottom: var(--block); }
.stat-note { margin-top: 12px; font-size: 15px; }

/* Строка опыта */
.job {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  gap: var(--col);
  padding-top: 24px;
  padding-bottom: var(--row);
}
/* Появление блоков при прокрутке. Исходное состояние навешивает
   скрипт: без него всё просто стоит на местах.

   Сдвиг вбок задан долей бокового поля, а не числом пикселей: так блок
   едет внутри полей страницы и на узком экране она не начинает
   ездить вбок. Для плиток сдвиг вертикальный, его можно задать
   в пикселях — вниз страница и так прокручивается. */
.fly-x {
  opacity: 0;
  transform: translateX(calc(var(--gut) * -0.6));
  will-change: opacity, transform;
}
.fly-x.fly-x-in {
  opacity: 1;
  transform: none;
  transition: opacity .6s ease, transform .75s cubic-bezier(.22, .68, .3, 1);
}
.fly-y {
  opacity: 0;
  transform: translateY(26px);
  will-change: opacity, transform;
}
.fly-y.fly-y-in {
  opacity: 1;
  transform: none;
  transition: opacity .55s ease, transform .7s cubic-bezier(.22, .68, .3, 1);
}

.job-title { font-size: clamp(24px, 2.8vw, 34px); letter-spacing: -0.03em; line-height: 1.05; }
.job-body { font-size: 15px; max-width: 560px; line-height: 1.5; }
.job-date { margin-top: 10px; }
.tags { margin-top: 16px; }

/* Категория портфолио */
/* scroll-margin-top — чтобы при переходе по якорю заголовок раздела
   не прилипал вплотную к верхнему краю окна */
.cat { margin-top: var(--block); padding-top: 24px; scroll-margin-top: 28px; }
.cat-head { margin-bottom: clamp(28px, 3.5vw, 44px); }
.cat-title { font-size: clamp(32px, 5vw, 56px); letter-spacing: -0.04em; line-height: 1; }
.cat-note { max-width: 420px; align-self: end; font-size: 15px; }
.cat-nav { display: flex; gap: clamp(20px, 3vw, 36px); flex-wrap: wrap; font-size: 15px; }

.tile-cap { margin-top: 18px; padding-top: 18px; font-size: 15px; line-height: 1.5; }
.tile-tags { margin-top: 8px; }

.lead { font-size: 15px; max-width: 460px; line-height: 1.5; }

/* Программы / образование в конце раздела «Опыт» */
.extras { margin-top: var(--block); }
.extras p { margin: 12px 0 0; font-size: 15px; line-height: 1.5; }
/* Ряду иконок нужна ширина, образованию хватает узкой колонки */
@media (min-width: 900px) {
  .extras { grid-template-columns: minmax(0, 1.9fr) minmax(0, 1fr); }
}

/* Программы: плитка с монограммой + название */
/* Сетка, а не просто перенос по строкам: названия выстраиваются в колонки */
.tools {
  list-style: none; margin: 18px 0 0; padding: 0;
  display: grid;
  /* колонка не уже 130px: иначе «PowerPoint» не влезает рядом с плиткой и вылезает за край */
  grid-template-columns: repeat(auto-fit, minmax(min(130px, 100%), 1fr));
  gap: 16px 24px;
}
@media (min-width: 900px) {
  .tools { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.tools li { display: flex; align-items: center; gap: 10px; font-size: 14px; color: #cfcfcf; }
.tool-ico {
  width: 36px; height: 36px; flex: none;
  display: flex; align-items: center; justify-content: center;
  border-radius: 8px;
  background: var(--ico-bg);
  color: var(--ico-fg);
  /* светлая обводка внутрь + мягкое свечение наружу в цвет самой иконки.
     Цвет свечения задан отдельной переменной, а не цветом знака:
     зелёный и голубой на тёмном фоне светятся заметно сильнее тёплых,
     поэтому прозрачность у каждого своя: подобрана на глаз так,
     чтобы все шесть светились одинаково, а не по яркости цвета. */
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.08),
    0 0 18px -3px var(--ico-glow);
  font-size: 15px; font-weight: 600; line-height: 1;
}
.tool-ico svg { height: 20px; width: auto; display: block; }
/* У Figma знака одного цвета нет, для свечения берём фиолетовый:
   самое крупное пятно в логотипе. */
.t-ai  { --ico-bg: #2e1200; --ico-fg: #ff9a00; --ico-glow: rgba(255, 154,   0, 0.50); }
.t-ps  { --ico-bg: #001e36; --ico-fg: #31a8ff; --ico-glow: rgba( 49, 168, 255, 0.36); }
.t-id  { --ico-bg: #2e0219; --ico-fg: #ff3366; --ico-glow: rgba(255,  51, 102, 0.55); }
.t-fg  { --ico-bg: #242424;                    --ico-glow: rgba(162,  89, 255, 0.68); }
.t-cdr { --ico-bg: #06240f; --ico-fg: #4ade80; --ico-glow: rgba( 74, 222, 128, 0.32); }
.t-ppt { --ico-bg: #35150c; --ico-fg: #ed6c47; --ico-glow: rgba(237, 108,  71, 0.56); }
.tools-note { margin-top: 18px; color: #9a9a9a; font-size: 14px; }

/* Контакты */
.contact-title {
  /* Две короткие строки, поэтому кегль почти как у первого экрана.
     Верхняя граница 200px: выше строка упирается в край колонки
     на широком мониторе. */
  font-size: clamp(42px, 12vw, 200px);
  margin: clamp(20px, 2.5vw, 36px) 0 clamp(40px, 5vw, 72px);
}
.contact-links { display: flex; gap: clamp(24px, 5vw, 72px); flex-wrap: wrap; font-size: 20px; }
/* значок и адрес на одной линии, как на первом экране */
.contact-links a { display: inline-flex; align-items: center; gap: 12px; }
/* значок повторяет цвет текста, поэтому гаснет вместе с ним при наведении */
.contact-links svg { width: 22px; height: 22px; flex: none; display: block; }
#contact { padding-bottom: clamp(56px, 7vw, 100px); }

/* ───────── Бегущая строка ─────────
   Лента состоит из двух одинаковых половин и едет влево ровно
   на половину своей длины. В этот момент вторая половина оказывается
   там, где была первая, и анимация начинается заново: стыка не видно.

   Разделителей между словами нет, их роль играет расстояние. Поэтому
   каждое слово — отдельный элемент, а промежуток задан через gap:
   точку пришлось бы ставить руками и она ломала бы ритм. */
.ticker {
  overflow: hidden;
  border-top: 1px solid #3a3a3a;
  border-bottom: 1px solid #3a3a3a;
  padding: clamp(12px, 1.4vw, 18px) 0;
  /* курсор над строкой не должен её выделять: это декор, а не текст */
  user-select: none;
}
.ticker-row {
  display: flex;
  width: max-content;
  animation: ticker 60s linear infinite;
  will-change: transform;
}
.ticker-half,
.ticker-set {
  display: flex;
  /* тот же промежуток, что между словами, нужен и на стыке наборов */
  gap: var(--ticker-gap);
  padding-right: var(--ticker-gap);
}
.ticker-half {
  padding-right: 0;
}
.ticker {
  --ticker-gap: clamp(34px, 4.5vw, 78px);
}
.ticker-set span {
  font-size: clamp(13px, 1.5vw, 19px);
  letter-spacing: 0.02em;
  color: #6a6a6a;
  white-space: nowrap;
}
@keyframes ticker {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
/* «уменьшить движение» в системе: строка остаётся, но стоит */
@media (prefers-reduced-motion: reduce) {
  .ticker-row { animation: none; }
}

/* Копирайт — тихая строка по центру, закрывает страницу */
.copyright {
  text-align: center;
  padding: clamp(28px, 3.5vw, 48px) var(--gut) clamp(32px, 4vw, 56px);
  color: #5e5e5e;
  font-size: 13px;
}

/* Обо мне: фото слева крупным кадром, текст справа по центру по высоте */
.about-grid { display: grid; gap: var(--col); }
@media (min-width: 900px) {
  .about-grid {
    grid-template-columns: minmax(0, 1.96fr) minmax(0, 1fr);
    /* в референсе колонки стоят теснее, чем остальные пары на странице */
    column-gap: clamp(28px, 3.8vw, 48px);
    /* фото от имени до «МОСКВА»: верх и низ на одной линии с текстом */
    align-items: stretch;
  }
  .about-photo { align-self: stretch; object-fit: cover; object-position: 57% 50%; }
}
/* На телефоне панорама во всю ширину вышла бы узкой полоской — подрезаем в 3:2 */
@media (max-width: 899px) {
  .about-photo { aspect-ratio: 3 / 2; object-fit: cover; object-position: 57% 50%; }
}
.about-text { max-width: 460px; }
/* Текст выключен по формату, как в исходном шаблоне; переносы спасают от «дыр» */
.about-text p { text-align: justify; hyphens: auto; font-size: 14px; line-height: 1.55; }
.about-status { text-align: left; }
/* Кадр широкий и невысокий — показываем его как есть, без подрезки */
.about-photo {
  display: block;
  width: 100%;
  height: auto;
  background: #2a2a2a;
  /* кадр отзеркален: взгляд направлен в сторону текста */
  transform: scaleX(-1);
}
.about-status { margin-top: clamp(24px, 3vw, 40px); }
.about-name {
  font-size: clamp(34px, 4vw, 54px);
  letter-spacing: -0.035em;
  line-height: 1;
  font-weight: 600;
  margin-bottom: clamp(32px, 4vw, 52px);
}

/* ───────── Страница отдельного кейса ───────── */
.case {
  padding-top: clamp(40px, 6vw, 80px);
  padding-bottom: clamp(64px, 8vw, 120px);
}
.case-kicker { margin-bottom: clamp(20px, 2.5vw, 32px); }
.case-title {
  font-size: clamp(40px, 8vw, 110px);
  margin: 0 0 clamp(14px, 1.6vw, 22px);
  letter-spacing: -0.055em;
}
/* Описание кейса — подзаголовком: имя бренда крупно, что это такое — мельче */
.case-sub {
  max-width: 760px;
  margin: 0 0 clamp(40px, 5vw, 72px);
  font-size: clamp(19px, 2.2vw, 28px);
  line-height: 1.2;
  letter-spacing: -0.03em;
  color: #9a9a9a;
}
.case-meta { margin-bottom: clamp(48px, 6vw, 88px); }
/* Две ячейки, но ширина колонки прежняя: справа остаётся воздух, а не растянутая строка */
@media (min-width: 900px) {
  .case-meta { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.case-meta p { margin: 12px 0 0; max-width: 420px; font-size: 15px; line-height: 1.5; }
.case-intro { max-width: 660px; font-size: 17px; line-height: 1.6; }
.case-intro p { margin: 0 0 1.1em; }
.case-intro p:last-child { margin-bottom: 0; }

/* Кадры кейса: во всю ширину колонки, высота по пропорциям картинки */
.case-shots { margin-top: clamp(56px, 7vw, 100px); display: grid; gap: var(--tile); }
.case-shots img { display: block; width: 100%; height: auto; background: #2a2a2a; }

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

   Кирпичи, их можно переставлять и повторять:
     .case-part     — заголовок части
     .case-wide     — кадр во всю ширину колонки
     .case-bleed    — кадр на вылет, за боковые поля
     .case-split    — крупный кадр и узкая колонка рядом
     .case-stagger  — два кадра разной ширины, второй опущен
     .case-row3     — три кадра, середина крупнее
     .case-trio     — три равных кадра
     .case-social   — сторис, последняя колонка остаётся пустой
     .case-side     — кадр и текст рядом (с --flip текст слева)
     .case-note     — короткая подпись под кадром

   Пропорция кадра задаётся классом заглушки:
     .ph--wide (16:9)  .ph--sq (1:1)  .ph--tall (4:5)  .ph--story (9:16) */

.case-part { margin-top: clamp(64px, 8vw, 120px); margin-bottom: clamp(24px, 3vw, 40px); }
.case-part-title { font-size: clamp(26px, 3.4vw, 40px); letter-spacing: -0.04em; line-height: 1.05; }
.case-part-note { max-width: 460px; align-self: start; font-size: 15px; line-height: 1.5; }

.case-wide { margin-top: var(--tile); }
/* первый кадр отбиваем от вводки сильнее, чем кадры друг от друга */
.case-intro + .case-wide,
.case-intro + .case-bleed { margin-top: clamp(56px, 7vw, 100px); }

/* Кадр на вылет. Поля отдаёт отрицательный отступ, а не ширина 100vw:
   с 100vw на системах с видимой полосой прокрутки страница уезжает вбок. */
.case-bleed { margin-top: clamp(40px, 5vw, 72px); margin-inline: calc(var(--gut) * -1); }

.case-pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
             gap: var(--tile); margin-top: var(--tile); }
.case-trio { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
             gap: var(--tile); margin-top: var(--tile); }

/* Асимметричная пара: крупный кадр и узкая колонка с мелким кадром
   и подписью. Колонки 7:5 — разница видна, но ряд не разваливается. */
.case-split { display: grid; gap: var(--tile); margin-top: var(--tile); align-items: start; }
@media (min-width: 860px) { .case-split { grid-template-columns: 7fr 5fr; } }

/* Ряд со сдвигом: второй кадр уже и опущен, строка перестаёт читаться
   как две одинаковые плитки. */
.case-stagger { display: grid; gap: var(--tile); margin-top: var(--tile); align-items: start; }
@media (min-width: 860px) {
  .case-stagger { grid-template-columns: 8fr 4fr; }
  .case-stagger > :last-child { margin-top: clamp(40px, 6vw, 96px); }
}

/* Три кадра, середина крупнее, крайние опущены — у ряда есть центр. */
.case-row3 { display: grid; gap: var(--tile); margin-top: var(--tile); align-items: start; }
@media (min-width: 720px) {
  .case-row3 { grid-template-columns: 5fr 7fr 5fr; }
  .case-row3 > :nth-child(odd) { margin-top: clamp(28px, 4vw, 64px); }
}

/* Сторис: сетка на четыре колонки, кадра три. Пустая колонка справа —
   это воздух, а не недосмотр. */
.case-social { display: grid; gap: var(--tile); margin-top: var(--tile);
               grid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 1fr)); }
@media (min-width: 720px) { .case-social { grid-template-columns: repeat(4, 1fr); } }

/* Кадр и текст рядом. Текст прижат к верху кадра, а не растянут по высоте:
   иначе короткая подпись висит посреди пустоты. */
.case-side { display: grid; gap: var(--col); margin-top: var(--tile); align-items: start; }
@media (min-width: 860px) {
  /* кадр всегда шире текста; в --flip текст просто стоит первым в разметке */
  .case-side { grid-template-columns: 3fr 2fr; }
  .case-side--flip { grid-template-columns: 2fr 3fr; }
}
.case-side-text { font-size: 15px; line-height: 1.6; max-width: 420px; }
.case-side-text p { margin: 0 0 1em; }
.case-side-text p:last-child { margin-bottom: 0; }

.case-note { margin: 14px 0 0; font-size: 14px; line-height: 1.55; color: #9a9a9a; max-width: 38ch; }

/* Кадры и заглушки внутри всех этих блоков ведут себя одинаково */
.case-wide img, .case-bleed img, .case-pair img, .case-trio img, .case-side img,
.case-split img, .case-stagger img, .case-row3 img, .case-social img {
  display: block; width: 100%; height: auto; background: #2a2a2a;
}

/* Заглушка внутри кейса: не серый ящик с подписью посередине, а слот
   с волосяной рамкой и меткой в углу — читается как раскладка, а не
   как дырка в странице. */
.case .ph {
  position: relative;
  background: #212121;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07);
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-end;
  gap: 6px;
  padding: clamp(14px, 1.8vw, 22px);
  text-align: left;
  min-height: 0;
}
/* пропорция будущего кадра — в верхнем углу слота */
.ph-r {
  position: absolute;
  top: clamp(14px, 1.8vw, 22px);
  left: clamp(14px, 1.8vw, 22px);
  font-size: 11px;
  letter-spacing: 0.16em;
  color: #6b6b6b;
}
/* что сюда встанет */
.ph-t { font-size: clamp(15px, 1.5vw, 18px); line-height: 1.25; color: #d0d0d0; }
/* чем именно наполнить кадр */
.ph-d { font-size: 13px; line-height: 1.45; color: #8a8a8a; max-width: 44ch; }
/* в узких слотах подсказка не помещается — остаётся только название */
.ph--story .ph-d, .ph--tall .ph-d { display: none; }
@media (min-width: 1100px) { .ph--tall .ph-d { display: block; } }
.ph--wide  { aspect-ratio: 16 / 9;  min-height: 0; }
.ph--sq    { aspect-ratio: 1;       min-height: 0; }
.ph--tall  { aspect-ratio: 4 / 5;   min-height: 0; }
.ph--story { aspect-ratio: 9 / 16;  min-height: 0; }


/* Переход к следующему кейсу */
.case-foot {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 24px;
  margin-top: clamp(56px, 7vw, 100px);
  padding-top: 24px;
  border-top: 1px solid #3a3a3a;
  font-size: 15px;
}
/* Обложка следующего кейса: переход видно, а не только читаешь */
.case-next-shot {
  display: block;
  width: clamp(160px, 20vw, 260px);
  height: auto;              /* см. комментарий у .shot */
  aspect-ratio: 4 / 3;
  object-fit: cover;
  margin: 16px 0 0 auto;
  background: #2a2a2a;
  transition: opacity .2s ease;
}
.case-next:hover .case-next-shot { opacity: .78; }
.case-next { text-align: right; }
.case-next b {
  display: block;
  margin-top: 6px;
  font-size: clamp(20px, 2.4vw, 30px);
  font-weight: 500;
  letter-spacing: -0.03em;
}

/* Видео на странице образа. Вертикальные ролики 9:16, в ряд.
   Ширина ряда ограничена: на всю колонку они были бы в рост экрана.
   980px — под три ролика примерно по 300px; при нехватке места
   ряд сам переносится. */
.case-video { margin-top: clamp(40px, 5vw, 64px); }
.video-row {
  margin-top: 18px;
  display: grid;
  gap: var(--tile);
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  max-width: 980px;
}
.video-row video {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 9 / 16;
  background: #2a2a2a;
}

/* Обложка приложения: одна иконка на фоне самой страницы, без подложки.
   Поле квадратное и иконка занимает его целиком — тогда линия над
   подписью идёт ровно по ширине иконки, а не торчит за её край. */
.app-cover {
  aspect-ratio: 1;
  background: none;
}
/* Иконка приложения как на телефоне: белая плашка со срезанными углами,
   знак внутри. В присланном файле только знак, на прозрачном фоне, —
   белая подложка рисуется здесь. Фигуры знака упираются в край, поэтому
   плашка обрезает содержимое: углы срезаются вместе со знаком. */
.app-icon {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  background: #fff;
  /* 22.4% — та же доля, что у иконок iOS */
  border-radius: 22.4%;
  overflow: hidden;
}
.app-icon img { display: block; width: 100%; height: 100%; }
/* заглушка под второе приложение в той же пропорции, что обложка */
#apps .ph { aspect-ratio: 1; min-height: 0; }

/* ───────── Страница приложения ─────────
   Экраны идут не одной сеткой, а тремя блоками по сценарию: у каждого
   свой заголовок, свой текст и пара экранов. Так страница читается
   как рассказ о пути человека, а не как контактный лист.

   Подложки под экранами нет: они висят прямо на чёрном фоне. Отрывает
   их от фона только тень — большая и мягкая, поэтому читается как
   расстояние до стены, а не как контур.

   На широком экране три кадра стоят стопкой: центральный впереди
   и крупнее, боковые уменьшены и заходят под него. При наведении
   боковой выезжает из-под центрального и вырастает до полного роста.
   На узком экране и на телефоне стопки нет — там нечем наводить,
   и кадры просто идут сеткой. */
.app-step { margin-top: clamp(56px, 7vw, 100px); }
.app-step-head { margin-bottom: clamp(24px, 3vw, 36px); }
.app-step-title { font-size: clamp(28px, 4vw, 46px); letter-spacing: -0.04em; line-height: 1.05; }
.app-step-note { max-width: 460px; align-self: start; font-size: 15px; }

.app-shots {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
  gap: clamp(28px, 5vw, 64px);
  justify-items: center;
  align-items: start;
  /* запас снизу, чтобы тень и подъём при наведении не обрезались */
  padding-bottom: clamp(24px, 3vw, 40px);
}
.app-shots img {
  display: block;
  width: 100%;
  max-width: 300px;
  height: auto;
  aspect-ratio: 9 / 19.5;
  object-fit: cover;
  /* скруглением экран читается как телефон, рамка для этого не нужна */
  border-radius: clamp(14px, 2vw, 26px);
  /* Две тени: дальняя задаёт высоту над фоном, ближняя прижимает
     нижний край, иначе экран выглядит приклеенным. */
  box-shadow: 0 34px 68px -16px rgba(0, 0, 0, 0.85),
              0 12px 26px -10px rgba(0, 0, 0, 0.7);
  transition: transform .5s cubic-bezier(.22, .68, .3, 1),
              box-shadow .5s cubic-bezier(.22, .68, .3, 1);
  will-change: transform;
}
.app-shots img:hover {
  transform: translateY(-14px) scale(1.015);
  box-shadow: 0 54px 96px -18px rgba(0, 0, 0, 0.9),
              0 18px 38px -12px rgba(0, 0, 0, 0.75);
}

/* ── Стопка-карусель. Только там, где есть мышь и хватает ширины ──
   Кадры лежат друг на друге в одной точке, а место каждого задаёт
   сдвиг. Поэтому их можно менять местами плавно: меняется только
   номер слота, а браузер сам доводит кадр до нового места.
   Номера слотов проставляет скрипт внизу страницы приложения. */
@media (hover: hover) and (min-width: 800px) {
  .app-shots--stack {
    display: block;
    position: relative;
    /* ширина одного кадра; высота блока — ровно высота кадра */
    --кадр: clamp(230px, 25vw, 330px);
    height: calc(var(--кадр) * 19.5 / 9);
    /* на сколько центры соседних кадров разведены в стороны */
    --сдвиг: calc(var(--кадр) * 0.72);
    /* боковой кадр при наведении выезжает наружу ещё на столько */
    --вылет: calc(var(--кадр) * 0.26);
    padding-bottom: 0;
    margin-bottom: clamp(24px, 3vw, 40px);
  }
  .app-shots--stack img {
    position: absolute;
    left: 50%;
    top: 0;
    width: var(--кадр);
    max-width: none;
    /* чтобы края уменьшенного кадра не дрожали при смене масштаба */
    backface-visibility: hidden;
    transition: transform .65s cubic-bezier(.22, .68, .3, 1),
                box-shadow .65s cubic-bezier(.22, .68, .3, 1),
                filter .65s cubic-bezier(.22, .68, .3, 1);
  }
  /* центральный: впереди всех, в полный рост и без затемнения */
  .app-shots--stack img[data-slot="0"] {
    transform: translateX(-50%) scale(1);
    z-index: 3;
  }
  .app-shots--stack img[data-slot="0"]:hover {
    transform: translateX(-50%) translateY(-14px) scale(1.015);
    z-index: 5;
  }
  /* боковые: мельче, заходят под центральный, тень слабее */
  /* боковые: мельче, темнее и с более слабой тенью — они дальше */
  .app-shots--stack img[data-slot="-1"],
  .app-shots--stack img[data-slot="1"] {
    filter: brightness(0.62);
    box-shadow: 0 24px 48px -16px rgba(0, 0, 0, 0.8),
                0 8px 18px -10px rgba(0, 0, 0, 0.65);
  }
  /* левый всегда в самом низу стопки: уходя под остальные, он и даёт
     ощущение, что карусель проворачивается, а не просто меняет места */
  .app-shots--stack img[data-slot="-1"] {
    transform: translateX(calc(-50% - var(--сдвиг))) scale(0.84);
    z-index: 0;
  }
  .app-shots--stack img[data-slot="1"] {
    transform: translateX(calc(-50% + var(--сдвиг))) scale(0.84);
    z-index: 1;
  }
  /* наведение: боковой выезжает из-под центрального и вырастает */
  .app-shots--stack img[data-slot="-1"]:hover {
    transform: translateX(calc(-50% - var(--сдвиг) - var(--вылет))) scale(1);
    filter: none;
    z-index: 5;
    box-shadow: 0 54px 96px -18px rgba(0, 0, 0, 0.9),
                0 18px 38px -12px rgba(0, 0, 0, 0.75);
  }
  .app-shots--stack img[data-slot="1"]:hover {
    transform: translateX(calc(-50% + var(--сдвиг) + var(--вылет))) scale(1);
    filter: none;
    z-index: 5;
    box-shadow: 0 54px 96px -18px rgba(0, 0, 0, 0.9),
                0 18px 38px -12px rgba(0, 0, 0, 0.75);
  }
}

/* у кого в системе выключены анимации — переходов нет, но раскладка
   остаётся: иначе стопка рассыпалась бы при наведении */
@media (prefers-reduced-motion: reduce) {
  .app-shots img { transition: none; }
  .app-shots img:nth-child(2):hover { transform: none; }
}

/* ───────── Страница AI-образа ─────────
   Кадры генерации небольшие по пикселям, поэтому показываем их сеткой,
   а не во всю ширину колонки: в ячейке ~350px картинка остаётся резкой. */
.ai-grid {
  margin-top: clamp(56px, 7vw, 100px);
  display: grid;
  gap: var(--tile);
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
}
@media (min-width: 900px) { .ai-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.ai-grid img {
  display: block;
  width: 100%;
  height: auto;              /* см. комментарий у .shot */
  aspect-ratio: 4 / 5;
  object-fit: cover;
  background: #2a2a2a;
}

/* Вводка к раскладке: временная строка, пока кейс не наполнен кадрами */
.case-plan { margin: clamp(40px, 5vw, 64px) 0 0; max-width: 560px;
             font-size: 14px; line-height: 1.55; color: #8a8a8a; }
