/* =========================================================
   Danila Bogatov — портфолио
   Дизайн-система описана в CLAUDE.md в корне проекта.
   Порядок блоков: токены → база → шапка → hero → цитата
   → навыки → галерея → адаптив → доступность
   ========================================================= */

/* ============ ШРИФТЫ ============
   Шрифты лежат на своём хостинге, а не на fonts.googleapis.com.
   Причина простая: если Google Fonts у посетителя недоступен или
   тормозит, страница отрисуется системным шрифтом и вся типографика
   поедет. Со своего сервера этого не случится, и внешних запросов
   у сайта не остаётся вовсе.

   Файлы ВАРИАТИВНЫЕ: один файл покрывает все нужные начертания
   (Onest 300–600, Space Grotesk 400–700) вместо файла на каждый вес.
   Скачиваются скриптом get-fonts.command в корне проекта.

   unicode-range обязателен: браузер качает только тот набор, который
   реально нужен странице. Русский текст не тянет латиницу и наоборот.
   Наборов ровно два — латиница и кириллица: я сверил все 153 символа
   сайта, latin-ext и cyrillic-ext не нужны ни одному.

   Стрелки ← и → (U+2190, U+2192) не входят НИ В ОДИН набор Google —
   их и раньше рисовал системный шрифт, так и остаётся. Это не ошибка
   подключения, добавить их некуда.

   font-display: swap — текст видно сразу системным шрифтом, потом он
   подменяется. Без него первый экран моргает пустотой.             */
@font-face{
  font-family:'Onest';
  font-style:normal;
  font-weight:300 600;
  font-display:swap;
  src:url('../fonts/onest-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face{
  font-family:'Onest';
  font-style:normal;
  font-weight:300 600;
  font-display:swap;
  src:url('../fonts/onest-cyrillic.woff2') format('woff2');
  unicode-range:U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face{
  font-family:'Space Grotesk';
  font-style:normal;
  font-weight:400 700;
  font-display:swap;
  src:url('../fonts/space-grotesk-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ============ ТОКЕНЫ ============ */
:root{
  --bg:#080A09;
  --cream:#ECE6D6;
  --cream-bright:#F2EEE2;
  --emerald:#2FB57E;
  --muted:#A6AEA4;
  --muted2:#9AA39B;
  --muted3:#6E766C;

  /* Space Grotesk кириллицу не содержит — только латинские
     дисплейные строки. Весь остальной текст набирает Onest. */
  --font-display:'Space Grotesk',system-ui,sans-serif;
  --font-text:'Onest',system-ui,-apple-system,sans-serif;
}

/* ============ БАЗА ============ */
*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth}
/* overflow-x: clip, а НЕ hidden. hidden делает body скролл-контейнером,
   и тогда position: sticky у блока навыков молча перестаёт работать —
   наезд панели кейсов держится именно на нём. clip обрезает так же,
   но контейнера не создаёт. */
body{position:relative;background:var(--bg);color:var(--cream);
  font-family:var(--font-text);overflow-x:clip}
body::before{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:
    radial-gradient(30% 15% at 82% 8%,  rgba(23,122,82,.13) 0%, transparent 72%),
    radial-gradient(26% 13% at 10% 40%, rgba(16,107,71,.10) 0%, transparent 74%),
    radial-gradient(28% 12% at 74% 72%, rgba(23,122,82,.09) 0%, transparent 74%)}
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
a{color:inherit;text-decoration:none;-webkit-tap-highlight-color:transparent}
:focus-visible{outline:2px solid var(--emerald);outline-offset:3px;border-radius:2px}

/* ============ ШАПКА ============ */
.hdr{display:flex;justify-content:space-between;align-items:center;gap:.6rem 1.5rem;flex-wrap:wrap;position:relative;z-index:3}
.hdr .nm{color:var(--cream);font-size:clamp(.82rem,1.45vw,1.05rem);font-weight:500;letter-spacing:.02em}
.hdr .nm span{color:#7E8A82;font-weight:400}
.hdr-rt{display:flex;align-items:center;gap:clamp(.7rem,1.6vw,1.3rem);margin-left:auto}
.hdr .rt{color:var(--cream);font-size:clamp(.82rem,1.45vw,1.05rem);font-weight:400;opacity:.85;cursor:pointer;white-space:nowrap}
.hdr .rt:hover{opacity:1}

/* переключатель языков — крайний справа, отделён тонкой линией */
.lang{display:flex;align-items:center;gap:.35rem;padding-left:clamp(.7rem,1.6vw,1.3rem);
  border-left:1px solid rgba(255,255,255,.14)}
.lang-b{background:none;border:0;padding:.15rem .1rem;font:inherit;cursor:pointer;
  font-size:clamp(.78rem,1.35vw,.95rem);font-weight:500;letter-spacing:.04em;
  color:var(--muted3);transition:color .25s}
.lang-b:hover{color:var(--cream)}
.lang-b.is-on{color:var(--cream-bright)}
.lang-sep{color:var(--muted3);font-size:.8rem;opacity:.6;user-select:none}

/* ============ БЛОК 1 — HERO (резиновый) ============ */
.hero{position:relative;width:100%;min-height:100vh;min-height:100svh;display:flex;flex-direction:column;
  padding:clamp(1.25rem,3.2vw,2.6rem) clamp(1.25rem,4.5vw,4.2rem);overflow:hidden;isolation:isolate}
.blob{position:absolute;border-radius:50%;filter:blur(78px);opacity:.5;z-index:0;pointer-events:none}
.b1{width:min(48%,540px);aspect-ratio:1;max-height:52%;left:4%;top:28%;background:radial-gradient(circle,#177A52 0%,#0C4A31 40%,transparent 74%);animation:drift1 14s ease-in-out infinite}
.b2{width:min(38%,440px);aspect-ratio:1;max-height:42%;right:3%;top:6%;background:radial-gradient(circle,#12664333 0%,#0C4A31 42%,transparent 74%);animation:drift2 18s ease-in-out infinite}
@keyframes drift1{0%,100%{transform:translate(0,0)}50%{transform:translate(8%,-6%)}}
@keyframes drift2{0%,100%{transform:translate(0,0)}50%{transform:translate(-7%,9%)}}
.hero-ghost{position:absolute;inset:0;display:none;flex-direction:column;justify-content:center;padding:0 clamp(1.25rem,4.5vw,4.2rem);z-index:0;pointer-events:none;overflow:hidden}
/* Фоновая надпись — только на узких экранах. На десктопе её нет:
   рядом с крупным заголовком она читается как вторая копия строк,
   Данила её оттуда убрал. Не включать обратно без просьбы. */
.hero-ghost span{display:block;font-family:var(--font-display);font-weight:700;font-size:33vh;line-height:.9;letter-spacing:-.02em;color:rgba(236,230,214,.022);white-space:nowrap}
.hero-main{flex:1;position:relative;display:flex;flex-direction:column;justify-content:center;z-index:1;padding:clamp(2rem,6vh,5rem) 0}
.hero-title{line-height:.9}
.hero-title .ln{display:block;font-family:var(--font-display);color:var(--cream);font-weight:700;font-size:clamp(2.59rem,13.77vw,14.58rem);letter-spacing:-.02em;opacity:0;transform:translateY(28px);animation:rise .9s cubic-bezier(.2,.7,.2,1) forwards}
.hero-title .ln2{animation-delay:.12s}
.hero-title .ln3{font-weight:400;color:var(--emerald);animation-delay:.24s}
@keyframes rise{to{opacity:1;transform:translateY(0)}}
.foot{position:relative;z-index:3;color:var(--muted2);font-size:clamp(.82rem,1.45vw,1rem);font-weight:300;letter-spacing:.01em}
.foot b{color:var(--cream);font-weight:500}
.glass{display:flex;align-items:center;align-self:flex-start;margin-top:clamp(1.5rem,4vh,2.5rem);border-radius:11px;
  padding:clamp(.7rem,1.5vw,1.15rem) clamp(.35rem,.7vw,.6rem);
  background:rgba(255,255,255,.025);backdrop-filter:blur(5px) saturate(1.2);-webkit-backdrop-filter:blur(5px) saturate(1.2);
  border:1px solid rgba(255,255,255,.13);box-shadow:0 8px 36px rgba(0,0,0,.28),inset 0 1px 0 rgba(255,255,255,.16);overflow:hidden;
  opacity:0;transform:translateY(20px);animation:rise .9s .5s cubic-bezier(.2,.7,.2,1) forwards}
.glass::after{content:"";position:absolute;top:0;left:-60%;width:40%;height:100%;background:linear-gradient(100deg,transparent,rgba(255,255,255,.15),transparent);transform:skewX(-18deg);animation:sheen 6s 1.6s ease-in-out infinite}
@keyframes sheen{0%{left:-60%}45%,100%{left:140%}}
.stat{flex:1 1 0;text-align:center;padding:0 clamp(.9rem,2.2vw,2rem);white-space:nowrap}
.stat+.stat{border-left:1px solid rgba(255,255,255,.12)}
.stat .v{font-family:var(--font-display);color:var(--cream-bright);font-size:clamp(1.3rem,2.5vw,2.1rem);font-weight:600;line-height:1;font-variant-numeric:tabular-nums}
.stat .l{color:#B9C0B6;font-size:clamp(.7rem,1.15vw,.92rem);font-weight:300;margin-top:5px}

/* десктоп: фирменное наложение стекла на нижний-правый угол заголовка */
@media (min-width:1024px){
  .hero-main{justify-content:center}
  .glass{position:absolute;right:0;bottom:clamp(4%,9vh,12%);margin-top:0;align-self:auto;z-index:2}
}
/* мобильный: стекло на всю ширину, статы равномерно, фоновый текст */
@media (max-width:600px){
  .glass{width:100%;align-self:stretch}
  .hero-ghost{display:flex}
}

/* ============ БЛОК 2 — ЦИТАТА ============ */
.quote{position:relative;width:100%;min-height:88vh;overflow:hidden;container-type:inline-size;display:flex;flex-direction:column;justify-content:center;padding:6% 6% 8%}
.q-wrap{width:78%;margin:0 auto}
.q-head{font-size:4cqw;line-height:1.16;font-weight:400;text-align:center;min-height:18cqw}
.q-head .cm{color:var(--cream)}
.q-head .em{color:var(--emerald)}
.q-head .cursor{display:inline-block;width:.4cqw;height:3.4cqw;background:var(--emerald);vertical-align:-.5cqw;margin-left:.25cqw;opacity:1}
.q-head .cursor.blink{animation:bl 1s steps(1) infinite}
@keyframes bl{50%{opacity:0}}
.q-sub{width:fit-content;max-width:50%;margin:3.2% 0 0 auto;text-align:right;color:var(--muted);font-size:1.35cqw;line-height:1.55;font-weight:300;opacity:0;transition:opacity .9s ease}
.q-cta{position:absolute;left:50%;bottom:5%;transform:translateX(-50%);text-align:center;opacity:0;transition:opacity .9s ease;cursor:pointer}
.q-cta .lnk{color:var(--emerald);font-size:1.2cqw;font-weight:400;letter-spacing:.05em}
.q-cta .arr{display:block;margin-top:.5cqw;color:var(--emerald);font-size:1.8cqw;line-height:1;animation:jump 1.5s ease-in-out infinite}
@keyframes jump{0%,100%{transform:translateY(0)}50%{transform:translateY(45%)}}
.show{opacity:1 !important}

/* ============ БЛОК 3 — ОБО МНЕ ============ */
/* Композиция повторяет макет Данилы: крупный заголовок, подзаголовок
   сдвинут вправо и подпирает его снизу, «Образование» — узлы на линии,
   «Опыт работы» — скоба слева и снизу, фото в правой колонке.
   Заголовок, метки и текст пунктов стоят на ОДНОЙ левой границе;
   узлы и скоба вынесены левее, в боковой отступ секции — так же,
   как в макете. Не выравнивать текст по узлам.

   Секция НЕ обрезает содержимое: overflow:hidden срезал размытую
   абстракцию по верхней кромке и на границе с цитатой появлялась
   ровная линия — тот самый видимый стык между блоками. */
.about{position:relative;width:100%;container-type:inline-size;padding:8% 0 0}
.ab-art{position:absolute;left:-10%;top:-10%;width:60%;height:66%;z-index:0;pointer-events:none}
/* overflow:visible обязателен: у корневого svg по умолчанию hidden,
   и размытые фигуры обрезались по его кромке — свечение заканчивалось
   прямой линией. Пятна размываем сильнее ленты, иначе она в них
   растворяется и в углу остаётся просто зелёное облако. */
.ab-art svg{display:block;width:100%;height:100%;overflow:visible;filter:blur(16px);opacity:.72}
.ab-art .haze{filter:blur(22px)}
.ab-grid{position:relative;z-index:1;display:grid;grid-template-columns:1fr 34%;gap:3%;
  align-items:end;padding:0 6%}
.ab-body{padding-bottom:8%}
.ab-title{font-size:6.44cqw;font-weight:600;line-height:.98;letter-spacing:-.02em;
  text-transform:uppercase;color:var(--cream)}
/* Подзаголовок сдвинут вправо и стоит вплотную под заголовком — как в макете */
.ab-sub{margin:.6% 0 0 16%;color:var(--muted);font-size:1.9cqw;font-weight:300;line-height:1.34}
.ab-part{position:relative;margin-top:6.4%}
.ab-label{color:var(--cream);font-size:1.65cqw;font-weight:600;letter-spacing:.01em}
.ab-list{margin-top:2.4%}
/* Линия — сегментом у каждого пункта, кроме последнего; отступ между
   пунктами задаёт padding-bottom самого пункта. Тогда линия всегда
   ровно от узла до узла и не зависит от высоты списка. */
.ab-item{position:relative;padding-bottom:3cqw}
.ab-item:last-child{padding-bottom:0}
.ab-item:not(:last-child)::before{content:"";position:absolute;left:-2.15cqw;top:1cqw;bottom:.4cqw;
  width:1px;background:rgba(255,255,255,.14)}
.ab-item::after{content:"";position:absolute;left:calc(-2.15cqw - 6px);top:calc(1cqw - 6px);
  width:12px;height:12px;border-radius:50%;background:var(--emerald);box-shadow:0 0 0 3px var(--bg)}
.ab-lead{display:block;color:var(--cream);font-size:1.18cqw;font-weight:400;line-height:1.5}
.ab-det{display:block;color:var(--muted2);font-size:1.18cqw;font-weight:300;line-height:1.5}
/* Опыт работы: скоба слева и снизу, как в макете */
.ab-part--exp::before{content:"";position:absolute;left:-2.15cqw;top:.3cqw;bottom:0;width:1px;
  background:rgba(255,255,255,.16)}
.ab-part--exp::after{content:"";position:absolute;left:-2.15cqw;bottom:0;width:12cqw;height:1px;
  background:rgba(255,255,255,.16)}
.ab-exp{margin-top:2.4%;padding-bottom:3cqw}
.ab-p{color:var(--muted2);font-size:1.18cqw;font-weight:300;line-height:1.55}
.ab-p+.ab-p{margin-top:2.6%}
/* Фото: чёрный свитер почти сливается с фоном, поэтому под фигурой
   слабое изумрудное свечение, а низ гасится маской — жёсткий обрез
   кадра иначе читается как ошибка. Сам файл не обрабатываем. */
.ab-photo{position:relative;align-self:end;justify-self:end;width:100%}
.ab-photo::before{content:"";position:absolute;left:50%;bottom:0;transform:translateX(-50%);
  width:120%;height:54%;z-index:0;pointer-events:none;
  background:radial-gradient(60% 62% at 50% 100%,rgba(47,181,126,.13),transparent 72%);
  filter:blur(18px)}
.ab-photo img{position:relative;z-index:1;display:block;width:100%;height:auto;
  -webkit-mask-image:linear-gradient(to bottom,#000 76%,rgba(0,0,0,.55) 92%,transparent 100%);
  mask-image:linear-gradient(to bottom,#000 76%,rgba(0,0,0,.55) 92%,transparent 100%)}

/* Появление текста при скролле. Класс .rv ставится на КАЖДУЮ строку —
   заголовок, подзаголовок, метки, обе строки пункта, абзацы опыта и
   фото, — иначе блок проявляется кусками. is-in добавляет main.js
   через IntersectionObserver, задержка считается по порядку элемента
   внутри его секции. .rv--soft для рамок и узлов: только проявление,
   без сдвига. */
/* Принудительные переносы в пунктах — разбивка строк как в макете.
   На мобильном они выключены: там своя ширина, и жёсткий перенос
   оставлял бы рваные строки. Перед каждым br стоит пробел — без него
   на мобильном соседние слова склеиваются. */
br.nb{display:none}
@media (min-width:761px){br.nb{display:inline}}

/* Скорость появления — токенами, чтобы страница могла её задать сама.
   --rv-step и --rv-max читает js/reveal.js: шаг задержки между
   элементами и предел в шагах. Числа без единиц: в CSS они не
   используются, только передаются в скрипт.
   Страница ставит свой темп атрибутом data-rv у <html>. */
:root{--rv-dur:1.15s;--rv-clip:1.3s;--rv-step:95;--rv-max:999}
/* Быстрый темп: на странице кейса веба .rv стоит на пятидесяти строках,
   и на штатном шаге 95ms элементы в конце длинной секции ждали больше
   трёх секунд после того, как попали в кадр. */
html[data-rv="fast"]{--rv-dur:.62s;--rv-clip:.72s;--rv-step:38;--rv-max:7}
.rv{opacity:0;transform:translateY(16px);
  transition:opacity var(--rv-dur) cubic-bezier(.2,.7,.2,1),
             transform var(--rv-dur) cubic-bezier(.2,.7,.2,1),
             clip-path var(--rv-clip) cubic-bezier(.2,.7,.2,1)}
.rv.is-in{opacity:1;transform:none}
.rv--soft{transform:none}
/* Заголовок выезжает из-под маски, а не просто всплывает */
.ab-title.rv{clip-path:inset(0 0 108% 0)}
.ab-title.rv.is-in{clip-path:inset(0 0 -14% 0)}

/* ============ БЛОК 4 — НАВЫКИ ============ */
/* Наезд панели кейсов на блок навыков — sticky, без работы на каждый кадр.

   Блок навыков ВЫШЕ экрана, поэтому обычный `top: 0` не годится: он
   прижал бы верх и нижнюю часть списка стало бы не прочитать. И `bottom: 0`
   не годится тоже — он прижимает элемент на входе, а не на выходе.
   Нужно смещение `100vh - высота блока`: тогда залипает именно нижняя
   кромка у низа экрана. Высоту меряет main.js и кладёт в --skills-h.

   .pin выше содержимого на --pin-travel — это и есть запас хода: пока он
   не израсходован, навыки стоят на месте. Панель кейсов начинается ровно
   на их нижней границе (отрицательный margin гасит padding обёртки) и при
   скролле едет вверх, закрывая их снизу. Контент навыков не двигается. */
/* Закрепляется первый элемент внутри .pin, кем бы он ни был: на главной
   это блок навыков, на странице команды — заголовок страницы.

   Смещение зависит от того, ВЫШЕ блок экрана или нет, и это не деталь:
   - блок ВЫШЕ экрана (навыки) — нужно `100vh - высота`, чтобы залипала
     нижняя кромка. Высоту мерит общий js/pin.js и кладёт в --pin-h;
   - блок НИЖЕ экрана (заголовок страницы) — там `100vh - высота` даёт
     ПОЛОЖИТЕЛЬНОЕ смещение, и блок залипает с самой загрузки, съезжая
     вниз на пару сотен пикселей. Такому блоку нужен обычный `top: 0`:
     он держится у верхней кромки, а панель наезжает на него снизу. */
.pin{--pin-travel:70vh;--pin-h:100vh}
.pin > :first-child{position:sticky;top:0;z-index:1}
.pin > .skills{top:calc(100vh - var(--pin-h))}
/* Ход задаёт распорка внутри .pin, а не padding: ограничитель sticky
   считается по content box родителя, и padding в него не входит —
   с padding залипания не происходит вообще. */
.pin-spacer{height:var(--pin-travel)}
.skills{width:100%;container-type:inline-size;padding:6% 0 16vh}
/* Кегль ниже 11px между 761 и ~1100px: мобильный пересчёт начинается
   только с 760, а на 768 контейнер ещё считается по десктопным
   правилам, и cqw даёт 8-10px. У мелких строк пол задан в пикселях
   через max() — выше 1100px работает обычный cqw. Не убирать. */
.sec-label{color:var(--emerald);font-size:max(11px,1.2cqw);font-weight:500;letter-spacing:.08em}
.cat{display:grid;grid-template-columns:40% 1fr;gap:3%;align-items:start;padding:5% 6%}
.cat-num{font-family:var(--font-display);font-size:22cqw;font-weight:700;color:transparent;-webkit-text-stroke:1.6px rgba(236,230,214,.3);line-height:.82;letter-spacing:-.03em;transition:-webkit-text-stroke-color .35s}
.cat:hover .cat-num{-webkit-text-stroke-color:rgba(47,181,126,.55)}
.cat-title{font-size:3.4cqw;font-weight:600;color:var(--cream);line-height:1.05}
.cat-desc{margin:2.2% 0 4%;color:var(--muted);font-size:1.3cqw;line-height:1.55;font-weight:300;max-width:88%}
.ac-h{width:100%;display:flex;justify-content:space-between;align-items:center;gap:1rem;
  border:0;border-radius:0;
  background:none;font:inherit;color:inherit;text-align:left;padding:1.6cqw 0;cursor:pointer}
.ac-t{color:var(--cream);font-size:1.5cqw;font-weight:400;letter-spacing:.005em;transition:color .3s}
.ac-n{color:var(--muted3);font-size:1.15cqw;font-weight:400;font-variant-numeric:tabular-nums}
.ac-h:hover .ac-t{color:var(--cream-bright)}
.ac.open .ac-t,.ac.open .ac-n{color:var(--emerald)}
.ac-c{max-height:0;overflow:hidden;transition:max-height .4s ease}
.ac.open .ac-c{max-height:240px}
.ac-c p{padding:.4cqw 0 2cqw;color:var(--muted2);font-size:1.25cqw;line-height:1.6;font-weight:300;max-width:82%}

/* ============ ГАЛЕРЕЯ (страница кейсов) ============ */
/* Ячейки горизонтальные и одного размера, а макеты в основном A4.
   Поэтому картинка НЕ подстраивается под ячейку, а обрезается ею:
   `object-fit: cover` + `object-position: center 15%` — видно верх
   макета, где обычно заголовок, но не вплотную к кромке.
   Оригинальный формат показывает лайтбокс, там кропа нет. */
.gallery{position:relative;width:100%;overflow:hidden;container-type:inline-size;padding:6% 0}
.g-title{color:var(--cream);font-size:3.4cqw;font-weight:600;padding:1.2% 6% 0}
.g-sub{color:var(--muted);font-size:1.3cqw;font-weight:300;padding:.6% 6% 0;max-width:62%}
.rows{margin-top:4%;display:flex;flex-direction:column;gap:1.4cqw}
.row{overflow:hidden;cursor:grab;user-select:none;-webkit-user-select:none}
.row.drag{cursor:grabbing}
.track{display:flex;gap:1.4cqw;width:max-content}
.card{flex:0 0 auto;position:relative;width:17cqw;height:12cqw;border-radius:8px;overflow:hidden;
  background:#0C1210;cursor:zoom-in;transition:transform .3s,box-shadow .3s}
.row:not(.drag) .card:hover{transform:translateY(-4px);box-shadow:0 10px 30px rgba(0,0,0,.4)}
.card-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  object-position:center 15%;
  filter:saturate(.5) contrast(1.02) brightness(.94);
  transition:filter .45s ease,transform .5s cubic-bezier(.2,.7,.2,1)}
/* Вуаль в нашей палитре: макеты разноцветные и без неё ряд рассыпается
   на пятна. На ховере вуаль почти уходит — видно настоящие цвета работы,
   в лайтбоксе её нет вообще. */
.card::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(152deg,rgba(8,10,9,.6) 0%,rgba(16,107,71,.42) 52%,rgba(8,10,9,.66) 100%);
  transition:opacity .45s ease}
.row:not(.drag) .card:hover::after{opacity:.1}
.row:not(.drag) .card:hover .card-img{filter:none;transform:scale(1.03)}
/* Широкие работы (логотипы) вписываются целиком — класс ставит
   gallery.js по пропорции файла. */
.card--wide .card-img{object-fit:contain;object-position:center;padding:9% 7%;box-sizing:border-box}
.card-n{position:absolute;left:.8cqw;bottom:.7cqw;z-index:2;pointer-events:none;
  color:rgba(236,230,214,.6);font-size:max(11px,1.1cqw);font-weight:500;letter-spacing:.05em;
  font-variant-numeric:tabular-nums}

/* ---- Лайтбокс: оригинальный формат, без кропа и без вуали ---- */
.lb{position:fixed;inset:0;z-index:100;display:none;align-items:center;justify-content:center;
  background:rgba(5,7,6,.92);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px)}
.lb.show{display:flex}
.lb-stage{display:flex;flex-direction:column;align-items:center;gap:clamp(.7rem,1.4vh,1.2rem);
  cursor:default}
.lb-img{display:block;max-width:min(88vw,1100px);max-height:80vh;width:auto;height:auto;
  border-radius:10px;box-shadow:0 20px 60px rgba(0,0,0,.5);background:#0C1210}
.lb-ph{width:min(64vw,820px);aspect-ratio:4/3;border-radius:10px;box-shadow:0 20px 60px rgba(0,0,0,.5)}
.lb-bar{display:flex;align-items:baseline;gap:clamp(.6rem,1.4vw,1.1rem);
  color:var(--muted2);font-size:clamp(.82rem,1.05vw,.98rem);font-weight:300}
.lb-num{color:var(--muted3);font-variant-numeric:tabular-nums}
/* Стрелки — та же открытая ломаная, что в карусели направлений:
   без подложек, рамок и вертикального штриха. */
.lb-nav{position:absolute;top:50%;transform:translateY(-50%);z-index:2;
  display:grid;place-items:center;width:clamp(2.6rem,4vw,3.6rem);height:clamp(2.6rem,4vw,3.6rem);
  padding:0;border:0;background:none;color:var(--muted2);cursor:pointer;transition:color .25s}
.lb-nav:hover,.lb-nav:focus-visible{color:var(--cream)}
.lb-nav svg{width:60%;height:60%;display:block}
.lb-nav--prev{left:clamp(.6rem,2.4vw,2.4rem)}
.lb-nav--next{right:clamp(.6rem,2.4vw,2.4rem)}
.lb-x{position:absolute;top:3.5%;right:4%;z-index:2;width:2.6rem;height:2.6rem;padding:0;border:0;
  /* Кнопка не наследует шрифт сама — крестик набирался Arial */
  font:inherit;
  background:none;color:var(--cream);opacity:.7;font-size:2.2rem;line-height:1;cursor:pointer;
  transition:opacity .25s}
.lb-x:hover,.lb-x:focus-visible{opacity:1}

/* ============ БЛОК 5 — ВЫБОР НАПРАВЛЕНИЯ ============ */
/* Три карточки 9:16 как сториз. Абстракция на SVG, а не фото:
   ничего не весит и не требует ассетов. Чтобы подменить на
   картинку — задать background у .dir, разметка не меняется. */
.dirs{position:relative;z-index:2;width:100%;container-type:inline-size;
  margin-top:calc(-1 * 70vh);padding:7% 0 6%;
  background:#040605;
  box-shadow:0 -24px 64px rgba(0,0,0,.68), inset 0 1px 0 rgba(255,255,255,.10)}
.dirs-head{padding:0 6%;display:flex;flex-direction:column;gap:1.1cqw}
.dirs-title{font-size:3.4cqw;font-weight:600;color:var(--cream);line-height:1.05}
.dirs-sub{color:var(--muted);font-size:max(13px,1.3cqw);line-height:1.55;font-weight:300;max-width:52%}
.dir-grid{position:relative;padding:4% 6% 6%}
.dir-track{display:grid;grid-template-columns:repeat(3,1fr);gap:2.2cqw}
/* Стрелки только на мобильном: на десктопе видны все три карточки. */
.dir-nav{display:none}
/* Слот держит карточку, её отражение и bloom под ней.
   Отражение — клон карточки, его собирает main.js:
   -webkit-box-reflect работает не везде и не рисуется в headless. */
.dir-slot{position:relative}
/* изумрудное свечение на «полу» под карточкой */
.dir-slot::after{content:"";position:absolute;left:-4%;right:-4%;top:100%;height:34%;
  z-index:-1;pointer-events:none;filter:blur(26px);
  background:radial-gradient(60% 100% at 50% 0%, rgba(47,181,126,.20) 0%,
    rgba(23,122,82,.08) 42%, transparent 78%);
  opacity:.8;transition:opacity .35s}
.dir-slot:hover::after{opacity:1}

.dir{position:relative;display:flex;flex-direction:column;justify-content:space-between;
  aspect-ratio:4/5;max-width:100%;border-radius:10px;overflow:hidden;isolation:isolate;
  padding:clamp(1rem,2.2cqw,2rem);
  background:
    radial-gradient(130% 36% at 50% 100%, rgba(47,181,126,.09) 0%, transparent 74%),
    linear-gradient(168deg,#0D1310 0%,#060807 68%);
  border:1px solid rgba(255,255,255,.09);
  transition:transform .35s cubic-bezier(.2,.7,.2,1),border-color .35s}
.dir:hover,.dir:focus-visible{transform:translateY(-4px);border-color:rgba(47,181,126,.32)}

/* свечение — то же семейство, что блобы в hero */
.dir-glow{position:absolute;border-radius:50%;filter:blur(52px);z-index:0;pointer-events:none;
  background:radial-gradient(circle,#177A52 0%,#0C4A31 44%,transparent 76%);opacity:.42;
  transition:opacity .45s,transform .45s}
.dir:hover .dir-glow{opacity:.6;transform:scale(1.08)}
.dir--1 .dir-glow{width:88%;aspect-ratio:1;left:6%;top:30%}
.dir--2 .dir-glow{width:96%;aspect-ratio:1;left:2%;top:18%}
.dir--3 .dir-glow{width:84%;aspect-ratio:1;right:-10%;top:36%}

.dir-mirror{position:absolute;top:100%;left:0;width:100%;pointer-events:none;
  transform:scaleY(-1);opacity:.62;filter:blur(5px);
  -webkit-mask-image:linear-gradient(to bottom,transparent 52%,rgba(0,0,0,.45) 82%,#000 100%);
  mask-image:linear-gradient(to bottom,transparent 52%,rgba(0,0,0,.45) 82%,#000 100%);
  transition:opacity .35s,transform .35s cubic-bezier(.2,.7,.2,1)}
.dir-slot:hover .dir-mirror{opacity:.78;transform:scaleY(-1) translateY(4px)}
.dir-mirror .dir{transform:none !important;transition:none}

/* Арт направления: между свечением (z-index 0) и текстом (z-index 2).
   Прижат к низу и центру, шире карточки — низ и бока подрезает
   overflow карточки, как на референсе. Клон-отражение подхватывает
   его автоматически, поэтому в глянце виден тот же силуэт. */
.dir-img{position:absolute;z-index:1;left:50%;bottom:-12%;
  transform:translateX(-50%);width:106%;height:auto;
  object-fit:contain;pointer-events:none;user-select:none;
  transition:transform .5s cubic-bezier(.2,.7,.2,1)}
.dir:hover .dir-img{transform:translateX(-50%) scale(1.04)}
/* Вуаль поверх арта: у верхней и нижней кромок он светлый, и текст на
   нём терялся. Порядок слоёв — арт 1, вуаль 2, текст 3. */
.dir::after{content:"";position:absolute;inset:0;z-index:2;pointer-events:none;
  background:
    linear-gradient(to bottom, rgba(4,6,5,.88) 0%, rgba(4,6,5,.38) 17%, transparent 33%),
    linear-gradient(to top,    rgba(4,6,5,.92) 0%, rgba(4,6,5,.5) 20%, transparent 40%)}

.dir-t{position:relative;z-index:3;flex:1 1 auto;min-width:0;font-size:1.9cqw;font-weight:600;line-height:1.18;
  color:var(--cream);text-wrap:balance}
.dir-t::after{content:"";display:block;width:0;height:1px;background:var(--emerald);
  margin-top:.9cqw;transition:width .4s cubic-bezier(.2,.7,.2,1)}
.dir:hover .dir-t::after,.dir:focus-visible .dir-t::after{width:2.8cqw}
.dir-go{position:relative;z-index:3;font-size:1.05cqw;font-weight:500;letter-spacing:.07em;
  text-transform:uppercase;color:var(--emerald);opacity:0;transform:translateY(6px);
  transition:opacity .35s,transform .35s}
.dir:hover .dir-go,.dir:focus-visible .dir-go{opacity:1;transform:none}

/* Заголовок и бейдж в одной строке — так они физически не могут
   наехать друг на друга ни на какой ширине. Раньше бейдж стоял
   абсолютом, и на узком экране длинный заголовок заезжал под него. */
.dir-top{position:relative;z-index:3;display:flex;align-items:flex-start;
  justify-content:space-between;gap:clamp(.6rem,1.4cqw,1.2rem);width:100%}
.dir-badge{flex:0 0 auto;z-index:3;margin-top:.2cqw;
  font-size:.95cqw;font-weight:500;letter-spacing:.1em;text-transform:uppercase;color:var(--muted3);
  border:1px solid rgba(255,255,255,.14);border-radius:3px;padding:.35cqw .7cqw;line-height:1}
/* направления, страницы которых ещё не собраны */
.dir.soon{cursor:default}
.dir.soon:hover{transform:none;border-color:rgba(255,255,255,.09)}
.dir.soon:hover .dir-glow{opacity:.26;transform:none}
.dir.soon .dir-glow{opacity:.26}
.dir.soon .dir-t{color:var(--muted2)}
.dir.soon .dir-go{display:none}

/* ============ СТРАНИЦА КЕЙСА — ШАПКА ============ */
.page-hdr{position:relative;z-index:3;padding:clamp(1.25rem,3.2vw,2.6rem) clamp(1.25rem,4.5vw,4.2rem) 0}
/* Свечение — не блоб с blur (его режут границы короткой секции),
   а градиент, который гаснет до нуля раньше края. Обрезать нечего. */
.page-top{position:relative;width:100%;container-type:inline-size;padding:6% 0 3%}
/* Пятно на странице кейса. Это градиент, а не блоб с blur: блоб режут
   границы короткой секции, и на стыке остаётся прямая линия. Градиент
   гаснет до нуля раньше краёв — обрезать нечего. */
.page-top::before{content:"";position:absolute;z-index:0;pointer-events:none;
  right:0;top:-22%;width:64%;height:160%;
  background:radial-gradient(48% 44% at 60% 40%,
    rgba(47,181,126,.26) 0%, rgba(23,122,82,.13) 44%, transparent 74%)}
.page-label{position:relative;z-index:2;color:var(--emerald);font-size:1.2cqw;font-weight:500;
  letter-spacing:.08em;padding:0 6%}
/* Заголовок страницы кейса — две строки лестницей: первая по левому
   краю, вторая уходит вправо. Капсом и в разбивку по макету Данилы,
   поэтому строки — отдельные span, а не одна строка с переносом. */
.page-h1{position:relative;z-index:2;padding:2.6% 6% 0;color:var(--cream);
  font-size:8cqw;font-weight:600;line-height:.98;letter-spacing:-.02em;text-transform:uppercase}
.ph-a{display:block}
.ph-b{display:block;text-align:right;padding-right:13%}
/* «И AI РАЗРАБОТКА» длиннее «ДИЗАЙНА»: при 13% отступа строка ломалась
   пополам и лестница превращалась в три строки. Отступ уменьшен ровно
   настолько, чтобы строка держалась в одну на любой ширине. */
.page-h1--long .ph-b{padding-right:8%}
/* Выноски: скоба из вертикали слева и короткой горизонтали сверху.
   Вторая ниже и правее первой — отсюда лестница. */
.page-notes{position:relative;z-index:2;display:grid;grid-template-columns:1fr 1fr;
  row-gap:1.6cqw;column-gap:4%;padding:4.4% 6% 0}
.pn{position:relative;padding:1.6cqw 0 1.6cqw 1.6cqw;border-left:1px solid rgba(236,230,214,.32)}
.pn::before{content:"";position:absolute;left:0;top:0;width:7.6cqw;height:1px;
  background:rgba(236,230,214,.32)}
.pn p{color:var(--muted);font-size:max(12px,1.2cqw);line-height:1.55;font-weight:300}
.pn--a{grid-column:1;grid-row:1}
.pn--b{grid-column:2;grid-row:2}
.page-intro{position:relative;z-index:2;color:var(--muted);font-size:1.35cqw;line-height:1.6;
  font-weight:300;padding:1.8% 6% 0;max-width:58%}

/* ============ СТРАНИЦА КЕЙСА — ПРОЕКТЫ ============
   Проект показывается как бренд-борд, а не как одна картинка:
   сначала мокапы, потом разбор — типографика, палитра, сетка.
   Без рамок и стёкол: ритм держат тонкие линии и отступы, как в
   блоке навыков.

   Плашки цвета берут значение из --c прямо в разметке. Это ДАННЫЕ
   проекта, а не токен системы: у каждого проекта своя палитра,
   и заводить под неё классы в общем файле нечего. Токены в :root
   при этом не трогаются.                                        */
.projects{position:relative;width:100%;container-type:inline-size;padding:2% 0 0}
.prj{padding:4.4% 6% 0}
.prj + .prj{padding-top:7.5%;margin-top:6%;border-top:1px solid rgba(236,230,214,.1)}

/* --- шапка проекта: номер, название, три поля --- */
.prj-head{display:grid;grid-template-columns:max-content 1fr max-content;gap:0 3%;align-items:start}
.prj-n{font-family:var(--font-display);font-size:5.4cqw;font-weight:700;line-height:.85;
  color:transparent;-webkit-text-stroke:1.4px rgba(236,230,214,.3);
  font-variant-numeric:tabular-nums;transition:-webkit-text-stroke-color .35s ease}
.prj:hover .prj-n{-webkit-text-stroke-color:rgba(47,181,126,.55)}
.prj-t{font-size:3.4cqw;font-weight:600;color:var(--cream);line-height:1.05}
.prj-sub{margin-top:.6cqw;color:var(--muted);font-size:max(12px,1.25cqw);font-weight:300;line-height:1.5}
.prj-meta{display:flex;gap:2.6cqw;padding-top:.5cqw}
.prj-meta dt{color:var(--muted3);font-size:max(11px,.98cqw);font-weight:400;letter-spacing:.07em;
  text-transform:uppercase}
.prj-meta dd{margin-top:.4cqw;color:var(--cream);font-size:max(12px,1.2cqw);font-weight:500;white-space:nowrap}

/* --- мокапы --- */
.prj-stage{display:grid;grid-template-columns:1fr 26%;row-gap:2.4cqw;column-gap:2.4%;
  align-items:start;margin-top:3.6%}
.prj-phones{display:grid;grid-template-columns:1fr 1fr;column-gap:6%}
.prj-strip{display:grid;grid-template-columns:1fr 1fr;row-gap:2.4cqw;column-gap:2.4%;margin-top:2.4%}

/* Кадр экрана: тонкая рамка и три точки сверху. Это рамка, а не
   имитация браузера — адресной строки нет, домена у сайта пока тоже. */
.scr{position:relative;margin:0;border:1px solid rgba(255,255,255,.1);border-radius:10px;
  overflow:hidden;background:#0A0C0B;box-shadow:0 10px 34px rgba(0,0,0,.34)}
.scr-bar{display:flex;align-items:center;gap:.5cqw;height:2.1cqw;padding:0 1cqw;
  background:rgba(255,255,255,.028);border-bottom:1px solid rgba(255,255,255,.07)}
.scr-bar i{width:.52cqw;height:.52cqw;border-radius:50%;background:rgba(236,230,214,.22)}
.scr img{display:block;width:100%;height:auto}
.scr--ph{border-radius:12px}
.scr--ph img{border-radius:11px}

/* --- бренд-борд --- */
.prj-board{display:grid;grid-template-columns:repeat(3,1fr);
  row-gap:3.4cqw;column-gap:3.4%;margin-top:4.4%}
.pb-k{color:var(--emerald);font-size:max(11px,1.05cqw);font-weight:500;letter-spacing:.08em;
  text-transform:uppercase;padding-bottom:1.5cqw;border-bottom:1px solid rgba(236,230,214,.12)}
.pb-font{display:flex;align-items:baseline;gap:1.2cqw;padding-top:1.5cqw}
.pb-aa{font-family:var(--font-text);font-size:2.9cqw;font-weight:500;color:var(--cream-bright);
  line-height:1}
.pb-aa--disp{font-family:var(--font-display);font-weight:700}
.pb-nm{display:block;color:var(--cream);font-size:max(12px,1.2cqw);font-weight:500}
.pb-nm small{display:block;margin-top:.3cqw;color:var(--muted3);font-size:max(11px,1cqw);font-weight:300}
.pb-scale{padding-top:1.6cqw;color:var(--muted);font-size:max(11px,1.05cqw);font-weight:300;
  font-variant-numeric:tabular-nums}

.pb-sw{list-style:none;padding-top:1.5cqw}
.pb-sw li{display:grid;grid-template-columns:2.1cqw max-content 1fr;gap:0 .9cqw;
  align-items:center;padding:.62cqw 0}
.pb-sw i{width:2.1cqw;height:2.1cqw;border-radius:5px;background:var(--c);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.12)}
.pb-sw b{color:var(--cream);font-size:max(11px,1.05cqw);font-weight:400;font-variant-numeric:tabular-nums}
.pb-sw small{color:var(--muted3);font-size:max(11px,1cqw);font-weight:300}

.pb-g{padding-top:1.6cqw}
.pg-w{color:var(--cream);font-size:max(12px,1.15cqw);font-weight:500;font-variant-numeric:tabular-nums}
.pg-c{display:flex;gap:2px;margin-top:.7cqw;height:1.5cqw}
.pg-c i{flex:1 1 auto;background:rgba(47,181,126,.16);border-radius:2px}
.pg-n{margin-top:.6cqw;color:var(--muted3);font-size:max(11px,1cqw);font-weight:300}

.pb-list{list-style:none;padding-top:1.5cqw}
.pb-list li{position:relative;padding:.62cqw 0 .62cqw 1.3cqw;color:var(--muted);
  font-size:max(12px,1.05cqw);font-weight:300;line-height:1.5}
.pb-list li::before{content:"";position:absolute;left:0;top:1.28cqw;width:4px;height:4px;
  border-radius:50%;background:var(--emerald);opacity:.6}

/* --- текст проекта --- */
.prj-text{margin-top:4.2%;max-width:68%}
.prj-text p{color:var(--muted);font-size:max(13px,1.3cqw);line-height:1.62;font-weight:300}
.prj-text p + p{margin-top:1.4cqw}
.prj-go{display:inline-block;margin-top:2.2cqw;color:var(--emerald);font-size:max(12px,1.2cqw);
  font-weight:400;text-decoration:none}
.prj-go:hover{text-decoration:underline;text-underline-offset:4px}

/* ============ СТРАНИЦА КЕЙСА — ПРОДУКТОВЫЙ КЕЙС ============
   У кейса Selfish AI сверх общего набора два блока — Motion и 3D.
   Оба на ОДНОЙ раскладке .feat, чтобы они читались как пара, а не
   как два разных куска: текст слева на 32%, медиа справа. Колонка
   текста растягивается на высоту медиа: заголовок с описанием сверху,
   список фактов прижат к низу. Верх и низ текста совпадают с краями
   картинки — отсюда баланс. */
.pb-aa--wide{font-weight:700;letter-spacing:.03em}

.feat{display:grid;grid-template-columns:32% 1fr;column-gap:5%;align-items:stretch;margin-top:5.4%}
.feat-tx{display:flex;flex-direction:column;justify-content:space-between;gap:2.4cqw}
.feat-tx .pb-list{padding-top:0}
.d3-b{margin-top:1.4cqw;color:var(--muted);font-size:max(13px,1.3cqw);font-weight:300;line-height:1.62}

/* --- плееры. Колонки в пропорции сторон роликов (16:9 и 1080:2340):
   тогда оба плеера ровно одной высоты. --- */
.mv{display:grid;grid-template-columns:1.7778fr .4615fr;column-gap:2.2cqw;align-items:start}
.player{position:relative;margin:0;overflow:hidden;background:#0A0C0B;
  border-radius:10px;box-shadow:0 10px 34px rgba(0,0,0,.34)}
/* Рамка — наложением, а не border: border добавляет по 2px к каждому
   плееру, в узкой мобильной колонке это 4px по высоте, и плееры
   расходились по нижнему краю */
.player::after{content:"";position:absolute;inset:0;z-index:2;pointer-events:none;
  border:1px solid rgba(255,255,255,.1);border-radius:inherit}
.player--ph{border-radius:12px}
.player video{display:block;width:100%;height:auto}
/* Вуаль на весь постер: без неё кнопка ложится на кнопки и тексты
   самого макета и читается как часть интерфейса, а не как плеер */
.pl-btn{position:absolute;inset:0;display:grid;place-items:center;padding:0;border:0;cursor:pointer;
  background:rgba(4,6,5,.42);color:inherit;transition:background .25s ease}
.pl-btn:hover{background:rgba(4,6,5,.22)}
/* Кнопка — стекло сайта, а не белый диск. Треугольник центрирован по
   центру тяжести (вершины 8.5/8.5/19 → ровно 12 из 24), без сдвига
   margin'ом. На узком мобильном плеере кнопка меньше. */
.pl-btn span{display:grid;place-items:center;width:64px;height:64px;border-radius:50%;
  background:rgba(8,10,9,.38);border:1px solid rgba(236,230,214,.55);
  -webkit-backdrop-filter:blur(8px) saturate(1.2);backdrop-filter:blur(8px) saturate(1.2);
  box-shadow:0 8px 30px rgba(0,0,0,.35);transition:transform .25s ease,background .25s ease}
.pl-btn svg{display:block;width:22px;height:22px;fill:var(--cream)}
.pl-btn:hover span{transform:scale(1.06);background:rgba(236,230,214,.14)}
.pl-btn:focus-visible{outline:2px solid var(--emerald);outline-offset:-5px;border-radius:10px}
.player--ph .pl-btn span{width:46px;height:46px}
.player--ph .pl-btn svg{width:17px;height:17px}
.player.is-on .pl-btn{display:none}

/* --- 3D: облёт рыбки. Карточка 16:9, как у десктопного плеера выше,
   рыбка рисуется в canvas по центру. Картинка не кликается и не
   тащится браузером — жест у контейнера; pan-y оставляет странице
   вертикальный скролл пальцем. --- */
.spin{position:relative;margin:0;aspect-ratio:16/9;overflow:hidden;
  border:1px solid rgba(255,255,255,.09);border-radius:10px;
  background:linear-gradient(170deg,#101815,#0A0C0B 62%);
  cursor:grab;touch-action:pan-y;-webkit-user-select:none;user-select:none;
  -webkit-tap-highlight-color:transparent}
.spin.is-drag{cursor:grabbing}
.spin-img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;pointer-events:none}
.spin-cv{position:absolute;inset:0;width:100%;height:100%;pointer-events:none}
/* <img> — только нулевой кадр до загрузки: как только canvas готов, он уходит */
.spin.is-live .spin-img{visibility:hidden}
.spin:focus-visible{outline:2px solid var(--emerald);outline-offset:4px}
/* В .feat карточка тянется на высоту колонки текста, а не держит 16:9:
   с aspect-ratio растянутая по высоте ячейка пересчитывала ширину и
   вылезала за правый край контента */
.feat .spin{aspect-ratio:auto;min-height:30cqw}

@media (max-width:760px){
  .feat{grid-template-columns:1fr;row-gap:6cqw;margin-top:11%}
  .feat-tx{justify-content:flex-start;gap:5cqw}
  .d3-b{margin-top:0;font-size:3.5cqw}
  /* Safari: растянутый (stretch) элемент сетки игнорирует aspect-ratio,
     а всё содержимое карточки — абсолютом, поэтому высота выходила 0 и
     рыбка пропадала на узком экране (в Chrome видно не было). Поэтому
     align-self:start и высота продублирована минимумом: ширина карточки
     88cqw (поля секции по 6%) × 3/4 = 66cqw */
  .feat .spin{aspect-ratio:4/3;align-self:start;min-height:66cqw}
  .mv{column-gap:3cqw}
  .spin{aspect-ratio:4/3}
}

/* ============ СТРАНИЦА КЕЙСА — ПРОЦЕСС ============ */
/* Нумерация здесь несёт смысл: это реальная очерёдность.
   Поэтому номера связаны вертикальной линией, а не разложены плитками. */
.process{position:relative;width:100%;container-type:inline-size;padding:6% 0}
.steps{margin-top:3.4%}
.step{display:grid;grid-template-columns:max-content 1fr;gap:4%;padding:0 6%;align-items:stretch}
.step-rail{position:relative;display:flex;align-items:flex-start;padding:2.2cqw 0 3cqw}
.step-rail::before{content:"";position:absolute;left:3.2cqw;top:0;bottom:0;width:1px;
  background:rgba(255,255,255,.1)}
.step:first-child .step-rail::before{top:3cqw}
.step:last-child .step-rail::before{bottom:auto;height:3cqw}
.step-rail::after{content:"";position:absolute;left:calc(3.2cqw - 3px);top:2.7cqw;
  width:7px;height:7px;border-radius:50%;background:var(--emerald);box-shadow:0 0 0 5px var(--bg)}
.step-num{font-family:var(--font-display);font-size:10cqw;font-weight:700;color:transparent;
  -webkit-text-stroke:1.4px rgba(236,230,214,.28);line-height:.8;letter-spacing:-.03em;
  padding-left:6.6cqw;transition:-webkit-text-stroke-color .35s}
.step:hover .step-num{-webkit-text-stroke-color:rgba(47,181,126,.55)}
.step-body{padding:2.2cqw 0 3cqw}
.step-t{font-size:2.2cqw;font-weight:600;color:var(--cream);line-height:1.1}
.step-b{margin-top:1.5%;color:var(--muted);font-size:max(13px,1.3cqw);line-height:1.62;font-weight:300;max-width:86%}

/* ============ СТРАНИЦА КЕЙСА — ФИНАЛ ============ */
.page-end{position:relative;container-type:inline-size;
  padding:5% 6% 7%;border-top:1px solid rgba(255,255,255,.08)}
.end-title{font-size:2.6cqw;font-weight:600;color:var(--cream);line-height:1.12;max-width:62%;text-wrap:balance}
.end-sub{color:var(--muted);font-size:max(13px,1.3cqw);line-height:1.6;font-weight:300;margin-top:1.4%;max-width:54%}
.end-back{display:inline-block;margin-top:2.8%;color:var(--emerald);font-size:max(12px,1.2cqw);
  font-weight:500;letter-spacing:.04em}
.end-back:hover{text-decoration:underline;text-underline-offset:4px}

/* ============ БЛОК 6 — КОНТАКТЫ ============ */
/* Шапки в этом блоке нет — он идёт последним перед футером.
   Фоновое слово CONTACT здесь допустимо: оно не дублирует заголовок,
   в отличие от hero, где такую надпись убрали. */
.contact{position:relative;width:100%;container-type:inline-size;padding:7% 0 8%;overflow:hidden}
.ct-ghost{position:absolute;left:0;right:0;top:2.5%;z-index:0;pointer-events:none;user-select:none;
  text-align:center;font-family:var(--font-display);font-weight:700;font-size:9.9cqw;line-height:.9;
  letter-spacing:-.02em;color:rgba(236,230,214,.12);white-space:nowrap}
.ct-grid{position:relative;z-index:1;display:grid;grid-template-columns:1fr 1fr;gap:3%;
  align-items:start;padding:0 6%}
.ct-chip{display:inline-flex;align-items:center;gap:.6cqw;padding:.7cqw 1.2cqw;border-radius:999px;
  background:rgba(255,255,255,.025);border:1px solid rgba(255,255,255,.12);
  color:var(--cream);font-size:1.1cqw;font-weight:500}
.ct-chip svg{width:1.4cqw;height:1.4cqw;flex:0 0 auto}
.ct-title{margin-top:2.6%;font-size:3.4cqw;font-weight:600;line-height:1.05;color:var(--cream)}
.ct-sub{margin-top:1.4%;color:var(--muted);font-size:1.25cqw;font-weight:300;line-height:1.55;max-width:70%}
.ct-list{margin-top:5.4%;display:flex;flex-direction:column;gap:1.4cqw}
.ct-card{display:flex;align-items:center;gap:1.6cqw;padding:1.5cqw 1.7cqw;border-radius:12px;
  background:linear-gradient(168deg,rgba(255,255,255,.032),rgba(255,255,255,.012));
  border:1px solid rgba(255,255,255,.09);
  transition:transform .35s cubic-bezier(.2,.7,.2,1),border-color .35s}
a.ct-card:hover,a.ct-card:focus-visible{transform:translateY(-3px);border-color:rgba(47,181,126,.32)}
/* Карточка без адреса: пока ссылки нет, она не кликается и приглушена. */
.ct-card.is-off{opacity:.5}
.ct-ico{flex:0 0 auto;display:grid;place-items:center;width:3.4cqw;height:3.4cqw;border-radius:10px;
  background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.08);color:var(--cream)}
.ct-ico svg{width:1.7cqw;height:1.7cqw}
.ct-tx{flex:1 1 auto;min-width:0;display:block}
.ct-k{display:block;color:var(--cream);font-size:1.2cqw;font-weight:600;line-height:1.2}
.ct-v{display:block;margin-top:.35cqw;color:var(--muted2);font-size:1.15cqw;font-weight:300;line-height:1.35;
  overflow-wrap:anywhere}
.ct-go{flex:0 0 auto;display:grid;place-items:center;width:2.6cqw;height:2.6cqw;border-radius:50%;
  background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.1);color:var(--cream);
  transition:background .3s,color .3s,border-color .3s}
.ct-go svg{width:1.1cqw;height:1.1cqw}
a.ct-card:hover .ct-go,a.ct-card:focus-visible .ct-go{background:var(--emerald);
  border-color:transparent;color:#08110C}

/* Форма — то же стекло, что у статов в hero */
.ct-form{display:flex;flex-direction:column;gap:1.1cqw;padding:1.5cqw;border-radius:14px;
  background:rgba(255,255,255,.025);backdrop-filter:blur(5px) saturate(1.2);
  -webkit-backdrop-filter:blur(5px) saturate(1.2);border:1px solid rgba(255,255,255,.1);
  box-shadow:0 8px 36px rgba(0,0,0,.28),inset 0 1px 0 rgba(255,255,255,.12)}
.ct-in,.ct-ta{width:100%;font:inherit;font-size:1.2cqw;font-weight:300;color:var(--cream);
  padding:1.35cqw 1.4cqw;border-radius:10px;background:rgba(255,255,255,.03);
  border:1px solid rgba(255,255,255,.1);transition:border-color .3s,background .3s}
/* Поле сообщения высокое: так низ формы встаёт на одну линию с
   последней карточкой слева, как в референсе. */
.ct-ta{min-height:22cqw;line-height:1.5;resize:vertical}
.ct-in::placeholder,.ct-ta::placeholder{color:var(--muted3)}
.ct-in:focus,.ct-ta:focus{outline:none;border-color:rgba(47,181,126,.5);background:rgba(255,255,255,.05)}
.ct-in[aria-invalid="true"],.ct-ta[aria-invalid="true"]{border-color:rgba(217,139,107,.6)}
/* Кнопка светлая, как на референсе: кремовый — это наш белый */
.ct-send{width:100%;padding:1.45cqw;border:0;border-radius:10px;background:var(--cream);
  color:#0A0C0B;font:inherit;font-size:1.25cqw;font-weight:600;cursor:pointer;
  transition:background .3s,transform .3s}
.ct-send:hover{background:var(--cream-bright);transform:translateY(-2px)}
.ct-send[disabled]{opacity:.6;cursor:default;transform:none}
.ct-note{min-height:1.6cqw;color:var(--muted2);font-size:1.05cqw;font-weight:300;line-height:1.4}
.ct-note.is-ok{color:var(--emerald)}
/* Единственный цвет вне палитры — только для ошибки формы. */
.ct-note.is-err{color:#D98B6B}

/* ============ СТРАНИЦА КЕЙСА — КОМАНДА ============
   Страница короткая по замыслу: общие формулировки, цифры и кадры.
   Разбора программ и блока процесса тут нет — на графике и вебе
   процесс объясняет работу с клиентом, здесь объяснять нечего.   */

/* --- что делал: горизонтальная ось с точками ---
   Ось — отдельный элемент в СРЕДНЕЙ строке сетки высотой 1px. Так она
   физически лежит между рядом «над линией» и рядом «под линией», и её
   не нужно позиционировать по посчитанной высоте верхнего ряда.

   Пункты идут через одного: нечётные в первую строку (прижаты книзу),
   чётные в третью (прижаты кверху). Вертикальный отросток — это
   padding пункта, поэтому он всегда ровно доходит до оси, сколько бы
   строк ни занял текст. Точка садится на ось через translate.       */
/* Заголовку страницы нужен запас воздуха снизу: панель сперва съедает
   его и только потом доходит до текста выноски. */
.pin > .page-top{padding-bottom:14vh}

/* Наезжающая панель. Тот же приём, что у «Кейсов по направлениям» на
   главной: отрицательный margin гасит высоту распорки, поэтому панель
   начинается ровно на нижней границе заголовка и при скролле едет
   вверх, закрывая его. Фон непрозрачный и темнее страницы — панель
   обязана перекрывать то, что под ней. */
.over{position:relative;z-index:2;width:100%;container-type:inline-size;
  margin-top:calc(-1 * 70vh);padding:6% 0 6%;
  background:#040605;
  box-shadow:0 -24px 64px rgba(0,0,0,.68), inset 0 1px 0 rgba(255,255,255,.10)}
/* Заголовок панели по центру — он ведёт весь блок, а не отбивает
   строку, как раньше «Что делал» слева. */
.over-t{padding:0 6%;color:var(--cream);font-size:3.4cqw;font-weight:600;
  line-height:1.05;text-align:center}
.tl{position:relative;display:grid;grid-template-columns:repeat(5,1fr);
  grid-template-rows:auto 1px auto;column-gap:2.4%;margin:5.4cqw 6% 0}
/* Ось — в той же сетке и во всю её ширину, поэтому линия уходит правее
   последней точки, как на макете. Отдельной вложенной сеткой это не
   собрать: у неё свои строки, и ось уезжает от точек. */
.tl-axis{grid-row:2;grid-column:1/-1;height:1px;background:rgba(236,230,214,.26)}
/* Колонка задаётся из --col прямо в разметке. Без неё grid раскладывает
   пункты автопотоком и упаковывает каждый ряд с начала: пункты над
   линией занимали колонки 1-2-3, а под линией — 1-2, и точки съезжали
   в кучу слева. Номер колонки — это данные пункта, а не стиль. */
.tl-i{grid-column:var(--col);position:relative;color:var(--cream);
  font-size:max(12px,1.15cqw);font-weight:300;line-height:1.45;padding-right:6%}
/* отросток от точки к тексту */
.tl-i::after{content:"";position:absolute;left:0;width:1px;
  background:rgba(236,230,214,.26)}
/* точка на оси */
.tl-i::before{content:"";position:absolute;left:0;z-index:2;
  width:1.1cqw;height:1.1cqw;min-width:9px;min-height:9px;border-radius:50%;
  background:var(--emerald);box-shadow:0 0 0 4px var(--bg)}
.tl-i--up{grid-row:1;align-self:end;padding-bottom:5.4cqw}
.tl-i--up::after{bottom:0;height:5.4cqw}
.tl-i--up::before{bottom:0;transform:translate(-50%,50%)}
.tl-i--dn{grid-row:3;align-self:start;padding-top:5.4cqw}
.tl-i--dn::after{top:0;height:5.4cqw}
.tl-i--dn::before{top:0;transform:translate(-50%,-50%)}

/* --- цифры с фото: главный блок страницы --- */
.nums{position:relative;width:100%;container-type:inline-size;
  display:grid;grid-template-columns:1fr 1fr;row-gap:2.2cqw;column-gap:2.2%;
  padding:6% 6% 0}
/* Кадры яркие — красный зал, зелёный лес. Приглушаем фильтром и
   накрываем вуалью снизу, иначе они выбиваются из тёмной палитры,
   а цифра на светлом участке теряется. Приём тот же, что у карточек
   галереи: насыщенность вниз, тёмный градиент от нижней кромки. */
.num{position:relative;aspect-ratio:3/2;border-radius:10px;overflow:hidden;
  border:1px solid rgba(255,255,255,.09);background:#0A0C0B}
.num img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  filter:saturate(.45) contrast(1.02) brightness(.72);
  transition:filter .45s ease,transform .5s cubic-bezier(.2,.7,.2,1)}
.num::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(to top, rgba(4,6,5,.92) 0%, rgba(4,6,5,.52) 30%, transparent 62%),
    linear-gradient(150deg, rgba(8,10,9,.34), rgba(16,107,71,.16) 54%, rgba(8,10,9,.4))}
.num:hover img{filter:saturate(.7) contrast(1.02) brightness(.84);transform:scale(1.03)}
.num-b{position:absolute;left:0;right:0;bottom:0;z-index:2;padding:2.2cqw}
.num-v{font-family:var(--font-display);font-size:6.4cqw;font-weight:700;line-height:.9;
  letter-spacing:-.02em;color:var(--cream-bright);font-variant-numeric:tabular-nums}
/* «часов» набирает Onest: в Space Grotesk кириллицы нет */
.num-u{font-family:var(--font-text);font-size:max(13px,1.5cqw);font-weight:400;letter-spacing:0;
  color:var(--cream);margin-left:.6cqw;vertical-align:.12em}
.num-k{margin-top:.5cqw;color:var(--muted);font-size:max(12px,1.2cqw);font-weight:300;
  line-height:1.45;max-width:86%}

/* --- полоса кадров: четыре в ряд, без подписей --- */
.shots{position:relative;width:100%;container-type:inline-size;
  display:grid;grid-template-columns:repeat(4,1fr);column-gap:2.2%;padding:2.2cqw 6% 0}
.shot{position:relative;margin:0;aspect-ratio:3/2;border-radius:8px;overflow:hidden;
  border:1px solid rgba(255,255,255,.08);background:#0A0C0B}
.shot img{display:block;width:100%;height:100%;object-fit:cover;
  filter:saturate(.4) brightness(.66);transition:filter .45s ease}
.shot::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(150deg, rgba(8,10,9,.42), rgba(16,107,71,.14) 56%, rgba(8,10,9,.46))}
.shot:hover img{filter:saturate(.68) brightness(.82)}

/* ============ ОБЩИЙ ФУТЕР ============ */
/* Разметку собирает js/footer.js — один источник на все страницы.
   Ссылки настраиваются в FOOTER_LINKS в начале того файла.
   Своего фона у футера нет: работает общий фон страницы. */
.site-footer{position:relative;container-type:inline-size;
  border-top:1px solid rgba(255,255,255,.08);
  padding:clamp(2rem,5cqw,4rem) 0 0}
.f-inner{padding:0 6%}

.f-top{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:clamp(1.8rem,4cqw,3.5rem)}
.f-brand{display:flex;flex-direction:column;align-items:flex-start;gap:clamp(.7rem,1.4cqw,1.1rem)}
.f-logo{font-family:var(--font-display);font-weight:700;letter-spacing:.02em;
  font-size:clamp(1.1rem,2.1cqw,1.6rem);color:var(--cream);line-height:1}
.f-cta{font-size:clamp(1.15rem,2.4cqw,2rem);font-weight:600;line-height:1.14;
  color:var(--cream);max-width:22ch;text-wrap:balance}
.f-sub{color:var(--muted);font-size:clamp(.85rem,1.25cqw,1rem);line-height:1.6;
  font-weight:300;max-width:42ch}

.f-cols{display:grid;grid-template-columns:repeat(3,max-content);justify-content:end;
  gap:clamp(1.4rem,3.4cqw,3.2rem)}
.f-col-t{color:var(--cream);font-size:clamp(.82rem,1.15cqw,.98rem);font-weight:500;
  margin-bottom:clamp(.7rem,1.4cqw,1.1rem)}
.f-list{list-style:none;display:flex;flex-direction:column;gap:clamp(.45rem,.9cqw,.7rem)}
.f-link{color:var(--muted2);font-size:clamp(.8rem,1.1cqw,.94rem);font-weight:300;
  transition:color .25s}
a.f-link:hover{color:var(--cream)}
.f-link.is-off{color:var(--muted3);cursor:default}

.f-bottom{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:.6rem clamp(1.8rem,4cqw,3.5rem);
  margin-top:clamp(1.6rem,3.6cqw,3rem);padding-top:clamp(.9rem,1.8cqw,1.4rem);
  border-top:1px solid rgba(255,255,255,.08);
  color:var(--muted3);font-size:clamp(.74rem,1.02cqw,.86rem);font-weight:300}
.f-bottom span:last-child{justify-self:end;text-align:right}

/* Имя во всю ширину. Просветы НАТУРАЛЬНЫЕ: viewBox выставляет footer.js
   по реальному bbox текста, и SVG масштабирует буквы целиком, равномерно.
   По высоте viewBox подрезан — видна верхняя часть букв, слово остаётся
   читаемым. Начертание тонкое (400), не 700 как в шапке.

   Тень по краям: маска гасит строку за боковыми 6% — там же, где
   заканчивается контент футера. Поэтому слово «проявляется» ровно
   от границ текста и уходит в темноту к краям экрана. */
.f-word{margin-top:clamp(1.4rem,3.4cqw,3rem);line-height:0;
  -webkit-mask-image:linear-gradient(90deg,
    transparent 0%, transparent 2%, rgba(0,0,0,.10) 5%, rgba(0,0,0,.42) 9%,
    rgba(0,0,0,.82) 13%, #000 18%, #000 82%, rgba(0,0,0,.82) 87%,
    rgba(0,0,0,.42) 91%, rgba(0,0,0,.10) 95%, transparent 98%, transparent 100%);
  mask-image:linear-gradient(90deg,
    transparent 0%, transparent 2%, rgba(0,0,0,.10) 5%, rgba(0,0,0,.42) 9%,
    rgba(0,0,0,.82) 13%, #000 18%, #000 82%, rgba(0,0,0,.82) 87%,
    rgba(0,0,0,.42) 91%, rgba(0,0,0,.10) 95%, transparent 98%, transparent 100%)}
.f-word svg{display:block;width:100%;height:auto}

/* Отражение: тот же SVG, перевёрнут, размыт и гаснет вниз.
   Градиент у него развёрнут — иначе у самой строки оказался бы тёмный конец. */
@container (max-width:760px){
  .f-top{grid-template-columns:1fr;gap:2rem}
  .f-cols{grid-template-columns:repeat(3,minmax(0,1fr));gap:1rem}
  .f-cta{font-size:6cqw;max-width:100%}
  .f-sub{font-size:3.5cqw;max-width:100%}
  .f-logo{font-size:4.4cqw}
  .f-col-t{font-size:3cqw}
  .f-link{font-size:3cqw}
  .f-bottom{grid-template-columns:1fr;font-size:2.9cqw}
  .f-bottom span:last-child{justify-self:start;text-align:left}
  .f-cols{grid-template-columns:repeat(3,minmax(0,1fr));justify-content:stretch;gap:1rem}
}

/* ============ АДАПТИВ ============ */
/* Планшет и узкий ноутбук. Мокапы в две колонки тут ломаются:
   при 768px телефон получает 83px ширины, а это уже не мокап.
   Поэтому большой экран и телефоны идут друг под другом, а
   телефоны сжаты до половины строки — их пропорция остаётся. */
@media (max-width:1024px){
  .prj-stage{grid-template-columns:1fr;row-gap:3.4cqw;column-gap:0}
  .prj-phones{max-width:52%;column-gap:5%}
  .prj-strip{grid-template-columns:1fr;row-gap:3.4cqw;column-gap:0}
  .prj-board{row-gap:4cqw;column-gap:4%}
}

@media (max-width:760px){
  .q-wrap{width:92%}.q-head{font-size:6.5cqw;min-height:30cqw}
  .q-sub{max-width:80%;font-size:3cqw}.q-cta .lnk{font-size:3cqw}.q-cta .arr{font-size:5cqw}
  .cat{grid-template-columns:1fr;gap:2%;padding:9% 6%}
  .cat-num{font-size:30cqw}.cat-title{font-size:7cqw}
  .cat-desc{font-size:3.5cqw;max-width:100%;margin:3.4% 0 7%}
  .ac-t{font-size:3.9cqw}.ac-n{font-size:2.9cqw}
  .ac-c p{font-size:3.5cqw;max-width:100%;padding:1.2cqw 0 4.6cqw}
  /* Линий-разделителей нет, поэтому ритм держат только отступы —
     на мобильном их нужно заметно больше, иначе пункты слипаются. */
  .ac-h{padding:4.6cqw 0}
  .ac-list{display:flex;flex-direction:column;gap:1.4cqw}
  .g-title{font-size:7cqw}.g-sub{font-size:3.5cqw;max-width:90%}
  .card{width:42cqw;height:30cqw}
  .card-n{font-size:2.6cqw;left:2cqw;bottom:1.6cqw}
  .lb-img{max-width:92vw;max-height:70vh}
  .lb-ph{width:88vw}
  .lb-nav{width:2.6rem;height:2.6rem}

  /* выбор направления: вместо трёх колонок — лента с прилипанием,
     иначе три карточки 9:16 дают три экрана пустой прокрутки */
  .sec-label{font-size:3cqw}
  .dirs-title{font-size:7cqw}
  .dirs-sub{font-size:3.5cqw;max-width:100%}
  /* Карусель вместо горизонтального скролла: активная карточка в потоке
     и по центру, две соседние абсолютом по бокам — размытые и уменьшенные.
     Ролями управляет main.js, и так как карточек ровно три, перелистывание
     замкнуто само на себя: любое смещение индекса снова даёт
     prev / active / next. */
  /* Боковые карточки по замыслу выходят за экран — обрезаем их здесь,
     на самом блоке. На десктопе overflow не ставим: там из карточек
     вниз свисают отражения, их бы срезало. */
  /* Снизу отведено место под отражения карточек: они висят под
     карточкой, а сетка обрезает содержимое, поэтому без этого запаса
     их бы срезало. */
  .dir-grid{padding:6% 13% 32%;overflow:hidden}
  .dir-track{display:block;position:relative}
  /* Наезд отключён: на вертикальном экране блок навыков сильно выше
     окна, панель успевает закрыть лишь малую его часть, и вместо
     перехода между слайдами получается непонятный сдвиг.
     Блоки идут обычным потоком, панель остаётся статичной. */
  .pin-spacer{display:none}
  /* Селектор тот же, что у десктопного правила: у .skills специфичность
     ниже, и `position:static` на нём наезд бы не отключил. */
  .pin > :first-child{position:static}
  .skills{padding:6% 0 10%}
  .dirs{margin-top:0}
  .dir-slot{position:absolute;top:0;left:0;width:100%;
    transition:transform .45s cubic-bezier(.2,.7,.2,1),
               opacity .45s ease, filter .45s ease}
  .dir-slot.is-active{position:relative;transform:none;filter:none;opacity:1;z-index:3}
  .dir-slot.is-prev{transform:translateX(-72%) scale(.84);
    filter:blur(3px);opacity:.42;z-index:1}
  .dir-slot.is-next{transform:translateX(72%) scale(.84);
    filter:blur(3px);opacity:.42;z-index:1}
  /* У боковых карточек текст не показываем: он выглядывал у края
     обрывками и на другой высоте — читалось как брак. Соседи должны
     быть просто размытыми плашками. */
  .dir-slot:not(.is-active) .dir-t,
  .dir-slot:not(.is-active) .dir-go,
  .dir-slot:not(.is-active) .dir-badge{opacity:0;transition:opacity .3s ease}

  /* Контурные треугольники: ни рамок, ни подложек, ни линий. */
  .dir-nav{display:flex;align-items:center;justify-content:center;
    position:absolute;top:50%;transform:translateY(-50%);z-index:4;
    width:11cqw;height:11cqw;padding:0;border:0;background:none;
    color:var(--muted2);cursor:pointer;transition:color .25s}
  .dir-nav:hover,.dir-nav:active{color:var(--cream)}
  .dir-nav svg{width:6.4cqw;height:6.4cqw;display:block}
  .dir-nav--prev{left:1.5cqw}
  .dir-nav--next{right:1.5cqw}
  /* Отражение короче, чем на десктопе: маска гасит его быстрее,
     иначе на телефоне оно съедает пол-экрана. */
  .dir-mirror{opacity:.5;filter:blur(4px);
    -webkit-mask-image:linear-gradient(to bottom,transparent 66%,rgba(0,0,0,.45) 88%,#000 100%);
    mask-image:linear-gradient(to bottom,transparent 66%,rgba(0,0,0,.45) 88%,#000 100%)}
  .dir-slot::after{height:26%;filter:blur(20px);opacity:.7}
  .dir-t{font-size:5.2cqw}
  .dir-t::after{margin-top:2.6cqw}
  .dir:hover .dir-t::after{width:8cqw}
  /* на тач-устройствах ховера нет — подпись видна сразу */
  .dir-go{font-size:2.8cqw;opacity:1;transform:none}
  .dir-badge{font-size:2.4cqw;padding:1cqw 1.8cqw}

  /* обо мне: одна колонка, фото после текста и по центру */
  .about{padding:11% 0 0}
  .ab-art{left:-16%;top:-6%;width:98%;height:40%}
  .ab-grid{grid-template-columns:1fr;gap:0;align-items:start}
  .ab-body{padding-bottom:7%}
  .ab-title{font-size:13.3cqw}
  .ab-sub{font-size:4.2cqw;margin:2% 0 0 8%}
  .ab-part{margin-top:11%}
  .ab-label{font-size:4.6cqw}
  .ab-list{margin-top:5%}
  .ab-item{padding-bottom:7cqw}
  .ab-item:not(:last-child)::before{left:-3.4cqw;top:2.4cqw}
  .ab-item::after{left:calc(-3.4cqw - 6px);top:calc(2.4cqw - 6px)}
  .ab-lead{font-size:3.6cqw}
  .ab-det{font-size:3.5cqw;max-width:100%}
  .ab-part--exp::before{left:-3.4cqw;top:1cqw}
  .ab-part--exp::after{left:-3.4cqw;width:22cqw}
  .ab-exp{margin-top:5%;padding-bottom:7cqw}
  .ab-p{font-size:3.5cqw;max-width:100%}
  .ab-photo{max-width:70cqw;justify-self:center}
  .ab-photo::before{width:108%}

  /* контакты: одна колонка, форма под списком */
  .contact{padding:11% 0 12%}
  .ct-ghost{font-size:16.5cqw;top:1%}
  .ct-grid{grid-template-columns:1fr;row-gap:7cqw;column-gap:0}
  .ct-chip{font-size:3cqw;gap:1.6cqw;padding:1.8cqw 3.2cqw}
  .ct-chip svg{width:3.6cqw;height:3.6cqw}
  .ct-title{font-size:7cqw;margin-top:5%}
  .ct-sub{font-size:3.5cqw;max-width:100%;margin-top:3%}
  .ct-list{margin-top:8%;gap:3.4cqw}
  .ct-card{gap:4cqw;padding:4cqw 4.4cqw}
  .ct-ico{width:9.6cqw;height:9.6cqw;border-radius:12px}
  .ct-ico svg{width:4.6cqw;height:4.6cqw}
  .ct-k{font-size:3.8cqw}
  .ct-v{font-size:3.4cqw;margin-top:1cqw}
  .ct-go{width:7.6cqw;height:7.6cqw}
  .ct-go svg{width:3.2cqw;height:3.2cqw}
  .ct-form{gap:3cqw;padding:4cqw;border-radius:14px}
  .ct-in,.ct-ta{font-size:3.6cqw;padding:3.6cqw}
  .ct-ta{min-height:40cqw}
  .ct-send{font-size:3.8cqw;padding:4cqw}
  .ct-note{font-size:3.2cqw;min-height:4cqw}

  /* страница кейса */
  .page-label{font-size:3cqw}
  /* 13cqw «ГРАФИЧЕСКИЙ» не влезает в боковые 6% — строка 440px при 352 доступных */
  .page-h1{font-size:10cqw;padding-top:6%}
  .ph-b{padding-right:0}
  /* На мобильном отступа нет вообще (правило селектором из двух классов,
     иначе десктопные 8% перебивают его по специфичности), но и 10cqw
     длинной строке уже мало — иначе ломается пополам. */
  .page-h1--long .ph-b{padding-right:0}
  .page-h1--long{font-size:8.2cqw}
  /* На узком экране лестница не нужна: выноски идут друг под другом */
  .page-notes{grid-template-columns:1fr;row-gap:5cqw;column-gap:0;padding-top:8%}
  .pn{padding:4cqw 0 4cqw 4cqw}
  .pn::before{width:18cqw}
  .pn p{font-size:3.5cqw}
  .pn--a,.pn--b{grid-column:1}
  .pn--a{grid-row:1}
  .pn--b{grid-row:2}
  .page-intro{font-size:3.5cqw;max-width:100%}
  /* --- команда: одна колонка --- */
  /* Наезда нет по той же причине, что и на главной: на вертикальном
     экране закреплённый блок сильно выше окна, и вместо перехода
     между слайдами читается непонятный сдвиг. */
  .pin > .page-top{padding-bottom:3%}
  .over{margin-top:0;padding:9% 0 8%}
  .over-t{font-size:7cqw;text-align:left}
  /* Пять колонок на телефоне не живут. Ось поворачивается: вертикаль
     слева, точки на ней, текст справа — тот же рельс, что у шагов
     процесса на странице графики. */
  .tl{grid-template-columns:1fr;grid-template-rows:auto;column-gap:0;margin-top:7cqw}
  /* Ось ложится вертикально слева. Абсолютом, а не ячейкой сетки:
     `grid-row:1/-1` считает только ЯВНЫЕ линии, а пункты на мобильном
     лежат в неявных строках — линия выходила высотой в один пункт.
     Отступы сверху и снизу подрезают её до первой и последней точки. */
  .tl-axis{position:absolute;grid-row:auto;grid-column:auto;
    left:1.5cqw;top:3.9cqw;bottom:6.4cqw;width:1px;height:auto;margin:0}
  .tl-i,.tl-i--up,.tl-i--dn{grid-row:auto;grid-column:1 !important;align-self:auto;
    padding:2.6cqw 0 2.6cqw 7cqw;font-size:3.5cqw}
  .tl-i::after{display:none}
  .tl-i--up::before,.tl-i--dn::before{top:3.9cqw;bottom:auto;left:1.5cqw;
    width:2.4cqw;height:2.4cqw;transform:translate(-50%,-50%)}
  .nums{grid-template-columns:1fr;row-gap:5cqw;column-gap:0;padding-top:10%}
  .num-b{padding:5cqw}
  .num-v{font-size:16cqw}
  .num-u{font-size:4cqw;margin-left:1.6cqw}
  .num-k{font-size:3.4cqw;margin-top:1.6cqw;max-width:100%}
  /* Четыре кадра в ряд на телефоне — это полоска по 80px.
     Две колонки: кадр остаётся кадром. */
  .shots{grid-template-columns:1fr 1fr;row-gap:3.4cqw;column-gap:3.4%;padding-top:6cqw}

  /* --- проекты на узком экране: всё в одну колонку --- */
  .prj{padding-top:9%}
  .prj + .prj{padding-top:12%;margin-top:11%}
  .prj-head{grid-template-columns:max-content 1fr;gap:0 4%}
  .prj-n{font-size:11cqw}
  .prj-t{font-size:6.4cqw}
  .prj-sub{font-size:3.5cqw;margin-top:1.6cqw}
  /* Поля переезжают под заголовок: в строку из трёх они на 390px
     не влезают, а white-space:nowrap у значений рвёт сетку. */
  .prj-meta{grid-column:1/-1;flex-wrap:wrap;gap:4cqw 7cqw;padding-top:5cqw}
  .prj-meta dt{font-size:max(10px,2.9cqw)}
  .prj-meta dd{font-size:3.6cqw;margin-top:1cqw}
  .prj-stage{grid-template-columns:1fr;row-gap:5cqw;column-gap:0}
  .prj-phones{column-gap:5%}
  .prj-strip{grid-template-columns:1fr;row-gap:5cqw;column-gap:0}
  .scr-bar{height:6cqw;padding:0 3cqw;gap:1.6cqw}
  .scr-bar i{width:1.5cqw;height:1.5cqw}
  .prj-board{grid-template-columns:1fr;row-gap:9cqw;column-gap:0}
  .pb-k{font-size:max(11px,3cqw);padding-bottom:4cqw}
  .pb-font{gap:3.4cqw;padding-top:4cqw}
  .pb-aa{font-size:8.4cqw}
  .pb-nm{font-size:3.6cqw}
  .pb-nm small{font-size:max(11px,3cqw);margin-top:.8cqw}
  .pb-scale{font-size:3.1cqw;padding-top:4cqw}
  .pb-sw{padding-top:4cqw}
  .pb-sw li{grid-template-columns:6cqw max-content 1fr;gap:0 2.6cqw;padding:1.8cqw 0}
  .pb-sw i{width:6cqw;height:6cqw}
  .pb-sw b{font-size:3.1cqw}
  .pb-sw small{font-size:max(11px,2.9cqw)}
  .pb-g{padding-top:4.4cqw}
  .pg-w{font-size:3.4cqw}
  .pg-c{height:4.4cqw;margin-top:2cqw}
  .pg-n{font-size:max(11px,2.9cqw);margin-top:1.8cqw}
  .pb-list{padding-top:4cqw}
  .pb-list li{font-size:3.3cqw;padding:1.8cqw 0 1.8cqw 4cqw}
  .pb-list li::before{top:3.7cqw}
  .prj-text{max-width:100%;margin-top:9%}
  .prj-text p{font-size:3.5cqw}
  .prj-text p + p{margin-top:3.4cqw}
  .prj-go{font-size:3.4cqw;margin-top:5cqw}
  .step{position:relative;grid-template-columns:1fr;gap:0;padding-left:calc(6% + 7cqw)}
  .step::before{content:"";position:absolute;left:6%;top:0;bottom:0;width:1px;
    background:rgba(255,255,255,.1)}
  .step:first-child::before{top:6cqw}
  .step:last-child::before{bottom:auto;height:6cqw}
  .step-rail{padding:3cqw 0 0}
  .step-rail::before{display:none}
  .step-rail::after{left:calc(-7cqw - 3px);top:3.4cqw}
  .step-num{font-size:14cqw;padding-left:0}
  .step-body{padding:1cqw 0 6cqw}
  .step-t{font-size:5.4cqw}
  .step-b{font-size:3.5cqw;max-width:100%}
  .end-title{font-size:6.4cqw;max-width:100%}
  .end-sub{font-size:3.5cqw;max-width:100%}
  .end-back{font-size:3.2cqw}
}

/* ============ ДОСТУПНОСТЬ ============ */
/* Фоновая анимация и параллакс отключаются, если система просит покоя.
   Галерея при этом остаётся перетаскиваемой руками. */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  .blob,.glass::after,.q-cta .arr,.q-head .cursor.blink{animation:none}
  .hero-title .ln,.glass{animation:none;opacity:1;transform:none}
  .card,.ac-c{transition:none}
  .dir,.dir-glow,.dir-img,.dir-t::after,.dir-go,.art1 .rays,.art2 .grid,.art3 .fan{transition:none}
  .dir:hover{transform:none}
  .dir-mirror,.dir-slot::after{transition:none}
  .dir-slot:hover .dir-mirror{transform:scaleY(-1)}
  .rv{opacity:1;transform:none;clip-path:none;transition:none}
}
