/* Golos Text — переменный шрифт. Файл несёт веса до 900, но прежнее объявление
   обрезало диапазон на 500, и тяжёлые начертания были недоступны даром. */
@font-face{font-family:'Golos Text';font-style:normal;font-weight:400 900;font-display:swap;src:url('assets/golos-text-latin.woff2') format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Golos Text';font-style:normal;font-weight:400 900;font-display:swap;src:url('assets/golos-text-cyrillic.woff2') format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}

:root{
  color-scheme:dark;
  /* Нейтральные со смещением в зелень: тёмное перестаёт читаться как просто серое,
     и акцент оказывается дома, а не кляксой на графитовом фоне. */
  --bg:#0C0E0C;
  --bg-2:#111410;
  --surface:#171B16;
  --pane:#0A0C0A;
  --ink:#F4F5F1;
  --muted:#8B928B;          /* 6,1:1 к фону */
  --dim:#828A82;            /* 5,5:1 к фону, 4,9:1 к карточке */
  --line:#242A23;           /* волосяные разделители, требований по контрасту нет */
  --line-2:#5E665F;         /* границы элементов управления: 3,3:1 — минимум */
  --accent:#34C759;
  --accent-deep:#1E7F39;
  --on-accent:#07120A;      /* 8,6:1 на зелёном */
  --danger:#FF8A80;
  --radius:14px;
  --gutter:clamp(18px,4vw,64px);
  --bar:56px;
  --display:'Unbounded','Golos Text',Arial,sans-serif;
  --body:'Golos Text','Helvetica Neue',Arial,sans-serif;
  font-family:var(--body);font-size:16px;font-synthesis:none;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth;scroll-padding-top:calc(var(--bar) + 20px)}
body{margin:0;background:var(--bg);color:var(--ink);font-size:16px;line-height:1.5;
  -webkit-font-smoothing:antialiased;overflow-x:hidden}
/* Плёночное зерно: снимает пластиковость плоской тёмной заливки. */
body::after{content:"";position:fixed;inset:0;pointer-events:none;z-index:60;opacity:.04;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}
h1,h2,h3,h4{margin:0;font-family:var(--display);font-weight:400;letter-spacing:-.04em;line-height:1;text-wrap:balance}
p{margin:0}
img{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
ul,ol{margin:0}
:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:4px}

/* ── кольцо фокуса — только для клавиатуры ─────────────────── */
/* После касания браузер нередко оставляет :focus-visible на кнопке, и
   поверх её собственной рамки повисает вторая обводка — на телефоне
   это видно чаще всего. Способ ввода помечает app.js в data-input у
   <html>: пришли пальцем или мышью — кольца нет и кнопка не остаётся
   в наведённом состоянии; пришли с клавиатуры — всё как было. */
html[data-input="pointer"] :focus-visible{outline:none!important}
html[data-input="pointer"] .service-card:focus-visible{box-shadow:none}
html[data-input="pointer"] .button:focus-visible:not(:hover) .blob{
  left:18px;top:calc(50% - 4px);width:8px;height:8px}
html[data-input="pointer"] .button:focus-visible:not(:hover) .f1{transform:none;opacity:1}
html[data-input="pointer"] .button:focus-visible:not(:hover) .f2{transform:translateX(24px);opacity:0}
html[data-input="pointer"] .button.solid:focus-visible:not(:hover){
  background:var(--accent);color:var(--on-accent)}

.site-shell{max-width:1560px;margin:0 auto;padding-inline:var(--gutter)}
.visually-hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
.skip-link{position:absolute;left:20px;top:-100px;padding:12px 16px;background:var(--accent);color:var(--on-accent);z-index:80;border-radius:8px}
.skip-link:focus{top:14px}

/* ── шапка ─────────────────────────────────────────────────── */
.home-header{position:sticky;top:0;z-index:40;display:flex;align-items:center;gap:clamp(14px,2.4vw,30px);
  min-height:var(--bar);padding-block:6px;background:color-mix(in srgb,var(--bg) 93%,transparent);
  backdrop-filter:blur(14px);border-bottom:1px solid var(--line);
  margin-inline:calc(-1*var(--gutter));padding-inline:var(--gutter)}
.home-header-left{display:flex;align-items:center;gap:clamp(14px,2.2vw,28px);min-width:0;flex:1}
.logo{display:block;width:clamp(86px,8vw,112px);flex:none;aspect-ratio:1523/712;background:var(--ink);
  transition:background .2s;
  -webkit-mask:url('assets/logo-mask.webp') center/100% 100% no-repeat;
  mask:url('assets/logo-mask.webp') center/100% 100% no-repeat}
.logo:hover{background:var(--accent)}
/* Знак студии: логотип и под ним мелкая подпись STUDIO. Логотип — это
   маска, текст внутрь не положить, поэтому оба лежат в одной ссылке.
   Логотип здесь чуть меньше обычного, чтобы шапка почти не выросла. */
.logo-studio{display:flex;flex-direction:column;align-items:center;gap:0;flex:none;
  text-decoration:none}
.logo-studio .logo{width:clamp(64px,5.8vw,80px)}
.logo-studio:hover .logo{background:var(--accent)}
.logo-tag{font-family:var(--display);font-size:6.5px;font-weight:600;line-height:1;
  letter-spacing:.4em;text-transform:uppercase;color:var(--accent);
  margin-top:-1px;margin-right:-.4em}
/* В шапке всё компактнее: кнопка «Связь» и пункты меню ниже, чем
   общие кнопки сайта, — иначе полоска меню не становится уже. */
.home-header .button{min-height:34px;min-width:0;padding:5px 16px 5px 28px;font-size:13px}
.home-header .button .blob{left:13px;top:calc(50% - 3px);width:6px;height:6px}
.home-header .site-nav a{min-height:34px}
html[data-input="pointer"] .home-header .button:focus-visible:not(:hover) .blob{left:13px;top:calc(50% - 3px);width:6px;height:6px}
.home-header-text{min-width:0;display:none}
.home-header-text h1,.home-header-text .home-header-title{margin:0;font-family:var(--body);font-size:14px;
  font-weight:500;line-height:1.3;letter-spacing:0}
.home-header-text p{margin:2px 0 0;font-size:13px;line-height:1.35;color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.home-header-arrow{display:none}
.site-nav{display:flex;gap:20px;margin-left:auto;font-size:14px;color:var(--muted)}
.site-nav a{display:inline-flex;align-items:center;min-height:44px;transition:color .2s}
.site-nav a:hover{color:var(--ink)}

/* ── кнопка со схлопывающейся точкой ───────────────────────── */
.button{position:relative;display:inline-grid;place-items:center;min-height:46px;min-width:134px;padding:11px 24px;
  border:1px solid var(--accent);border-radius:99px;background:none;color:var(--ink);cursor:pointer;
  font-family:var(--display);font-size:14px;font-weight:600;letter-spacing:.01em;overflow:hidden;flex:none}
.button .blob{position:absolute;left:18px;top:calc(50% - 4px);width:8px;height:8px;border-radius:99px;
  background:var(--accent);transition:all .34s cubic-bezier(.4,0,.2,1);z-index:0}
.button .f1{grid-area:1/1;z-index:1;transition:transform .34s cubic-bezier(.4,0,.2,1),opacity .3s}
.button .f2{grid-area:1/1;z-index:1;display:flex;align-items:center;gap:8px;color:var(--on-accent);
  transform:translateX(24px);opacity:0;transition:transform .34s cubic-bezier(.4,0,.2,1),opacity .3s}
.button .f2 svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:2.2}
.button:hover .blob,.button:focus-visible .blob{left:0;top:0;width:100%;height:100%}
.button:hover .f1,.button:focus-visible .f1{transform:translateX(24px);opacity:0}
.button:hover .f2,.button:focus-visible .f2{transform:none;opacity:1}
.button:focus-visible{outline:2px solid var(--ink);outline-offset:3px}
.button:disabled{opacity:.45;cursor:not-allowed}
/* Ширина подобрана так, чтобы точка стояла ровно посередине между левым
   краем кнопки и первой буквой: надпись в кнопке центрируется, поэтому
   этот просвет задаётся именно шириной, а не отступом. */
.button.lg{min-height:58px;min-width:140px;font-size:16px;padding:14px 30px}
.button.solid{background:var(--accent);border-color:var(--accent);color:var(--on-accent);
  transition:background .28s ease,color .28s ease}
.button.solid .blob{display:none}
.button.solid .f1,.button.solid .f2{color:inherit;transition:transform .34s cubic-bezier(.4,0,.2,1),opacity .3s}
/* При наведении кнопка выворачивается наизнанку: тёмная заливка, зелёная
   надпись, рамка на месте. Зелёный на тёмном держит 8,4:1. */
.button.solid:hover,.button.solid:focus-visible{background:transparent;color:var(--accent)}
.button.solid:focus-visible{outline-color:var(--ink)}

.text-link,.link{display:inline-flex;align-items:center;gap:9px;min-height:44px;width:fit-content;
  color:var(--accent);font-weight:500}
.text-link svg,.link svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:2;transition:transform .25s}
.text-link:hover svg,.link:hover svg{transform:translateX(4px)}

/* ── подвал ────────────────────────────────────────────────── */
/* Верхний отступ подвала отдан холсту: поле частиц начинается прямо от
   серой линии и доходит до строки со ссылками. */
.footer{border-top:1px solid var(--line);margin-top:clamp(40px,6vw,90px);
  padding-block:0 32px}
/* Знак собирается из частиц: маска логотипа рисуется в невидимый холст,
   из его пикселей рождаются точки, каждая пружиной держится за своё
   место. Пропорции холста — пропорции знака, иначе он терялся бы
   посреди широкой полосы. */
/* Холст шире и выше своего места в потоке: отрицательные поля выпускают
   его за серую линию сверху и за строку ссылок снизу, а занимаемая
   высота остаётся прежней. Курсор он не перехватывает — иначе перекрыл
   бы ссылки подвала; координаты берём из окна. */
/* --bleed объявлен через @property, чтобы скрипт мог прочитать его
   уже посчитанным в пикселях: он вписывает знак в полосу без этой
   прибавки, а разлёт частиц считает вместе с ней. */
@property --bleed{syntax:"<length>";inherits:false;initial-value:0px}
.footer-word{display:block;width:100%;--bleed:clamp(24px,7vw,120px);
  height:calc(clamp(160px,28vw,410px) + var(--bleed) * 2);
  margin-block:calc(-1 * var(--bleed));pointer-events:none}

.footer-row{position:relative;z-index:1;
  display:flex;gap:26px;justify-content:space-between;flex-wrap:wrap;align-items:flex-end;
  margin-top:0}
.footer nav{display:flex;gap:18px;flex-wrap:wrap;font-size:14px;color:var(--muted)}
.footer nav a{display:inline-flex;align-items:center;min-height:44px;transition:color .2s}
.footer nav a:hover{color:var(--accent)}
.footer small{color:var(--dim);font-size:13px}

/* ── форма ─────────────────────────────────────────────────── */
/* Окно прибито к экрану, а не к странице. По умолчанию dialog
   позиционируется абсолютно, то есть от начала документа: если открыть
   форму, пролистав страницу вниз, окно оказывается у самого верха
   документа — за пределами экрана. На десктопе это не бросалось в
   глаза, потому что блокировка прокрутки заодно отматывала страницу
   наверх; на телефоне прокрутка остаётся на месте, и форма просто
   пропадала из виду. */
.contact-dialog{position:fixed;inset:0;border:0;padding:0;background:none;
  max-width:none;max-height:none;width:100%;height:100%;height:100dvh;
  overflow:auto;overscroll-behavior:contain}
/* safe center: если форма выше экрана, центрирование не должно срезать
   её верх — тогда она просто прижимается к началу и листается. */
.contact-dialog[open]{display:flex;justify-content:center;align-items:center;
  align-items:safe center;padding-block:16px}
.contact-dialog::backdrop{background:rgba(4,6,4,.82);backdrop-filter:blur(6px)}
/* overflow:hidden здесь не ради прокрутки: экран отправки размывает фон
   через backdrop-filter, а размытая область у браузеров прямоугольная и
   собственное скругление её не обрезает — по углам карточки вылезали
   квадратные заплатки. Обрезка на самой карточке убирает их. */
.contact-inner{width:min(760px,calc(100% - 2*var(--gutter)));margin-block:auto;background:var(--bg-2);color:var(--ink);
  border:1px solid var(--line-2);border-radius:var(--radius);padding:clamp(20px,3vw,44px);
  overflow:hidden;display:flex;flex-direction:column;gap:20px}
.contact-top{display:flex;justify-content:space-between;align-items:center;font-size:12px;
  letter-spacing:.18em;color:var(--muted)}
.close-button{width:44px;height:44px;border:1px solid var(--line-2);border-radius:50%;background:none;
  color:var(--ink);display:grid;place-items:center;cursor:pointer;transition:border-color .2s,color .2s}
.close-button:hover{border-color:var(--accent);color:var(--accent)}
.close-button svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:1.8}
.contact-inner h2{font-size:clamp(28px,4.4vw,52px);font-weight:600;line-height:.98}
.form-fields{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.field{display:flex;flex-direction:column;gap:7px;min-width:0}
.field.project-field,.field:nth-of-type(3){grid-column:1/-1}
.field>span{font-size:12px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.field input,.field textarea{font:inherit;color:var(--ink);background:var(--pane);border:1px solid var(--line);
  border-radius:9px;padding:13px 14px;min-height:48px;resize:vertical}
.field input:focus,.field textarea:focus{outline:none;border-color:var(--accent)}
.field input[aria-invalid="true"]{border-color:var(--danger)}
.field-error{color:var(--danger);font-size:13px}
/* Форма — отдельный поток: без этого кнопка отправки упиралась прямо
   в нижний край поля «О проекте», вплотную к ручке изменения размера. */
#contact-form{display:flex;flex-direction:column;gap:clamp(20px,2.4vw,28px)}
.form-bottom{display:flex;justify-content:space-between;align-items:center;gap:16px;flex-wrap:wrap}
/* ── робот в форме ─────────────────────────────────────────── */
/* Живёт в пустой полосе слева от кнопки отправки: следит за курсором,
   идёт к нему, когда тот рядом, и гуляет из края в край, когда нет.
   Сцена на three.js подгружается лениво — при первом открытии формы.
   Полоса выше строки ровно настолько, насколько позволяют отступы
   формы: отрицательные поля возвращают строке её прежнюю высоту. */
.walker{--walk-h:clamp(74px,8vw,98px);
  position:relative;flex:1 1 90px;min-width:0;
  height:var(--walk-h);margin-block:calc((46px - var(--walk-h)) / 2);
  pointer-events:none;transition:opacity .3s}
.walker canvas{position:absolute;inset:0;width:100%;height:100%;display:block}
/* Как только форме есть что сказать, робот уступает место. */
.form-bottom:has(.form-status:not(:empty)) .walker{opacity:0}
.form-status{font-size:14px;color:var(--muted);margin:0}
.form-status.error{color:var(--danger)}
.form-status a{text-decoration:underline;text-underline-offset:3px}
.form-status a:hover{color:var(--accent)}
.form-status.success{color:var(--accent)}
.honeypot{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

/* ── экран отправки ────────────────────────────────────────── */
/* Куб вращается над треугольным основанием. Две анимации не могут висеть
   на одном элементе: обе пишут в transform, и вторая затирает первую —
   поэтому подъём живёт на обёртке, а вращение на самом кубе. */
.contact-inner{position:relative}
.sending{display:none}
.sending.is-on{position:absolute;inset:0;z-index:5;display:grid;place-content:center;justify-items:center;
  gap:30px;border-radius:var(--radius);overflow:hidden;
  background:color-mix(in srgb,var(--bg-2) 90%,transparent);backdrop-filter:blur(4px)}
.cube-scene{position:relative;width:150px;height:150px;perspective:560px;display:grid;place-items:center}
.cube-lift{transform-style:preserve-3d;animation:cube-float 2.3s ease-in-out infinite alternate}
.cube{--s:52px;position:relative;width:var(--s);height:var(--s);transform-style:preserve-3d;
  animation:cube-spin 3.6s linear infinite}
.cube span{position:absolute;inset:0;border:1px solid var(--accent);background:rgba(52,199,89,.12);
  box-shadow:0 0 18px rgba(52,199,89,.4),inset 0 0 20px rgba(52,199,89,.22)}
.cube span:nth-child(1){transform:translateZ(26px)}
.cube span:nth-child(2){transform:rotateY(180deg) translateZ(26px)}
.cube span:nth-child(3){transform:rotateY(90deg) translateZ(26px)}
.cube span:nth-child(4){transform:rotateY(-90deg) translateZ(26px)}
.cube span:nth-child(5){transform:rotateX(90deg) translateZ(26px)}
.cube span:nth-child(6){transform:rotateX(-90deg) translateZ(26px)}
.cube-plinth{position:absolute;bottom:16px;width:0;height:0;border-left:38px solid transparent;
  border-right:38px solid transparent;border-bottom:34px solid rgba(52,199,89,.34);
  transform:rotateX(68deg);filter:drop-shadow(0 0 11px rgba(52,199,89,.55));
  animation:plinth-pulse 2.3s ease-in-out infinite alternate}
.cube-glow{position:absolute;bottom:26px;width:96px;height:20px;border-radius:50%;
  background:radial-gradient(ellipse,rgba(52,199,89,.35),transparent 70%);filter:blur(5px);
  animation:plinth-pulse 2.3s ease-in-out infinite alternate}
.sending-text{font-size:14px;letter-spacing:.14em;text-transform:uppercase;color:var(--dim)}
@keyframes cube-spin{from{transform:rotateX(-22deg) rotateY(0deg)}to{transform:rotateX(-22deg) rotateY(360deg)}}
@keyframes cube-float{from{transform:translateY(6px)}to{transform:translateY(-10px)}}
@keyframes plinth-pulse{from{opacity:.55}to{opacity:1}}

/* Фон под окном не должен листаться. Одного overflow:hidden мало: на
   iOS он прокрутку не держит, а в Chrome сбрасывает её в ноль, и после
   закрытия человек оказывается в начале страницы. Тело фиксируем и
   сдвигаем на текущую прокрутку — app.js потом возвращает её обратно. */
body.dialog-open{position:fixed;left:0;right:0;width:100%;overflow:hidden}

/* ── заставка ──────────────────────────────────────────────── */
@property --intro-r{syntax:'<length>';inherits:false;initial-value:0px}
#intro-splash{position:fixed;inset:0;z-index:80;overflow:hidden}
#intro-splash .intro-base{position:absolute;inset:0;background:var(--bg);--intro-r:0px;
  mask-image:radial-gradient(circle at 50% 50%,transparent var(--intro-r),#000 var(--intro-r));
  -webkit-mask-image:radial-gradient(circle at 50% 50%,transparent var(--intro-r),#000 var(--intro-r))}
#intro-splash .intro-logo{position:absolute;top:50%;left:50%;margin:-46.75px 0 0 -100px;width:200px;
  aspect-ratio:1523/712;display:block;background:var(--ink);opacity:1;transform:scale(.6);
  mask:url('assets/logo-mask.webp') center/100% 100% no-repeat;
  -webkit-mask:url('assets/logo-mask.webp') center/100% 100% no-repeat}
#intro-splash.intro-play .intro-base{animation:intro-reveal .75s cubic-bezier(.4,0,.7,.3) forwards}
#intro-splash.intro-play .intro-logo{animation:intro-logo-dive .75s cubic-bezier(.4,0,.7,.3) forwards}
#intro-splash.skip{visibility:hidden!important}
#intro-splash.skip .intro-base,#intro-splash.skip .intro-logo{animation:none!important}
#intro-splash.skip .intro-logo{opacity:0!important}
@keyframes intro-reveal{to{--intro-r:160vmax}}
@keyframes intro-logo-dive{0%{transform:scale(.6);opacity:1}58%{opacity:1}100%{transform:scale(70);opacity:0}}

@media (min-width:900px){
  .home-header-text{display:block}
}
@media (max-width:899px){
  .site-nav{display:none}
  .home-header .button{margin-left:auto}
  .form-fields{grid-template-columns:1fr}
}
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  #intro-splash{visibility:hidden!important}
  #intro-splash .intro-base,#intro-splash .intro-logo{animation:none!important}
  .button .blob,.button .f1,.button .f2,.text-link svg,.link svg{transition:none}
  /* Куб замирает в статичной позе — экран отправки остаётся понятным,
     но ничего не крутится. */
  .cube,.cube-lift,.cube-plinth,.cube-glow{animation:none}
  .cube{transform:rotateX(-22deg) rotateY(38deg)}
}
