/* ═══════════════════════════════════════════════════════════
   POZIN
   ═══════════════════════════════════════════════════════════ */

:root{
  --cream:#F8F6EB;
  --bg:#000;
  --paper:#fff;

  /* масштаб меню: 1 «единица» исходного png в px экрана */
  --mk: clamp(.26px, .02375vw, .55px);
  --gap: calc(189 * var(--mk));
  --arrow: clamp(38px, 5.2vw, 104px);
  --edge: clamp(18px, 2.6vw, 54px);

  /* плавность */
  --e:   cubic-bezier(.16,1,.3,1);       /* expo out  */
  --eio: cubic-bezier(.76,0,.24,1);      /* expo in-out */
  --es:  cubic-bezier(.33,1,.68,1);      /* cubic out */
  --ez:  cubic-bezier(.37,0,.63,1);      /* синус in-out — для наезда */

  --t-fast: .45s;
  --t-mid:  .9s;
  --t-slow: 1.4s;
}

*,*::before,*::after{box-sizing:border-box}
html{
  -webkit-user-select:none; user-select:none;
  -webkit-touch-callout:none;
}
img{-webkit-user-drag:none; user-drag:none; pointer-events:none}
.tile img,.tile video,.slides img{pointer-events:none}
html,body{margin:0;padding:0}
html{
  background:var(--bg);
  -webkit-text-size-adjust:100%;
  scroll-behavior:auto;              /* скроллим сами, с плавной кривой */
}
body{
  background:var(--bg);
  color:var(--cream);
  font:400 16px/1.55 "Helvetica Neue",Helvetica,Arial,sans-serif;
  overflow-x:hidden;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
body.is-loading{overflow:hidden;height:100%}
body.no-scroll{position:fixed; left:0; right:0; width:100%; overflow:hidden}
img,video{display:block;max-width:100%}
button{font:inherit;color:inherit;background:none;border:0;padding:0;cursor:pointer;-webkit-tap-highlight-color:transparent}
a{color:inherit;text-decoration:none}
::selection{background:var(--cream);color:#000}

/* ── прелоадер ─────────────────────────────────────────── */
#loader{
  position:fixed; inset:0; z-index:200;
  background:var(--paper);
  display:grid; place-items:center;
  transition:opacity 1.15s var(--e), visibility 0s linear 1.15s;
}
#loader video{
  width:clamp(120px, 21vw, 240px); height:auto;
  opacity:0; transform:scale(.965);
  transition:opacity .9s var(--e), transform 1.6s var(--e);
}
#loader.ready video{opacity:1; transform:none}
#loader.done{opacity:0; visibility:hidden; pointer-events:none}

/* ── меню ──────────────────────────────────────────────── */
#menu{
  position:fixed; z-index:120;
  top:0; left:0; right:0;
  height:calc(11vh + 1rem);
  padding:0 var(--edge);
  display:flex; align-items:center; justify-content:flex-end;
  pointer-events:none;
}
.menu-row{
  display:flex; align-items:center;
  gap:var(--gap);
  /* ряд заканчивается ровно на один просвет левее стрелки */
  margin-right:calc(var(--arrow) + var(--gap));
  pointer-events:none;
  opacity:0; transform:translateY(-10px);
  transition:opacity .75s var(--e), transform .95s var(--e);
}
#menu.reveal .menu-row{
  opacity:1; transform:none; pointer-events:auto;
}
.mi{
  display:block; line-height:0;
  opacity:.94;
  transition:opacity var(--t-mid) var(--e), transform var(--t-mid) var(--e), filter var(--t-mid) var(--e);
}
.mi img{
  width:calc(var(--w) * var(--mk));
  height:auto;
  filter:drop-shadow(0 1px 14px rgba(0,0,0,.32));
}
.mi:hover,.mi:focus-visible{opacity:1; transform:translateY(-2px) scale(1.035)}
.mi:active{transform:translateY(0) scale(.99); transition-duration:.18s}

/* бургер: на компьютере его нет совсем, включается ниже в медиазапросе */
#burger{display:none}

/* @ и выпадающие контакты */
.at-wrap{position:relative; display:flex; align-items:center}
.at-menu{
  position:absolute; top:100%; left:50%;
  transform:translate(-50%,6px);
  padding-top:calc(64 * var(--mk) - 3px);
  width:max-content;                      /* иначе иконки жмёт шириной @ */
  display:flex; flex-direction:column; align-items:center;
  gap:calc(64 * var(--mk) + 1px);
  opacity:0; visibility:hidden;
  transition:opacity .7s var(--e), transform .9s var(--e), visibility 0s linear .9s;
}
.at-wrap.open .at-menu,.at-wrap:hover .at-menu{
  opacity:1; visibility:visible; transform:translate(-50%,0);
  transition:opacity .55s var(--e), transform .8s var(--e), visibility 0s;
}
.at-link{
  display:flex; flex-direction:column; align-items:center; gap:.45em;
  opacity:0; transform:translateY(-10px);
  transition:opacity .7s var(--e), transform .8s var(--e);
}
.at-wrap.open .at-link,.at-wrap:hover .at-link{opacity:.92; transform:none}
.at-wrap.open .at-link:nth-child(2),.at-wrap:hover .at-link:nth-child(2){transition-delay:.09s}
.at-link:hover{opacity:1}
.at-ico{display:block; line-height:0}
.at-ico img{
  width:calc(var(--w) * var(--mk)); height:auto; max-width:none;
  filter:drop-shadow(0 1px 12px rgba(0,0,0,.4));
  transition:transform .8s var(--e);
}
.at-link:hover .at-ico img{transform:translateY(-3px) rotate(-2deg)}


/* стрелка «наверх» */
#toTop{
  position:absolute; right:var(--edge);
  top:50%; translate:0 -50%;
  pointer-events:auto;
  opacity:.94;
  transition:opacity var(--t-mid) var(--e), transform var(--t-mid) var(--e);
}
#toTop i{
  display:block;
  width:var(--arrow); aspect-ratio:425/487;
  background:var(--cream);
  -webkit-mask:url(../assets/ui/right.png) center/contain no-repeat;
  mask:url(../assets/ui/right.png) center/contain no-repeat;
  rotate:-90deg;
  filter:drop-shadow(0 1px 14px rgba(0,0,0,.32));
  transition:rotate var(--t-mid) var(--e);
}
#toTop:hover{transform:translateY(-4px)}
#toTop:active{transform:translateY(0); transition-duration:.18s}
/* вверху страницы стрелка смотрит вниз и ведёт к портфолио;
   внизу переворачивается и ведёт наверх — направление ставит app.js */
#toTop.down i{rotate:90deg}
#toTop.down:hover{transform:translateY(4px)}

/* пункты выезжают по очереди, когда полоса раскрыта */
#menu.reveal .menu-row .mi:nth-child(1){transition-delay:.02s}
#menu.reveal .menu-row .mi:nth-child(2){transition-delay:.08s}
#menu.reveal .at-wrap .mi{transition-delay:.14s}
.menu-row .mi{
  opacity:0; transform:translateY(-8px);
  transition:opacity .7s var(--e), transform .85s var(--e);
}
#menu.reveal .menu-row .mi{opacity:.94; transform:none}

/* появление стрелки после загрузки */
#toTop{opacity:0; transform:translateY(-14px)}
body.ready #toTop{
  opacity:.94; transform:none;
  transition:opacity 1.2s var(--e) .35s, transform 1.3s var(--e) .35s;
}

/* крестик на полотнах «мы кто» / «мы что»: закреплён в углу и
   остаётся на месте при прокрутке — как стрелка на главном экране */
#paneClose{
  position:fixed; z-index:300;
  right:var(--edge);
  top:calc((11vh + 1rem) / 2);
  translate:0 -50%;
  width:clamp(26px, 2.96vw, 58px); aspect-ratio:123/122;
  background:#111;
  -webkit-mask:url(../assets/ui/black_cross.png) center/contain no-repeat;
  mask:url(../assets/ui/black_cross.png) center/contain no-repeat;
  opacity:0;
  transition:opacity .6s var(--e), transform .7s var(--e);
}
body.pane #paneClose{opacity:.9}
#paneClose:hover{opacity:1; transform:scale(1.08)}
#paneClose:active{transform:scale(.97); transition-duration:.15s}

/* ── главный экран ─────────────────────────────────────── */
#hero{
  position:relative;
  height:100svh; min-height:520px;
  overflow:hidden;
  background:#0a0a0a;
}
.hero-video{position:absolute; inset:0; overflow:hidden}
.hero-video video,.hero-video img{
  width:100%; height:100%; object-fit:cover;
  transform:scale(1.06);
  opacity:0;
  transition:opacity 1.8s var(--es), transform 9s var(--e);
}
body.ready .hero-video video{opacity:1; transform:scale(1)}
#hero::after{                       /* лёгкая виньетка под текст */
  content:""; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(180deg,rgba(0,0,0,.30) 0%,rgba(0,0,0,0) 26%,
                                     rgba(0,0,0,0) 62%,rgba(0,0,0,.34) 100%);
}

.hero-logo{
  position:absolute; left:50%; top:46%;
  translate:-50% -50%;
  width:53.5vw; height:32svh;
  display:grid; place-items:center;
  z-index:3; pointer-events:none;
}
.hero-logo img{
  grid-area:1/1;
  max-width:100%; max-height:100%;
  width:auto; height:auto;
  object-fit:contain;
  opacity:0;
  transform:scale(1.035);
  filter:drop-shadow(0 4px 40px rgba(0,0,0,.35));
  transition:opacity .85s var(--es), transform 1.4s var(--e);
}
.hero-logo img.on{
  opacity:1; transform:none;
  transition:opacity 1.25s var(--es), transform 2s var(--e);
}

.hero-note{
  position:absolute; left:clamp(18px,3vw,64px); bottom:clamp(22px,4.2vh,58px);
  z-index:3; width:min(42vw,780px);
  opacity:0; transform:translateY(14px);
  transition:opacity 1.4s var(--e) .5s, transform 1.6s var(--e) .5s;
}
body.ready .hero-note{opacity:1; transform:none}
.note-img{width:100%; height:auto; opacity:.94}
.note-txt{display:none}

/* ── портфолио ─────────────────────────────────────────── */
#work{background:var(--bg)}
.row{display:flex; width:100%}
.row.h540{aspect-ratio:1920/540}
.row.h675{aspect-ratio:1920/675}

.tile{
  position:relative; overflow:hidden;
  flex:0 0 auto;
  background:#0d0d0d;
  opacity:0; transform:translateY(34px) scale(.985);
  transition:opacity 1.15s var(--e), transform 1.25s var(--e);
}
.tile.u1{width:25%} .tile.u2{width:50%} .tile.u3{width:75%}
.tile.in{opacity:1; transform:none}

.tile .shot{
  position:absolute; inset:0;
  width:100%; height:100%; object-fit:cover;
  opacity:0;
  transform:scale(1.001);
  transition:opacity 1.5s var(--es), transform 1.6s var(--e);
  backface-visibility:hidden;
}
.tile .shot.on{opacity:1; z-index:2}
.tile .shot.fading{z-index:1}
.tile video.shot{object-fit:cover}          /* уходящий кадр держит непрозрачность
                                          под входящим — фон не просвечивает */
.tile.link{cursor:pointer}
.tile.link:hover .shot.on{transform:scale(1.045)}
.tile.link::after{
  content:""; position:absolute; inset:0;
  background:rgba(0,0,0,.16);
  opacity:0; transition:opacity var(--t-mid) var(--e);
  pointer-events:none;
}
.tile.link:hover::after{opacity:1}
.tile.link:active .shot.on{transform:scale(1.02); transition-duration:.25s}

/* ── общие оверлеи ─────────────────────────────────────── */
.overlay{
  position:fixed; inset:0; z-index:150;
  opacity:0; visibility:hidden;
  transition:opacity .8s var(--e), visibility 0s linear .8s;
}
.overlay.open{opacity:1; visibility:visible; transition:opacity .7s var(--e), visibility 0s}

/* ── мы кто ────────────────────────────────────────────── */
#about,#what{background:var(--paper)}
.about-scroll{
  position:absolute; inset:0;
  overflow-y:auto; overflow-x:hidden;
  -webkit-overflow-scrolling:touch;
  overscroll-behavior:contain;
}
.about-inner{
  position:relative;
  width:100%;
  transform:translateY(26px);
  opacity:0;
  transition:transform 1.2s var(--e), opacity 1s var(--e);
}
.overlay.open .about-inner{transform:none; opacity:1}
.about-inner video{width:100%; height:auto; display:block}
#what .about-close{left:95.7%; top:2.8%; width:5%}
.about-close{
  position:absolute; left:96.4%; top:29.4%;
  translate:-50% -50%;
  width:6.6%; aspect-ratio:1;
  border-radius:50%;
}

/* ── слайды ────────────────────────────────────────────── */
#deck{background:#000}
.deck-stage{
  position:absolute; inset:0;
  display:grid; place-items:center;
  padding:0;
}
.deck-box{
  position:relative;
  width:100%; max-width:calc(100svh * 16/9);
  aspect-ratio:16/9;
  overflow:hidden;
  transform:scale(.985); opacity:0;
  transition:transform 1s var(--e), opacity .8s var(--e);
}
#deck.open .deck-box{transform:none; opacity:1}

.deck-zoom{position:absolute; inset:0; transform-origin:0 0; touch-action:none}
.slides{position:absolute; inset:0}
.slides .sl{
  position:absolute; inset:0;
  width:100%; height:100%; object-fit:contain;
  background:#000;
  pointer-events:none;
  /* короткое затухание без трансформаций: полноэкранный кадр 1920×1080
     двигать дорого, а листать надо часто */
  opacity:0; visibility:hidden;
  transition:opacity .2s linear;
}
.slides .sl.on{opacity:1; visibility:visible; z-index:2}
.slides .sl.on.fading{z-index:1; transition:none}
.slides video.sl{object-fit:contain}

/* слайд из четырёх вертикальных роликов */
.sl-cards{background:#141414}
.sl-cards .cardsv{
  position:absolute; inset:0;
  width:100%; height:100%; object-fit:contain; display:block;
}
.sl-cards .ov{
  position:absolute; translate:-50% -50%;
  background:var(--cream);
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  -webkit-mask-size:contain;     mask-size:contain;
  -webkit-mask-position:center;  mask-position:center;
  pointer-events:none; z-index:3;
}
/* размеры и точки сняты с настоящих слайдов деки */
.ov-prev {left:4.08%;  top:5.60%;  width:4.20%; aspect-ratio:169/122}
.ov-close{left:96.90%; top:5.50%;  width:2.96%; aspect-ratio:123/122}
.ov-next {left:91.73%; top:91.78%; width:6.04%; aspect-ratio:487/425}
.ov-coza {left:95.76%; top:96.19%; width:3.87%; aspect-ratio:156/90}
.ov-mark {left:50.15%; top:96.39%; width:3.43%; aspect-ratio:130/76}
.ov-copy {left:5.23%;  top:96.54%; width:6.43%; aspect-ratio:250/21}

.zone{position:absolute; z-index:5; background:transparent}
.z-prev {left:0;   top:0;    width:11%; height:13%}
.z-close{right:0;  top:0;    width:11%; height:13%}
.z-next {right:0;  bottom:0; width:16%; height:17%}
.deck-box{cursor:pointer}
.z-close{cursor:pointer}

.own-cross{
  position:absolute; left:96.90%; top:5.50%;
  translate:-50% -50%;
  width:2.96%; aspect-ratio:1;
  z-index:6; pointer-events:none;
  opacity:0; transition:opacity .6s var(--e);
  -webkit-mask:url(../assets/ui/black_cross.png) center/contain no-repeat;
  mask:url(../assets/ui/black_cross.png) center/contain no-repeat;
}
.own-cross.show{opacity:1}
.own-cross.black{background:#111}
.own-cross.white{background:#fff}

/* тонкая стрелка «назад» на последних слайдах — своей у них нет */
.own-back{
  position:absolute; left:4.08%; top:5.60%;
  translate:-50% -50%;
  width:4.20%; aspect-ratio:169/122;
  z-index:6; pointer-events:none;
  opacity:0; transition:opacity .6s var(--e);
  -webkit-mask:url(../assets/ui/light_strelka_black.png) center/contain no-repeat;
  mask:url(../assets/ui/light_strelka_black.png) center/contain no-repeat;
}
.own-back.show{opacity:1}
.own-back.black{background:#111}
.own-back.white{background:#fff}

.deck-progress{
  position:absolute; left:0; right:0; bottom:0; height:2px;
  background:rgba(255,255,255,.13);
}
.deck-hint{
  position:absolute; left:0; right:0; bottom:26px;
  text-align:center;
  font-size:11px; letter-spacing:.08em; color:var(--cream);
  opacity:0; pointer-events:none;
  transition:opacity 1.1s var(--e);
  display:none;
}
.deck-hint.show{opacity:.55}
.deck-progress span{
  display:block; height:100%; width:0;
  background:var(--cream);
  transition:width .9s var(--e);
}

/* ── адаптив ───────────────────────────────────────────── */
/* ── телефонная страница проекта ───────────────────────── */
/* длинная прокрутка вместо листалки слайдов; открывается только
   на телефоне, на компьютере остаётся прежняя дека */
#tele{background:var(--paper)}
.tele-scroll{
  position:absolute; inset:0;
  overflow-y:auto; overflow-x:hidden;
  -webkit-overflow-scrolling:touch;
  overscroll-behavior:contain;
  background:var(--paper);
}
/* это телефонная страница: своей полосы прокрутки у неё быть не должно,
   на телефоне её и нет — полоса появлялась только на широком экране */
.tele-scroll{scrollbar-width:none; -ms-overflow-style:none}
.tele-scroll::-webkit-scrollbar{width:0; height:0}
/* шапка без подложки: поверх страницы едут только буквы.
   Чёрное начертание пропадает на тёмных фото, поэтому держим рядом
   белое и меняем их местами, когда под шапкой тёмная секция */
.tele-top{
  position:sticky; top:0; z-index:4;
  padding:max(12px,env(safe-area-inset-top)) 16px 12px;
  pointer-events:none;
}
/* знак — родной, тот же, что на главной. Он нарисован одним цветом
   на прозрачном фоне, поэтому чёрный и белый получаем не двумя
   файлами, а фильтром */
.tele-home{
  display:block; padding:0;
  background:none; border:0; pointer-events:auto; cursor:pointer;
}
/* начертаний много и они разной формы. В оригинале все надписи
   нарисованы в одном размере, поэтому ровнять их по высоте нельзя:
   длинная надпись тогда вылезает втрое шире квадратной. Ровняем
   по площади — её считает app.js, когда знак загрузился; высота
   здесь стоит про запас, на случай если файл ещё не пришёл */
.tele-home img{
  height:52px; width:auto; max-width:70vw; display:block;
  filter:brightness(0);
  transition:filter .18s linear;
}
#tele.dark-top .tele-home img{filter:brightness(0) invert(1)}

/* крестик свой: знак берём маской, цвет меняем вместе со знаком */
.tele-close{
  position:absolute; top:max(12px,env(safe-area-inset-top)); right:16px;
  width:7.4%; max-width:34px; aspect-ratio:1;
  pointer-events:auto; cursor:pointer;
  background:#111;
  -webkit-mask:url(../assets/ui/black_cross.png) center/contain no-repeat;
  mask:url(../assets/ui/black_cross.png) center/contain no-repeat;
  transition:background .18s linear;
}
#tele.dark-top .tele-close{background:#fff}

.tele-body{
  opacity:0; transform:translateY(22px);
  transition:opacity 1s var(--e), transform 1.3s var(--e);
}
.overlay.open .tele-body{opacity:1; transform:none}
.tele-body > img{width:100%; height:auto; display:block}

/* слот: кадры сменяют друг друга на одном месте */
.tele-slot{position:relative; width:100%; overflow:hidden; background:var(--paper)}
.tele-slot .fr{
  position:absolute; inset:0;
  opacity:0; visibility:hidden;
  transition:opacity 1.2s var(--es), visibility 0s linear 1.2s;
}
.tele-slot .fr.on{
  opacity:1; visibility:visible;
  transition:opacity 1.2s var(--es), visibility 0s;
}
.tele-slot .fr img{width:100%; height:100%; object-fit:cover; display:block}

/* «едут слева направо, встают, секунду стоят и меняются»:
   кадры не растворяются друг в друге, а въезжают слева поверх
   предыдущего. Предыдущий терпеливо ждёт под ним и прячется
   только когда новый встал на место — иначе в прогалине слева
   проглядывала бы бумага. Въезд считается частью стоянки кадра:
   dwell у таких кадров — это въезд плюс секунда на месте */
.tele-slot.list .fr{
  opacity:1;
  visibility:hidden;
  transition:visibility 0s linear var(--list-dur,.9s);
  z-index:1;
}
.tele-slot.list .fr.on{visibility:visible; transition:visibility 0s; z-index:2}
.tele-slot.list .fr.on.go{animation:teleList var(--list-dur,.9s) var(--es) both}
@keyframes teleList{
  from{translate:-100% 0}
  to  {translate:0 0}
}

/* картинка в картинке: фотография стоит неподвижно, а сменяются
   только кадры в окошке внутри неё. Место окошка задаёт скрипт
   в процентах — поэтому оно держится на любой ширине экрана */
/* «коробки увеличиваются только при наведении»: сам по себе кадр
   не меняется. Зритель наводит мышью или придерживает пальцем ту
   коробку, которую хочет разглядеть, — крупной становится только она.
   Отклик короткий, иначе наведения не чувствуешь */
.tele-slot.byhand .fr{transition:opacity .45s var(--ez), visibility 0s linear .45s}
.tele-slot.byhand .fr.on{transition:opacity .45s var(--ez), visibility 0s}
.tele-slot .tele-zone{
  position:absolute; left:0; right:0; z-index:2;
  padding:0; border:0; background:none; cursor:pointer;
  -webkit-tap-highlight-color:transparent}
/* накладка поверх слота: в макете круглый знак лежит внахлёст на фото
   и свисает ниже его края. Если оставить его внутри кадра, он поедет
   вместе с наездом и разъедется надвое, поэтому кладём его отдельным
   слоем сверху. Обрезку тогда берёт на себя сам кадр, иначе
   приближающаяся картинка вылезет за пределы места */
.tele-slot.capped{overflow:visible}
.tele-slot.capped .fr{overflow:hidden}
.tele-slot .tele-cap,
.tele-vid .tele-cap{position:absolute; z-index:3; height:auto; display:block;
  pointer-events:none}
.tele-slot > .bgp{width:100%; height:100%; object-fit:cover; display:block}
.tele-slot > .pip{position:absolute; overflow:hidden}

/* кадр шире экрана: не режем, а медленно провозим вбок за один проход.
   По дороге он может подрастать к середине и возвращаться к концу —
   за это отвечает --panzoom (1 = без увеличения) */
.tele-slot .fr.pan img{width:auto; height:100%; max-width:none; object-fit:fill}
.tele-slot .fr.pan.go img{
  will-change:transform;
  animation:telePan var(--pan-dur,10s) var(--eio) var(--pan-wait,0s) forwards;
}
/* единственный кадр в слоте: ездит туда-обратно без конца */
.tele-slot.solo .fr.pan.go img{
  animation-iteration-count:infinite; animation-direction:alternate;
}
/* проезд задом наперёд: кадр стоит дальним концом, как в колонке
   макета, и уезжает к ближнему */
.tele-slot.solo .fr.pan.rev.go img{animation-direction:alternate-reverse}
.tele-slot:not(.solo) .fr.pan.rev.go img{animation-direction:reverse}
/* в начале и в конце кадр доезжает ровно до края экрана, и на дробных
   пикселях с краю проглядывала бумага — поэтому он всё время чуть
   крупнее нужного, на пару пикселей с каждой стороны */
@keyframes telePan{
  0%  {transform:translate(0, 0) scale(1.012)}
  50% {transform:translate(calc(var(--pan,-28%) / 2), calc(var(--pany,0%) / 2)) scale(var(--panzoom,1))}
  100%{transform:translate(var(--pan,-28%), var(--pany,0%)) scale(1.012)}
}
/* обратный случай из макета: «едет слева направо, уменьшаясь» —
   кадр начинает крупным и к концу приходит к своему размеру */
/* кадр, который едет один раз и уступает место следующему,
   идёт ровным ходом: «едет не останавливаясь до конца и тогда
   меняется». Плавное торможение тут читается как остановка
   на полпути, поэтому кривую убираем */
.tele-slot:not(.solo) .fr.pan.go img{animation-timing-function:linear}
.tele-slot .fr.pan.out.go img{animation-name:telePanOut}
/* и прямой случай: «едет слева направо, увеличиваясь к концу» */
.tele-slot .fr.pan.grow.go img{animation-name:telePanGrow}
@keyframes telePanGrow{
  0%  {transform:translate(0, 0) scale(1.012)}
  /* множитель 1.004 — тот же волосок про запас, что и у обычного
     проезда: без него правый край упирается в край кадра ровно
     в ноль и подпиксель вылезает белой ниткой */
  100%{transform:translate(var(--pan,-28%), var(--pany,0%))
                scale(calc(var(--panzoom,1.25) * 1.004))}
}
@keyframes telePanOut{
  0%  {transform:translate(0, 0) scale(var(--panzoom,1.25))}
  100%{transform:translate(var(--pan,-28%), var(--pany,0%)) scale(1.012)}
}

/* «две секунды постоял — поехал; доехал, две секунды постоял —
   поехал обратно». Весь путь туда и обратно укладывается в один
   проход, а стоянки стоят прямо в кадрах, поэтому сами кадры
   считает app.js: их доли зависят и от времени проезда, и от
   длины стоянки. Сдвиг и укрупнение разведены по разным
   свойствам — translate и scale: у каждого своя кривая. Пока оба
   сидели в одном transform, общая кривая тормозила ровно посреди
   дороги, и зритель читал это как лишнюю остановку.
   Кривая тут мягкая, синусная: на резкой экспоненте кадр после
   стоянки ещё секунды четыре еле полз, и две секунды на месте
   превращались в шесть */
.tele-slot .fr.pan.waits.go img,
.tele-slot.solo .fr.pan.waits.go img,
.tele-slot.solo .fr.pan.waits.rev.go img{
  will-change:translate, scale;
  animation:var(--pan-keys) var(--pan-cycle,36s) var(--ez) var(--pan-wait,0s) infinite normal both,
            var(--swell-keys) var(--pan-cycle,36s) var(--ez) var(--pan-wait,0s) infinite normal both;
}

/* кадр выше своего места: медленно уплывает вверх, и то, что было
   внизу, уходит под обрез — как помечено в макете у лисы */
.tele-slot .fr.vpan img{width:100%; height:auto; max-width:none; object-fit:fill}
.tele-slot .fr.vpan.go img{
  will-change:transform;
  animation:teleUp var(--up-dur,16s) var(--eio) infinite alternate;
}
@keyframes teleUp{
  from{transform:translateY(0)}
  to  {transform:translateY(var(--up,-30%))}
}

/* «одна гаснет, уходя в темноту, вторая появляется из темноты»:
   кадры не перетекают друг в друга, а расходятся через чёрное */
.tele-slot.night{background:#0b0b0b}
/* длительность растворения и кривую можно задать по месту: где-то
   темнота держится дольше, где-то кадры должны сменяться быстрее
   и мягче. Без этих величин всё как было — .9 с на прежней кривой */
.tele-slot.night .fr{
  transition:opacity var(--fade,.9s) var(--fade-e,var(--es)),
             visibility 0s linear var(--fade,.9s)}
.tele-slot.night .fr.on{
  transition:opacity var(--fade,.9s) var(--fade-e,var(--es)) var(--fade,.9s),
             visibility 0s}

/* рисунок на бумаге, который чуть живёт: медленно ползёт вбок
   или изредка подёргивается */
.tele-drift{position:relative; overflow:hidden; background:var(--paper)}
.tele-drift img{display:block; width:100%; height:auto; will-change:transform}
.tele-drift.go img{animation:teleDrift var(--drift-dur,26s) var(--eio) infinite alternate}
@keyframes teleDrift{
  from{transform:translateX(var(--drift,3%))}
  to  {transform:translateX(calc(var(--drift,3%) * -1))}
}
.tele-drift.twitch.go img{animation:teleTwitch var(--drift-dur,6s) steps(1,end) infinite}
@keyframes teleTwitch{
  0%,  90%{transform:translate(0,0) rotate(0deg)}
  91%     {transform:translate(-0.4%,0.3%) rotate(-0.35deg)}
  93%     {transform:translate(0.35%,-0.2%) rotate(0.3deg)}
  95%     {transform:translate(-0.2%,0.1%) rotate(-0.15deg)}
  97%,100%{transform:translate(0,0) rotate(0deg)}
}

/* «едет, приближается к постеру, постоял секунду, отдалился, поехал
   к следующему». Кадр приезжает сбоку, наезжает, держит, отъезжает
   и уходит. Базовое увеличение 1.14 — чтобы по краям при сдвиге
   не проглядывала бумага */
.tele-slot.ride .fr{transition:opacity .3s linear, visibility 0s linear .3s}
.tele-slot.ride .fr.on{transition:opacity .3s linear, visibility 0s}
.tele-slot.ride .fr.go img{
  will-change:transform;
  animation:teleRide var(--ride-dur,9s) var(--eio) forwards;
}
@keyframes teleRide{
  0%  {transform:translateX(6%)  scale(1.14)}
  16% {transform:translateX(0)   scale(1.14)}
  36% {transform:translateX(0)   scale(var(--zoom,1.35))}
  58% {transform:translateX(0)   scale(var(--zoom,1.35))}
  78% {transform:translateX(0)   scale(1.14)}
  100%{transform:translateX(-6%) scale(1.14)}
}

/* проезд, который доехал и начинает сначала, а не идёт обратно */
/* «доезжает и zoom» — и дальше стоит статично в зуме:
   проезд с ростом идёт один раз и держит конечный кадр */
.tele-slot.solo .fr.pan.grow.go img{
  animation-direction:normal;
  animation-iteration-count:1;
  animation-timing-function:var(--ez)}

/* «камера подплывает к надписи, отплывает — а там уже новые карточки».
   Кадр приходит крупным планом, отъезжает, держит и снова наезжает;
   подмена приходится на крупный план, поэтому её не видно */
.tele-slot.focus .fr{transition:opacity .35s linear, visibility 0s linear .35s}
.tele-slot.focus .fr.on{transition:opacity .35s linear, visibility 0s}
.tele-slot.focus .fr.go img{
  will-change:transform;
  transform-origin:var(--zoom-at, 50% 55%);
  animation:teleFocus var(--focus-dur,11s) var(--eio) forwards;
}
@keyframes teleFocus{
  0%  {transform:scale(var(--zoom,1.45))}
  26% {transform:scale(1.01)}
  74% {transform:scale(1.01)}
  100%{transform:scale(var(--zoom,1.45))}
}

/* кадр, который медленно наезжает, пока его показывают */
/* наезд начинается не при сборке страницы, а когда кадр дошёл
   до экрана — за это отвечает та же метка go, что и у проезда */
/* наезд не всегда из середины кадра — в макете видно, на что он идёт */
.tele-slot .fr.zoom img{transform-origin:var(--zoom-at, 50% 50%)}
.tele-slot .fr.zoom.go img{
  will-change:transform;
  animation:teleZoom var(--zoom-dur,6s) var(--ez) var(--zoom-wait,0s) forwards;
}
@keyframes teleZoom{
  from{transform:scale(1)}
  to  {transform:scale(var(--zoom,1.06))}
}
/* «отдаляется»: обратный ход — кадр начинает приближённым и отъезжает
   к своему настоящему размеру. Точка отъезда снята с макета: там
   крупный план кадрирован снизу, поэтому по дороге открывается верх */
.tele-slot .fr.zoom.back.go img{animation-name:teleZoomBack}
@keyframes teleZoomBack{
  from{transform:scale(var(--zoom,1.06))}
  to  {transform:scale(1)}
}

/* секция-видео: ведёт себя как картинка, но живая */
/* место под видео задано по пропорциям самого кадра, поэтому он
   встаёт в него один к одному: ни подложки, ни обрезки, ни растяжки */
.tele-vid{position:relative; width:100%; overflow:hidden}
.tele-vid video{width:100%; height:100%; object-fit:cover; display:block}
/* у кадра по краям пустые поля, из-за них видео читалось отдельной
   серой плашкой. Показываем только ту часть, в которой за весь ролик
   умещается сфера: само изображение при этом целое */
.tele-vid.cut video{position:absolute; height:auto; max-width:none;
  object-fit:fill}   /* max-width:none — иначе общее правило для видео
                        обрежет кадр обратно по ширине секции */
/* секция с накладкой выпускает её за свои края, поэтому обрезку кадра
   держит внутренняя обёртка */
.tele-vid.capped{overflow:visible}
.tele-vid.capped > .hold{position:absolute; inset:0; overflow:hidden}

/* концовка: одна плашка из макета на все телефонные страницы.
   Она идёт во всю ширину — поля у неё свои, нарисованные.
   Отступ сверху ставит скрипт: он задан в данных, в пикселях макета */
.tele-foot{background:var(--paper); padding:0 0 calc(4vh + env(safe-area-inset-bottom))}
.tele-plate{position:relative}
.tele-plate > img{width:100%; height:auto; display:block; opacity:.92}

/* нажимают по невидимым областям поверх плашки. Доли посчитаны
   по самой картинке: 2000×784, «собака» 1294..1506, самолётик
   1621..1847, нижняя строка 500..684 */
.tele-all{
  position:absolute; left:0; right:0; top:0; height:47%;
  padding:0; border:0; background:none; cursor:pointer;
}
.tele-c{position:absolute; top:58%; height:36%}
#teleMail{left:62.5%; width:16%}
#teleTg{left:78.5%; width:17%}

@media (max-width:900px){
  /* в раскрытой панели пункты стоят столбиком и занимают почти всю ширину:
     «мы кто» — самая широкая надпись (533 единицы), от неё и считаем масштаб */
  :root{
    --mk: calc(min(62vw, 430px) / 533);
    --arrow: clamp(24px, 7vw, 38px);
  }

  #menu{
    height:auto; align-items:flex-start;
    padding:max(13px,env(safe-area-inset-top)) 12px 12px;
    justify-content:flex-start;
  }
  #toTop{right:12px; top:max(11px,env(safe-area-inset-top)); translate:0 0}

  /* ── бургер ──────────────────────────────────────────── */
  #burger{
    display:block;
    position:fixed; z-index:140;
    left:12px; top:max(11px,env(safe-area-inset-top));
    width:38px; padding:10px 4px;
    pointer-events:auto;
  }
  #burger i{
    display:block; height:2px; border-radius:2px;
    background:var(--cream);
    filter:drop-shadow(0 1px 10px rgba(0,0,0,.55));
    transition:transform .55s var(--e), opacity .3s var(--e), width .55s var(--e);
  }
  #burger i:nth-child(1){width:100%}
  #burger i:nth-child(2){width:72%; margin:7px 0}
  #burger i:nth-child(3){width:100%}
  /* три полоски складываются в крестик */
  #menu.nav-open #burger i:nth-child(1){transform:translateY(9px) rotate(45deg)}
  #menu.nav-open #burger i:nth-child(2){opacity:0; transform:scaleX(.15)}
  #menu.nav-open #burger i:nth-child(3){transform:translateY(-9px) rotate(-45deg)}
  /* стрелка «наверх» под раскрытой панелью не нужна */
  #menu.nav-open #toTop{opacity:0; pointer-events:none}

  /* ── панель меню ─────────────────────────────────────── */
  /* второй селектор гасит десктопное правило #menu.reveal .menu-row:
     на телефоне панель открывается только бургером, а не наведением */
  .menu-row,
  #menu.reveal .menu-row{
    position:fixed; inset:0; z-index:130;
    margin:0; max-width:none; flex-wrap:nowrap;
    flex-direction:column; align-items:center; justify-content:center;
    gap:calc(118 * var(--mk));
    padding:14vh 18px calc(10vh + env(safe-area-inset-bottom));
    background:rgba(8,8,8,.95);
    -webkit-backdrop-filter:blur(20px); backdrop-filter:blur(20px);
    opacity:0; visibility:hidden; pointer-events:none; transform:none;
    transition:opacity .5s var(--e), visibility 0s linear .5s;
  }
  #menu.nav-open .menu-row{
    opacity:1; visibility:visible; pointer-events:auto;
    transition:opacity .45s var(--e), visibility 0s;
  }

  /* пункты выплывают по очереди, когда панель раскрылась */
  .menu-row .mi,
  .menu-row .at-wrap,
  #menu.reveal .menu-row .mi{
    opacity:0; transform:translateY(16px);
    transition:opacity .5s var(--e), transform .75s var(--e);
  }
  #menu.nav-open .menu-row .mi,
  #menu.nav-open .menu-row .at-wrap{opacity:.94; transform:none}
  #menu.nav-open .menu-row > .mi:nth-of-type(1){transition-delay:.05s}
  #menu.nav-open .menu-row > .mi:nth-of-type(2){transition-delay:.11s}
  #menu.nav-open .menu-row > .mi:nth-of-type(3){transition-delay:.17s}
  #menu.nav-open .menu-row .at-wrap{transition-delay:.23s}

  /* контакты в панели раскрыты сразу: место есть, лишний тап ни к чему.
     «@» остаётся подписью над ними, но нажимать его больше не надо */
  .at-wrap{
    flex-direction:column; gap:calc(74 * var(--mk));
  }
  .mi-at{pointer-events:none}
  .at-menu,
  .at-wrap.open .at-menu,.at-wrap:hover .at-menu{
    position:static; transform:none; padding-top:0; width:auto;
    flex-direction:row; align-items:center; gap:calc(150 * var(--mk));
    opacity:1; visibility:visible; transition:none;
  }
  .at-link,
  .at-wrap.open .at-link,.at-wrap:hover .at-link{
    opacity:.92; transform:none; transition:opacity .4s var(--e);
  }
  .at-link:active{opacity:1}

  .hero-logo{width:78vw; height:26svh; top:44%}
  .hero-note{
    left:0; right:0; bottom:calc(18px + env(safe-area-inset-bottom));
    width:auto; padding:0 18px;
  }
  .note-img{display:none}
  .note-txt{
    display:block; margin:0;
    font-size:11.5px; line-height:1.5;
    color:var(--cream); opacity:.9;
    text-shadow:0 1px 12px rgba(0,0,0,.55);
  }
  .note-txt em{font-style:italic; opacity:.85}

  /* сетка разворачивается в поток */
  .row{display:block; aspect-ratio:auto}
  .tile{width:100% !important; aspect-ratio:var(--ar)}
  .about-close{width:11%}
  .deck-box{max-width:100%}
  .deck-hint{display:block}
  .z-prev,.z-close{height:16%; width:15%}
  .z-next{height:20%; width:22%}
}

/* ── главный экран на телефоне ───────────────────────────
   Ролик снят горизонтально, но люди в кадре лежат поперёк. При обычном
   object-fit:cover вертикальный экран срезает ему бока — остаётся
   примерно треть кадра. Поэтому кадр не режем, а поворачиваем на 90°:
   он встаёт вертикально и заполняет экран почти целиком.
   Меняется только направление поворота — через --hero-rot (90deg / -90deg).
   Если нужен кадр совсем без обрезки — поставить object-fit:contain,
   но тогда сверху и снизу появятся поля.                              */
@media (max-width:900px) and (orientation:portrait){
  :root{--hero-rot:90deg}
  .hero-video video,
  .hero-video img{
    position:absolute; top:50%; left:50%;
    width:100svh;        /* после поворота станет высотой экрана */
    height:100vw;        /* после поворота станет шириной экрана  */
    max-width:none;      /* иначе общее правило img,video обрежет до ширины экрана */
    transform-origin:center center;
    transform:translate(-50%,-50%) rotate(var(--hero-rot)) scale(1.06);
  }
  body.ready .hero-video video{
    transform:translate(-50%,-50%) rotate(var(--hero-rot)) scale(1);
  }
}

/* ── «мы что» на телефоне ─────────────────────────────────
   Полотно почти квадратное (0.83), а телефон втрое вытянутее (0.46),
   поэтому под ним оставалась пустота почти в пол-экрана.
   Делаем две вещи: срезаем вшитые в картинку белые поля
   (слева 8%, справа 12%, сверху 4.3%, снизу 9.6%, плюс чёрная
   рамка по краю) и ставим полотно по центру экрана, чтобы остаток
   пустоты разошёлся поровну, а не висел дырой снизу.
   Границы рисунка: x 128..1961, y 92..2181 в кадре 2160×2412 —
   считано по порогу 254, иначе светло-серые плашки под рисунками
   не засекаются и край срезает кота слева и «упаковку» справа.
   С каждой стороны оставлено по 3% поля.                      */
@media (max-width:900px) and (orientation:portrait){
  #what .about-scroll{display:flex; flex-direction:column}
  #what .about-inner{
    overflow:hidden;
    aspect-ratio:1 / 1.1312;      /* рисунок плюс поля по 3% */
    flex:0 0 auto;
    margin-top:auto; margin-bottom:auto;   /* ровно по центру экрана */
  }
  #what .about-inner video{
    position:absolute;
    width:110.71%; max-width:none; height:auto;
    left:-3.56%; top:-1.52%;
  }
  /* кнопка стояла поверх угла полотна; после обрезки её место уехало,
     а закрывать и так есть чем — закреплённым крестиком #paneClose */
  #what .about-close{display:none}
}

@media (max-width:900px) and (orientation:landscape){
  .hero-logo{width:56vw; height:34svh}
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important;
    transition-duration:.01ms !important;
  }
}
