/* ——— Intro-оркестрация появления страницы ———————————————————————————
   Движок ОБЩИЙ — css/components.css (data-intro + data-i="1..7"). Раньше здесь
   лежала его полная копия со своими длительностями и своими @keyframes; копия
   удалена, страница переведена на общие правила и разметку .intro-lines.
   Порядок шагов задаётся в projects.html через data-i, здесь ничего не нужно. */

/* ——— Hero ——— */
.proj-hero{
  position:relative; overflow:hidden; display:flex; flex-direction:column;
  min-height:clamp(320px,44vh,500px);
  padding:clamp(124px,15vh,168px) clamp(18px,5vw,72px) 0;
  background:radial-gradient(120% 90% at 50% 0%, #F2F6F7 0%, #EAF6FB 56%, #DDE9EE 100%);
  text-align:center;
}
.proj-hero [data-hero-shader]{ mask-image:radial-gradient(135% 130% at 50% 30%, #000 58%, rgba(0,0,0,0.5) 84%, transparent 100%); -webkit-mask-image:radial-gradient(135% 130% at 50% 30%, #000 58%, rgba(0,0,0,0.5) 84%, transparent 100%); }
/* Canvas скрыт до первого отрисованного кадра (mesh-shader.js навесит .is-lit),
   чтобы при загрузке не мелькал пустой буфер поверх светлого героя. */
.proj-hero [data-hero-shader] canvas{ filter:blur(15px); transform:scale(1.06); opacity:0; }
.proj-hero [data-hero-shader] canvas.is-lit{ opacity:1; }
@media (prefers-reduced-motion: no-preference){
  .proj-hero [data-hero-shader] canvas{ transition:opacity .5s var(--iw-ease); }
}
.proj-hero-head{ position:relative; z-index:1; display:flex; align-items:center; justify-content:center; padding:clamp(28px,4vh,48px) 0 clamp(44px,7vh,80px); }
.proj-hero-head h1{ font-weight:800; font-size:clamp(34px,5.4vw,68px); line-height:1.0; letter-spacing:-0.035em; max-width:26ch; text-wrap:balance; }
/* ——— Projects list section ——— */
.proj-list-section{ padding:clamp(20px,2.6vh,32px) clamp(18px,5vw,72px) clamp(72px,11vh,128px); background:var(--iw-cloud); }
.proj-list-inner{ max-width:var(--iw-container); margin:0 auto; }

.cat-filter{ margin-bottom:clamp(40px,5vw,64px); }
.cat-reset-row{ display:flex; justify-content:center; align-items:center; gap:16px; margin-bottom:18px; min-height:16px; } /* место под «Сбросить» зарезервировано — кнопки не прыгают */
[data-cat-reset]{
  display:none; background:none; border:none; cursor:pointer;
  font-family:'IBM Plex Mono',monospace; font-size:11px; letter-spacing:var(--iw-eyebrow-track); color:var(--iw-accent);
}
[data-cat-scroll]{ display:flex; flex-wrap:wrap; justify-content:center; gap:9px; }
[data-cat-scroll]::-webkit-scrollbar{ height:0; }
@media (max-width:720px){ [data-cat-scroll]{ flex-wrap:wrap; gap:8px; } }
[data-cf]{
  border:1px solid rgba(20,37,49,0.14); background:transparent; color:var(--iw-body);
  font-weight:500; font-size:14px; padding:8px 16px; white-space:nowrap; cursor:pointer;
  transition:background .25s ease, border-color .25s ease, color .25s ease;
}
[data-cf]:hover:not([aria-pressed="true"]){ border-color:var(--iw-accent); color:var(--iw-ink); }
[data-cf][aria-pressed="true"]{ background:var(--iw-accent); color:#fff; border-color:var(--iw-accent); }

[data-list]{ display:flex; flex-direction:column; }

/* ——— featured rows ——— */
[data-row][hidden]{ display:none !important; }
[data-row][data-feat] [data-rline]{ border-top:1px solid rgba(20,37,49,0.16); padding:clamp(28px,3.5vw,44px) 0; transition:border-color .45s ease; }
[data-feat-grid]{ display:grid; grid-template-columns:1.05fr 1fr; gap:clamp(28px,4vw,64px); align-items:center; }
[data-feat-grid].media-left{ grid-template-columns:1fr 1.05fr; }
[data-feat-grid].media-left [data-feat-media]{ order:-1; }
@media (max-width:900px){
  [data-feat-grid]{ grid-template-columns:1fr !important; }
  [data-feat-media]{ order:-1; }
}
.feat-text{ display:flex; flex-direction:column; }
.feat-eyebrow-row{ display:flex; align-items:center; gap:16px; margin-bottom:20px; }
.feat-eyebrow{ font-family:'IBM Plex Mono',monospace; font-size:11px; letter-spacing:var(--iw-eyebrow-track); color:var(--iw-label); text-transform:uppercase; }
[data-rname]{ font-weight:700; font-size:clamp(2rem,4.6vw,3.6rem); line-height:0.98; letter-spacing:-0.035em; margin:0 0 18px; transition:color .4s ease, transform .55s var(--iw-ease); }
[data-feat-desc]{ font-size:16px; line-height:1.6; color:var(--iw-body); max-width:44ch; margin-bottom:26px; }
.feat-link{ display:inline-flex; align-items:center; gap:12px; font-weight:600; font-size:15px; color:var(--iw-ink); }
.feat-link [data-arrow]{ font-family:'IBM Plex Mono',monospace; font-size:15px; }
[data-arrow]{ display:inline-block; transition:transform .5s var(--iw-ease), color .3s ease; }

[data-feat-media]{ position:relative; overflow:hidden; background:var(--iw-media); aspect-ratio:16/11; }
/* Единый плавный hover-zoom для ВСЕХ проектов (как на главной): масштабируется контейнер
   [data-cover] целиком, а не отдельные media. Так все внутренние JS/CSS-анимации
   (gulf-crossfade, salam-slide, сцена БК, видео) увеличиваются одинаково и не конфликтуют. */
[data-cover]{ position:absolute; inset:0; will-change:transform; transition:transform .8s var(--iw-ease); }
[data-cover] video, [data-cover] img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; display:block; transition:filter .55s ease; }
[data-wash]{ position:absolute; inset:0; opacity:0; transition:opacity .55s ease; background:linear-gradient(120deg, rgba(5,178,216,0.16), transparent 60%); mix-blend-mode:multiply; pointer-events:none; }
.media-placeholder{ position:absolute; inset:0; background:repeating-linear-gradient(135deg,#dfe4ea 0 10px,#e9edf1 10px 20px); }
.media-placeholder span{ position:absolute; left:16px; bottom:16px; font-family:'IBM Plex Mono',monospace; font-size:10px; letter-spacing:var(--iw-eyebrow-track); color:#8694a0; }
.gcard-placeholder{ position:relative; overflow:hidden; aspect-ratio:1/1; margin-bottom:14px; background:repeating-linear-gradient(135deg,#dfe4ea 0 10px,#e9edf1 10px 20px); }
.gcard-placeholder span{ position:absolute; left:14px; bottom:14px; font-family:'IBM Plex Mono',monospace; font-size:9px; letter-spacing:var(--iw-eyebrow-track); color:#8694a0; }

[data-row]:hover [data-rline]{ border-top-color:var(--iw-accent); }
[data-row]:hover [data-rname]{ transform:translateX(10px); }
[data-row]:hover [data-arrow]{ transform:rotate(-45deg); color:var(--iw-accent); }
[data-row]:hover [data-cover]{ transform:scale(1.03); }
[data-row]:hover [data-cover] video, [data-row]:hover [data-cover] img{ filter:saturate(1.06); }
[data-row]:hover [data-wash]{ opacity:1; }

/* ——— touch / no-hover: JS вешает .is-inview на избранную строку, пока она в фокусе
   прокрутки (см. bindFeatAutoplayInView в js/projects.js). Повторяем здесь ту же
   отделку, что даёт :hover на десктопе, чтобы scroll-анимация выглядела законченной.
   Десктопные правила выше не тронуты. ——— */
@media (hover: none){
  [data-row][data-feat].is-inview [data-rline]{ border-top-color:var(--iw-accent); }
  [data-row][data-feat].is-inview [data-rname]{ transform:translateX(10px); }
  [data-row][data-feat].is-inview [data-arrow]{ transform:rotate(-45deg); color:var(--iw-accent); }
  [data-row][data-feat].is-inview [data-cover]{ transform:scale(1.03); }
  [data-row][data-feat].is-inview [data-cover] video,
  [data-row][data-feat].is-inview [data-cover] img{ filter:saturate(1.06); }
  [data-row][data-feat].is-inview [data-wash]{ opacity:1; }
  [data-row][data-feat].is-inview [data-gulf-crossfade] img[data-gulf-top]{ animation-play-state:running; }
  [data-row][data-feat].is-inview [data-bk-scene] img{ filter:none; }
}

/* ——— Gulfstream: two stacked images crossfade in CSS (replaces the video) ———
   Bottom img (night) is always visible; top img (day) animates its opacity,
   revealing the night frame beneath as it fades out, then fades back in. */
[data-gulf-crossfade] img[data-gulf-top]{ animation:gulfstreamCrossfade 3.005s linear infinite; animation-play-state:paused; }
[data-row]:hover [data-gulf-crossfade] img[data-gulf-top]{ animation-play-state:running; }
/* 2px overscan on every side (clipped by [data-feat-media] overflow:hidden) — kills the sub-pixel gap from object-fit:cover on a fractional-height box.
   max-width/max-height:none opts out of tokens.css `img,video{max-width:100%}`, which would otherwise clamp the width overscan back to 100% and leave a side strip. */
[data-gulf-crossfade] img{ inset:-2px; width:calc(100% + 4px); height:calc(100% + 4px); max-width:none; max-height:none; }
@keyframes gulfstreamCrossfade{
  0%      { opacity:1; animation-timing-function:ease-in; }
  30.877% { opacity:0; }
  75.178% { opacity:0; animation-timing-function:cubic-bezier(0.5,0,0.5,1); }
  91.923% { opacity:1; }
  100%    { opacity:1; }
}
@media (prefers-reduced-motion: reduce){
  [data-gulf-crossfade] img[data-gulf-top]{ animation:none; opacity:1; }
}

/* ——— SalamPay: long image slides horizontally (ping-pong) instead of a video.
   Full height, no upscaling — the long image overflows horizontally to give the pan. ——— */
[data-cover] img[data-salam-slide]{
  inset:auto; right:auto; bottom:auto; left:0; top:0;
  width:auto; height:100%;
  max-width:none; max-height:none; /* opt out of tokens.css `img{max-width:100%}` */
  transform:translate3d(0,0,0); transform-origin:left center; will-change:transform;
  transition:none; /* JS drives the transition per leg */
}
[data-row]:hover [data-cover] img[data-salam-slide]{ filter:saturate(1.06); }
@media (prefers-reduced-motion: reduce){
  [data-cover] img[data-salam-slide]{ transform:translate3d(0,0,0) !important; transition:none !important; }
}

/* ——— Братья Караваевы: CSS-сцена вместо видео (как на главной, подогнано под кадр 16:11) ———
   Слои снизу вверх: A фон-еда · B качающийся левый телефон · C правый телефон (лента под корпусом).
   Анимации играют по наведению, а на уходе плавно отматываются назад — логика в projects.js (WAAPI). */
[data-bk-scene]{
  position:absolute; inset:0; overflow:hidden;
  background:#ebe0d3;                                   /* фолбэк-беж под цвет фона, против пустоты при незагрузке */
}
/* сцена БК больше НЕ масштабируется отдельно — общий hover-zoom даёт контейнер [data-cover] (см. выше).
   нейтрализуем только родовой saturate-фильтр на отдельных <img> сцены */
[data-row]:hover [data-bk-scene] img{ filter:none; }
[data-bk-scene] .bk-bg{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
[data-bk-scene] .bk-phone{ position:absolute; }
/* сброс родовых [data-cover] img только для «текучих» картинок (левый телефон + лента);
   корпус .bk-body НАМЕРЕННО исключён — ему нужен position:absolute + z-index (иначе лента перекроет рамку). */
[data-bk-scene] .bk-phone-left img, [data-bk-scene] .bk-scroll{ position:static; inset:auto; width:100%; height:auto; object-fit:contain; display:block; }
/* B — левый телефон, целиком качается. Стартует на паузе (0-й кадр), JS играет по наведению и отматывает назад.
   fill-mode:both — чтобы после обратной отмотки анимация не выпадала из getAnimations(). */
.bk-phone-left{ left:1%; bottom:-4%; width:53%; z-index:1; will-change:transform; animation:karavaevPhoneLeft 3.857s linear infinite both; animation-play-state:paused; }
/* C — правый телефон: рамка фиксирована, прибит к низу; аспект = корпусу (720×1204), окно экрана считается в % */
.bk-phone-right{ left:57%; bottom:0; width:35%; z-index:2; aspect-ratio:720/1204; }
/* C1 — окно экрана под Dynamic Island: overflow здесь, не на всём корпусе.
   Прозрачная область экрана в исходнике phone_1: x 43..827, y 43..1455 из 870×1455. */
.bk-screen{ position:absolute; left:4.94%; top:2.96%; width:90.11%; height:97.04%; overflow:hidden; z-index:1; }
/* лента скроллится в 1.5× медленнее качания: 3.857s × 1.5 = 5.7855s */
.bk-scroll-track{ position:absolute; top:0; left:0; width:100%; will-change:transform; animation:karavaevContent 5.7855s linear infinite both; animation-play-state:paused; }
.bk-scroll-track .bk-scroll{ width:100%; height:auto; display:block; }
/* C2 — корпус (рамка + Dynamic Island) ПОВЕРХ ленты; прозрачный экран показывает ленту.
   Специфичность (0,3,0) перебивает родовой [data-bk-scene] .bk-phone img — чтобы position/z-index не сбрасывались. */
[data-bk-scene] .bk-phone-right .bk-body{ position:absolute; inset:0; width:100%; height:100%; object-fit:contain; z-index:2; }
@keyframes karavaevPhoneLeft{
  0%      { transform:translateY(0); animation-timing-function:ease-in-out; }
  45.588% { transform:translateY(-2.94%); animation-timing-function:ease-in-out; } /* ≈ −16.864px Фигмы в масштабе телефона */
  91.176% { transform:translateY(0); }
  100%    { transform:translateY(0); }
}
/* −733.413px из Фигмы пересчитаны под наш масштаб: полный ход = (высота_ленты − высота_окна)
   = 60.33% собственной высоты ленты (окно 1.801×ширины, лента 4.5396×ширины). */
@keyframes karavaevContent{
  0%      { transform:translateY(0); }
  75.283% { transform:translateY(-60.33%); animation-timing-function:ease-in-out; }
  87.322% { transform:translateY(0); }
  100%    { transform:translateY(0); }
}
@media (prefers-reduced-motion: reduce){
  .bk-phone-left, .bk-scroll-track{ animation:none !important; transform:none !important; }
  [data-bk-scene]{ transition:none; }
  [data-row]:hover [data-bk-scene]{ transform:none; }
  /* единый hover-zoom тоже отключаем — как на главной */
  [data-cover], [data-gimg]{ transition:none; }
  [data-row]:hover [data-cover]{ transform:none; }
  [data-gcard]:hover [data-gimg]{ transform:none; }
}

/* ——— square grid (full catalog) ——— */
.grid-wrap{
  border-top:1px solid rgba(20,37,49,0.16); margin-top:clamp(6px,1vw,14px);
  margin-left:calc(50% - 50vw); margin-right:calc(50% - 50vw); background:var(--iw-surface);
  padding-top:clamp(40px,5vw,64px); padding-bottom:clamp(40px,5vw,64px);
  padding-left:max(calc(50vw - 50%), clamp(18px,5vw,72px)); padding-right:max(calc(50vw - 50%), clamp(18px,5vw,72px));
}
[data-grid]{ max-width:var(--iw-container); margin:0 auto; display:grid; grid-template-columns:repeat(4,1fr); gap:clamp(60px,6.4vw,84px) clamp(34px,3.6vw,52px); }
@media (max-width:1000px){ [data-grid]{ grid-template-columns:repeat(2,1fr) !important; } }
@media (max-width:560px){ [data-grid]{ grid-template-columns:1fr !important; } }
[data-gcard]{ display:flex; flex-direction:column; height:100%; color:var(--iw-ink); }
.gcard-media{ position:relative; overflow:hidden; background:var(--iw-media); aspect-ratio:1/1; margin-bottom:14px; }
[data-gimg]{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; display:block; will-change:transform; transition:transform .8s var(--iw-ease), filter .55s ease; }
[data-gwash]{ position:absolute; inset:0; opacity:0; transition:opacity .55s ease; background:linear-gradient(120deg, rgba(5,178,216,0.16), transparent 60%); mix-blend-mode:multiply; pointer-events:none; }
[data-gline]{ flex:1 1 auto; display:flex; flex-direction:column; border-top:1px solid rgba(20,37,49,0.14); padding-top:14px; transition:border-color .4s ease; }
[data-gline] > *:last-child{ margin-top:auto; }
.gname-row{ display:flex; align-items:baseline; gap:10px; }
[data-gname]{ font-weight:700; font-size:19px; letter-spacing:-0.02em; transition:transform .55s var(--iw-ease); }
[data-garrow]{ margin-left:auto; display:inline-block; font-family:'IBM Plex Mono',monospace; font-size:14px; transition:transform .5s var(--iw-ease), color .3s ease; }
.gdesc{ font-size:13.5px; line-height:1.5; color:var(--iw-body); margin-top:9px; display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical; overflow:hidden; }
.gtag{ font-family:'IBM Plex Mono',monospace; font-size:10.5px; letter-spacing:var(--iw-eyebrow-track); color:var(--iw-label); text-transform:uppercase; margin-top:12px; padding-top:14px; }
[data-gcard]:hover [data-gimg]{ transform:scale(1.03); filter:saturate(1.06); }
[data-gcard]:hover [data-gwash]{ opacity:1; }
[data-gcard]:hover [data-gline]{ border-top-color:var(--iw-accent); }
[data-gcard]:hover [data-gname]{ transform:translateX(6px); }
[data-gcard]:hover [data-garrow]{ transform:rotate(-45deg); color:var(--iw-accent); }

/* ——— archive header ——— */
.archive-head{ margin-top:clamp(56px,7vw,96px); margin-bottom:clamp(20px,2.4vw,30px); }
.archive-head h2{ font-weight:800; font-size:clamp(30px,3.8vw,48px); line-height:1.0; letter-spacing:-0.035em; }

/* ——— compact rows (archive) ——— */
[data-row][data-compact] [data-rline]{
  display:flex; align-items:center; gap:clamp(16px,3vw,40px); padding:clamp(22px,2.6vw,32px) 0;
  border-top:1px solid rgba(20,37,49,0.16); transition:border-color .45s ease;
}
.compact-main{ flex:1 1 auto; min-width:0; }
[data-compact] [data-rname]{ font-weight:700; font-size:clamp(1.4rem,2.8vw,2.2rem); line-height:1.05; letter-spacing:-0.03em; margin:0; }
[data-compact-desc]{ font-size:14.5px; line-height:1.55; color:var(--iw-body); max-width:52ch; margin-top:8px; }
[data-preview]{
  flex:0 0 auto; width:132px; height:88px; overflow:hidden; background:var(--iw-media);
  position:relative; opacity:0; transform:scale(.9) translateY(6px);
  transition:opacity .45s var(--iw-ease), transform .5s var(--iw-ease);
}
[data-preview] img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; display:block; }
[data-preview] span{ position:absolute; left:8px; bottom:8px; font-family:'IBM Plex Mono',monospace; font-size:8.5px; letter-spacing:var(--iw-eyebrow-track); color:#8694a0; }
.compact-tag{ flex:0 0 auto; width:120px; text-align:right; font-family:'IBM Plex Mono',monospace; font-size:11px; letter-spacing:var(--iw-eyebrow-track); color:var(--iw-label); text-transform:uppercase; line-height:1.5; }
[data-compact] [data-arrow]{ flex:0 0 auto; font-family:'IBM Plex Mono',monospace; font-size:17px; color:var(--iw-ink); }
@media (max-width:720px){ [data-preview], [data-compact-desc]{ display:none !important; } }
[data-row][data-compact]:hover [data-rline]{ border-top-color:var(--iw-accent); }
[data-row][data-compact]:hover [data-preview]{ opacity:1; transform:scale(1) translateY(0); }
[data-row][data-compact]:hover [data-arrow]{ transform:rotate(-45deg); color:var(--iw-accent); }

[data-list-end]{ border-top:1px solid rgba(20,37,49,0.16); }
.list-more{ text-align:center; margin-top:clamp(32px,4vw,52px); }

/* ——— empty state ——— */
[data-empty]{ display:none; padding:clamp(48px,7vw,88px) 0; text-align:center; }
[data-empty] .eyebrow{ font-family:'IBM Plex Mono',monospace; font-size:13px; letter-spacing:var(--iw-eyebrow-track); color:var(--iw-label); }
[data-empty] p{ font-size:17px; line-height:1.5; color:var(--iw-body); max-width:420px; margin:16px auto 24px; }

/* ——— CTA card variant (quote + button, no form on this page) ——— */
.cta-card{ background:var(--iw-surface-dark); border:1px solid #2C3D49; padding:clamp(30px,3.4vw,48px); display:flex; flex-direction:column; gap:26px; }
.cta-card p{ font-size:clamp(19px,2.2vw,26px); font-weight:700; line-height:1.3; letter-spacing:-0.015em; }
