/* Шрифты подключены в WOFF2 и подрезаны до латиницы, кириллицы и знаков
   пунктуации: исходные OTF/TTF содержали греческий, иврит, арабское письмо,
   деванагари и тайский — около мегабайта, который никогда не отрисуется.
   Лоадер главной ждёт document.fonts.ready, поэтому вес шрифтов напрямую
   определяет момент первой отрисовки. Проверка покрытия — tools/check-fonts.py.
   Начертание Semibold (600) вернулось: его просит заголовок плашки о cookie,
   так в макете. Файл подрезан по тому же набору символов, что остальные.
   Скачивается он только когда плашка на экране: пока она скрыта, ни одно
   отрисованное правило шрифт не запрашивает. */
@font-face {
  font-family: "LT Superior";
  src: url("assets/fonts/LTSuperior-Semibold.woff2") format("woff2");
  font-style: normal;
  font-weight: 600;
  font-display: swap;
}

@font-face {
  font-family: "LT Superior";
  src: url("assets/fonts/LTSuperior-Regular.woff2") format("woff2");
  font-style: normal;
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: "LT Superior";
  src: url("assets/fonts/LTSuperior-Medium.woff2") format("woff2");
  font-style: normal;
  font-weight: 450;
  font-display: swap;
}

@font-face {
  font-family: "LT Superior";
  src: url("assets/fonts/LTSuperior-Bold.woff2") format("woff2");
  font-style: normal;
  font-weight: 700;
  font-display: swap;
}

/* Ось начертания подрезана до 400-500 — единственных значений, которые
   использует вёрстка. Полный диапазон 100-900 весил 217 КБ против 78 КБ.
   Понадобится жирный Roboto — вернуть диапазон в этом объявлении и
   пересобрать файл. */
@font-face {
  font-family: "Roboto";
  src: url("assets/fonts/Roboto-Variable.woff2") format("woff2");
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
}

:root {
  --dark: #082554;
  --light: #f0faff;
  --blue: #d7f0ff;
  --accent: #f2551b;
  --muted: #93a5bb;
  --white: #fff;
  --line: 1px solid var(--dark);
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  background: var(--light);
  scrollbar-width: none;
  -ms-overflow-style: none;
}

html::-webkit-scrollbar,
body::-webkit-scrollbar {
  display: none;
  width: 0;
  height: 0;
}

body {
  scrollbar-width: none;
  -ms-overflow-style: none;
}

html.lenis {
  height: auto;
}

.lenis.lenis-smooth {
  scroll-behavior: auto;
}

.lenis.lenis-smooth [data-lenis-prevent] {
  overscroll-behavior: contain;
}

.lenis.lenis-stopped {
  overflow: hidden;
}

body {
  min-width: 320px;
  margin: 0;
  overflow-x: hidden;
  color: var(--dark);
  background: var(--light);
  font-family: "Roboto", Arial, sans-serif;
  font-size: 14px;
  font-synthesis: none;
  font-weight: 400;
  line-height: 1.4;
}

body.menu-open {
  overflow: hidden;
}

body.menu-closing {
  overflow: hidden;
}

html::before {
  position: fixed;
  z-index: 90;
  inset: 0;
  display: block;
  background: rgba(0, 0, 0, .24);
  content: "";
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 420ms ease, visibility 0s linear 820ms;
}

html.menu-open::before {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition-delay: 110ms, 0s;
}

html.menu-closing::before {
  pointer-events: auto;
}

button,
a {
  color: inherit;
}

a {
  text-decoration: none;
}

button {
  border: 0;
  font: inherit;
  cursor: pointer;
}

h1,
h2,
h3,
p {
  margin: 0;
}

img {
  display: block;
  max-width: 100%;
}

:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 4px;
}

/* Skip-link виден только при навигации с клавиатуры (:focus-visible).
   Встроенный браузер Telegram программно фокусирует первую ссылку и
   сдвигает viewport под своей панелью — прежний translateY(-150%) тогда
   показывал кнопку под логотипом. Теперь она вырезана clip-path и
   прозрачна, пока не получит именно клавиатурный фокус. */
.skip-link {
  position: fixed;
  z-index: 1000;
  top: 8px;
  left: 8px;
  padding: 10px 14px;
  color: var(--light);
  background: var(--dark);
  opacity: 0;
  pointer-events: none;
  clip-path: inset(50%);
}

.skip-link:focus-visible {
  opacity: 1;
  pointer-events: auto;
  clip-path: none;
}

/* Постоянный фон соединяет два HTML-документа без смены цвета.
   Прозрачность body включает шапку и canvas, сохраняя fixed-позиционирование. */
html {
  background-color: var(--light);
}

html.is-page-entering:not(.is-page-entering-home) body {
  opacity: 0;
}

html.is-page-leaving-to-home {
  background-color: var(--dark);
}

html.is-page-entering body,
html.is-page-leaving body {
  pointer-events: none;
}

.section-title,
.hero__title,
.company-intro__lead,
.stats__title,
.project-card h3 {
  font-family: "LT Superior", Arial, sans-serif;
  font-weight: 450;
}

.button {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 56px;
  border-radius: 3px;
  color: var(--light);
  background: var(--dark);
  font-size: 16px;
  line-height: 1.4;
  text-align: center;
  text-transform: uppercase;
  transition: color 180ms ease;
}

.button::before {
  position: absolute;
  z-index: 0;
  top: 100%;
  left: 50%;
  width: 200%;
  height: 100%;
  border-radius: 0;
  background: var(--accent);
  content: "";
  pointer-events: none;
  transform: translate(-50%, 0);
  transition: transform 720ms cubic-bezier(.22, 1, .36, 1);
}

.button__text {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 15px;
  text-align: center;
  z-index: 1;
  transform: translateY(0);
  transition: transform 720ms cubic-bezier(.22, 1, .36, 1);
}

.button__text--hover {
  transform: translateY(100%);
}

.button:hover,
.button:focus-visible {
  color: var(--light);
  background: var(--dark);
}

.button:hover::before,
.button:focus-visible::before {
  transform: translate(-50%, -100%);
}

.button:hover .button__text--current,
.button:focus-visible .button__text--current {
  transform: translateY(-100%);
}

.button:hover .button__text--hover,
.button:focus-visible .button__text--hover {
  transform: translateY(0);
}

/* Header buttons use the same bottom-up orange hover as the main buttons. */
.button--fill-hover {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}

.button--fill-hover::before {
  position: absolute;
  z-index: 0;
  top: 100%;
  left: 50%;
  width: 200%;
  height: 100%;
  background: var(--light);
  content: "";
  pointer-events: none;
  transform: translate(-50%, 0);
  transition: transform 720ms cubic-bezier(.22, 1, .36, 1);
}

.button--fill-hover:hover,
.button--fill-hover:focus-visible,
.menu-button[aria-expanded="true"] {
  color: var(--dark);
}

.button--fill-hover:hover::before,
.button--fill-hover:focus-visible::before,
.menu-button[aria-expanded="true"]::before {
  transform: translate(-50%, -100%);
}

.button--fill-hover:hover .button__text--current,
.button--fill-hover:focus-visible .button__text--current,
.menu-button[aria-expanded="true"] .button__text--current {
  transform: translateY(-100%);
}

.button--fill-hover:hover .button__text--hover,
.button--fill-hover:focus-visible .button__text--hover,
.menu-button[aria-expanded="true"] .button__text--hover {
  transform: translateY(0);
}

.text-link {
  display: inline-block;
  border-bottom: 1px solid currentColor;
  font-weight: 500;
  line-height: 1.15;
  text-transform: uppercase;
  transition: color 180ms ease;
}

.text-link:hover,
.text-link:focus-visible {
  color: var(--accent);
}

.image-tone {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: var(--blue);
}

.image-tone::before {
  position: absolute;
  z-index: 3;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(rgba(8, 37, 84, 0.7), rgba(8, 37, 84, 0.7)),
    linear-gradient(180deg, rgba(0, 0, 0, 0) 46.57%, rgba(0, 0, 0, 0.3) 100%);
  content: "";
}

/* Новый общий WebGL-дизер: один слой на весь viewport. */
.site-dither-canvas {
  position: fixed;
  z-index: 2;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  /* Высота «большого» viewport не меняется, когда панель браузера
     (Safari, Telegram) сворачивается при скролле. Иначе canvas
     перевыделял буфер на каждом кадре анимации панели. */
  height: 100lvh;
  pointer-events: none;
}

.image-tone > img:not(.project-card__arrow) {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Hero — mobile */
.hero {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  overflow: hidden;
  color: var(--light);
  background: var(--dark);
}

.hero__media {
  position: absolute;
  z-index: 0;
  inset: 0;
  isolation: isolate;
  contain: layout paint;
  /* Фото рисует <img> внутри блока; фоновая картинка дублировала тот же
     файл вторым декодом и вторым большим paint, а после готовности дизера
     всё равно оказывалась под его canvas. Путь к файлу остаётся только в
     разметке — это то, что подставит CMS. */
  --dither-position-x: 37%;
}

.hero__media > img:first-child {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--dither-position-x) center;
}

.site-header {
  position: absolute;
  /* Выше слоя контента hero (.hero__lines / .hero__descriptor / .hero__title —
     z-index 3). Дескриптор идёт в DOM после шапки, и при равном z-index он
     перекрывал кнопку меню в правой колонке. */
  z-index: 4;
  top: 0;
  left: 0;
  display: flex;
  width: 100%;
  height: 61px;
  align-items: flex-start;
  justify-content: space-between;
  padding: 14px 15px 0;
}

/* На iOS Safari абсолютная шапка внутри overflow-контейнера hero может
   оказаться под следующими секциями во время scroll. Фиксируем сам контейнер
   шапки на мобильном, а не только его логотип и кнопки: так весь header
   остаётся в верхнем слое viewport. */
@media (max-width: 599px) {
  .site-header {
    position: fixed;
    z-index: 110;
  }
}

.site-header--light {
  color: var(--light);
}

.site-header--dark {
  color: var(--dark);
}

.site-header--light .desktop-nav__group a {
  color: var(--light);
}

.site-header--dark .desktop-nav__group a {
  color: var(--dark);
}

/* Детальные страницы используют общий header; эти линии — часть сетки экрана,
   а не локальный фон или отдельная версия шапки. */
@media (min-width: 1200px) {
  body[data-site-page="project-detail"] .site-header::before,
  body[data-site-page="project-detail"] .site-header::after,
  body[data-site-page="news-detail"] .site-header::before,
  body[data-site-page="news-detail"] .site-header::after {
    position: absolute;
    z-index: 2;
    top: 0;
    width: 1px;
    height: var(--detail-guide-height, 100%);
    pointer-events: none;
    background: var(--dark);
    content: "";
  }

  body[data-site-page="project-detail"] .site-header::before,
  body[data-site-page="news-detail"] .site-header::before {
    left: 50.5208vw;
  }

  body[data-site-page="project-detail"] .site-header::after,
  body[data-site-page="news-detail"] .site-header::after {
    left: 74.2188vw;
  }
}

.site-logo {
  position: fixed;
  z-index: 20;
  top: 14px;
  left: 15px;
}

.site-logo img {
  width: 113px;
  height: 42px;
}

.site-logo--en {
  display: grid;
  width: 113px;
  height: 42px;
  place-items: center;
  border-radius: 3px;
  background: #082554;
}

.site-logo--en img {
  width: 62%;
  height: auto;
}

.desktop-nav {
  display: none;
}

.site-header__actions {
  position: fixed;
  z-index: 120;
  top: 14px;
  right: 15px;
  display: flex;
  gap: 1px;
}

body.menu-open .site-header__actions {
  z-index: 120;
}

body.menu-closing .site-header__actions {
  z-index: 120;
}

body.menu-open .site-header,
body.menu-closing .site-header {
  z-index: 2147483646;
}

body.menu-open .hero__descriptor,
body.menu-closing .hero__descriptor {
  visibility: hidden;
}

.site-scrollbar {
  position: fixed;
  z-index: 80;
  top: 0;
  right: 4px;
  bottom: 0;
  width: 12px;
  opacity: 1;
  pointer-events: none;
  transition: opacity 240ms ease;
}

.site-scrollbar::before {
  display: none;
}

.site-scrollbar__thumb {
  position: absolute;
  top: 0;
  left: 50%;
  width: 7.2px;
  min-height: 38px;
  border: 1px solid rgba(8, 37, 84, .5);
  border-radius: 999px;
  background: rgba(255, 255, 255, .38);
  content: "";
  transform: translate3d(-50%, 0, 0);
  transform-origin: center top;
  pointer-events: auto;
  cursor: pointer;
  touch-action: none;
  user-select: none;
  /* height здесь был вреден: это не composited-свойство, и объявление
     держало ползунок в постоянной готовности к layout. Высота теперь
     пишется только при resize, поэтому на кадрах скролла меняется
     исключительно transform. */
  will-change: transform;
}

.site-scrollbar__thumb:hover {
  border-color: var(--dark);
  background: var(--dark);
}

.site-scrollbar__thumb.is-dragging {
  border-color: var(--dark);
  background: var(--dark);
  cursor: grabbing;
}

.site-scrollbar__thumb.is-dragging.is-over-dark {
  border-color: rgba(255, 255, 255, .7);
  background: rgba(255, 255, 255, .42);
}

.site-scrollbar.is-hidden {
  opacity: 0;
}

.site-scrollbar.is-hidden .site-scrollbar__thumb {
  pointer-events: none;
}

.menu-panel__close {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  height: 42px;
  border-radius: 3px;
  font-size: 14px;
  font-weight: 500;
  text-transform: uppercase;
}

.menu-button {
  height: 42px;
  border-radius: 3px;
  font-size: 14px;
  font-weight: 500;
  text-transform: uppercase;
}

.menu-button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 110px;
  color: var(--dark);
  background: var(--white);
  transition: color 180ms ease, background-color 180ms ease;
}

.menu-button:hover,
.menu-button:focus-visible {
  color: var(--dark);
  background: var(--light);
}

.language-button {
  width: 42px;
  border: 1px solid var(--dark);
  border-radius: 3px;
  color: var(--light);
  background: var(--dark);
  transition: color 180ms ease, background-color 180ms ease;
}

.desktop-nav a,
.menu-panel__nav a,
.menu-panel__contacts-links a {
  transition: color 180ms ease;
}

.desktop-nav a:hover,
.desktop-nav a:focus-visible,
.menu-panel__nav a:hover,
.menu-panel__nav a:focus-visible,
.menu-panel__contacts-links a:hover,
.menu-panel__contacts-links a:focus-visible {
  color: var(--muted);
}

.desktop-nav a[aria-current="page"],
.desktop-nav a[aria-current="page"]:hover,
.desktop-nav a[aria-current="page"]:focus-visible,
.menu-panel__nav a[aria-current="page"],
.menu-panel__nav a[aria-current="page"]:hover,
.menu-panel__nav a[aria-current="page"]:focus-visible {
  color: var(--muted);
  cursor: default;
  pointer-events: none;
}

.language-button:hover,
.language-button:focus-visible {
  color: var(--dark);
  background: var(--light);
}

.hero__lines {
  position: absolute;
  z-index: 1;
  inset: 0;
  pointer-events: none;
}

.hero__line {
  position: absolute;
  z-index: 1;
  left: 15px;
  width: 1px;
  background: var(--light);
}

.hero__line--top {
  top: 16.8831%;
  height: 37.2913%;
}

.hero__line--bottom {
  display: none;
}

.hero__line--left-bottom {
  display: none;
}

.hero__line--nav-left,
.hero__line--nav-right {
  display: none;
}

.hero__descriptor {
  position: absolute;
  z-index: 2;
  top: 59.7403%;
  left: 15px;
  /* На мобильном колонка уже поля: на всю ширину экрана текст ложится в две
     длинные строки, а по макету их три. Ограничение снимают правила
     планшета и десктопа — там ширина задана своя. */
  width: min(calc(100% - 30px), 300px);
  font-family: "LT Superior", Arial, sans-serif;
  font-size: 16px;
  font-weight: 400;
  line-height: normal;
  /* Текст приходит из админки: длина неизвестна, поэтому строки набираются
     переносом, а слово длиннее колонки рвётся, а не свисает за край. */
  overflow-wrap: break-word;
}

.hero__title {
  position: absolute;
  z-index: 2;
  top: 74.397%;
  left: 15px;
  width: calc(100% - 42px);
  font-size: 40px;
  line-height: 1;
}

.menu-panel[hidden] {
  display: none;
}

.menu-panel {
  position: fixed;
  z-index: 2147483647;
  top: 61px;
  right: 15px;
  bottom: 15px;
  left: 15px;
  display: flex;
  flex-direction: column;
  overflow: auto;
  padding: 30px 20px 20px;
  color: var(--light);
  background: var(--dark);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
  transform: translate3d(100%, 0, 0);
  transition:
    opacity 420ms ease,
    transform 500ms cubic-bezier(.55, .085, .68, .53),
    visibility 0s linear 500ms;
  will-change: opacity, transform;
}

.menu-panel.is-open,
.menu-panel.is-closing {
  visibility: visible;
}

.menu-panel.is-open {
  opacity: 1;
  pointer-events: auto;
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
  transform: translate3d(0, 0, 0);
  transition-delay: 0s;
}

.menu-panel.is-closing {
  pointer-events: none;
  transition:
    opacity 520ms ease,
    transform 980ms cubic-bezier(.33, 1, .68, 1),
    visibility 0s linear 980ms;
}

/* Когда GSAP доступен, панель и её внутренние элементы ведутся одной
   timeline-анимацией, поэтому CSS-переходы не должны добавлять второй
   параллельный transform/opacity. */
.menu-panel--gsap,
.menu-panel--gsap .menu-panel__nav,
.menu-panel--gsap .menu-panel__nav a,
.menu-panel--gsap .menu-panel__contacts,
.menu-panel--gsap .menu-panel__contacts-title,
.menu-panel--gsap .menu-panel__contacts-content {
  transition: none !important;
}

.menu-panel--gsap .menu-panel__nav a {
  opacity: 1 !important;
  visibility: visible !important;
  transform: none !important;
}

.menu-panel--gsap {
  transform: translate3d(var(--menu-panel-x, 100%), 0, 0) !important;
}

.menu-panel--gsap .menu-panel__contacts::before,
.menu-panel--gsap .menu-panel__contacts::after {
  transform: scaleX(var(--menu-line-progress, 0));
  transition: none !important;
}

.menu-panel__nav,
.menu-panel__contacts {
  opacity: 0;
  transform: translate3d(0, 18px, 0);
  transition: opacity 360ms ease, transform 620ms cubic-bezier(.22, 1, .36, 1);
}

.menu-panel.is-open .menu-panel__nav,
.menu-panel.is-open .menu-panel__contacts {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

.menu-panel.is-open .menu-panel__nav {
  transition-delay: 150ms;
}

.menu-panel.is-open .menu-panel__contacts {
  transition-delay: 230ms;
}

.menu-panel.is-closing .menu-panel__nav,
.menu-panel.is-closing .menu-panel__contacts {
  transition-duration: 760ms;
}

.menu-panel__nav {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  font-family: "LT Superior", Arial, sans-serif;
  font-size: clamp(21.6px, 6.1538vw, 26.4px);
  font-weight: 450;
  line-height: 1.2;
}

@media (max-width: 599px) {
  .menu-panel__nav {
    gap: 10px;
    font-size: clamp(26.6px, calc(6.1538vw + 5px), 31.4px);
  }
}

.menu-panel__nav a {
  --menu-item-delay: 0ms;
  width: fit-content;
  max-width: 100%;
  white-space: nowrap;
  opacity: 0;
  transform: translate3d(0, 100%, 0);
  transition: color 180ms ease, opacity 420ms ease, transform 620ms cubic-bezier(.22, 1, .36, 1);
}

.menu-panel__nav a:nth-child(2) { --menu-item-delay: 55ms; }
.menu-panel__nav a:nth-child(3) { --menu-item-delay: 110ms; }
.menu-panel__nav a:nth-child(4) { --menu-item-delay: 165ms; }
.menu-panel__nav a:nth-child(5) { --menu-item-delay: 220ms; }

.menu-panel.is-open .menu-panel__nav a {
  opacity: 1;
  transform: translate3d(0, 0, 0);
  transition-delay: calc(185ms + var(--menu-item-delay));
}

.menu-panel.is-closing .menu-panel__nav a {
  transition-duration: 760ms;
}

.menu-panel__contacts {
  position: relative;
  display: grid;
  gap: 20px;
  margin-top: auto;
  padding: 20px 0;
  border-top: 0;
  border-bottom: 0;
  font-size: 13px;
  font-weight: 400;
  line-height: 1.4;
  text-transform: uppercase;
}

.menu-panel__contacts::before,
.menu-panel__contacts::after {
  position: absolute;
  right: 0;
  left: 0;
  height: 1px;
  background: var(--light);
  content: "";
  pointer-events: none;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 520ms cubic-bezier(.22, 1, .36, 1);
}

.menu-panel__contacts::before { top: 0; }
.menu-panel__contacts::after { bottom: 0; }

.menu-panel.is-open .menu-panel__contacts::before,
.menu-panel.is-open .menu-panel__contacts::after {
  transform: scaleX(1);
  transition-delay: 300ms;
}

.menu-panel.is-closing .menu-panel__contacts::before,
.menu-panel.is-closing .menu-panel__contacts::after {
  transition-duration: 700ms;
}

.menu-panel__contacts-title,
.menu-panel__contacts-content {
  opacity: 0;
  transform: translate3d(0, 12px, 0);
  transition: opacity 360ms ease, transform 520ms cubic-bezier(.22, 1, .36, 1);
}

.menu-panel.is-open .menu-panel__contacts-title,
.menu-panel.is-open .menu-panel__contacts-content {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

.menu-panel.is-open .menu-panel__contacts-title { transition-delay: 335ms; }
.menu-panel.is-open .menu-panel__contacts-content { transition-delay: 380ms; }

.menu-panel.is-closing .menu-panel__contacts-title,
.menu-panel.is-closing .menu-panel__contacts-content {
  transition-duration: 650ms;
}

.menu-panel__contacts-title {
  width: 190px;
}

.menu-panel__contacts-content,
.menu-panel__contacts-links {
  display: flex;
  flex-direction: column;
}

.menu-panel__contacts-content {
  gap: 16px;
}

.menu-panel__contacts-links {
  gap: 7px;
}

.menu-panel__contacts-links a {
  width: fit-content;
  text-decoration: underline;
  text-underline-position: from-font;
}

/* Company intro — mobile */
/* min-height, а не height: секция задаёт минимальный кадр макета, но
   растёт вслед за содержимым. С фиксированной высотой абзац на строку
   длиннее просто уезжал под нижнюю границу — при редактируемых из CMS
   текстах это вопрос времени. overflow: hidden заодно создаёт BFC, так что
   margin детей не «протекает» наружу секции. */
.company-intro {
  position: relative;
  overflow: hidden;
  /* Отступ под текстом, не зависит от заданной высоты секции. */
  padding-bottom: 40px;
  background: var(--light);
  /* Пол под высоту фона-«лестницы» ниже: нижняя полоса заканчивается на
     44.4271vw от верха секции, плюс такой же отступ снизу, как в Figma
     (50px при кадре 1920) — иначе на коротком тексте её обрезает раньше,
     чем она успевает дорисоваться. На телефоне и планшете текста обычно
     достаточно, чтобы секция и так была выше, но на всякий случай общий
     для всех разрешений. */
  min-height: 47.0313vw;
}

/* Ступенчатый фон по Figma: 4 горизонтальные полосы var(--blue), каждая
   шире секции и сдвинута правее и ниже предыдущей, идут строго друг под
   другом (низ одной совпадает с верхом следующей) — не участвует в сетке
   и не привязана к тексту, лежит под ним сплошной подложкой. Общий для
   всех разрешений, вместе со скролл-анимацией в animations.js. */
.company-intro__steps {
  position: absolute;
  z-index: 0;
  inset: 0;
  pointer-events: none;
}
.company-intro__steps span {
  position: absolute;
  display: block;
  width: 100vw;
  background: var(--blue);
}
.company-intro__steps span:nth-child(1) { top: 0; left: 0; height: 16.6146vw; }
.company-intro__steps span:nth-child(2) { top: 16.6146vw; left: 6.9792vw; height: 8.4375vw; }
.company-intro__steps span:nth-child(3) { top: 25.0521vw; left: 26.875vw; height: 9.7917vw; }
.company-intro__steps span:nth-child(4) { top: 34.8438vw; left: 50.5208vw; height: 9.5833vw; }

/* Главная: у каждого адаптивного макета своя геометрия лестницы. */
@media (max-width: 599px) {
  body[data-site-page="home"] .company-intro {
    min-height: 660px;
    padding-top: 50px;
    padding-bottom: 50px;
  }
  body[data-site-page="home"] .company-intro__steps span { height: 25%; }
  body[data-site-page="home"] .company-intro__steps span:nth-child(1) { top: 0; left: 0; height: 25%; }
  body[data-site-page="home"] .company-intro__steps span:nth-child(2) { top: 25%; left: 13.0667%; height: 25%; }
  body[data-site-page="home"] .company-intro__steps span:nth-child(3) { top: 50%; left: 30.9333%; height: 25%; }
  body[data-site-page="home"] .company-intro__steps span:nth-child(4) { top: 75%; left: 51.4667%; height: 25%; }
}

@media (min-width: 600px) and (max-width: 1199px) {
  body[data-site-page="home"] .company-intro { min-height: 710px; }
  body[data-site-page="home"] .company-intro__steps span:nth-child(1) { top: 0; left: 0; height: 220px; }
  body[data-site-page="home"] .company-intro__steps span:nth-child(2) { top: 220px; left: 13.0208%; height: 170px; }
  body[data-site-page="home"] .company-intro__steps span:nth-child(3) { top: 390px; left: 30.8594%; height: 170px; }
  body[data-site-page="home"] .company-intro__steps span:nth-child(4) { top: 560px; left: 51.5625%; height: 150px; }
}

.company-intro__lead {
  position: relative;
  z-index: 1;
  width: calc(100% - 44px);
  margin-left: 15px;
  font-size: 23.438px;
  line-height: 1.3;
}

/* Зазор под лидом вместо координаты: на 375 px лид занимает четыре строки, и
   текст начинался на 352. Дальше расстояние держится само — поменяется длина
   лида, двигать это число не нужно. В 58 входят 2 px, которые SplitText
   забирает отрицательным нижним полем последней строки (см. README). */
.company-intro__copy {
  position: relative;
  z-index: 1;
  display: grid;
  margin: 58px 15px 0;
  gap: 47px;
  text-transform: uppercase;
}

.company-intro__copy p {
  max-width: 345px;
  font-size: 14px;
}

/* Statistics — mobile */
.stats {
  position: relative;
  min-height: 1052px;
  overflow: hidden;
  background: var(--light);
}

/* Обёртка левой колонки. На мобильном и планшете она не создаёт бокса —
   подзаголовок и фото там позиционируются от секции, как раньше. */
.stats__aside {
  display: contents;
}

.stats__title {
  position: absolute;
  top: 35px;
  left: 15px;
  display: block;
  width: calc(100% - 30px);
  font-size: 35px;
  line-height: 1;
}

.stats__title span {
  display: inline-block;
}

.stats__title span + span::before {
  content: none;
}

.stats__eyebrow {
  position: absolute;
  top: 84px;
  left: 15px;
  width: calc(100% - 30px);
  font-size: 14px;
  text-transform: uppercase;
}

.stats__image {
  position: absolute;
  top: 170px;
  left: 15px;
  width: calc(100% - 30px);
  height: 214px;
}

.stats__image-layer {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 700ms cubic-bezier(.22, 1, .36, 1);
}

.stats__image-layer.is-active {
  opacity: 1;
}

.stats__image-layer.is-front {
  z-index: 1;
}

.stats__image-layer > img:first-child {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1.25);
}

.stats__image::before {
  background:
    linear-gradient(rgba(8, 37, 84, 0.7), rgba(8, 37, 84, 0.7)),
    linear-gradient(180deg, rgba(0, 0, 0, 0) 46.57%, rgba(0, 0, 0, 0.3) 100%);
}

.stats__list {
  position: absolute;
  top: 421px;
  left: 15px;
  width: calc(100% - 30px);
}

.stat-item {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 132px;
  border-top: 0;
  color: var(--dark);
}

/* Линия у показателя одна — сверху. Нижних в базовом виде нет: там, где
   карточки идут столбиком, линия под третьей ложится ровно на линию над
   четвёртой, две по пикселю рисуются друг на друге, и черта выглядит вдвое
   толще остальных. Нижние линии включаются там, где им есть что закрывать:
   на планшете это нижний ряд сетки, на десктопе — последняя строка. */
.stat-item::before,
.stat-item:nth-child(3)::after,
.stat-item:nth-of-type(4)::after {
  position: absolute;
  right: 0;
  left: 0;
  height: 1px;
  background: var(--dark);
  transform: none !important;
  will-change: auto;
}

.stat-item::before {
  top: 0;
  content: "";
}

.stat-item:nth-child(3)::after,
.stat-item:nth-of-type(4)::after {
  bottom: 0;
  content: none;
}

.stat-item:nth-child(4) {
  min-height: 160px;
  border-bottom: 0;
}

.stat-item:nth-child(3) {
  min-height: 113px;
}

.stat-item strong {
  display: block;
  margin-top: 0;
  font-family: "LT Superior", Arial, sans-serif;
  font-size: 39.844px;
  font-weight: 700;
  line-height: 1.04;
}

.stat-item p {
  margin-top: 13px;
  font-size: 14.063px;
  font-weight: 400;
  line-height: 1.35;
  text-transform: uppercase;
}

.stats__button {
  width: 100%;
}

/* Projects — mobile */
/* Высота секций и карточек — минимум кадра макета, а не жёсткая рамка:
   описание проекта из инфоблока может оказаться на строку длиннее. */
.projects {
  position: relative;
  min-height: 1559px;
  padding: 35px 15px 55px;
  background: var(--light);
}

.projects__title {
  width: 100%;
  font-size: 35px;
  line-height: 1;
  text-align: center;
}

.projects__grid {
  display: grid;
  gap: 50px;
  margin-top: 25px;
}

.project-card {
  position: relative;
}

.project-card::before {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  display: none;
  width: 1px;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    var(--dark) 0,
    var(--dark) var(--project-line-gap-start, 0px),
    var(--light) var(--project-line-gap-start, 0px),
    var(--light) var(--project-line-gap-end, 0px),
    var(--dark) var(--project-line-gap-end, 0px),
    var(--dark) 100%
  );
  content: "";
}

.project-card__number {
  display: block;
  margin-bottom: 12px;
  font-size: 16.406px;
}

.project-card h3 {
  min-height: 26px;
  margin-bottom: 25px;
  font-size: 25.781px;
  line-height: 1;
}

.project-card__media {
  display: block;
  width: 100%;
  height: 216px;
  /* Стрелка должна быть отдельным верхним слоем над общим WebGL-canvas.
     Изоляция image-tone запирала её внутри stacking context, поэтому на
     мобильном она исчезала под fixed-дизером. Остальные слои изображения
     сохраняют порядок через свои z-index. */
  isolation: auto;
}

.project-card__media::before {
  background:
    linear-gradient(rgba(8, 37, 84, 0.7), rgba(8, 37, 84, 0.7)),
    linear-gradient(180deg, rgba(0, 0, 0, 0) 46.57%, rgba(0, 0, 0, 0.3) 100%);
  transition: opacity 260ms ease;
}

.project-card__media:hover::before,
.project-card__media:focus-visible::before {
  opacity: 0;
}

.project-card__media > img:first-child {
  transition: filter 260ms ease, transform 260ms ease;
}

.project-card__arrow {
  position: absolute;
  z-index: 4;
  right: 0;
  bottom: 0;
  width: 60px;
  height: 60px;
}

.project-card__arrow > img {
  display: block;
  width: 100%;
  height: 100%;
}

.project-card__media:hover > img:first-child {
  opacity: 1;
  filter: none;
  transform: scale(1.025);
}

.project-card__media:hover > img:first-child,
.project-card__media:focus-visible > img:first-child {
  opacity: 1;
  filter: none;
}

.project-card p {
  margin-top: 15px;
  font-size: 14px;
  line-height: 1.4;
  text-transform: uppercase;
}

.projects__button--desktop {
  display: none;
}

.projects__button--adaptive {
  width: 100%;
  margin-top: 54px;
}

/* Services — mobile */
.services {
  position: relative;
  min-height: 2154px;
  overflow: hidden;
  padding: 35px 15px 68px;
  background: var(--light);
}

.services__intro .section-title {
  font-size: 35px;
  line-height: 1;
}

.services__intro > p {
  width: 100%;
  margin-top: 14px;
  font-size: 14px;
  text-transform: uppercase;
}

.services__list {
  display: grid;
  gap: 29px;
  margin-top: 35px;
}

.service-card {
  display: flex;
  min-height: 366px;
  flex-direction: column;
  overflow: hidden;
  background: var(--white);
}

/* will-change держал пять композиторных слоёв на всю жизнь страницы, хотя
   карточки едут, только пока секция услуг проходит экран. Класс ставит
   IntersectionObserver в initServicesCardsReveal — за пол-экрана до входа,
   так что слой готов к первому кадру анимации и снимается после выхода. */
.services__list.is-services-in-view .service-card {
  will-change: transform;
}

.service-card:nth-child(4) {
  min-height: 345px;
}

.service-card:nth-child(5) {
  min-height: 345px;
}

.service-card__media {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  width: 100%;
  height: 188px;
  flex: 0 0 188px;
  background: var(--blue);
}

.service-card__media > img:first-child {
  position: relative;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: filter 260ms ease, transform 260ms ease;
}

.service-card__media::before {
  position: absolute;
  z-index: 3;
  inset: 0;
  content: "";
  pointer-events: none;
  background:
    linear-gradient(rgba(8, 37, 84, 0.7), rgba(8, 37, 84, 0.7)),
    linear-gradient(180deg, rgba(0, 0, 0, 0) 46.57%, rgba(0, 0, 0, 0.3) 100%);
  transition: opacity 260ms ease;
}

.service-card__content {
  position: relative;
  display: flex;
  min-height: 0;
  flex: 1;
  flex-direction: column;
  padding: 20px 10px 20px;
}

.service-card__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  padding-bottom: 13px;
  border-bottom: var(--line);
  font-family: "LT Superior", Arial, sans-serif;
  font-size: 25.781px;
  font-weight: 450;
  line-height: 1;
}

.service-card__head h3 {
  max-width: 270px;
  font-family: "Roboto", Arial, sans-serif;
  font-size: 19.922px;
  font-style: normal;
  font-weight: 400;
  line-height: 1.4;
}

.service-card__head span {
  font-family: "LT Superior", Arial, sans-serif;
  font-size: 25.781px;
  font-weight: 450;
  line-height: 1;
}

.service-card__content > p {
  max-width: 326px;
  margin-top: 13px;
  font-size: 14px;
  line-height: 1.4;
  text-transform: uppercase;
}

.service-card .text-link {
  align-self: flex-end;
  margin-top: auto;
  font-size: 14px;
}

/* Video — mobile */
.video-section {
  position: relative;
  height: 316px;
  overflow: hidden;
  border-top: var(--line);
  border-bottom: var(--line);
  background: var(--light);
}

.video-frame {
  --ticker-thickness: 14px;
  --ticker-gap: 5px;
  --ticker-media-inset: calc(var(--ticker-thickness) + var(--ticker-gap));
  --ticker-frame-height: 254.15px;
  position: absolute;
  top: calc((100% - var(--ticker-frame-height)) / 2);
  left: 15px;
  width: calc(100% - 30px);
  height: var(--ticker-frame-height);
  overflow: hidden;
  font-size: 10px;
  line-height: 1.4;
  text-transform: uppercase;
}

.video-frame__media {
  position: absolute;
  inset: var(--ticker-media-inset);
}

/* Сцена плеера — сестринский слой к .image-tone, а не потомок. У .image-tone
   есть isolation: isolate, поэтому весь вложенный интерфейс запирался в её
   stacking context, а общий WebGL-дизер — это position: fixed; z-index: 2 в
   корне документа. Кнопка play с z-index: 3 внутри изолированного слоя
   оказывалась ПОД дизером и не была видна до старта видео. Отдельная сцена
   с z-index: 3 в корневом контексте держит видео и панель выше дизера,
   при этом рисунок самого дизера не меняется. */
.video-frame__stage {
  position: absolute;
  z-index: 3;
  /* Тот же inset, что у .video-frame__media выше: сцена обязана точно
     повторять коробку обложки. Переопределяя геометрию на конкретной
     странице, меняйте оба селектора сразу. */
  inset: var(--ticker-media-inset);
  overflow: hidden;
  cursor: pointer;
}

.video-frame__video {
  position: absolute;
  z-index: 1;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #000;
  opacity: 0;
  visibility: hidden;
  transition: opacity 260ms ease, visibility 0s linear 260ms;
}

.video-frame.is-playing .video-frame__video {
  opacity: 1;
  visibility: visible;
  transition: opacity 260ms ease, visibility 0s linear 0s;
}

.video-frame.is-playing .video-frame__media::before {
  opacity: 0 !important;
}

.video-frame__media::before {
  background:
    linear-gradient(rgba(8, 37, 84, 0.7), rgba(8, 37, 84, 0.7)),
    linear-gradient(180deg, rgba(0, 0, 0, 0) 46.57%, rgba(0, 0, 0, 0.3) 100%);
}

.video-frame__ticker {
  position: absolute;
  z-index: 2;
  height: var(--ticker-thickness);
  overflow: hidden;
  white-space: nowrap;
}

.video-frame__ticker-track {
  display: flex;
  width: max-content;
  contain: layout paint style;
  animation: video-ticker-forward 24s linear infinite;
  animation-play-state: paused;
  backface-visibility: hidden;
  transform: translate3d(0, 0, 0);
}

/* Четыре трека держали композиторный слой всегда, хотя анимация стоит на
   паузе, пока секция видео вне экрана (класс ставит initVideoTicker). */
.video-section.is-ticker-active .video-frame__ticker-track {
  animation-play-state: running;
  will-change: transform;
}

.video-frame__ticker-item {
  flex: none;
  padding-right: 2em;
}

.video-frame__ticker--top,
.video-frame__ticker--bottom {
  right: 0;
  left: 0;
}

.video-frame__ticker--top { top: 0; }
.video-frame__ticker--bottom { bottom: 0; }

.video-frame__ticker--left,
.video-frame__ticker--right {
  top: var(--ticker-media-inset);
  width: calc(var(--ticker-frame-height) - var(--ticker-media-inset) - var(--ticker-media-inset));
  transform-origin: top left;
}

.video-frame__ticker--left { left: var(--ticker-thickness); transform-origin: top left; transform: rotate(90deg); }
.video-frame__ticker--right { right: calc(0px - var(--ticker-frame-height) + var(--ticker-media-inset) + var(--ticker-media-inset)); transform: rotate(90deg); }

.video-frame__ticker--top .video-frame__ticker-track,
.video-frame__ticker--right .video-frame__ticker-track {
  animation-name: video-ticker-reverse;
}

/* Запасное значение на случай, если JS не отработал: точную длительность
   initVideoTicker считает от фактической ширины трека, чтобы скорость не
   зависела от длины строки. 150s здесь были подогнаны под старый трек в
   45892px и на нормальном треке дают ползущую строку. */
.video-frame__ticker--left .video-frame__ticker-track,
.video-frame__ticker--right .video-frame__ticker-track {
  animation-duration: 13s;
}

@keyframes video-ticker-forward {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(-50%, 0, 0); }
}

@keyframes video-ticker-reverse {
  from { transform: translate3d(-50%, 0, 0); }
  to { transform: translate3d(0, 0, 0); }
}

.play-button {
  position: absolute;
  z-index: 3;
  isolation: isolate;
  top: 50%;
  left: 50%;
  width: 64px;
  height: 64px;
  overflow: hidden;
  padding: 0;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  background: transparent;
  transition: background-color 180ms ease;
}

.play-button img {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: contain;
  transition: opacity 180ms ease;
}

.play-button::after {
  z-index: 2;
  position: absolute;
  top: 34.65%;
  left: 41.34%;
  width: 25.98%;
  height: 30%;
  background: var(--dark);
  clip-path: polygon(0 0, 100% 50%, 0 100%);
  content: "";
  opacity: 0;
  pointer-events: none;
  transition: opacity 180ms ease;
}

.play-button:hover,
.play-button:focus-visible {
  background-color: var(--light);
}

.play-button:hover img,
.play-button:focus-visible img {
  opacity: 0;
}

.play-button:hover::after,
.play-button:focus-visible::after {
  opacity: 1;
}

.video-frame.is-playing:not(.is-paused) .play-button {
  opacity: 0;
  pointer-events: none;
}

.video-controls {
  position: absolute;
  z-index: 3;
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 48px 12px 10px;
  /* Хвост градиента — чистый чёрный. В полноэкранном режиме под панелью
     лежат чёрные поля letterbox, и прежний синий хвост давал видимый стык:
     «чёрная заливка под градиентом». */
  background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, .26) 28%, rgba(0, 0, 0, .55) 58%, rgba(0, 0, 0, .84) 100%);
  color: var(--light);
  /* Кадр под панелью бывает почти белым (небо), поэтому светлые элементы
     подсвечиваем собственной тенью, а не одним градиентом. */
  text-shadow: 0 1px 2px rgba(0, 0, 0, .5);
  cursor: default;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  text-transform: none;
  transition: opacity 220ms ease, visibility 0s linear 220ms;
}

.video-frame.is-playing .video-controls,
.video-frame__stage:focus-within .video-controls {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 220ms ease, visibility 0s linear 0s;
}

/* Простой курсор и панель уезжают вместе — как в системных плеерах. */
.video-frame.is-controls-hidden:not(.is-paused) .video-controls {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 220ms ease, visibility 0s linear 220ms;
}

.video-frame.is-controls-hidden:not(.is-paused) .video-frame__stage {
  cursor: none;
}

.video-controls__scrub {
  display: flex;
  align-items: center;
  padding: 0 2px;
}

.video-controls__bar {
  display: flex;
  align-items: center;
  gap: 2px;
}

.video-controls__spacer {
  flex: 1 1 auto;
}

.video-controls__time {
  margin: 0 10px;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.video-control {
  display: grid;
  width: 40px;
  height: 40px;
  flex: 0 0 auto;
  padding: 9px;
  border: 0;
  border-radius: 4px;
  place-items: center;
  color: var(--light);
  background: transparent;
  cursor: pointer;
  transition: color 160ms ease, background-color 160ms ease;
}

.video-control:hover,
.video-control:focus-visible {
  color: var(--dark);
  background: var(--light);
}

.video-control__icon {
  display: block;
  width: 100%;
  height: 100%;
  fill: currentColor;
}

.video-control--rate {
  width: auto;
  min-width: 40px;
  padding: 0 9px;
  font: inherit;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

/* Одна кнопка — три состояния; лишние иконки просто не рисуются. */
.video-control__icon--pause,
.video-control__icon--replay,
.video-control__icon--muted,
.video-control__icon--exit {
  display: none;
}

.video-frame.is-playing:not(.is-paused) .video-control__icon--play { display: none; }
.video-frame.is-playing:not(.is-paused) .video-control__icon--pause { display: block; }
.video-frame.is-ended .video-control__icon--play,
.video-frame.is-ended .video-control__icon--pause { display: none; }
.video-frame.is-ended .video-control__icon--replay { display: block; }
.video-frame.is-muted .video-control__icon--sound { display: none; }
.video-frame.is-muted .video-control__icon--muted { display: block; }
.video-frame.is-fullscreen .video-control__icon--enter { display: none; }
.video-frame.is-fullscreen .video-control__icon--exit { display: block; }

/* Ползунок собран из div вместо input[type=range]: у нативного элемента
   поведение перетаскивания различается между движками, а полоса буфера и
   подсказка времени ему вообще недоступны. */
.video-slider {
  position: relative;
  display: flex;
  height: 24px;
  flex: 1 1 auto;
  align-items: center;
  cursor: pointer;
  /* Без этого браузер отдаёт вертикальный свайп странице и перетаскивание
     ползунка на телефоне срывается на первом же движении пальца. */
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
}

.video-slider__track {
  position: relative;
  width: 100%;
  height: 4px;
  border-radius: 4px;
  background: rgba(240, 240, 240, .28);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .4);
  transition: height 140ms ease;
}

.video-slider:hover .video-slider__track,
.video-slider:focus-visible .video-slider__track,
.video-slider.is-scrubbing .video-slider__track {
  height: 6px;
}

.video-slider__buffer,
.video-slider__fill {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 100%;
  border-radius: inherit;
}

.video-slider__buffer {
  background: rgba(240, 240, 240, .4);
}

.video-slider__fill {
  background: var(--light);
  /* timeupdate приходит четыре раза в секунду. Линейный переход растягивает
     эти шаги в ровное движение, не занимая кадр анимацией на JS. */
  transition: width 260ms linear;
}

.video-slider--volume .video-slider__fill,
.video-slider.is-scrubbing .video-slider__fill {
  transition: none;
}

.video-slider__thumb {
  position: absolute;
  top: 50%;
  right: 0;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: var(--light);
  transform: translate(50%, -50%) scale(0);
  transition: transform 140ms ease;
}

.video-slider:hover .video-slider__thumb,
.video-slider:focus-visible .video-slider__thumb,
.video-slider.is-scrubbing .video-slider__thumb {
  transform: translate(50%, -50%) scale(1);
}

.video-slider__tooltip {
  position: absolute;
  bottom: calc(100% + 4px);
  left: 0;
  padding: 3px 7px;
  border-radius: 3px;
  background: rgba(0, 0, 0, .85);
  color: var(--light);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transform: translateX(-50%);
  transition: opacity 140ms ease;
}

.video-slider.is-hovered .video-slider__tooltip,
.video-slider.is-scrubbing .video-slider__tooltip {
  opacity: 1;
}

.video-slider[aria-disabled="true"] {
  opacity: .45;
  cursor: default;
}

.video-volume {
  display: flex;
  align-items: center;
}

/* Шкала громкости раскрывается по наведению — на узкой панели телефона она
   только мешала бы, там громкость системная. */
.video-volume .video-slider--volume {
  width: 0;
  flex: 0 0 auto;
  margin-left: 0;
  opacity: 0;
  transition: width 180ms ease, margin-left 180ms ease, opacity 180ms ease;
}

.video-volume:hover .video-slider--volume,
.video-volume:focus-within .video-slider--volume {
  width: 76px;
  margin-left: 6px;
  opacity: 1;
}

.video-controls__popup {
  position: relative;
  display: flex;
}

.video-menu {
  position: absolute;
  z-index: 2;
  right: 0;
  bottom: calc(100% + 8px);
  min-width: 136px;
  padding: 4px;
  border-radius: 4px;
  background: rgba(8, 37, 84, .96);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .35);
}

.video-menu[hidden] {
  display: none;
}

.video-menu__item {
  display: flex;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  border-radius: 3px;
  align-items: center;
  justify-content: space-between;
  color: var(--light);
  background: transparent;
  cursor: pointer;
  font: inherit;
  font-size: 13px;
  text-align: left;
  text-transform: none;
}

.video-menu__item:hover,
.video-menu__item:focus-visible {
  color: var(--dark);
  background: var(--light);
}

.video-menu__item[aria-checked="true"]::after {
  margin-left: 12px;
  content: "✓";
}

.video-spinner {
  position: absolute;
  z-index: 2;
  top: 50%;
  left: 50%;
  width: 46px;
  height: 46px;
  margin: -23px 0 0 -23px;
  border: 3px solid rgba(240, 240, 240, .3);
  border-top-color: var(--light);
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
  transition: opacity 160ms ease;
}

.video-spinner.is-visible {
  opacity: 1;
  animation: video-spin 900ms linear infinite;
}

@keyframes video-spin {
  to { transform: rotate(360deg); }
}

.video-status {
  position: absolute;
  z-index: 4;
  top: 12px;
  right: 12px;
  left: 12px;
  display: flex;
  width: fit-content;
  max-width: calc(100% - 24px);
  margin: 0;
  padding: 8px 12px;
  border-radius: 3px;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
  background: rgba(0, 0, 0, .78);
  color: #fff;
  font-size: 13px;
  line-height: 1.4;
  text-transform: none;
  opacity: 0;
  pointer-events: none;
  transition: opacity 180ms ease;
}

.video-status.is-visible {
  opacity: 1;
}

.video-status.is-error {
  background: rgba(122, 20, 20, .92);
}

/* Клики принимает только кнопка: сама плашка не должна перехватывать
   указатель у кадра под ней. */
.video-status__action {
  padding: 5px 10px;
  border: 1px solid rgba(255, 255, 255, .6);
  border-radius: 3px;
  color: #fff;
  background: transparent;
  cursor: pointer;
  font: inherit;
  font-size: 12px;
  pointer-events: auto;
  white-space: nowrap;
  transition: color 160ms ease, background-color 160ms ease;
}

.video-status__action:hover,
.video-status__action:focus-visible {
  color: #000;
  background: #fff;
}

.video-status__action[hidden] {
  display: none;
}

/* В полный экран уходит только сцена: бегущая строка и обложка остаются на
   странице. position/inset дублируем — авторское правило .video-frame__stage
   объявляет absolute, и не во всех движках UA-стиль :fullscreen помечен
   !important. Псевдоклассы :fullscreen и :-webkit-full-screen нельзя
   объединять в один селектор: неизвестный псевдокласс гасит всё правило. */
.video-frame__stage:fullscreen {
  /* !important перебивает выравнивающий inline-inset из video-player.js. */
  position: fixed !important;
  inset: 0 !important;
  width: 100% !important;
  height: 100% !important;
  background: #000;
}

.video-frame__stage:-webkit-full-screen {
  /* !important перебивает выравнивающий inline-inset из video-player.js. */
  position: fixed !important;
  inset: 0 !important;
  width: 100% !important;
  height: 100% !important;
  background: #000;
}

.video-frame__stage.is-fullscreen {
  background: #000;
}

/* Полный экран можно открыть и до старта: видео там показываем всегда,
   иначе пользователь смотрит в чёрный прямоугольник. */
.video-frame__stage.is-fullscreen .video-frame__video {
  opacity: 1;
  visibility: visible;
}

.video-frame__stage.is-fullscreen .video-controls {
  padding:
    72px max(20px, env(safe-area-inset-right))
    max(16px, env(safe-area-inset-bottom))
    max(20px, env(safe-area-inset-left));
  gap: 4px;
  /* Доводим до непрозрачного чёрного: полоса letterbox под панелью и её
     фон становятся одним цветом, стык исчезает. */
  background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, .3) 26%, rgba(0, 0, 0, .62) 58%, rgba(0, 0, 0, 1) 100%);
}

.video-frame__stage.is-fullscreen .video-control {
  width: 46px;
  height: 46px;
  padding: 11px;
}

.video-frame__stage.is-fullscreen .video-controls__time {
  font-size: 15px;
}

.video-frame__stage.is-fullscreen .video-slider {
  height: 28px;
}

/* Без JS остаются нативные контролы браузера — видео управляемо всегда. */
.video-frame:not(.is-enhanced) .video-frame__video {
  z-index: 2;
  /* Без JS сцены нет: видео лежит прямо в .video-frame и повторяет
     геометрию обложки, чтобы не залезть на бегущую строку. */
  inset: var(--ticker-media-inset);
  opacity: 1;
  visibility: visible;
}

.video-frame:not(.is-enhanced) .play-button { display: none; }
.video-frame:not(.is-enhanced) .video-frame__media::before { display: none; }
.video-frame .play-button[hidden],
.video-control[hidden] { display: none; }

.video-frame__stage:focus-visible,
.play-button:focus-visible {
  outline: 2px solid #fff;
  outline-offset: -2px;
}

.video-slider:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 3px;
}

/* На светлой подложке ховера белая обводка не видна — берём тёмную. */
.video-control:focus-visible,
.video-menu__item:focus-visible {
  outline: 2px solid var(--dark);
  outline-offset: -2px;
}

@media (hover: none) {
  .video-volume .video-slider--volume { display: none; }
  .video-slider__tooltip { display: none; }
  .video-slider { height: 30px; }
  .video-slider__track { height: 5px; }
  .video-slider__thumb { transform: translate(50%, -50%) scale(1); }
}

@media (max-width: 599px) {
  .video-controls { padding: 40px 6px 8px; }
  .video-control { width: 36px; height: 36px; padding: 8px; }
  .video-control--rate { min-width: 34px; padding: 0 5px; font-size: 12px; }
  .video-controls__time { margin: 0 4px; font-size: 11px; }
  .video-menu { min-width: 118px; }
  /* Мини-плеер на телефоне даёт сама система, а место на панели дороже. */
  .video-control--pip { display: none; }
}

/* News — mobile */
.news {
  height: auto;
  min-height: 0;
  padding: 35px 15px 53px;
  border-bottom: var(--line);
  background: var(--light);
}

.news__header {
  display: flex;
  min-height: 35px;
  align-items: center;
  justify-content: space-between;
}

.news__header .section-title {
  font-size: 35px;
  line-height: 1;
}

.news__header .text-link {
  margin-top: 0;
  font-size: 14px;
}

.news__layout {
  margin-top: 20px;
}

.news__image {
  position: relative;
  width: 100%;
  height: 233px;
  overflow: hidden;
  background: var(--blue);
}

.news__image-layer {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 700ms cubic-bezier(.22, 1, .36, 1);
}

.news__image-layer.is-active {
  opacity: 1;
}

.news__image-layer.is-front {
  z-index: 1;
}

.news__image-layer::before {
  background:
    linear-gradient(rgba(8, 37, 84, 0.7), rgba(8, 37, 84, 0.7)),
    linear-gradient(180deg, rgba(0, 0, 0, 0) 46.57%, rgba(0, 0, 0, 0.3) 100%);
}

.news__image-layer img {
  object-position: center 60%;
}

.news__image-layer:first-child img {
  object-position: center bottom;
}

.news__grid {
  margin-top: 20px;
  border-top: var(--line);
}

.news-card {
  position: relative;
  display: flex;
  min-height: 0;
  flex-direction: column;
  gap: 14px;
  justify-content: flex-start;
  padding: 20px 0;
  border-bottom: var(--line);
  font-size: 14px;
  line-height: 1.4;
}

.news-card time {
  font-weight: 400;
}

.news-card > span:not(.news-card__arrow) {
  display: -webkit-box;
  overflow: hidden;
  margin-top: 0;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  text-overflow: ellipsis;
  font-weight: 400;
}

.news-card__arrow {
  display: none;
}

/* Общая стрелка блока новостей живёт только на десктопе, где есть наведение.
   Ниже 1200px карточки показывают свою собственную стрелку. */
.news__arrow {
  display: none;
}

.news-card--featured {
  color: var(--dark);
  background: transparent;
}

/* Footer — mobile */
.footer {
  position: relative;
  display: flex;
  min-height: 871px;
  flex-direction: column;
  padding: 35px 0;
  overflow: hidden;
  color: var(--light);
  background: var(--dark);
  text-transform: uppercase;
}

.footer__logo {
  width: calc(100% - 30px);
  height: 66px;
  margin-left: 15px;
}

.footer__nav {
  align-self: flex-start;
  margin: 55px 0 0 15px;
}

.footer__nav nav,
.footer__socials,
.footer__contacts,
.footer__contacts > div {
  display: flex;
  flex-direction: column;
}

.footer__nav nav {
  align-items: flex-start;
  gap: 16px;
}

.footer__nav a {
  width: fit-content;
  max-width: 100%;
  font-size: 16px;
  font-weight: 500;
  /* 19px, а не 20: в макете строка ссылки ровно такой высоты, и с шагом
     19 + 16 восемь пунктов встают в те же места, что нарисованы. */
  line-height: 19px;
}

.footer a:hover,
.footer a:focus-visible {
  color: var(--muted);
}

.footer a {
  font-weight: 400;
}

.footer__legal a {
  display: flex;
  width: 100%;
  height: 2.6em;
  flex-direction: column;
  overflow: hidden;
}

.footer__legal-line {
  display: block;
  flex: 0 0 1.3em;
  white-space: nowrap;
}

.footer__socials {
  align-items: flex-start;
  gap: 19px;
  margin-top: 56px;
}

.footer__socials a,
.footer__contacts > div:first-child a {
  width: fit-content;
  max-width: 100%;
}

.footer__contacts {
  width: 100%;
  /* Нижний auto забирает свободную высоту подвала (min-height больше
     содержимого): копирайт остаётся прижат к низу, как когда стоял
     координатой. Содержимое переросло min-height — отступ схлопывается. */
  margin: 30px 0 auto;
  padding: 22px 15px 0;
  border-top: 1px solid rgba(240, 250, 255, 0.3);
}

.footer__contacts > div:first-child {
  /* 11, а не 10: строка телефона в макете на пиксель выше нашей, и с этим
     зазором почта встаёт на нарисованное место. */
  gap: 11px;
  font-size: 18.75px;
  font-weight: 500;
  line-height: 1.4;
}

.footer__legal {
  gap: 14px;
  margin-top: 34px;
  font-size: 14.063px;
  font-weight: 500;
  line-height: 1.3;
}

.footer__copyright {
  align-self: flex-start;
  /* 46, а не 51: после правки отступов выше содержимое подвала доросло до
     871 px, и запас, из которого нижний auto прижимал копирайт, кончился.
     С этим отступом строка встаёт на нарисованное место, а подвал остаётся
     ровно той высоты, что в макете. */
  margin: 47px 0 0 15px;
  font-size: 12.891px;
}

@media (max-width: 599px) {
  main {
    --mobile-section-padding: 25px;
  }

  /* Подвал по макету телефона: линия над меню, все ссылки одного размера,
     телефон и почта в общем столбце, вторая линия перед правовыми ссылками.
     Жёстких высот нет — подвал считается от содержимого, min-height только
     повторяет макет. */
  .footer {
    min-height: 768px;
    padding: 40px 0;
  }

  .footer__nav {
    /* stretch, а не прежний flex-start: линию рисует верхняя граница блока,
       и с прижатым к левому краю блоком она обрывалась по ширине самого
       длинного пункта меню. */
    align-self: stretch;
    margin: 40px 15px 0;
    padding-top: 30px;
    border-top: 1px solid var(--blue);
  }

  .footer__nav nav {
    gap: 14px;
  }

  .footer__nav a {
    font-size: 13px;
    line-height: 15px;
  }

  .footer__socials {
    gap: 14px;
    margin-top: 30px;
  }

  .footer__contacts {
    margin: 32px 0 auto;
    padding: 0 15px;
    border-top: 0;
  }

  .footer__contacts > div:first-child {
    gap: 14px;
    font-size: 13px;
    font-weight: 500;
    line-height: 15px;
  }

  .footer__legal {
    gap: 14px;
    margin-top: 30px;
    padding-top: 30px;
    border-top: 1px solid var(--blue);
    font-size: 13px;
    line-height: 15px;
  }

  /* Правовые ссылки на телефоне переносятся сами, как в макете. Жёсткие
     переносы из разметки нужны широким экранам, где колонка узкая; на
     245 px они дают не ту разбивку, что нарисована. */
  .footer__legal a {
    display: block;
    max-width: 245px;
    height: auto;
  }

  .footer__legal-line {
    display: inline;
    white-space: normal;
  }

  .footer__copyright {
    margin: 30px 0 0 15px;
    font-size: 13px;
    line-height: 18px;
  }

  .company-intro {
    padding-top: var(--mobile-section-padding);
  }

  /* Показатели по макету телефона: от линии до числа 16, от числа до
     подписи 9. Содержимое карточки прижато к верху, а не отцентровано по
     её высоте: в четвёртой карточке, самой высокой, центровка уводила
     число на 34 от линии вместо 16. Правила только для телефона — на
     планшете и десктопе у карточки своя раскладка. */
  .stat-item {
    justify-content: flex-start;
    padding-top: 16px;
  }

  .stat-item strong {
    line-height: 42px;
  }

  .stat-item p {
    margin-top: 9px;
  }

  /* min-height, а не height: из админки текст приходит любой длины, и жёсткая
     высота обрезала бы секцию. Пол остаётся прежним, вид не меняется. */
  .stats {
    min-height: 1029px;
    padding-block: var(--mobile-section-padding);
    padding-inline: 15px;
  }

  /* Заголовок, подзаголовок, фото и список раньше стояли каждый на своей
     координате от верха секции, снятой с макета для однострочного
     заголовка. У длинного текста в админке заголовок и подзаголовок
     переносятся на 2–3 строки и высота растёт — координаты этого не знали
     и съезжали друг на друга (заметно на 320 px и при смене эмуляции
     устройства). Теперь всё в потоке: отступ каждого элемента считается от
     низа предыдущего, а не от верха секции, поэтому лишняя строка просто
     раздвигает соседей, а не наезжает на них. */
  .stats__title,
  .stats__eyebrow,
  .stats__image,
  .stats__list {
    position: relative;
    top: auto;
    left: auto;
    width: auto;
  }

  .stats__eyebrow { margin-top: 4px; }
  .stats__image { margin-top: 33px; }
  .stats__list { margin-top: 31px; }

  /* Проекты на телефоне: раскладка по макету, но без единой жёсткой высоты.
     Заголовок, описание и число карточек приходят из админки, поэтому
     карточка растёт под содержимое, фотография держит пропорцию, а min-height
     секции — только пол макета, не потолок. */
  .projects {
    min-height: 1489px;
    padding: var(--mobile-section-padding) 15px var(--mobile-section-padding);
  }

  /* Две строки по 40, как в макете. */
  .projects__title {
    line-height: 40px;
  }

  .projects__grid {
    gap: 30px;
    margin-top: 20px;
  }

  /* Содержимое отодвинуто от вертикальной черты у номера. */
  .project-card {
    padding-left: 11px;
  }

  .project-card::before {
    display: block;
    bottom: auto;
    height: 60px;
    background: var(--dark);
  }

  /* Размеры сняты из макета: номер Roboto 15/21, заголовок LT Superior 24,
     описание Roboto 13/18. Номер вместе с отступом занимает те же 60, что и
     черта слева от него. */
  .project-card__number {
    margin-bottom: 39px;
    font-size: 15px;
    line-height: 21px;
  }

  .project-card h3 {
    margin-bottom: 15px;
    font-size: 24px;
  }

  /* Пропорция вместо высоты: на любой ширине экрана кадр остаётся тем же,
     что нарисован, и не зависит от размера исходного файла. */
  .project-card__media {
    height: auto;
    aspect-ratio: 334 / 216;
  }

  .project-card__arrow {
    width: 54px;
    height: 54px;
  }

  .project-card p {
    font-size: 13px;
    line-height: 18px;
  }

  .projects__button--adaptive {
    margin-top: 30px;
  }

  /* Услуги на телефоне: размеры и отступы сняты из макета, высоты нигде не
     заданы. Название, описание и число карточек приходят из админки, поэтому
     карточка растёт под содержимое, фотография держит пропорцию, min-height
     секции — только пол макета. */
  .services {
    min-height: 2116px;
    padding: var(--mobile-section-padding) 15px var(--mobile-section-padding);
  }

  .services__intro .section-title {
    line-height: 40px;
  }

  .services__intro > p {
    margin-top: 15px;
    font-size: 15px;
    line-height: 1.4;
  }

  .services__list {
    gap: 20px;
    margin-top: 30px;
  }

  .service-card,
  .service-card:nth-child(4),
  .service-card:nth-child(5) {
    min-height: 0;
  }

  .service-card__media {
    height: auto;
    flex: 0 0 auto;
    aspect-ratio: 345 / 185;
  }

  /* Название и номер одним начертанием, как в макете: LT Superior 24.
     Раньше название было набрано Roboto 19.9, а номер — LT Superior 25.8. */
  .service-card__head {
    padding-bottom: 8px;
    font-size: 24px;
  }

  .service-card__head h3 {
    max-width: 250px;
    font-family: "LT Superior", Arial, sans-serif;
    font-size: 24px;
    font-weight: 450;
    line-height: 1;
  }

  .service-card__head span {
    font-size: 24px;
  }

  .service-card__content > p {
    max-width: 240px;
    margin-top: 15px;
    font-size: 13px;
  }

  /* Ссылка отбивается от текста на 30 и стоит справа. Отступ вместо прежнего
     margin-top: auto: тот прижимал её к низу карточки и зависел от заданной
     высоты, а высоты больше нет. */
  .service-card .text-link {
    margin-top: 30px;
    padding-bottom: 2px;
    font-size: 13px;
  }

  .video-section {
    height: auto;
    padding-block: var(--mobile-section-padding);
    /* Разделяющих линий вокруг видео на телефоне нет: в макете блок отбит
       от соседей воздухом. На планшете и десктопе линии остаются. */
    border-top: 0;
    border-bottom: 0;
  }

  .video-frame {
    --ticker-gap: 3px;
    --ticker-frame-height: calc(56.25vw - 2px);
    position: relative;
    top: auto;
  }

  /* Новости на телефоне по макету: квадратная фотография, дата и стрелка в
     одной строке, заголовок в две строки под ними. Высот нет: пол секции
     равен макету, но карточки считаются от содержимого. */
  .news {
    min-height: 1043px;
    /* Между секциями 25 сверху и снизу, начиная с блока «Компания в
       цифрах». Новости — последний блок перед подвалом, поэтому снизу не
       25, а 50: воздух перед подвалом должен быть заметнее, чем между
       соседними блоками. */
    padding: var(--mobile-section-padding) 15px 50px;
  }

  .news__header .section-title {
    line-height: 40px;
  }

  .news__header .text-link {
    font-size: 13px;
  }

  .news__layout {
    margin-top: 15px;
  }

  /* Формат фотографии по макету — квадрат. Пропорция вместо высоты: кадр
     остаётся квадратным на любой ширине экрана. */
  .news__image {
    height: auto;
    aspect-ratio: 1;
  }

  .news__grid {
    margin-top: 15px;
  }

  .news-card {
    display: grid;
    /* 19, а не 20: линию карточка рисует своей нижней границей, и этот
       пиксель входит в шаг между строками. С ним шаг ровно 137, как в макете. */
    padding: 15px 0 19px;
    align-items: start;
    gap: 30px 0;
    grid-template-columns: 1fr 36px;
    /* Начертание то же, что на планшете и десктопе: LT Superior Regular.
       Дата и заголовок его наследуют. */
    font-family: "LT Superior", Arial, sans-serif;
    font-weight: 400;
  }

  .news-card time {
    grid-area: 1 / 1;
    font-size: 18px;
    line-height: 1.1;
  }

  /* Заголовок в три строки с многоточием: из админки придёт
     текст любой длины, а шаг карточек должен остаться прежним. */
  .news-card > span:not(.news-card__arrow) {
    display: -webkit-box;
    overflow: hidden;
    max-width: 280px;
    grid-area: 2 / 1 / 3 / 3;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    font-size: 16.406px;
    line-height: 18px;
  }

  /* Стрелка та же, что в карточках на странице новостей, только 36 пикселей.
     font-size: 0 прячет текстовую стрелку из разметки, знак рисует маска. */
  .news-card__arrow {
    position: relative;
    display: block;
    width: 36px;
    height: 36px;
    border: var(--line);
    background: var(--dark);
    grid-area: 1 / 2;
    font-size: 0;
  }

  .news-card__arrow::after {
    position: absolute;
    inset: 32%;
    background: var(--light);
    content: "";
    -webkit-mask: url("assets/icons/arrow-back.svg") center / contain no-repeat;
    mask: url("assets/icons/arrow-back.svg") center / contain no-repeat;
  }
}

@media (min-width: 600px) and (max-width: 1199px) {
  body { font-size: 16px; }

  main {
    --tablet-section-padding: 80px;
  }

  .button { height: 80px; font-size: 19px; }

  .hero { --hero-description-line-gap: clamp(30px, 4.5496vh, 50px); min-height: 100vh; min-height: 100svh; }
  .hero__media { --dither-position-x: 20%; }
  .site-header { height: 120px; padding: 24px 4.1667vw 0; }
  .site-logo { top: 24px; left: 4.1667vw; }
  .site-logo img { width: 142px; height: 54px; }
  .site-logo--en { width: 142px; height: 54px; }
  .site-logo--en img { width: 62%; height: auto; }
  .site-header__actions { top: 24px; right: 4.1667vw; }
  .menu-button, .language-button { height: 54px; font-size: 16px; }
  .menu-button { width: 134px; }
  .language-button { width: 54px; }
  .hero__line { left: calc(50% + 10px); }
  .hero__line--top { top: 0; height: max(0px, calc(var(--hero-descriptor-top, 46.8608%) - var(--hero-description-line-gap))); }
  .hero__line--bottom { top: calc(var(--hero-descriptor-bottom, 56.6879%) + var(--hero-description-line-gap)); display: block; height: max(0px, calc(75.5232% - var(--hero-descriptor-bottom, 56.6879%) - var(--hero-description-line-gap))); }
  .hero__descriptor { top: 46.8608%; left: calc(50% + 10px); width: calc(50% - 3.125vw - 10px); font-size: clamp(18.75px, 3.125vw, 24px); }
  .hero__title { top: 80.0728%; left: 4.1667vw; width: 91.4vw; font-size: clamp(46.7px, 7.7865vw, 59.8px); }

  .menu-panel { top: 83px; right: 4.1667vw; bottom: 24px; left: 4.1667vw; padding: 48px 45px 45px; }
  .menu-panel__nav { gap: 10px; font-size: 54px; }
  .menu-panel__contacts { grid-template-columns: 190px 1fr; gap: clamp(60px, 12vw, 205px); padding: 30px 0; font-size: 16px; }
  .menu-panel__contacts-content { gap: 20px; }

  .company-intro { padding-top: var(--tablet-section-padding); }
  .company-intro__lead { width: 80.34vw; margin-left: 4.1667vw; font-size: 28.08px; line-height: 1.2; }
  /* То же, что на мобильном: на 768 px лид занимает пять строк, текст
     начинался на 318; 3 px из 70 съедает нижнее поле последней строки. */
  .company-intro__copy { margin: 70px 4.1667vw 0; grid-template-columns: 1fr 1fr; gap: 26px; }
  .company-intro__copy p { max-width: 336px; font-size: 16px; }

  .stats { min-height: 1114px; }
  .stat-item { display: block; }
  .stats { padding-block: var(--tablet-section-padding); }
  .stats__title { top: var(--tablet-section-padding); left: 4.1667vw; width: 91.6667vw; font-size: 75px; }
  .stats__eyebrow { top: 199px; left: calc(50% + 10px); width: 289px; font-size: 19px; }
  .stats__image { top: 199px; left: 4.1667vw; width: 44.531vw; height: 224px; }
  .stats__list { top: 514px; left: 4.1667vw; display: grid; width: 91.6667vw; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 20px; }
  .stat-item,
  .stat-item:nth-child(3),
  .stat-item:nth-child(4) { min-height: 200px; }
  /* Здесь карточки стоят в два столбца, третья и четвёртая образуют нижний
     ряд, и линии под ними закрывают сетку. Ни на что не накладываются. */
  .stat-item:nth-child(3)::after,
  .stat-item:nth-of-type(4)::after { content: ""; }
  .stat-item strong { margin-top: 19px; font-size: 52px; }
  .stat-item p { width: min(300px, 100%); margin-top: 21px; font-size: 16px; }
  .stats__button { grid-column: 1 / -1; margin-top: 40px; }

  .projects { min-height: 3088px; padding: var(--tablet-section-padding) 4.1667vw; }
  .projects__title { width: 100%; margin: 0 auto; font-size: 75px; }
  .projects__grid { gap: 0; margin-top: 91px; }
  .project-card { min-height: 876px; padding-top: 0; border-left: 0; }
  .project-card:first-child { min-height: 916px; }
  .project-card::before { z-index: 2; display: block; pointer-events: none; }
  .project-card__number { position: relative; top: 17px; height: 160px; margin: 0; padding: 0 0 0 18px; font-size: 19px; }
  .project-card:first-child .project-card__number { top: 52px; }
  .project-card h3 { margin: 0 0 30px; padding-left: 0; font-size: 40px; }
  .project-card:first-child h3 { margin-bottom: 70px; }
  .project-card__media { height: 462px; }
  .project-card__arrow { width: 90px; height: 90px; }
  .project-card p { margin: 30px 0 0; font-size: 19px; }
  .projects__button--adaptive { margin-top: 30px; }

  .services { min-height: 1808px; padding: var(--tablet-section-padding) 4.1667vw; }
  .services__intro .section-title { font-size: 75px; }
  .services__intro > p { width: 66vw; margin-top: 30px; font-size: 19px; }
  .services__list { gap: 20px; margin-top: 45px; }
  .service-card,
  .service-card:nth-child(4),
  .service-card:nth-child(5) { min-height: 274px; height: auto; margin-top: 0; flex-direction: row; }
  .service-card__content { order: 1; width: 61.5%; flex: 0 0 61.5%; padding: 20px 30px; }
  .service-card__media { order: 2; width: 38.5%; height: auto; align-self: stretch; flex: 0 0 38.5%; }
  .service-card__head { padding-bottom: 8px; }
  .service-card__head h3 { max-width: 373px; font-size: 32px; line-height: 1.25; }
  .service-card__head span { font-size: 40px; font-weight: 450; }
  .service-card__content > p { margin-top: 30px; font-size: 16px; }
  .service-card .text-link { align-self: flex-start; font-size: 16px; }

  .video-section { height: auto; padding-block: var(--tablet-section-padding); }
  .video-frame { --ticker-thickness: 22px; --ticker-gap: 10px; --ticker-frame-height: calc(51.5625vw + 28px); position: relative; top: auto; left: 4.1667vw; width: 91.6667vw; height: var(--ticker-frame-height); font-size: 16px; transform: none; }

  .news { min-height: 1731px; padding: var(--tablet-section-padding) 4.1667vw; }
  .news__header { min-height: 60px; height: auto; }
  .news__header .section-title { font-size: 75px; }
  .news__header .text-link { margin-top: 0; font-size: 16px; }
  .news__layout { margin-top: 50px; }
  .news__image { height: 500px; }
  .news__grid { display: grid; margin-top: 30px; border-top: var(--line); grid-template-columns: 1fr 1fr; }
  .news-card,
  .news-card:nth-child(2),
  .news-card:nth-child(3) { min-height: 476px; padding: 20px 20px 30px; border-right: var(--line); font-family: "LT Superior", Arial, sans-serif; font-size: 24px; font-weight: 400; line-height: 1.1; }
  .news-card > span:not(.news-card__arrow) { margin-top: auto; }
  .news-card:nth-child(2n) { border-right: 0; }
  .news-card time { font-weight: 400; }
  .news-card__arrow { position: absolute; top: 20px; right: 20px; display: grid; width: 90px; height: 90px; border: var(--line); place-items: center; background: var(--dark); font-size: 0; }
  .news-card__arrow::after { position: absolute; inset: 32%; background: var(--light); content: ""; -webkit-mask: url("assets/icons/arrow-back.svg") center / contain no-repeat; mask: url("assets/icons/arrow-back.svg") center / contain no-repeat; }
  .news-card--featured { color: var(--dark); background: transparent; }

  /* Подвал: колонки сеткой вместо координат. Навигация начиналась на
     4.1667vw, контакты — на calc(50% + 10px); третий трек и есть этот зазор,
     поэтому колонки стоят там же, где стояли абсолютом. */
  .footer {
    display: grid;
    grid-template-columns: 4.1667vw 44.53vw calc(50% + 10px - 48.6967vw) 44.53vw 1fr;
    min-height: 1056px;
    align-content: start;
    padding: 100px 0 45px;
  }
  .footer__logo { grid-area: 1 / 2 / 2 / 6; width: 91.6667vw; height: 140px; margin: 0; }
  .footer__nav { grid-area: 2 / 2 / 3 / 3; align-self: start; width: auto; min-height: 555px; margin: 118px 0 0; padding: 20px 0 0 20px; border-left: 1px solid var(--light); }
  .footer__nav nav { gap: 7px; }
  .footer__nav a { font-size: 21px; line-height: normal; }
  .footer__socials { gap: 15px; margin-top: 100px; }
  .footer__contacts { grid-area: 2 / 4 / 3 / 5; align-self: start; width: auto; min-height: 555px; margin: 118px 0 0; justify-content: space-between; padding: 20px 0 20px 20px; border-top: 0; border-left: 1px solid var(--light); }
  .footer__contacts > div:first-child { gap: 10px; font-size: 21px; }
  .footer__legal { width: min(299px, 100%); gap: 15px; margin: 0; font-size: clamp(12.5px, 2.0833vw, 16px); line-height: normal; }
  .footer__copyright { grid-area: 3 / 1 / 4 / 6; justify-self: center; margin: 75px 0 0; font-size: 16px; white-space: nowrap; }
}

@media (min-width: 1200px) {
  .projects { z-index: 1; }

  .button { height: 4.1667vw; font-size: .9896vw; }

  .hero { --hero-description-line-gap: clamp(30px, 4.5496vh, 50px); min-height: 100vh; min-height: 100svh; }
  .hero__media { --dither-position-x: 50%; }
  .site-header { height: 10.4167vw; padding: 1.5625vw 3.125vw 0; }
  .site-logo { top: 1.5625vw; left: 3.125vw; }
  .site-logo img { width: 7.3958vw; height: 2.8125vw; }
  .site-logo--en { width: 7.3958vw; height: 2.8125vw; }
  .site-logo--en img { width: 62%; height: auto; }
  .desktop-nav { position: fixed; z-index: 99999; inset: 0 0 auto; display: block; height: 10.4167vw; pointer-events: none; }
  .desktop-nav__group { position: absolute; top: 0; height: 36.3542vw; padding: 2.0833vw 0 0 1.0417vw; }
  .desktop-nav__group:first-child { left: 50.5208vw; width: 23.6979vw; }
  .desktop-nav__group:last-child { left: 74.2188vw; width: 20vw; height: 17.2917vw; }
  .desktop-nav__group a { display: block; width: fit-content; max-width: 100%; margin-bottom: 9px; color: var(--light); font-size: .8333vw; font-weight: 400; line-height: 1; text-transform: uppercase; }
  .desktop-nav__group a { pointer-events: auto; }
  body.is-scrolled .desktop-nav__group a { pointer-events: none; }
  .site-header__actions { position: fixed; z-index: 120; top: 1.5625vw; right: 3.125vw; width: 9.8438vw; height: 2.8125vw; overflow: hidden; align-items: center; justify-content: flex-end; border-radius: 3px; pointer-events: auto; }
  .site-header__actions .menu-button { z-index: 0; display: flex; width: 6.9792vw; height: 2.8125vw; flex: 0 0 6.9792vw; align-items: center; justify-content: center; padding: .625vw 1.5625vw; transform: translateX(calc(100% + 5px)); pointer-events: auto; font-size: .8333vw; transition: background-color 180ms ease, transform 420ms cubic-bezier(.22, 1, .36, 1); will-change: transform; }
  body.is-scrolled .site-header__actions .menu-button { transform: translateX(0); }
  .language-button { position: relative; z-index: 1; width: 2.8125vw; height: 2.8125vw; flex: 0 0 2.8125vw; pointer-events: auto; font-size: .8333vw; }
  .menu-panel { top: 4.5313vw; right: 3.125vw; bottom: 1.5625vw; left: auto; width: 46.3542vw; padding: 0; overflow: hidden; }
  .menu-panel__nav { position: absolute; top: 4.1667vw; left: 3.125vw; width: 15.2083vw; gap: .5208vw; font-size: 2.8125vw; line-height: 1.2; }
  .menu-panel__nav a { height: 3.3854vw; }
  .menu-panel__contacts { position: absolute; right: 3.125vw; bottom: 2.0833vw; left: 3.125vw; display: flex; height: 12.4479vw; gap: 10.6771vw; margin: 0; padding: 1.5625vw 0; font-size: .8333vw; }
  .menu-panel__contacts-title { width: 9.8958vw; flex: 0 0 9.8958vw; }
  .menu-panel__contacts-content { width: 14.7396vw; flex: 0 0 14.7396vw; gap: 1.0417vw; }
  .menu-panel__contacts-links { gap: .3646vw; }
  .hero__line { left: 74.2188vw; }
  /* Длина направляющих масштабируется от ширины макета, но на невысоких
     экранах не доходит до текста. В исходном desktop-кадре зазоры составляют
     18px до заголовка и 50px до дескриптора — сохраняем их пропорционально. */
  .hero__line--nav-left {
    top: 0;
    left: 50.5208vw;
    display: block;
    height: min(36.3542vw, calc(66.2964% - max(8px, .9375vw)));
  }
  /* Обе линии в правой колонке отбиваются от дескриптора одним и тем же
     отступом и считаются от его фактических границ (--hero-descriptor-top /
     --hero-descriptor-bottom; их публикует initTextBoxVars в script.js по
     метке data-box-var у самого текста).
     Раньше концы стояли на фиксированных долях высоты: на 1920×1080 сверху
     получалось 50px, снизу 74px, а на других высотах разъезжалось ещё
     сильнее — и любой текст длиннее трёх строк наезжал на нижнюю линию. */
  .hero__line--nav-right {
    top: 0;
    left: 74.2188vw;
    display: block;
    height: max(0px, calc(var(--hero-descriptor-top, 35.3703%) - var(--hero-description-line-gap)));
  }
  .hero__line--top {
    /* Запасное значение подобрано так, чтобы без JS линия встала ровно на
       прежние 50% высоты: отступ прибавляется к нему тем же calc'ом. */
    --hero-line-top-start: calc(var(--hero-descriptor-bottom, calc(50% - var(--hero-description-line-gap))) + var(--hero-description-line-gap));
    top: var(--hero-line-top-start);
    height: max(0px, calc(64.7223% - var(--hero-line-top-start)));
  }
  /* Нижние засечки тоже считаются от текста, а не от доли высоты: раньше
     до заголовка оставалось 18px на 1920×1080 и 37px на 1440×900, а если
     заголовок набирался в одну строку — больше сотни. Нижним краем они
     по-прежнему упираются в низ первого экрана. */
  .hero__line--bottom,
  .hero__line--left-bottom {
    --hero-line-bottom-start: calc(var(--hero-title-bottom, calc(92.037% - var(--hero-description-line-gap))) + var(--hero-description-line-gap));
    top: var(--hero-line-bottom-start);
    display: block;
    height: max(0px, calc(100% - var(--hero-line-bottom-start)));
  }
  .hero__line--left-bottom { left: 50.5208vw; }
  /* Ширина колонки доведена до правого поля макета (96.875vw): на 20vw
     строка «строительные и инфраструктурные» не помещалась четырьмя
     пикселями и уезжала на четвёртую строку. */
  .hero__descriptor { top: 35.3703%; left: 74.2188vw; width: 22.6563vw; font-size: 1.25vw; }
  .hero__title { top: 66.2964%; left: 2.8646vw; width: 79.4792vw; font-size: 6.7708vw; }

  /* Сетка секции повторяет колонки макета, но лид и текст лежат в потоке:
     отступ между ними задан gap'ом, а не координатой абзаца. Лид на строку
     длиннее теперь сдвигает текст вниз и растягивает секцию, а не наезжает
     на него. Ступени остаются декоративным слоем поверх — их координаты
     переведены в проценты, чтобы лестница тянулась вместе с секцией.

     Пока только для главной. На about.html тот же блок с лидом на строку
     длиннее: там переход в поток сдвинет абзацы на 49px, и эту страницу
     нужно смотреть отдельно. Когда до неё дойдут руки — снять привязку к
     data-site-page и удалить абсолютные координаты ниже. */
  /* Секция в потоке для обеих страниц, где она есть: лид в первой строке
     сетки, колонка текста во второй. min-height вместо height — длинный лид
     раздвигает секцию, а не наезжает на текст. */
  .company-intro {
    display: grid;
    height: auto;
    /* min-height (47.0313vw, под нижнюю ступеньку фона) общий для всех
       разрешений — см. базовое правило .company-intro в начале файла. */
    grid-template-columns: 3.125vw 47.3958vw 46.3542vw 3.125vw;
    align-content: start;
    padding-top: 5.5729vw;
  }
  /* Зазор под лидом — единственное, чем страницы отличаются: текст начинался
     на 24.3229vw, а лид главной занимает 4 строки (2.8125vw * 1.2 * 4 =
     13.5vw) против 5 строк на «О компании» (16.875vw). Дальше расстояние
     держится само. Поменяется длина лида — двигать это число не нужно. */
  body[data-site-page="home"] .company-intro { row-gap: 5.25vw; }
  body[data-site-page="about"] .company-intro { row-gap: 1.875vw; }
  .company-intro__lead { grid-area: 1 / 2 / 2 / 4; width: 70.3125vw; margin: 0; font-size: 2.8125vw; line-height: 1.2; position: relative; z-index: 1; }
  .company-intro__copy { grid-area: 2 / 3 / 3 / 4; width: auto; margin: 0; grid-template-columns: 1fr 1fr; gap: 3.5417vw; position: relative; z-index: 1; }
  .company-intro__copy p { width: 19.6354vw; font-size: .8333vw; }

  /* Заголовок на всю ширину, под ним две независимые колонки: слева
     подзаголовок с фотографией, справа список показателей. Каждая растёт
     сама по себе, поэтому длинный текст в одной из них больше не наезжает
     на соседнюю и не упирается в фиксированную высоту секции. */
  .stats {
    min-height: calc(56.875vw + 10px);
    display: grid;
    grid-template-columns: 3.125vw 47.3958vw 46.3542vw 3.125vw;
    align-content: start;
    padding-top: 8.3333vw;
    border-bottom: var(--line);
  }
  .stats__title { position: relative; inset: auto; grid-area: 1 / 2 / 2 / 4; display: block; width: 93.75vw; margin: 0; font-size: 6.7708vw; }
  .stats__title span { position: absolute; top: 0; white-space: nowrap; }
  .stats__title span:first-child { left: 0; }
  .stats__title span:nth-child(2) { left: 46.875vw; }
  .stats__title span + span::before { content: none; }
  /* Отступы отсчитываются от низа заголовка, а не от верха секции. */
  .stats__aside { grid-area: 2 / 2 / 3 / 3; display: block; align-self: start; margin-top: 2.0486vw; }
  .stats__eyebrow { position: static; inset: auto; width: 26.0938vw; margin: 0 0 0 7.9167vw; font-size: .9896vw; }
  .stats__image { position: relative; inset: auto; width: 23.0208vw; height: 15.3125vw; margin: 9.7222vw 0 0 10.0521vw; }
  .stats__list { position: relative; inset: auto; grid-area: 2 / 3 / 3 / 4; align-self: start; width: 46.3542vw; margin-top: 5.2083vw; }
  /* Линия слева от списка тянется вместе с ним: держим верх и низ, а не высоту. */
  .stats__list::before { content: none; }
  .stats::before { position: absolute; top: 2.6042vw; bottom: 0; left: 49.4271vw; width: 1px; content: ""; background: linear-gradient(to bottom, var(--dark) 0, var(--dark) 5.7292vw, transparent 5.7292vw, transparent 12.5vw, var(--dark) 12.5vw, var(--dark) 100%); pointer-events: none; }
  .stat-item,
  .stat-item:nth-child(3),
  .stat-item:nth-child(4) { display: grid; min-height: 7.5vw; padding-top: 2.1354vw; padding-bottom: 1.0417vw; align-items: center; grid-template-columns: 14.0625vw 1fr; column-gap: 9.6354vw; opacity: .4; transition: opacity 180ms ease; }
  .stat-item:hover,
  .stat-item:focus { opacity: 1; }
  .stat-item:nth-child(4) { border-bottom: 0; }
  /* Столбик из четырёх строк: закрывающая линия нужна только под последней. */
  .stat-item:nth-of-type(4)::after { content: ""; }
  .stat-item strong { margin: 0; font-size: 4.1667vw; }
  .stat-item p { width: 19.6354vw; margin: 0; font-size: .8333vw; }
  .stats__button { width: 100%; margin-top: 1.0417vw; }

  .projects { position: relative; min-height: 85.5729vw; padding: 8.3333vw 3.125vw 0; border-bottom: var(--line); }
  /* Линии проекта принадлежат секции, а не карточкам. Поэтому при
     параллаксе карточек они остаются неподвижными и доходят до нижней
     границы блока. Координаты совпадают с тремя колонками сетки. */
  .projects::before {
    position: absolute;
    z-index: 0;
    top: 27.0833vw;
    right: 0;
    bottom: 0;
    left: 0;
    display: block;
    pointer-events: none;
    background:
      linear-gradient(var(--dark), var(--dark)) var(--projects-line-1-x, 3.125vw) 0 / 1px 100% no-repeat,
      linear-gradient(var(--dark), var(--dark)) var(--projects-line-2-x, 34.7396vw) 0 / 1px 100% no-repeat,
      linear-gradient(var(--dark), var(--dark)) var(--projects-line-3-x, 66.3542vw) 0 / 1px 100% no-repeat;
    content: "";
  }
  /* Разрыв во второй линии на высоте кнопки «Все проекты»: линия не
     пересекает кнопку, как и у карточек над номером/фото. */
  .projects::after {
    position: absolute;
    z-index: 2;
    top: 77.2396vw;
    left: calc(var(--projects-line-2-x, 34.7396vw) - 1vw);
    display: block;
    width: 2vw;
    height: 4.1667vw;
    background: var(--light);
    content: "";
    pointer-events: none;
  }
  .projects__title,
  .projects__grid,
  .projects__button { position: relative; z-index: 1; }
  .projects__title { width: 49.4271vw; margin: 0 auto; font-size: 6.7708vw; }
  .projects__grid { display: grid; gap: 3.2813vw; margin-top: 5.2083vw; grid-template-columns: repeat(3, 28.3333vw); }
  .project-card { min-height: 58.4375vw; padding-left: .9375vw; border-left: 0; isolation: isolate; }
  .project-card::before { z-index: 2; display: block; pointer-events: none; }
  .project-card::after { position: absolute; z-index: 3; top: var(--project-line-gap-start); left: -1vw; width: 2vw; height: calc(var(--project-line-gap-end) - var(--project-line-gap-start)); background: var(--light); content: ""; pointer-events: none; }
  .project-card:nth-child(1) { --project-line-gap-start: 8.4896vw; --project-line-gap-end: 27.5521vw; }
  .project-card:nth-child(2),
  .project-card:nth-child(3) { --project-line-gap-start: 12.1354vw; --project-line-gap-end: 31.1979vw; }
  .project-card:nth-child(3)::before { display: none; }
  .project-card__number { height: 8.4896vw; margin: 0; font-size: .9896vw; }
  .project-card h3 { width: 27.3958vw; min-height: 2.0833vw; margin: 0 0 1.5625vw; font-size: 2.0833vw; text-wrap: balance; }
  .project-card__media { width: 26.0417vw; height: 19.0625vw; }
  .project-card:first-child .project-card__number { height: 4.8438vw; }

  /* .project-card из-за transform параллакса — отдельный контекст наложения,
     поэтому z-index стрелки не может подняться над общим WebGL-дизером
     (fixed, z-index 2). initProjectsParallax переносит сами узлы стрелок в
     .projects-arrow-layer на уровне body и держит их по вертикали в такт
     карточкам. До переноса стрелка в карточке скрыта — там она всё равно
     под дизером. */
  .project-card__media .project-card__arrow { display: none; }

  .projects-arrow-layer {
    position: absolute;
    z-index: 3;
    top: 0;
    left: 0;
    pointer-events: none;
  }
  .projects-arrow-layer .project-card__arrow {
    position: absolute;
    right: auto;
    bottom: auto;
    display: block;
    width: 4.6875vw;
    height: 4.6875vw;
    overflow: hidden;
    border: 1px solid var(--dark);
    background: transparent;
  }
  /* Та же двухфазная hover-анимация, что у новостей, но раскрытие идёт из
     нижнего правого угла карточки проекта. Основной transform элемента
     остаётся за scroll-параллаксом, поэтому анимируем псевдоэлементы. */
  .projects-arrow-layer .project-card__arrow > img { display: none; }
  .projects-arrow-layer .project-card__arrow::before {
    position: absolute;
    inset: 0;
    background: var(--light);
    content: "";
    transform: scale(0);
    transform-origin: bottom right;
    transition: transform 500ms cubic-bezier(.165, .84, .44, 1);
  }
  .projects-arrow-layer .project-card__arrow::after {
    position: absolute;
    inset: 32%;
    background: var(--dark);
    content: "";
    -webkit-mask: url("assets/icons/arrow-back.svg") center / contain no-repeat;
    mask: url("assets/icons/arrow-back.svg") center / contain no-repeat;
    transform: scale(0);
    transform-origin: center;
    transition: transform 400ms cubic-bezier(.165, .84, .44, 1);
  }
  /* Слой готовится, когда стрелка становится видимой, и отпускается обратно. */
  .projects-arrow-layer .project-card__arrow.is-visible::before,
  .projects-arrow-layer .project-card__arrow.is-visible::after { will-change: transform; }
  .projects-arrow-layer .project-card__arrow.is-visible::before,
  .projects-arrow-layer .project-card__arrow.is-visible::after {
    transform: scale(1);
  }
  .projects-arrow-layer .project-card__arrow.is-visible::after {
    transition-delay: 100ms;
  }
  .project-card p { width: 26.1979vw; margin-top: 1.5625vw; font-size: .8333vw; }
  .projects__button--adaptive { display: none; }
  .projects__button--desktop { position: absolute; top: 77.2396vw; left: 35.7813vw; display: flex; width: 16.5625vw; margin: 0; }

  /* Две колонки в потоке: слева рельса залипающего интро, справа список
     карточек. Раньше список был position: absolute, поэтому секции
     приходилось задавать высоту руками, а рельсе — ровно ту же высоту
     вторым числом (5 карточек * 14.2708vw + 4 промежутка = 77.6042vw).
     Теперь высоту строки задаёт сам список, рельса тянется до неё, и
     шестая карточка из инфоблока продлевает залипание сама. */
  .services {
    min-height: 94.2708vw;
    display: grid;
    grid-template-columns: 3.125vw 38vw 2.8854vw 44.6354vw 1fr;
    align-content: start;
    overflow: clip;
    padding: 8.3333vw 0 0;
    border-bottom: var(--line);
    background-image: linear-gradient(to right, transparent 34.7396vw, var(--dark) 34.7396vw, var(--dark) calc(34.7396vw + 1px), transparent calc(34.7396vw + 1px), transparent 66.3542vw, var(--dark) 66.3542vw, var(--dark) calc(66.3542vw + 1px), transparent calc(66.3542vw + 1px));
  }
  .services__intro-sticky { position: relative; z-index: 2; grid-area: 1 / 2 / 2 / 3; width: auto; height: auto; margin-left: 0; }
  .services__intro { position: sticky; top: 8.3333vw; width: 100%; height: max-content; margin-left: 0; }
  .services__intro .section-title { font-size: 6.7708vw; }
  .services__intro > p { width: 18.4375vw; margin: 2.0833vw 0 0 7.9167vw; font-size: .9896vw; }
  .services__list { position: static; inset: auto; grid-area: 1 / 4 / 2 / 5; align-self: start; display: grid; width: auto; gap: 1.5625vw; margin: 0; }
  .service-card,
  .service-card:nth-child(4),
  .service-card:nth-child(5) { min-height: 14.2708vw; height: auto; margin: 0; flex-direction: row; }
  .service-card__content { order: 1; width: 68.2614%; flex: 0 0 68.2614%; padding: 1.0417vw 1.5625vw; }
  /* Медиа тянется на высоту карточки, а не задаёт её своим числом. */
  .service-card__media { order: 2; width: 31.7386%; height: auto; align-self: stretch; flex: 0 0 31.7386%; }
  .service-card__head { padding-bottom: .4167vw; font-size: 2.0833vw; }
  .service-card__head h3 { max-width: 22.0313vw; font-family: "LT Superior", Arial, sans-serif; font-size: 2.0833vw; font-weight: 450; line-height: 1; }
  .service-card__head span { font-size: 2.0833vw; }
  .service-card__content > p { width: 19.4271vw; margin-top: 1.5625vw; font-size: .8333vw; }
  .service-card .text-link { align-self: flex-start; font-size: .8333vw; }

  /* Верхняя линия секции убрана: она дублирует нижнюю линию .services над ней. */
  .video-section { height: auto; padding-block: 8.3333vw; border-top: 0; }
  .video-frame { --ticker-thickness: 1.3542vw; --ticker-frame-height: calc(49.8177vw + 4.375px); position: relative; top: auto; left: 6.7708vw; width: 86.4583vw; height: var(--ticker-frame-height); font-size: .9896vw; transform: none; }
  .play-button { width: 6.6146vw; height: 6.6146vw; }

  .news { min-height: 69.2708vw; padding: 4.1146vw 3.125vw 0; border-top: var(--line); }
  .news__header { height: auto; }
  .news__header .section-title { margin-bottom: 0; font-size: 6.7708vw; }
  .news__header .text-link { margin-top: 0; font-size: .8333vw; }
  .news__layout { display: grid; margin-top: 70px; column-gap: 20px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .news__image { height: 46.3542vw; }
  .news__grid { --news-indicator-x: 0%; --news-indicator-y: 0%; position: relative; isolation: isolate; display: grid; margin: 0; border: 0; grid-template-columns: 1fr 1fr; }
  .news__grid::before { position: absolute; z-index: 0; top: 0; left: 0; width: 50%; height: 50%; transform: translate(var(--news-indicator-x), var(--news-indicator-y)); background: var(--dark); content: ""; transition: transform 320ms cubic-bezier(.22, 1, .36, 1); }
  .news__grid::after { display: none; }
  .news-card,
  .news-card:nth-child(2),
  .news-card:nth-child(3) { z-index: 1; min-height: 23.1771vw; padding: 1.0417vw 1.5625vw 1.5625vw; border-right: var(--line); border-bottom: var(--line); color: var(--dark); background: transparent; font-family: "LT Superior", Arial, sans-serif; font-size: 1.25vw; font-weight: 400; line-height: 1.1; transition: color 220ms ease; }
  .news-card:nth-child(2n) { border-right: 0; }
  .news-card:nth-child(n + 3) { border-bottom: 0; }
  .news-card { overflow: hidden; }
  .news-card > span:not(.news-card__arrow) { margin-top: auto; }
  /* Стрелка на десктопе одна на весь блок, поэтому своя у карточки не нужна. */
  .news-card__arrow { display: none; }

  /* Как в Latest News у OCI: сначала из правого верхнего угла раскрывается
     квадрат кнопки, затем с небольшой задержкой масштабируется стрелка.
     Раньше стрелка была у каждой карточки и при переходе на соседнюю гасла
     и раскрывалась заново. Теперь она одна: слот повторяет размер и перенос
     тёмной подложки и едет тем же переходом, поэтому стрелка переезжает
     вместе с фоном. Гаснет она только когда указатель уходит из блока. */
  .news__arrow { --news-arrow-size: 4.6875vw; position: absolute; z-index: 2; top: 0; left: 0; display: block; width: 50%; height: 50%; pointer-events: none; transform: translate(var(--news-indicator-x), var(--news-indicator-y)); transition: transform 320ms cubic-bezier(.22, 1, .36, 1); }
  /* Раскрытие и закрытие идут в обратном порядке. Открываем: сначала
     раскрывается квадрат, через 100 мс подхватывает стрелка. Закрываем:
     сначала уходит стрелка, квадрат схлопывается следом. Задержка закрытия
     живёт в основном правиле, задержка раскрытия — в правиле наведения. */
  .news__arrow::before { position: absolute; top: 0; right: 0; width: var(--news-arrow-size); height: var(--news-arrow-size); border: var(--line); background: var(--light); content: ""; transform: scale(0); transform-origin: top right; transition: transform 500ms cubic-bezier(.165, .84, .44, 1) 100ms; }
  .news__arrow::after { position: absolute; top: calc(var(--news-arrow-size) * .32); right: calc(var(--news-arrow-size) * .32); width: calc(var(--news-arrow-size) * .36); height: calc(var(--news-arrow-size) * .36); background: var(--dark); content: ""; -webkit-mask: url("assets/icons/arrow-back.svg") center / contain no-repeat; mask: url("assets/icons/arrow-back.svg") center / contain no-repeat; transform: scale(0); transform-origin: center; transition: transform 400ms cubic-bezier(.165, .84, .44, 1); }
  /* will-change поднимается на время наведения, а не держит композиторные
     слои всю жизнь страницы. Слоя теперь три вместо восьми. */
  .news__grid.is-arrow-visible .news__arrow,
  .news__grid.is-arrow-visible .news__arrow::before,
  .news__grid.is-arrow-visible .news__arrow::after { will-change: transform; }
  .news__grid.is-arrow-visible .news__arrow::before { transform: scale(1); transition-delay: 0ms; }
  .news__grid.is-arrow-visible .news__arrow::after { transform: scale(1); transition-delay: 100ms; }
  .news-card.is-active { color: var(--light); }
  .news-card--featured { background: transparent; }

  /* Подвал — сетка из трёх колонок макета: логотип с копирайтом слева,
     навигация и контакты справа. Раньше каждый блок стоял на своей
     координате, а высота колонок с бордюром задавалась числом: лишний
     пункт меню из админки вылезал за линию. Теперь колонки растут сами,
     подвал — следом. */
  .footer {
    min-height: 22.8646vw;
    display: grid;
    grid-template-columns: 3.125vw 47.3958vw 23.6979vw 21.6146vw 1fr;
    align-content: start;
    padding: 1.5625vw 0 0;
    /* Расстояние от логотипа до копирайта в исходном кадре:
       20.3125vw - 1.5625vw - 7.6563vw. */
    row-gap: 11.0937vw;
  }
  .footer__logo { grid-area: 1 / 2 / 2 / 3; width: 38.4375vw; height: 7.6563vw; margin: 0; }
  .footer__nav { grid-area: 1 / 3 / 3 / 4; align-self: start; width: auto; min-height: 19.7396vw; margin: 0; padding: 1.0417vw 0 0 1.0417vw; border-left: 1px solid var(--light); }
  .footer__nav nav,
  .footer__socials,
  .footer__contacts > div:first-child { align-items: flex-start; }
  .footer__nav nav { gap: 7px; }
  .footer__nav a,
  .footer__socials a,
  .footer__contacts > div:first-child a { width: fit-content; max-width: 100%; font-size: .8333vw; line-height: 1; }
  .footer__socials { gap: .3646vw; margin-top: auto; transform: translateY(6.2vw); }
  .footer__contacts { grid-area: 1 / 4 / 3 / 5; align-self: start; display: flex; width: auto; min-height: 19.7396vw; margin: 0; justify-content: space-between; padding: 1.0417vw 0 0 1.0417vw; border: 0; border-left: 1px solid var(--light); }
  .footer__contacts > div:first-child { gap: .3646vw; font-size: .8333vw; line-height: 1; }
  .footer__legal { width: 15.625vw; gap: .5208vw; margin: 0 0 .5208vw; font-size: .8333vw; line-height: 1; }
  .footer__legal a { height: 2em; }
  .footer__legal-line { flex-basis: 1em; }
  .footer__copyright { grid-area: 2 / 2 / 3 / 3; justify-self: start; margin: 0; font-size: .8333vw; white-space: nowrap; }
}

/* ==========================================================================
   Лоадер: держит страницу закрытой, пока не готовы шрифты и hero-фото.
   Вся тяжёлая разовая подготовка (декодирование картинки, дизер, разбор
   текста SplitText) идёт за этим экраном — пользователь не видит рывков,
   потому что их пока некому видеть. Снимается один раз классом .is-loaded
   на <html> (см. script.js).
   ========================================================================== */
.loader {
  position: fixed;
  z-index: 1000;
  inset: 0;
  overflow: hidden;
  pointer-events: auto;
  transition: opacity 180ms ease;
}

.loader__backdrop {
  position: absolute;
  z-index: 0;
  inset: 0;
  display: block;
  background: var(--dark);
  transform: translate3d(0, 0, 0) scale(1);
  transform-origin: top left;
  transition: transform 950ms cubic-bezier(.76, 0, .24, 1);
  will-change: transform;
}

.loader__logo {
  position: fixed;
  z-index: 1;
  top: 50%;
  left: 50%;
  width: clamp(270px, 46vw, 760px);
  max-width: calc(100vw - 40px);
  height: auto;
  transform: translate(-50%, -50%);
  animation: loader-pulse 1.4s ease-in-out infinite;
  transform-origin: top left;
  transition: transform 950ms cubic-bezier(.76, 0, .24, 1);
  will-change: transform;
}

@keyframes loader-pulse {
  0%, 100% { opacity: .45; }
  50% { opacity: 1; }
}

.loader.is-exiting .loader__logo {
  animation: none;
  opacity: 1;
}

.loader.is-preparing .loader__logo {
  animation: none;
  transition: none;
}

html.is-loaded .loader {
  opacity: 0;
  pointer-events: none;
}

/* Пока GSAP не расставил стартовые состояния — прячем анимируемые элементы,
   чтобы не было вспышки готового контента */
.has-anim [data-anim] {
  visibility: hidden;
}

.has-anim [data-anim].is-anim-ready {
  visibility: visible;
}

/* Карточки услуг открываются только после того, как GSAP выставил им
   стартовое диагональное положение — без вспышки готовой сетки. */
.has-anim .services__list .service-card {
  visibility: hidden;
}

.has-anim .services__list.is-services-anim-ready .service-card {
  visibility: visible;
}

/* Рекомендации GSAP для SplitText: убираем кернинг, чтобы буквы не «прыгали»
   при разбивке на символы */
.split-text {
  font-kerning: none;
  text-rendering: optimizeSpeed;
}

/* Компенсация обрезки выносных элементов (у, р, д) маской строки */
.line-split {
  padding-bottom: .1em;
  margin-bottom: -.1em;
}

/* Линии hero анимируются один раз на входе, дальше стоят неподвижно.
   Постоянный will-change держал под них пять композиторных слоёв на всю
   жизнь страницы; GSAP сам поднимает слой на время твина. */

.image-tone.is-shared-dither-ready > img:last-of-type,
.hero__media.is-shared-dither-ready > img:first-child {
  opacity: 0;
}

/* Все элементы, оформленные прописными буквами, используют Regular. */
.button,
.text-link,
.language-button,
.menu-button,
.menu-panel__contacts,
.company-intro__copy,
.stats__eyebrow,
.stat-item p,
.project-card p,
.services__intro > p,
.service-card__content > p,
.video-frame__ticker,
.footer,
.footer *,
.documents-contact__eyebrow,
.documents-contact__details,
.documents-tab,
.news-detail__back,
.about-leadership article > p,
.about-clients__copy,
.about-career__label,
.leadership-modal__person p,
.leadership-modal__detail-label,
.contacts-info__eyebrow,
.contacts-info__details,
.contact-field label,
.project-detail__back,
.project-detail__meta,
.services-catalog__intro h2,
.service-accordion__description,
.service-accordion__panel-link,
.advantage-card p,
.projects-page-card__category {
  font-weight: 400 !important;
}

/* Собственные градиенты у ::before каждого блока с фотографией гасятся:
   общий тон задаётся ниже одним правилом .image-tone::before, а его в свою
   очередь снимает дизер, когда действительно рисует картинку. Второй слой
   (::after) здесь же гасился до конца и не рисовал ничего — он убран вместе
   с правилами, которые им управляли. */
.image-tone::before {
  background: none !important;
  opacity: 1 !important;
}

/* Затемнение располагается отдельным слоем поверх общего WebGL-дизера. */
.hero__media {
  z-index: 0;
}

.hero::after {
  position: absolute;
  z-index: 2;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(0deg, rgba(0, 0, 0, 0.00) 0%, rgba(0, 0, 0, 0.00) 100%),
    linear-gradient(0deg, rgba(8, 37, 84, 0.60) 0%, rgba(8, 37, 84, 0.60) 100%);
  background-blend-mode: normal, soft-light;
  content: "";
}

/* Тёмно-синий soft-light применяется ко всем фото сайта. */
.image-tone::before {
  background: rgba(8, 37, 84, 0.70) !important;
  mix-blend-mode: soft-light;
}

/* Правило выше писалось под старый движок, где canvas лежал ВНУТРИ .image-tone
   с z-index 2, а ::before накрывал его сверху. У общего WebGL-слоя canvas
   position: fixed с z-index 2 в корневом контексте, то есть выше и .projects
   (z-index 1), и .video-section — подняться над ним ::before с z-index 3 уже
   не может. Эффект не виден, но mix-blend-mode всё равно заставляет браузер
   на каждом кадре читать backdrop и пересчитывать блендинг. Дороже всего это
   там, где элемент движется: карточки проектов едут параллаксом, а под ними
   перерисовывается canvas — простой сдвиг слоя превращается в полный пересчёт.
   Гасим ровно тогда, когда дизер действительно рисует эту картинку. Если он
   не работает (нет WebGL, reduced-motion), класс не ставится и soft-light
   остаётся как раньше — запасной вид не меняется. */
.image-tone.is-shared-dither-ready::before {
  display: none;
}

.hero__lines,
.hero__descriptor,
.hero__title {
  z-index: 3;
}

/* Кликабельная поверхность плеера — сцена поверх обложки. */
.video-frame__stage {
  cursor: pointer;
}


/* ==========================================================================
   Плашка о cookie. Значения сняты из макета: фон #0a1a34 (это НЕ --dark
   сайта, там #082554), текст #f0faff, кнопка белая с радиусом 3.
   Раскладок три: на телефоне полоса во всю ширину внизу экрана, на планшете
   и десктопе — карточка с отступом от края. Пока согласие не дано, плашка
   висит поверх всего; после нажатия скрипт ставит ей hidden.
   ========================================================================== */
/* Плашка ставит себе display: flex, а это перебивает [hidden] браузера —
   без этой строки скрипт снимает согласие, но плашка остаётся на экране. */
.cookie-notice[hidden] {
  display: none;
}

.cookie-notice {
  position: fixed;
  z-index: 1001;
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
  gap: 20px;
  flex-direction: column;
  align-items: flex-start;
  padding: 15px;
  color: var(--light);
  background: #0a1a34;
}

.cookie-notice__text {
  display: flex;
  gap: 10px;
  width: 100%;
  flex-direction: column;
  word-break: break-word;
}

.cookie-notice__title {
  margin: 0;
  font-family: "LT Superior", Arial, sans-serif;
  font-size: 20px;
  font-weight: 600;
  line-height: 1.4;
}

.cookie-notice__copy {
  margin: 0;
  font-family: "LT Superior", Arial, sans-serif;
  font-size: 13px;
  font-weight: 450;
  line-height: 1.2;
}

.cookie-notice__copy a {
  color: inherit;
  text-decoration: underline;
  text-decoration-skip-ink: none;
  text-underline-position: from-font;
}

/* Ховер тот же, что у кнопки «Меню» в шапке: заливка --light выезжает снизу,
   надпись меняется на свою копию. Механику даёт .button--fill-hover, здесь
   только размеры и цвет надписи — он остаётся цветом плашки, а не --dark. */
.cookie-notice__accept {
  position: relative;
  display: flex;
  width: 100%;
  height: 34px;
  padding: 12px 30px;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 3px;
  color: #0a1a34;
  background: var(--white);
  font-family: "Roboto", Arial, sans-serif;
  font-size: 14px;
  font-weight: 500;
  line-height: normal;
  text-transform: uppercase;
  white-space: nowrap;
  transition: color 180ms ease, background-color 180ms ease;
  cursor: pointer;
}

.cookie-notice__accept .button__text {
  padding: 0 30px;
  font-family: inherit;
  font-size: inherit;
  font-weight: inherit;
  line-height: inherit;
  text-transform: inherit;
}

.cookie-notice__accept.button--fill-hover:hover,
.cookie-notice__accept.button--fill-hover:focus-visible {
  color: #0a1a34;
}

@media (min-width: 600px) and (max-width: 1199px) {
  .cookie-notice {
    right: 10px;
    bottom: 32px;
    left: 10px;
    padding: 20px;
    border-radius: 3px;
  }

  .cookie-notice__title { font-size: 22px; }
  /* Ширину текста не ограничиваем: в макете планшет нарисован дважды, при
     704 и при 748, и ширина абзаца там разная (576 против 653). Пусть
     заполняет плашку — тогда на всём диапазоне 600-1199 выходит та же
     раскладка, что в варианте 748. */
  .cookie-notice__copy { font-size: 18px; }
  .cookie-notice__accept { height: 43px; font-size: 16px; }
}

@media (min-width: 1200px) {
  .cookie-notice {
    right: 10px;
    bottom: 10px;
    left: auto;
    width: 476px;
    padding: 20px;
    border-radius: 3px;
  }

  .cookie-notice__title { color: var(--white); font-size: 22px; }
  .cookie-notice__copy { font-size: 18px; line-height: 1.15; }

  .cookie-notice__accept {
    width: 159px;
    height: 43px;
    font-size: 16px;
  }
}

/* Главная: внешние отступы секций по макетам 375 и 768. */
@media (max-width: 599px) {
  body[data-site-page="home"] .company-intro { padding-top: 50px; }
  body[data-site-page="home"] .stats { min-height: 0; padding-block: 50px; }
  body[data-site-page="home"] .projects { min-height: 0; padding-top: 51px; padding-bottom: 50px; }
  body[data-site-page="home"] .services { min-height: 0; padding-top: 60px; padding-bottom: 50px; }
  body[data-site-page="home"] .video-section { padding-block: 50px; }
  body[data-site-page="home"] .news { min-height: 0; padding-top: 50px; padding-bottom: 50px; }
}
@media (min-width: 600px) and (max-width: 1199px) {
  body[data-site-page="home"] .video-section { padding-top: 90px; padding-bottom: 80px; }
}

/* О компании: ширина полос для сдвига лестницы, как на главной. */
body[data-site-page="about"] .company-intro__steps span { width: 100vw; right: auto; }

/* Главная: высота первого экрана учитывает фактическую высоту редактируемого заголовка. */
body[data-site-page="home"] .hero {
  height: 100vh;
  height: 100svh;
  min-height: 0;
  padding-bottom: 0;
}

body[data-site-page="home"] .hero__descriptor { top: 59.7403vh; }

body[data-site-page="home"] .hero__title {
  position: relative;
  top: auto;
  margin-top: 74.397vh;
}

@media (min-width: 600px) and (max-width: 1199px) {
  body[data-site-page="home"] .hero__descriptor { top: 46.8608vh; }
  body[data-site-page="home"] .hero__title {
    top: auto;
    margin-top: 80.0728vh;
  }
}

@media (min-width: 1200px) {
  body[data-site-page="home"] .hero__descriptor { top: 35.3703vh; }
  body[data-site-page="home"] .hero__title {
    top: auto;
    margin-top: 66.2964vh;
  }

  html[lang="en"] body[data-site-page="home"] .hero__title {
    width: calc(100% - 5.7292vw);
    text-wrap: balance;
  }
}

/* Главная: высота первого экрана учитывает фактическую высоту редактируемого заголовка. */
body[data-site-page="home"] .hero {
  height: 100vh;
  height: 100svh;
  min-height: 0;
  padding-bottom: 0;
}

body[data-site-page="home"] .hero__descriptor { top: 59.7403vh; }

body[data-site-page="home"] .hero__title {
  position: relative;
  top: auto;
  margin-top: 74.397vh;
}

@media (min-width: 600px) and (max-width: 1199px) {
  body[data-site-page="home"] .hero__descriptor { top: 46.8608vh; }
  body[data-site-page="home"] .hero__title {
    top: auto;
    margin-top: 80.0728vh;
  }
}

@media (min-width: 1200px) {
  body[data-site-page="home"] .hero__descriptor { top: 35.3703vh; }
  body[data-site-page="home"] .hero__title {
    top: auto;
    margin-top: 66.2964vh;
  }

  html[lang="en"] body[data-site-page="home"] .hero__title {
    width: calc(100% - 5.7292vw);
    text-wrap: balance;
  }
}
