/* ============================================================
   ТЁМНАЯ ПОЛОСА: СЦЕНА С КУБОМ
   Космос, токены полосы и перекраска шапки переехали
   в styles/cosmos.css — они понадобились и на странице услуги.
   Здесь остались стекло, бенто, сцена и вспышка.
   ============================================================ */

/* ============================================================
   ИЗБРАННЫЕ ПРОЕКТЫ
   ============================================================ */
.works{ padding:clamp(46px, 5.4vw, 96px) 0 clamp(64px, 7vw, 128px); }

.works__head{
  display:flex;
  align-items:flex-end;
  justify-content:space-between;
  flex-wrap:wrap;
  gap:clamp(20px, 3vw, 48px);
  margin-bottom:clamp(26px, 3.2vw, 54px);
}

/* левый акцентный штрих у заголовка */
.works__titles{
  position:relative;
  padding-left:clamp(14px, 1.2vw, 22px);
}
.works__titles::before{
  content:'';
  position:absolute;
  left:0; top:.2em; bottom:.1em;
  width:3px;
  border-radius:2px;
  background:linear-gradient(180deg, var(--accent-1), var(--accent-2));
}

/* строка честности под заголовком (25.09.2026): в плитках пока наш сайт */
.works__note{
  margin:clamp(10px, 1vw, 16px) 0 0; max-width:36rem;
  font-size:clamp(14px, 1vw, 17px); line-height:1.5;
  color:rgba(233,238,255,.72);
}
.works .eyebrow{
  margin:0 0 clamp(8px, .8vw, 14px);
  font-size:clamp(12px, .8vw, 13px);
  font-weight:600;
  letter-spacing:.18em;
  text-transform:uppercase;
  color:#6f83ff;
}
.works__title{
  margin:0;
  font-family:var(--font-display);
  font-weight:550;
  font-stretch:105%;
  font-size:clamp(24px, 2.45vw, 42px);
  line-height:1.12;
  letter-spacing:-.015em;
  text-transform:uppercase;
}

/* ссылка «смотреть все работы» */
.works__all{
  display:inline-flex;
  align-items:center;
  gap:clamp(14px, 1.2vw, 22px);
  padding-bottom:4px;
  font-size:clamp(12px, .82vw, 14px);
  font-weight:600;
  letter-spacing:.1em;
  text-transform:uppercase;
  white-space:nowrap;
}
.works__ring{
  display:grid;
  place-items:center;
  width:clamp(44px, 3.35vw, 56px);
  aspect-ratio:1;
  border:1px solid var(--line);
  border-radius:50%;
  transition:background-color .24s var(--ease), border-color .24s var(--ease);
}
.works__ring svg{ width:14px; height:14px; transition:transform .28s var(--ease); }
.works__all:hover .works__ring{ background:rgba(255,255,255,.07); border-color:rgba(255,255,255,.6); }
.works__all:hover .works__ring svg{ transform:translate(3px,-3px); }

/* ============================================================
   БЕНТО ИЗ МАТОВОГО СТЕКЛА
   Плитки разной формы. Свет снизу. При наведении плитка
   переворачивается — на обороте разбор проекта.
   ============================================================ */

/* стеклу нужно что размывать: под сеткой лежит световая подложка */
.works{ position:relative; isolation:isolate; }

/* Сцена играет на месте, а не на ходу.
   Раньше прогресс считался от положения сетки в кадре, поэтому блок
   всё время сцены полз вверх и к моменту полного раскрытия заголовок
   уже уходил под шапку. Теперь секция прилипает, дорожку прокрутки
   держит .works-stage, а высоту дорожки задаёт скрипт: сцена + пауза
   на собранной раскладке. Отступ сверху отмеряет место под шапкой —
   при нём заголовок встаёт ровно под ней, а бенто целиком влезает в окно. */
/* overflow-x:clip — слои космоса шире экрана (обойма нарочно с запасом)
   и без обрезки страница ездила вбок на 57px при окне 1440. Именно clip,
   а не hidden: hidden сделал бы дорожку контейнером прокрутки, и sticky
   у .works перестал бы прилипать к окну. 25.09.2026 */
.works-stage{ position:relative; overflow-x:clip; }
.works{ position:sticky; top:var(--works-pin, 24px); }

/* без прилипания дорожка не нужна: высоту скрипт не задаёт, сцены нет */
@media (prefers-reduced-motion:reduce){
  .works{ position:relative; top:auto; }
}


/* --- сетка --- */
.works__grid{
  display:grid;
  grid-template-columns:repeat(12, 1fr);
  grid-auto-rows:clamp(118px, 10.6vw, 186px);
  gap:clamp(12px, 1.05vw, 19px);

  /* Куб можно собрать только в общей сцене: если перспектива стоит
     на каждой плитке, грани проецируются из разных точек схода
     и фигура разъезжается. Поэтому одна камера на всю сетку,
     а 3D-контекст протянут насквозь до .tile__inner. */
  perspective:1700px;
  perspective-origin:50% 34%;
  transform-style:preserve-3d;
}

/* --- контейнер плитки: сам по себе прозрачный, всё стекло на гранях --- */
.tile{
  --r:22px;
  --d:clamp(10px, .85vw, 15px);   /* толщина стеклянного блока */
  position:relative;
  display:block;
  border-radius:var(--r);
  transform-style:preserve-3d;   /* звено общей сцены, перспектива живёт на сетке */
  transition:transform .3s var(--ease);
}
.tile:hover{ transform:translateY(-3px); }

.tile__inner{
  position:relative;
  width:100%;
  height:100%;
  transform-style:preserve-3d;
  /* угол задаёт курсор: --ry от горизонтали, --rx от вертикали */
  transform:rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  /* этот переход работает на возврате, когда курсор ушёл */
  transition:transform .55s cubic-bezier(.32,.86,.34,1);
}
/* пока курсор внутри — короткий переход, чтобы плитка шла за мышью почти один в один */
.tile:hover .tile__inner{ transition:transform .13s linear; }

/* с клавиатуры покрутить нечем — показываем оборот сразу */
.tile:focus-visible .tile__inner{ transform:rotateY(180deg); transition:transform .4s var(--ease); }

/* ============================================================
   ТОЛЩИНА СТЕКЛА
   Боковых стенок нет намеренно: три плитки круглые и в форме
   пилюли, прямые панели разорвали бы их силуэт. Вместо этого
   в глубину уходит стопка слоёв — каждый повторяет радиус
   родителя, поэтому приём работает с любой формой.
   ============================================================ */
.tile__slab{
  position:absolute;
  inset:0;
  border-radius:var(--r);
  transform-style:preserve-3d;
  pointer-events:none;
}
.tile__sheet{
  position:absolute;
  inset:0;
  border-radius:inherit;
  transform:translateZ(calc(var(--d) * var(--z)));
  background:rgba(168,196,255,.05);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.06);
}
/* дальняя грань ловит свет сильнее — это и читается как торец */
.tile__sheet:first-child{
  background:rgba(150,180,250,.07);
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,.13),
    inset 0 -2px 3px rgba(255,255,255,.20);
}


/* ============================================================
   СБОРКА И РАЗБОР ПО СКРОЛЛУ
   До того как раздел попал в кадр, все плитки сведены в центр
   и сложены в глубину — получается один стеклянный блок.
   По мере прокрутки он разбирается в раскладку бенто.

   Трансформацию сборки держит отдельный слой .tile__pos:
   на .tile висит перспектива и подъём при наведении,
   на .tile__inner — поворот за курсором. Смешивать нельзя.
   ============================================================ */
.tile__pos{
  position:relative;
  width:100%;
  height:100%;
  transform-style:preserve-3d;   /* без этого перспектива не дойдёт до .tile__inner */
  will-change:transform;
}

/* --- грань --- */
.tile__face{
  position:absolute;
  inset:0;
  border-radius:var(--r);
  overflow:hidden;
  backface-visibility:hidden;
  -webkit-backface-visibility:hidden;

  background:
    /* медленно ползущий отсвет — стекло не стоит на месте */
    linear-gradient(112deg,
      transparent 20%, rgba(255,255,255,.055) 42%,
      rgba(255,255,255,.02) 56%, transparent 78%) 0% 0% / 280% 100% no-repeat,
    linear-gradient(165deg,
      rgba(255,255,255,.20) 0%,
      rgba(255,255,255,.085) 48%,
      rgba(255,255,255,.16) 100%);
  backdrop-filter:blur(22px) saturate(150%) brightness(1.12);
  -webkit-backdrop-filter:blur(22px) saturate(150%) brightness(1.12);

  box-shadow:
    0 20px 40px -24px rgba(0,0,0,.92),
    inset 0 1px 1px rgba(255,255,255,.15),
    inset 0 -2px 2px rgba(255,255,255,.28);

  animation:glass-drift 13s ease-in-out infinite alternate;
}
@keyframes glass-drift{ to{ background-position:100% 0, 0 0; } }

/* разводим ритм: синхронное движение всех плиток выдаёт генерацию */
.tile:nth-child(3n)   .tile__face{ animation-duration:17s; animation-delay:-4s; }
.tile:nth-child(3n+1) .tile__face{ animation-duration:11s; animation-delay:-7s; }

.tile__face--front{ transform:translateZ(var(--d)); }

.tile__face--back{
  transform:rotateY(180deg);
  background:
    linear-gradient(112deg,
      transparent 20%, rgba(255,255,255,.045) 42%,
      rgba(255,255,255,.015) 56%, transparent 78%) 0% 0% / 280% 100% no-repeat,
    linear-gradient(165deg,
      rgba(126,152,235,.24) 0%,
      rgba(70,92,180,.16) 48%,
      rgba(150,178,255,.22) 100%);
}

/* кромка: тусклая сверху, яркая снизу */
.tile__face::before{
  content:'';
  position:absolute;
  inset:0;
  border-radius:inherit;
  padding:1px;
  background:linear-gradient(180deg,
    rgba(255,255,255,.52) 0%,
    rgba(255,255,255,.14) 36%,
    rgba(255,255,255,.30) 66%,
    rgba(255,255,255,.88) 100%);
  -webkit-mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;
          mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask-composite:exclude;
  pointer-events:none;
  z-index:4;
}

/* блик от курсора — только на лицевой грани */
.tile__face--front::after{
  content:'';
  position:absolute;
  inset:0;
  border-radius:inherit;
  background:radial-gradient(240px circle at var(--mx, 50%) var(--my, 50%),
    rgba(255,255,255,.22) 0%,
    rgba(255,255,255,.08) 38%,
    transparent 66%);
  opacity:0;
  transition:opacity .32s var(--ease);
  pointer-events:none;
  z-index:3;
}
.tile:hover .tile__face--front::after{ opacity:1; }

/* --- формы --- */
.tile--pill{ --r:var(--r-card); }   /* была капсула — таблетки на сайте не делаем (28.09.2026) */
.tile--round{
  --r:50%;
  aspect-ratio:1;
  height:100%;
  width:auto;
  justify-self:center;
}

/* --- раскладка бенто --- */
.t1{ grid-column:span 6; grid-row:span 2; }
.t2{ grid-column:span 3; }
.t3{ grid-column:span 3; }
.t4{ grid-column:span 6; }
.t5{ grid-column:span 3; }
.t6{ grid-column:span 3; }
.t7{ grid-column:span 4; }
.t8{ grid-column:span 2; }

/* --- снимок проекта --- */
.tile__media{ position:absolute; inset:0; z-index:0; }
.tile__media img{ width:100%; height:100%; object-fit:cover; }
.tile__scrim{
  position:absolute;
  inset:0;
  z-index:1;
  background:linear-gradient(180deg,
    rgba(6,7,14,.55) 0%, rgba(6,7,14,.12) 24%, rgba(6,7,14,.62) 70%, rgba(6,7,14,.92) 100%);
  pointer-events:none;
}

/* --- содержимое --- */
.tile__body{
  position:relative;
  z-index:2;
  height:100%;
  display:flex;
  flex-direction:column;
  justify-content:flex-end;
  padding:clamp(14px, 1.35vw, 26px) clamp(15px, 1.5vw, 28px);
}
.tile--pill .tile__body{ justify-content:center; padding-inline:clamp(26px, 2.4vw, 46px); }
.tile--round .tile__body{ justify-content:center; align-items:center; text-align:center; padding:14px; }

.tile__top{
  display:flex;
  align-items:center;
  gap:9px;
  margin-bottom:auto;
  font-family:var(--font);
  font-size:clamp(12px, .72vw, 12px);
  font-variant-numeric:tabular-nums;
  letter-spacing:.06em;
  color:rgba(255,255,255,.46);
}
.tile--pill .tile__top,
.tile--round .tile__top{ margin-bottom:6px; }
.tile__num{ color:#8fa0ff; }
.tile__year{ margin-left:auto; }
.tile--pill .tile__year{ margin-left:14px; }
.tile__go{
  width:12px; height:12px;
  flex-shrink:0;
  opacity:0;
  transform:translate(-3px, 3px);
  transition:opacity .22s var(--ease), transform .22s var(--ease);
}
.tile:hover .tile__go{ opacity:1; transform:none; }

.tile__name{
  margin:0 0 clamp(4px, .4vw, 7px);
  font-size:clamp(13px, 1vw, 17px);
  font-weight:700;
  line-height:1.14;
  letter-spacing:.03em;
  text-transform:uppercase;
}
.t1 .tile__name{ font-size:clamp(19px, 1.75vw, 31px); letter-spacing:-.005em; }

.tile__desc{
  margin:0 0 clamp(4px, .4vw, 7px);
  font-size:clamp(14px, .85vw, 14.5px);
  line-height:1.4;
  color:var(--fg-lead);
}
.tile__meta{
  display:block;
  font-family:var(--font);
  font-size:clamp(12px, .76vw, 13px);
  line-height:1.35;
  letter-spacing:-.01em;
  color:rgba(255,255,255,.44);
}
.tile__meta b{ font-weight:500; color:var(--metric); }

.tile--pill .tile__row{
  display:flex;
  align-items:baseline;
  gap:clamp(10px, 1vw, 18px);
  flex-wrap:wrap;
}

/* --- оборот --- */
.tile__face--back .tile__body{ justify-content:center; }
.tile--pill .tile__face--back .tile__body{ justify-content:center; }

.tile__task{
  margin:0 0 clamp(9px, .9vw, 15px);
  font-size:clamp(14px, .88vw, 15px);
  line-height:1.5;
  color:#eef1f8;
}
.t1 .tile__task{ font-size:clamp(14px, 1.12vw, 19px); }
.tile__specs{
  display:grid;
  gap:clamp(3px, .3vw, 6px);
  font-family:var(--font);
  font-size:clamp(12px, .76vw, 13px);
  line-height:1.4;
  color:rgba(255,255,255,.62);
}
.tile__specs b{ font-weight:500; color:#c6f2cb; }
.tile__specs span{ color:rgba(255,255,255,.42); }
.tile--pill .tile__specs{ grid-auto-flow:column; gap:clamp(14px, 1.4vw, 28px); justify-content:start; }

.tile--round .tile__face--back .tile__body{ align-items:center; }
.tile--round .tile__task{ margin:0; font-size:clamp(14px, .82vw, 14px); }

/* тем, кто просил меньше движения: без переворота и без ползущего отсвета */
@media (prefers-reduced-motion:reduce){
  .tile__inner{ transition:none; transform:none; }
  .tile__face{ animation:none; }
  .tile__face--back{ display:none; }
  .tile__face--front::after{ display:none; }
}


/* ============================================================
   ПОЯВЛЕНИЕ РАЗДЕЛА
   Стекло не «всплывает», а отливается: сначала снизу разгорается
   свет, потом плитки приходят из глубины, разворачиваясь лицом,
   и на подлёте набирают толщину — слои расходятся из нуля.
   ============================================================ */

/* сама сетка не двигается — работают плитки */
.works__grid.reveal{ opacity:1; transform:none; transition:none; }

/* Фон приходит тремя ступенями по прокрутке: сначала темнота, за ней
   звёзды, последней дымка. Ступени считает скрипт и пишет в переменные
   `--bg-dark`, `--bg-stars`, `--bg-haze` на самой секции.

   Раньше всё включалось разом по `is-lit` через `transition`. Отказались
   не от хорошей жизни: переход — событие, у него своя длительность, и он
   не умеет ехать назад вместе с прокруткой. Прогресс по положению блока
   разматывается в обе стороны и не спорит с анимациями дрейфа, потому
   что трогает только `opacity`.

   Значение по умолчанию — 1: если скрипт не отработает, фон просто
   виден целиком, а не пропадает. */


/* ============================================================
   РЕЖИМ РАЗВОРОТА
   Пока куб раскрывается, декоративные слои только мешают:
   слои толщины под косым углом расходятся в двойные контуры,
   ползущий отсвет даёт диагональную складку. Плюс шестнадцать
   размытий фона не дают держать 60 кадров. На время движения
   всё это снимаем — на глаз незаметно, зато плавно.
   ============================================================ */
.works__grid.is-folding .tile__sheet{ display:none; }
.works__grid.is-folding .tile__face{
  animation:none;
  backdrop-filter:none;
  -webkit-backdrop-filter:none;
  /* компенсируем пропавшее размытие чуть более плотной заливкой */
  background:linear-gradient(165deg,
    rgba(255,255,255,.17) 0%,
    rgba(255,255,255,.075) 48%,
    rgba(255,255,255,.14) 100%);
}
.works__grid.is-folding .tile__face--back{
  background:linear-gradient(165deg,
    rgba(126,152,235,.26) 0%,
    rgba(70,92,180,.18) 48%,
    rgba(150,178,255,.24) 100%);
}

/* распорка под запас прокрутки, снять вместе с добавлением следующих секций */
.scroll-room{ height:22vh; pointer-events:none; }


/* ============================================================
   ВСПЫШКА
   Живёт в секции, а не в сетке: сетка — 3D-сцена с preserve-3d,
   и режим наложения внутри неё ведёт себя непредсказуемо.
   Координаты ставит скрипт, они совпадают с точкой сборки куба.
   ============================================================ */
/* Обойма вспышки. Сам свет — круг в 150vmax: без обрезки он вырастал
   за нижнюю кромку страницы и добавлял к ней около тысячи лишних
   пикселей пустой прокрутки, причём высота документа скакала прямо
   по ходу сцены. Режем по секции — на пике она и так занимает весь
   кадр, а кромка отреза приходится за шапку. */
.works__flashbox{
  position:absolute;
  inset:0;
  overflow:clip;
  pointer-events:none;
  z-index:4;
}

.works__flash{
  position:absolute;
  left:var(--fx, 50%);
  top:var(--fy, 34%);
  /* размер такой, чтобы на пике свет уходил за края экрана */
  width:150vmax;
  aspect-ratio:1;
  margin:0;
  border-radius:50%;
  transform:translate(-50%, -50%) scale(var(--fs, .06));
  background:radial-gradient(closest-side,
    rgba(255,255,255,1)    0%,
    rgba(255,255,255,.98)  6%,
    rgba(236,244,255,.80) 13%,
    rgba(198,220,255,.44) 24%,
    rgba(146,180,255,.20) 38%,
    rgba(96,136,240,.07)  54%,
    transparent 70%);
  opacity:var(--fo, 0);
  visibility:var(--fv, hidden);
  mix-blend-mode:screen;
  pointer-events:none;
  z-index:4;
  will-change:opacity, transform;
}

@media (prefers-reduced-motion:reduce){
  .works__flash{ display:none; }
}


/* ============================================================
   ПОЯВЛЕНИЕ ЗАГОЛОВКА РАЗДЕЛА
   Тот же приём, что рендерит лид в первом экране: луч идёт слева
   направо и проявляет за собой текст. Здесь он же вводит раздел,
   поэтому заголовок читается как часть одной сцены, а не как
   отдельно всплывающий блок.

   --hp и --lp пишет скрипт от положения заголовка в кадре.
   По умолчанию единица: без скрипта и при выключенной анимации
   всё видно сразу.
   ============================================================ */
.works__titles{ --hp:1; }

.works__titles::before{
  transform-origin:top;
  transform:scaleY(var(--hp));
}

.works .eyebrow{
  opacity:var(--hp);
  transform:translateX(calc((1 - var(--hp)) * -12px));
}

.works__h2wrap{
  position:relative;
  display:inline-block;
}
/* текст открывается по мере ухода луча вправо */
.works__title{
  clip-path:inset(0 calc(100% - var(--hp) * 100%) 0 0);
}
.works__beam{
  position:absolute;
  top:-.1em;
  bottom:-.06em;
  left:calc(var(--hp) * 100%);
  width:2px;
  margin-left:-1px;
  background:linear-gradient(180deg,
    transparent, #9fb4ff 18%, #ffffff 50%, #9fb4ff 82%, transparent);
  box-shadow:0 0 14px 2px rgba(140,165,255,.85);
  /* гаснет на самых краях: в начале ещё нечего проявлять, в конце уже нечего */
  opacity:calc(min(var(--hp), 1 - var(--hp)) * 5);
  pointer-events:none;
}

.works__all{
  --lp:1;
  opacity:var(--lp);
  transform:translateY(calc((1 - var(--lp)) * 10px));
}
.works__all .works__ring{
  transform:scale(calc(.72 + .28 * var(--lp)));
}


