/* ─────────────────────────────────────────────────────────────────────────
   Manrope, вариативное начертание 200–800, свои файлы вместо Google Fonts.

   Было: семь статических начертаний с fonts.googleapis.com. Браузер тянул
   по файлу на каждое начертание и на каждый алфавит — четырнадцать запросов
   и 267 КБ на русской странице, и отрисовка ждала ответа чужого домена.
   Стало: один файл на алфавит, два запроса и 38 КБ с того же домена.
   Подмножества размечены unicode-range: браузер скачивает только те буквы,
   которые есть на странице.
   ───────────────────────────────────────────────────────────────────────── */

@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url('../fonts/cyrillic-ext.woff2') format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}

/* ─────────────────────────────────────────────────────────────────────────
   Шрифты реплики сайта вышивки. Живут только на странице этого кейса, но
   тянулись из Google так же, как основной шрифт. Забраны к себе по той же
   причине: чужой домен на пути к первой отрисовке и IP посетителя у Google.
   ───────────────────────────────────────────────────────────────────────── */

@font-face {
  font-family: 'Cormorant Garamond';
  font-style: italic;
  font-weight: 300;
  font-display: swap;
  src: url('../fonts/cormorant-garamond-300-italic-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'Cormorant Garamond';
  font-style: italic;
  font-weight: 300;
  font-display: swap;
  src: url('../fonts/cormorant-garamond-300-italic-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Cormorant Garamond';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('../fonts/cormorant-garamond-300-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'Cormorant Garamond';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('../fonts/cormorant-garamond-300-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/inter-400-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/inter-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url('../fonts/cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url('../fonts/greek.woff2') format('woff2');
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}

@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url('../fonts/vietnamese.woff2') format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}

@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url('../fonts/latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url('../fonts/latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ============================================================
   Lana Svitla — Portfolio v2 design system
   Style family: Manrope, large display type, generous whitespace,
   rounded full-bleed imagery, lime accent, floating pill nav.
   ============================================================ */

:root{
  /* Base ink: black. One value serves text and the footer ground. */
  --ink: #0a0a0a;
  /* The DESIGN mark keeps the tone it was drawn in in V1 — the only place on
     the site that is deliberately lighter than ink. */
  --mark: #434343;
  --muted: #666666;
  --line: #e6e6e6;
  --surface: #ffffff;
  --surface-soft: #f4f4f2;
  /* One light grey for every soft fill: the header pill and the hero button
     were #e0e0e0 at 15% and #f0f0f0 — two different greys side by side on the
     first screen. Declared as a colour plus an alpha so the pill can stay
     translucent and the button can sit on the same tone. */
  --tint: 224, 224, 224;
  --tint-soft: rgba(var(--tint), .15);
  /* opaque twin of the same grey, for the one place that sits on the black
     footer, where a 15% tint would read as dark instead of light */
  --tint-solid: #f0f0f0;

  /* Two shades of grey with a rule instead of a habit:
     --tone-soft only on display type from 24px up, where 3.0:1 is enough;
     --muted on everything smaller, where AA asks for 4.5:1 and it gives 5.7. */

  /* Shade, not ink: shadows stay near-black so they read on any surface. */
  --shadow-soft: rgba(10, 10, 10, .18);
  --shadow-lift: rgba(10, 10, 10, .32);
  /* Highlights and veils on top of imagery */
  --glow-inset: rgba(255, 255, 255, .4);
  --veil: rgba(255, 255, 255, .94);
  --scrim: rgba(190, 190, 190, .72);
  /* подложка круглой кнопки на обложке кейса: мягче и прозрачнее scrim */
  --scrim-soft: rgba(255, 255, 255, .58);
  --focus-ring: rgba(10, 10, 10, .35);
  --footer: var(--ink);
  /* on the black footer this gives 7.5:1 — comfortably above AA */
  --footer-muted: #9a9a9a;
  --accent: #ddff8d;
  --accent-ink: #0a0a0a;
  --radius-lg: 28px;
  --radius-md: 18px;
  --radius-pill: 999px;
  /* Шапка липкая: 87px на десктопе, 79px в мобилке. Цель якоря должна
     отступить на её высоту плюс воздух, иначе заголовок уезжает под плашку. */
  --anchor-offset: 120px;

  /* DESIGN/WORKS lockup, measured from V1: word 176 at line-height .75 stands
     exactly as tall as the 132px shapes beside it */
  /* one gap token for the whole first screen: above the mark and between
     the portrait and the text beside it */
  --stack-gap: clamp(32px, 7svh, 72px);
  --lockup-size: clamp(72px, 9.2vw, 132px);
  --lockup-word: clamp(96px, 12.2vw, 176px);

  --grid-max: 1320px;
  --header-max: 1080px;
  --page-x: clamp(20px, 4vw, 64px);

  --font-display: "Manrope", "Helvetica Neue", Arial, sans-serif;
  --font-body: "Manrope", "Helvetica Neue", Arial, sans-serif;

  --fs-hero: clamp(40px, 6vw, 76px);
  --fs-h1: clamp(32px, 4.4vw, 56px);
  --fs-h2: clamp(24px, 3vw, 34px);
  --fs-h3: 20px;
  --fs-footer-title: clamp(36px, 5vw, 64px);
  --fs-about-lead: clamp(26px, 3.2vw, 40px);
  /* Manrope: cap height sits lineHeight/2 - 0.3475 x fontSize below the
     top of the line box. Measured in the browser from the font metrics. */
  --cap-k: 0.3475;
  --tone-soft: #969696;   /* серый второго плана: копирайт, Copy, вторая часть фразы */
  --fs-lead: clamp(17px, 1.6vw, 20px);
  --fs-body: 16px;
  --fs-small: 13px;
  --fs-nav: 14px;

  --ease: cubic-bezier(.16,.84,.44,1);

  /* Увеличение картинки внутри неподвижной рамки. Одно поведение на весь
     сайт: карточки каталога и блоки услуг на «Процессе». Рамка не двигается,
     края подрезает overflow у обёртки. */
  --media-zoom: 1.06;
  --media-zoom-dur: .6s;
}

*{ box-sizing: border-box; }
html{ scroll-behavior: auto; overflow-x: clip; }
/* clip на body одном не держит границу надёжно: html — настоящий корневой
   скроллер, и в части случаев overflow-x:clip с body на него не переносится.
   Полноэкранная лента обложек на «Обо мне» это и обнажила: scrollWidth не
   рос, но document.scrollTo(500,0) реально прокручивал страницу на 48px. */
body{
  margin: 0;
  overflow-x: clip;
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
img{ max-width: 100%; display: block; }
a{ color: inherit; text-decoration: none; }
ul{ list-style: none; margin: 0; padding: 0; }
h1,h2,h3,p{ margin: 0; }

.wrap{
  max-width: var(--grid-max);
  margin: 0 auto;
  padding: 0 var(--page-x);
}

/* ---------- reveal-on-scroll ----------
   Site-wide entrance: blocks drift in from the right, each one a beat after the
   previous. `--i` is the element's index within the batch appearing together
   (set in main.js), so a single block scrolled into view starts immediately. */
/* Любая цель якоря отступает от липкой шапки. Свойство ни на что не влияет,
   пока к элементу не перешли по ссылке с #, поэтому задаём его всем сразу. */
[id]{ scroll-margin-top: var(--anchor-offset); }

/* ВНИМАНИЕ. Правило стоит в начале файла, а `transition` — шорткат: любое
   более позднее правило с тем же весом, объявившее свою `transition`,
   стирает эту и появление происходит мгновенно. Класс при этом на месте,
   `opacity` уходит с 0 на 1 — глазами это выглядит как «блок стоит каменно».
   Если компоненту с `.reveal` нужна своя `transition`, он обязан перечислить
   `opacity` и `transform` сам, вместе с задержкой `calc(var(--i, 0) * 110ms)`.
   Так сделано у `.dcard` и `.list-more`. */
.reveal{
  opacity: 0;
  transform: translate3d(48px, 0, 0);
  transition: opacity .8s var(--ease), transform .8s var(--ease);
  transition-delay: calc(var(--i, 0) * 110ms);
}
.reveal.is-visible{
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

@media (max-width: 720px){
  :root{ --anchor-offset: 108px; }
}

@media (max-width: 640px){
  .reveal{ transform: translate3d(0, 24px, 0); }
  .reveal.is-visible{ transform: translate3d(0, 0, 0); }
}

@media (prefers-reduced-motion: reduce){
  .teaser__row{ animation: none; transform: none; }
  .reveal{ transform: none; transition-delay: 0s; }
}

/* ---------- header ---------- */
.site-header{
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  justify-content: center;
  padding: 20px var(--page-x) 0;
  background: transparent;
}
/* The pill carries its faint tint at all times, exactly as in the reference —
   measured there at scrollY 0: rgba(224,224,224,.15) + blur(6px) + inset glow. */
.site-header__inner{
  width: 100%;
  max-width: calc(var(--header-max) + 22px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: var(--tint-soft);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  box-shadow: var(--glow-inset) 0 -2px 11px 0 inset;
  border: none;
  border-radius: 999px;
  padding: 12px 12px 12px 10px;
}
.site-header__logo{
  display: inline-flex;
  align-items: center;
  height: 1.1em;
  margin-left: 20px;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 20px;
  letter-spacing: -0.01em;
  color: var(--muted);
}
.site-header__logo .brand__mark{
  width: 20px;
  height: 20px;
  display: block;
  color: inherit;
}
.site-header__logo .brand__short{
  max-width: 40px;
  opacity: 1;
  overflow: hidden;
  white-space: nowrap;
  transition: max-width .45s cubic-bezier(.16,1,.3,1), opacity .3s cubic-bezier(.16,1,.3,1);
}
.site-header__logo .brand__full{
  max-width: 0;
  opacity: 0;
  overflow: hidden;
  white-space: nowrap;
  color: var(--muted);
  transition: max-width .45s cubic-bezier(.16,1,.3,1) .04s, opacity .35s cubic-bezier(.16,1,.3,1) .06s;
}
.site-header__logo:hover .brand__short{
  max-width: 0;
  opacity: 0;
}
.site-header__logo:hover .brand__full{
  max-width: 280px;
  opacity: 1;
}
.site-header__nav{
  display: flex;
  align-items: center;
  gap: 32px;
}
.site-header__nav-links{
  display: flex;
  align-items: center;
  gap: 32px;
}
.site-header__nav a:not(.site-header__cta){
  display: inline-block;
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 500;
  color: var(--muted);
  transition: color .35s cubic-bezier(.16,1,.3,1), transform .35s cubic-bezier(.16,1,.3,1);
}
.site-header__nav a:not(.site-header__cta):hover{
  color: var(--ink);
  transform: translateX(3px);
}
/* current page stays black in the menu */
.site-header__nav a.is-current{ color: var(--ink); }
.site-header__cta{
  background: var(--accent);
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 500;
  padding: 8px 16px;
  border-radius: var(--radius-pill);
  box-shadow: 0 0 0 transparent;
  transition:
    background .3s cubic-bezier(.16,1,.3,1),
    color .3s cubic-bezier(.16,1,.3,1),
    box-shadow .3s cubic-bezier(.16,1,.3,1);
}
.site-header__cta:hover{
  background: var(--ink);
  color: var(--accent);
  box-shadow: 0 12px 22px var(--shadow-lift);
}

.site-header__menu-btn{
  display: none;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 5px;
  /* 44px — минимум зоны нажатия по Apple HIG. Фон прозрачный и полоски стоят
     по центру, поэтому рост с 41px виден только пальцу, не глазу. */
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
  background: transparent;
  border: none;
  border-radius: 50%;
  padding: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  outline: none;
}
.site-header__menu-btn:focus-visible{
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}
.menu-btn__bar{
  width: 19px;
  height: 2px;
  border-radius: 2px;
  background: var(--ink);
  transition: transform .3s cubic-bezier(.16,1,.3,1), opacity .3s cubic-bezier(.16,1,.3,1);
}
.site-header.is-open .menu-btn__bar:nth-child(1){ transform: translateY(7px) rotate(45deg); }
.site-header.is-open .menu-btn__bar:nth-child(2){ opacity: 0; }
.site-header.is-open .menu-btn__bar:nth-child(3){ transform: translateY(-7px) rotate(-45deg); }

@media (max-width: 720px){
  /* Mobile header: equal 14px inset on top and both sides (author's choice —
     the header sits slightly wider than the content grid). */
  .site-header{ padding: 14px 14px 0; }
  .site-header__inner{ flex-wrap: wrap; }
  .site-header__menu-btn{ display: flex; }
  .site-header__nav{ display: none; }
  .site-header.is-open .site-header__logo{ margin-left: 0; }
  /* Меню списком, а не строкой. В строку помещались четыре пункта, пятый
     («Направления») сжал их до нечитаемого; на 375px пункты вставали в 15px
     без отступов, и попасть пальцем можно было только в сам текст.
     Теперь каждый пункт — строка во всю ширину с зоной нажатия 48px:
     это выше минимума Apple HIG (44pt) и WCAG. */
  .site-header.is-open .site-header__nav{
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    width: 100%;
    margin-top: 14px;
  }
  .site-header.is-open .site-header__nav-links{
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
  }
  .site-header.is-open .site-header__nav-links a{
    display: flex;
    align-items: center;
    min-height: 48px;
    padding: 12px 2px;
    font-size: 17px;
  }
  /* волосяная линия между строками: видно, где кончается одна зона нажатия
     и начинается следующая */
  .site-header.is-open .site-header__nav-links a + a{
    border-top: 1px solid var(--line);
  }
  /* сдвиг вправо на hover в списке не нужен: на тач-экране наведения нет,
     а в вертикальном ряду он ломает левый край */
  .site-header.is-open .site-header__nav-links a:hover{ transform: none; }
  .site-header.is-open .site-header__nav a:not(.site-header__cta){ display: flex; }
  .site-header.is-open .site-header__cta{
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 48px;
    margin-top: 14px;
    padding: 12px 16px;
    font-size: 17px;
    white-space: nowrap;
  }
  .site-header.is-open .site-header__inner{
    background: var(--tint-soft);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    box-shadow: var(--glow-inset) 0 -2px 11px 0 inset;
    padding: 12px;
    border-radius: 28px;
  }
}

/* ---------- hero ---------- */
.hero{
  padding: 64px 0 40px;
}
.hero__eyebrow{
  font-size: var(--fs-nav);
  color: var(--muted);
  margin-bottom: 18px;
}
.hero__title{
  font-family: var(--font-display);
  font-size: var(--fs-hero);
  font-weight: 500;
  line-height: 1.08;
  letter-spacing: -0.02em;
  max-width: 18ch;
}
.hero__title b, .hero__title strong{ font-weight: 700; }
.hero__lead{
  margin-top: 26px;
  max-width: 46ch;
  font-size: var(--fs-lead);
  color: var(--muted);
  line-height: 1.5;
}
.hero__media{
  margin-top: 40px;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--surface-soft);
  aspect-ratio: 16/8.2;
}
.hero__media img{ width: 100%; height: 100%; object-fit: cover; }/* Home about teaser: the V1 portrait interaction in the quieter V2 system. */
.home-about{
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: var(--stack-gap);
  padding: 0 0 clamp(64px, 9svh, 112px);
}
/* The portrait is sized off the text beside it: its height matches the big
   headline block, top edge to bottom edge. `--portrait-h` is written by the
   script after the text has laid out, because the number depends on how many
   lines the Russian copy wraps to. */
.home-about__portrait{
  position: relative;
  height: var(--portrait-h, 260px);
  aspect-ratio: 1;
  overflow: visible;
}.home-about__text{
  max-width: 30ch;
  font-family: var(--font-display);
  font-size: var(--fs-about-lead);
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: -0.01em;
  color: var(--tone-soft);
  text-wrap: pretty;
}
.home-about__text b{
  color: var(--ink);
  font-weight: 500;
}.home-about__more:hover .icon-arrow-ne{ transform: rotate(45deg); }.home-about__more .icon-arrow-ne{
  width: 16px;
  height: 16px;
  transition: transform .3s var(--ease);
}/* Амплитуда ±7px по каждой оси: путь по диагонали ≈19.8px — вдвое короче
   прежнего. Период 12s: на этом пути даёт 3.3 px/s — на треть медленнее,
   чем 8s, по отдельной правке Ланы. */
@keyframes home-hi-float{
  0%, 100%{ transform: translate3d(-7px, 7px, 0); }
  50%{ transform: translate3d(7px, -7px, 0); }
}
@media (hover: hover) and (pointer: fine){
  .home-about__portrait:hover .home-about__image--base{ opacity: 0; transform: scale(.995); }
  .home-about__portrait:hover .home-about__image--hover{ opacity: 1; transform: scale(1.005); }
}

/* ---------- services ---------- */
.services{
  padding: 96px 0;
  border-top: 1px solid var(--line);
}
.section-head{
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 48px;
  flex-wrap: wrap;
}
.section-head h2{
  font-family: var(--font-display);
  font-size: var(--fs-h1);
  font-weight: 500;
  letter-spacing: -0.01em;
  max-width: 14ch;
}
.section-head p{
  color: var(--muted);
  max-width: 40ch;
  font-size: var(--fs-lead);
}@media (max-width: 860px){
  .home-about{
    grid-template-columns: minmax(220px, 320px) minmax(0, 1fr);
    gap: 48px;
  }}

@media (max-width: 640px){  .home-about{
    grid-template-columns: 1fr;
    gap: 40px;
    padding: 32px 0 88px;
  }
  .home-about__portrait{
    width: min(82vw, 360px);
  }  .home-about__text{ max-width: none; }}

.chip{
  font-size: 12px;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  padding: 5px 12px;
}

/* process steps as a row of chips, static arrow between them (not a link,
   so it uses the straight icon and never rotates) */
.process-chips{
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 24px;
}
.process-chips .ic{ width: 14px; height: 14px; color: var(--muted); }

/* ---------- case page ---------- */
/* padding-bottom is required, not decorative: whatever the hero's last child
   is (media, video, a live-link) needs guaranteed clearance from whatever
   section follows — relying on the NEXT section to bring its own top space
   glued case-hero straight into the first .case-gallery on pages with no
   .case-overview between them (0px gap, confirmed in the browser) */
.case-hero{ padding: 48px 0 80px; }
/* consecutive gallery blocks (case-gallery--tight-bottom stacks of full/half
   images) had zero gap between them for the same reason — the padding they
   carry is padding-BOTTOM only, so a gallery has none of its own above it */
.case-gallery + .case-gallery{ margin-top: 24px; }
/* Two abstract shapes above the title, each swapped on its own timer by the
   dormant [data-form-root] cycle in main.js (ported from V1's brand-forms) */
.case-forms{
  display: flex;
  align-items: flex-start;
  gap: clamp(28px, 3.5vw, 40px);
  width: fit-content;
  margin: 0 0 28px;
  pointer-events: none;
}
.case-forms__frame{
  position: relative;
  display: grid;
  place-items: center;
  width: clamp(96px, 11vw, 132px);
  height: clamp(96px, 11vw, 132px);
  transform-style: preserve-3d;
  perspective: 700px;
}
.case-forms__frame--flip{ transition: transform 740ms var(--ease); }
.case-forms__frame--spin{ transition: transform 920ms var(--ease); }
.case-forms__frame.is-flipping{ transform: rotateY(90deg); }
.case-forms__frame.is-flipping-reverse{ transform: rotateY(-90deg); }
.case-forms__img{ display: block; width: 100%; height: 100%; object-fit: contain; }
@media (max-width: 700px){
  .case-forms{ display: none; }
}

/* Верхушка кейса в две колонки: формы слева, заголовок и подпись справа.

   Было (до 09.09.2026): формы занимали всю строку, и на первом экране посетитель видел
   132 пикселя воздуха вместо сути — заголовок с подписью уезжали ниже.
   Стало: формы держат тот же размер, но встают слева, а текст поднимается
   к ним на ту же высоту.

   Раскладку держит сетка, а не разметка: верхушка одинакова на всех 51
   странице кейсов (формы → заголовок → подпись), поэтому правка живёт
   в одном месте и ни одной страницы не трогает.

   Формы занимают обе строки. Заголовок прижат к низу своей строки, подпись —
   к верху своей, поэтому между ними остаётся ровно их собственный отступ,
   а лишняя высота уходит выше заголовка и ниже подписи: пара встаёт по
   центру форм при любой длине текста. Остальные дети верхушки —
   метаданные, обложка, ссылка на живой сайт — остаются во всю ширину. */
.case-hero{
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: clamp(32px, 4.2vw, 60px);
  align-content: start;
  /* от строки метрик до превью: было 80px, стало 60 */
  padding-bottom: 60px;
}
.case-hero > *{ grid-column: 1 / -1; }
/* Текст и формы стоят на одной оси, кто бы из них ни оказался выше.
   Заголовок прижат к низу своей строки, подпись — к верху своей: пара
   держится вместе и центрируется, когда формы выше. Когда выше текст —
   центрируются формы. */
.case-hero .case-hero__title{ grid-area: 1 / 2 / 2 / 3; align-self: end; }
.case-hero .case-hero__subtitle{ grid-area: 2 / 2 / 3 / 3; align-self: start; }
.case-hero .case-forms{
  grid-area: 1 / 1 / 3 / 2;
  margin-bottom: 0;
  align-self: center;
}
/* Ось считаем по буквам, а не по боксам. Над заглавной висит половина
   интерлиньяжа плюс запас шрифта над капителью, под подписью — почти
   ничего; из-за этой асимметрии отцентрованный по боксам текст читается
   ниже оси. Поднимаем пару на половину разницы — это 0.25 кегля заголовка.

   Так буквы встают в габарит форм симметрично: от верха форм до верха
   заглавной столько же, сколько от низа подписи до низа форм. Вплотную к
   краям текст не дотянется — его буквы занимают 116px против 132px у форм,
   и этот запас честно делится пополам, по 8px сверху и снизу.

   Сдвиг через position, а не через margin: margin менял бы высоту строк
   сетки, а от неё зависит само центрирование — поправка съедала бы себя.
   position: relative двигает только картинку, раскладка не шелохнётся,
   поэтому ось сходится и когда текст выше форм, и когда формы выше. */
.case-hero .case-hero__title,
.case-hero .case-hero__subtitle{
  position: relative;
  top: calc(var(--fs-h1) * -0.25);
}
/* Заголовок придвинут к подписи на пять пикселей. Двигается только он:
   подпись остаётся там же, где стояла, поэтому нижняя грань текста
   от низа форм не уезжает. */
.case-hero .case-hero__title{ top: calc(var(--fs-h1) * -0.25 + 5px); }
/* строка метрик: до линии стало на десять больше */
.case-hero .case-meta{ margin-top: 50px; }
@media (max-width: 700px){
  /* формы скрыты — без этого осталась бы пустая колонка и её отступ слева */
  .case-hero{ display: block; }
}
.case-hero__title{
  font-family: var(--font-display);
  font-size: var(--fs-h1);
  font-weight: 400;
  letter-spacing: -0.01em;
  /* строки заголовка делятся поровну, а не «длинная и одно слово» */
  text-wrap: balance;
}
.case-hero__subtitle{
  margin-top: 12px;
  font-size: var(--fs-lead);
  color: var(--muted);
  /* последняя строка не остаётся с одним словом; неразрывные пробелы
     после артиклей и предлогов ставит типографика, это — про остальное */
  text-wrap: pretty;
}
.case-meta{
  margin: 40px 0 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
  padding-top: 28px;
  border-top: 1px solid var(--line);
}
.case-hero--mark-n-post .case-meta{
  grid-template-columns: calc(2 * clamp(96px, 11vw, 132px) + clamp(28px, 3.5vw, 40px)) minmax(0, calc(320px - clamp(32px, 4.2vw, 60px))) minmax(0, 1fr);
  column-gap: clamp(32px, 4.2vw, 60px);
}
.case-meta dt{
  font-size: 13px;
  color: var(--muted);
  margin-bottom: 8px;
}
.case-meta dd{
  margin: 0;
  font-size: 15px;
  font-weight: 500;
}
/* Когда полей всего два, второе занимает оба оставшихся столбца. Иначе
   развёрнутое значение — у Sensotex это «Решение» целой фразой — рвётся
   на две строки в трети ширины и читается как обрубок. Позиции столбцов
   при этом не меняются: сдвигается только правый край второго поля. */
.case-meta > div:nth-child(2):last-child{ grid-column: span 2; }
.case-hero__media{
  margin-top: 40px;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--surface-soft);
}
/* Первая картинка страницы, идущая за строкой метрик, отбивается сильнее
   обычного: 40px тут читались как «прилипла» — строка метрик мелкая, и
   картинке нужен собственный воздух, чтобы начать новый смысловой блок.
   Селектор общего соседства (~), а не прямого (+): на части кейсов между
   метриками и картинкой стоит ещё кнопка Live site. */
.case-meta ~ .case-hero__media{ margin-top: 60px; }
/* height: auto is required, not optional: the width/height attributes on the
   <img> act as a presentational hint, so scaling the width alone leaves the
   old pixel height in place and squashes the picture */
.case-hero__media img{ width: 100%; height: auto; display: block; }.case-hero__media--video{ aspect-ratio: 16 / 9; }
.case-hero__media--video iframe{ display: block; width: 100%; height: 100%; border: 0; }

.case-overview{
  padding: 80px 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 40px;
  border-top: 1px solid var(--line);
}
/* Линия-разделитель не нужна, когда блок стоит сразу после медиа или хиро:
   в этих случаях выше уже есть своя граница (линия case-meta или край
   картинки), и вторая читается как случайно оставленное правило.
   --no-border — для случаев, когда блок вклинивается между картинками. */
.case-hero + .case-overview,
.case-overview--no-border{ border-top: 0; padding-top: 0; }
/* То же основание, что и выше, но отступ сохраняем: у превью сайта снизу
   свой край рамки, вторая линия под ним читается как лишняя. Воздух между
   ними при этом нужен — блок начинает новую мысль. */
.site-preview-wrap + .case-overview{ border-top: 0; padding-top: 60px; }
.site-preview-wrap + .case-overview.case-overview--balanced-preview-gap{ padding-top: 0; }
.case-overview--three{ grid-template-columns: repeat(3, 1fr); }
/* Метка блока живёт по тем же правилам, что и остальные метки на кейсе
   (case-meta dt, case-story__label): 13px, обычное начертание, серый.
   font-weight обязателен: у h3 браузерный дефолт 700, и без сброса
   заголовок выпадал из системы — единственный жирный среди меток. */
.case-overview h3{
  font-size: 13px;
  font-weight: 400;
  color: var(--muted);
  margin-bottom: 14px;
}
/* Описательный абзац — базовый размер текста, как в insight-grid.
   Раньше стоял --fs-lead (20px), из-за чего два одинаковых по смыслу блока
   на одной странице набирались разным кеглем. */
.case-overview p{
  font-size: var(--fs-body);
  line-height: 1.55;
}
.case-overview .spec-chips{ margin-top: 16px; }

.case-gallery{
  padding-bottom: 80px;
  display: grid;
  gap: 24px;
}
.case-gallery img{
  width: 100%;
  height: auto;
  border-radius: var(--radius-lg);
}
.case-gallery--two{ grid-template-columns: 1fr 1fr; }.case-gallery--tight-bottom{ padding-bottom: 80px; }
/* Идущие подряд галереи — это одна сетка, разбитая на секции только ради
   разной раскладки строк (2 в ряд / во всю ширину). Поэтому по вертикали
   между ними тот же шаг, что и между картинками внутри строки (gap: 24px),
   иначе ряды одного набора разъезжаются на 104px и ритм рвётся.
   Полные 80px остаются только у последней — до следующей секции. */
.case-gallery:has(+ .case-gallery){ padding-bottom: 0; }

/* ---------- case story (benchmark / hypothesis / journeys / wireframes) ---------- */
.case-story{
  padding: 80px 0;
  border-top: 1px solid var(--line);
}
.case-story__label{
  font-size: 13px;
  color: var(--muted);
  margin-bottom: 16px;
}
.case-story__grid{
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 24px 56px;
  align-items: start;
}
.case-story__title{
  font-family: var(--font-display);
  font-size: var(--fs-h2);
  font-weight: 500;
  line-height: 1.25;
  letter-spacing: -0.01em;
}
.case-story__intro{
  font-size: var(--fs-lead);
  line-height: 1.55;
  color: var(--muted);
}
/* Подпись к ряду картинок: та же метка, что открывает блоки-истории.
   grid-column растягивает её на всю сетку, иначе она встала бы первой
   ячейкой ряда и сдвинула картинки. */
.case-gallery__label{
  grid-column: 1 / -1;
  margin-bottom: 4px;
  font-size: 13px;
  color: var(--muted);
}

/* Плашка с итогами теста: тёмная, чтобы цифры читались как результат, а не
   как ещё один абзац. Цвета — footer-токены, те же, что у подвала. */
.metric-board{
  margin-top: 48px;
  display: grid;
  /* колонки по числу метрик: auto-fit схлопывает лишние треки, поэтому
     плашка не рассыпается, если метрик станет три или пять */
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 32px 24px;
  padding: 44px 40px;
  border-radius: var(--radius-lg);
  background: var(--footer);
}
.metric-board__item{ min-width: 0; }
.metric-board__item b{
  display: block;
  font-family: var(--font-display);
  font-size: clamp(32px, 3.4vw, 44px);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--surface);
}
.metric-board__item span{
  display: block;
  margin-top: 12px;
  font-size: 14px;
  line-height: 1.45;
  color: var(--footer-muted);
}

/* Без линии сверху: разделители в системе отбивают блоки друг от друга,
   а сетка инсайтов — часть того же блока, что и заголовок над ней.
   Разделяет их только воздух. */
.insight-grid{
  margin-top: 48px;
  padding-top: 32px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 32px 40px;
}
/* селектор по колонке, а не по классу .insight: в разметке колонки размечены
   как обычные div (им нужен только .reveal), поэтому правило на .insight
   не применялось и подзаголовок стоял вплотную к тексту — 0px вместо 14px */
.insight-grid h3{ font-size: 13px; color: var(--muted); margin-bottom: 14px; font-weight: 400; }
.insight-grid p{ font-size: var(--fs-body); line-height: 1.55; }
/* тот же шаг от заголовка секции до её вводного абзаца, что и от подзаголовка
   до текста внутри колонки — раньше стоял инлайном на самих страницах */
.case-story__title + .case-story__intro{ margin-top: 14px; }

/* journeys variant: copy + two step lanes on the left, a media frame on the right */
.case-story--journeys .case-story__grid{ grid-template-columns: minmax(0, 1fr) minmax(280px, 0.86fr); }
.journeys{
  margin-top: 48px;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 32px;
  max-width: 420px;
}
.journey-lane h3{ font-size: 13px; color: var(--muted); font-weight: 400; }
.journey-lane h3 span{ display: block; margin-top: 4px; font-size: var(--fs-body); color: var(--ink); }
.journey-steps{
  list-style: none;
  margin: 16px 0 0;
  padding-left: 16px;
  border-left: 1px solid var(--line);
  display: grid;
  gap: 10px;
}
.journey-step{ font-size: var(--fs-body); line-height: 1.4; }
.journeys-visual{
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--surface-soft);
  align-self: stretch;
}
.journeys-visual img{ width: 100%; height: 100%; object-fit: cover; display: block; }

/* wireframes variant: horizontal-scroll track of phone mocks, arrow-linked */
.wireframes-scroll{
  margin-top: 48px;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
}
.wireframes-scroll::-webkit-scrollbar{ display: none; }
.wireframes-track{ display: flex; align-items: flex-start; width: max-content; }
.wireframe-item{ position: relative; flex: 0 0 146px; width: 146px; text-align: center; }
.wireframe-item:not(:last-child){ margin-right: 64px; }
.wireframe-item h3{ font-size: var(--fs-body); font-weight: 500; margin-bottom: 12px; }
.wireframe-item img{
  display: block;
  width: 146px;
  height: 353px;
  margin: 0 auto;
  object-fit: cover;
  border-radius: 16px;
  border: 1px solid var(--line);
}
.wireframe-item__arrow{
  position: absolute;
  top: 190px;
  left: calc(100% + 21px);
  width: 22px;
  height: 22px;
  color: var(--tone-soft);
}

/* Воздух над линией и под ней должен читаться одинаково. Снизу линии стоят
   те же 80px, но заголовок «Другие проекты» набран крупно (--fs-h1) и его
   полулидинг добавляет сверху ещё ~22px пустоты — оптически низ выглядел
   просторнее верха. Компенсируем это margin'ом над линией, считая пустоту
   по метрикам шрифта: половина интерлиньяжа минус расстояние до капители.
   Множитель 0.75 — это line-height 1.5, поделённый пополам. */
/* Воздух вокруг линии — 120px с обеих сторон. Снизу это padding секции,
   сверху складывается из 80px, которые несёт предыдущий блок, и 40px
   собственного margin: до линии и после неё получается поровну.
   К margin добавлена компенсация полулидинга заголовка (он набран --fs-h1
   и его верхняя пустота зрительно увеличивала нижнюю половину). */
.case-other{
  margin-top: calc(40px + 0.75 * var(--fs-h1) - var(--cap-k) * var(--fs-h1));
  padding: 120px 0 96px;
  border-top: 1px solid var(--line);
}
/* Браузеры с text-box-trim сами срезают полулидинг — остаётся чистые 40px */
@supports (text-box-trim: trim-start){
  .case-other{ margin-top: 40px; }
  .section-head h2{ text-box-trim: trim-start; text-box-edge: cap alphabetic; }
}.case-other__grid{ margin-top: 40px; padding-bottom: 0; }

/* ---------- about page ----------
   Reference /about: narrow label column on the left (16px/500), content on the
   right (40px/500, line-height 56). Rows separated by a hairline. */
.about-page{
  --page-x: clamp(20px, 6.25vw, 80px);
  padding-bottom: 96px;
}

/* portrait set inline in the headline */
.inline-portrait{
  display: inline-block;
  vertical-align: middle;
  width: 1.15em;
  height: 1.15em;
  border-radius: 999px;
  object-fit: cover;
  object-position: 50% 32%;
  transform: translateY(-0.08em);
}

.about-intro__title{
  font-family: var(--font-display);
  font-size: var(--fs-about-lead);
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: -0.01em;
  max-width: 900px;
  color: var(--tone-soft);
  text-wrap: pretty;
}
/* Reference trick: same size and weight, only the colour changes — the leading
   clause stays black, the rest goes grey. */
.about-intro__title b,
.about-lead b{
  font-weight: 500;
  color: var(--ink);
}

.about-row{
  display: grid;
  grid-template-columns: minmax(0, 230px) 1fr;
  gap: 40px;
  padding: 56px 0;
  border-top: 1px solid var(--line);
  align-items: start;
}
/* Порядок важен: специфичность у обоих правил одинаковая, побеждает объявленное
   ниже. Пока это правило стояло выше .about-row, линия первого раздела
   упиралась в шапку, а верхний отступ не применялся. */
.about-row--first{ border-top: none; padding-top: 96px; }
/* Первый экран страницы направления собран из двух строк сетки.
   Строка с переключателем: метка и переключатель выравниваются по центру
   друг друга — раньше метка пыталась встать одновременно и по переключателю,
   и по крупному заголовку, и привязка получалась неверной. */
.about-row--switch{ align-items: center; padding-bottom: 40px; }
/* Строка с заголовком: линии и верхнего отступа нет — переключатель
   и вводный блок читаются как одна зона, а не два раздела. */
.about-row--intro{ border-top: none; padding-top: 0; }
/* min-width: auto у грид-элемента позволяет содержимому растягивать колонку:
   раскрытая лента обложек раздувала строку до своей полной ширины */
.about-row__body{ min-width: 0; }
.about-row__label{
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 500;
  line-height: 1.4;
  color: var(--ink);
}
/* Optical alignment of the row label with the first line of its body.
   `align-items: start` lines up the *boxes*, but the ink inside a box starts
   lower the larger the type: half-leading and the ascender gap both scale with
   font-size. Next to a 40px lead line the 16px label therefore floats ~9px too
   high. For Manrope the distance from box top to cap height is
   lineHeight/2 - 0.3475 x fontSize (measured in the browser, not guessed), so
   the label is pushed down by the difference between the two. Both terms are
   expressed in tokens: change the lead size and the shift follows by itself.
   Only rows whose body opens with a lead line need it — everywhere else the
   difference is under 1px. */
.about-row--lead .about-row__label{
  margin-top: calc(0.7 * var(--fs-about-lead) - var(--cap-k) * var(--fs-about-lead) - 5.64px);
}
/* When the browser can trim the leading itself, the measured constant is not
   needed: both boxes start at cap height and plain `start` alignment is exact. */
@supports (text-box-trim: trim-start){
  .about-row--lead .about-row__label{ margin-top: 0; }
  /* trim both sides of the pair, and only inside a lead row: trimming the label
     alone would lift it off every other row, where the two already agree */
  .about-row--lead .about-row__label,
  .about-row--lead .about-lead,
  .about-row--lead .about-intro__title{
    text-box-trim: trim-start;
    text-box-edge: cap alphabetic;
  }
}
.about-lead{
  font-family: var(--font-display);
  font-size: var(--fs-about-lead);
  font-weight: 400;
  line-height: 1.4;
  /* 800, а не 780: строке «6+ лет на senior- / руководящих позициях»
     нужно 788px, и на прежней ширине она разрывалась ради восьми пикселей */
  max-width: 800px;
  color: var(--tone-soft);
  text-wrap: pretty;
}
.about-note + .about-note{ margin-top: 12px; }
/* Тот же приём, что в `.about-lead b` и `.about-notes b`: ключевая часть
   фразы уходит в чёрный, остальная строка остаётся серой. */
.about-note b{ font-weight: 500; color: var(--ink); }
/* верхний отступ нужен, только когда над абзацем что-то есть: если он
   открывает раздел (как в «Локации»), 24px опускали текст ниже заголовка
   слева, и строка переставала начинаться с ним на одном уровне */
.about-row__body > .about-note:first-child{ margin-top: 0; }
.about-note{
  margin-top: 24px;
  max-width: 640px;
  font-size: var(--fs-body);
  line-height: 1.55;
  color: var(--muted);
  text-wrap: pretty;
}

/* experience */
.about-list{ margin-top: 40px; display: flex; flex-direction: column; }
/* first block in a row starts flush with its label */
.about-row__body > .about-list:first-child{ margin-top: 0; }
.about-list li{
  display: grid;
  grid-template-columns: minmax(0, 130px) 1fr;
  gap: 24px;
  padding: 16px 0;
  border-top: 1px solid var(--line);
  font-size: var(--fs-body);
  line-height: 1.5;
}
.about-list li:first-child{ border-top: none; padding-top: 0; }/* A row hidden with hidden="until-found" keeps its box: the browser skips the
   contents, not the padding and the hairline, so it would leave an empty
   striped band behind. Zeroing both collapses it to nothing while the row stays
   reachable by find-in-page. */
.about-list li[data-extra][hidden]{
  padding: 0;
  border-top: 0;
}

/* «Показать все» under a shortened list. The hidden rows carry
   hidden="until-found", so find-in-page still reaches them and the browser
   opens the list by itself; browsers without that support treat the attribute
   as a plain `hidden` and the button remains the way in. */
.list-more{
  margin-top: 20px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--muted);
  cursor: pointer;
  /* то же, что у .dcard: своя transition обязана нести и появление */
  transition: color .3s var(--ease),
              opacity .8s var(--ease) calc(var(--i, 0) * 110ms),
              transform .8s var(--ease) calc(var(--i, 0) * 110ms);
}
.list-more:hover{ color: var(--ink); }
/* стрелка из спрайта смотрит вправо — поворачиваем её вниз, а в раскрытом
   состоянии вверх; размер меньше обычного, чтобы не спорить с подписью */
.list-more .ic{ width: 14px; height: 14px; transition: transform .3s var(--ease); }
.list-more .list-more__chev{ transform: rotate(90deg); }
.list-more[aria-expanded="true"] .list-more__chev{ transform: rotate(-90deg); }
.list-more:hover .list-more__chev{ transform: rotate(90deg) translateX(2px); }
.list-more[aria-expanded="true"]:hover .list-more__chev{ transform: rotate(-90deg) translateX(2px); }
/* a shortened list ends on a row, so the button needs the breathing room that
   the list's own bottom padding would otherwise provide */
.about-list + .list-more{ margin-top: 8px; }

.about-list__when{ color: var(--muted); }
.about-list__what{ color: var(--muted); }
.about-list__what b{ font-weight: 500; color: var(--ink); }

/* expertise: two tracks side by side, and below them — separated by a rule —
   what both tracks share. The split is what the reader sees first; the shared
   band is the point, so it spans the full width instead of hiding in a column. */
.expertise{
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 40px;
  max-width: 780px;
}.about-tags__line{ max-width: 780px; font-size: var(--fs-body); line-height: 1.55; color: var(--muted); }
/* Компетенции чипсами — те же `.chip` с фоном, что под кейсами. */
.tag-chips{ margin: 0; padding: 0; list-style: none; display: flex; flex-wrap: wrap; gap: 8px; max-width: 780px; }
.tag-chips .chip{ background: var(--surface); }
/* акцентный чипс — черный контур вместо заливки: в ряду серых пилюль хватает
   одного контраста рамки, цвет здесь звучал бы громче остальной страницы */
.tag-chips .chip--accent{ border-color: var(--ink); color: var(--ink); }

/* numbers */
.about-facts{
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 32px;
}
/* align-content: start обязателен. Без него строки внутреннего грида тянутся
   до высоты самой длинной карточки ряда, и описания под короткими числами
   уезжают вниз на 36 px. */
.about-facts li{ display: grid; align-content: start; gap: 20px; }
.about-facts b{
  font-family: var(--font-display);
  font-size: clamp(30px, 2.8vw, 38px);
  font-weight: 300;
  line-height: 1;
  letter-spacing: -0.01em;
}
.about-facts span{ font-size: var(--fs-body); line-height: 1.55; color: var(--muted); }
/* the tag line may wrap between tags, never inside one */
.about-facts i{ font-style: normal; color: var(--muted); }
.about-facts i > span{ white-space: nowrap; }

.about-notes{ margin-top: 32px; display: grid; gap: 20px; max-width: 780px; }
.about-notes p{ font-size: var(--fs-body); line-height: 1.55; color: var(--muted); }
/* тот же прием, что в `.about-lead b`: смысловая часть уходит в черный,
   остальная строка остается серой — размер и начертание почти не меняются */
.about-notes b{ font-weight: 500; color: var(--ink); }

/* Три компетенции направления. Значения приходят из общего реестра, поэтому
   разметка одна на три страницы. Маркеров нет намеренно: список держится
   строчным ритмом, как в карточках направлений. */
.direction-skills{
  margin: 24px 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.direction-skills li{
  font-size: var(--fs-body);
  line-height: 1.55;
  color: var(--muted);
}

/* fact sheet: skills / tools / location */
.about-spec{ margin: 0; display: grid; gap: 20px; }
.about-spec > div{
  display: grid;
  grid-template-columns: minmax(0, 150px) 1fr;
  gap: 24px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--line);
}
.about-spec > div:last-child{ border-bottom: none; padding-bottom: 0; }
.about-spec dt{ font-size: var(--fs-body); line-height: 1.5; color: var(--muted); }
.about-spec dd{ margin: 0; font-size: var(--fs-body); line-height: 1.5; }
.spec-chips{ display: flex; flex-wrap: wrap; gap: 8px; }

/* process */
/* ---------- DESIGN / WORKS lockup ----------
   Ported from V1: the word morphs into WORKS as the projects section comes up,
   and the two shapes wipe out ahead of it. Sizes are V1 measurements (word 176,
   forms 132, gap 40); colour and family come from the V2 tokens. */
.lockup{
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: clamp(20px, 4vw, 40px);
  padding: 0 0 var(--stack-gap);
}
/* Values lifted from V1 as it runs live: Helvetica Neue at weight 100, 176px on
   a 132px line, colour #434343. Manrope has no 100, so the family comes across
   with the word — this is the one place on the site that is not set in Manrope,
   and that is deliberate: the thinness is the whole point of the mark. */
.lockup__word{
  position: relative;
  isolation: isolate;
  flex: 0 0 auto;
  height: var(--lockup-size);
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: var(--lockup-word);
  font-weight: 100;
  line-height: .75;
  letter-spacing: normal;
  color: var(--mark);
}/* WORKS is the longer word: the heading keeps room for it so the shapes do not
   jump sideways halfway through the morph */
.lockup__word::after{
  content: "WORK";
  display: block;
  height: 0;
  overflow: hidden;
  visibility: hidden;
}

.lockup__forms{
  display: flex;
  align-items: flex-start;
  gap: clamp(20px, 3vw, 40px);
  pointer-events: none;
}.lockup__frame--flip.is-flipping{ transform: rotateY(90deg); }
.lockup__frame--spin.is-flipping-reverse{ transform: rotateY(-90deg); }
.lockup__form{
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

@media (prefers-reduced-motion: reduce){}

/* ============================================================
   Figma: Home / Approved hero + Directions (118:1118)
           Portfolio / Works catalog (125:146)
           Build / Works & Directions / Components (122:87)
   Значения сняты из файла, а не подобраны на глаз.
   ============================================================ */

/* Контейнер по сетке макета: контент 1248 при полях 96 на 1440.
   Обычный .wrap даёт 1320 и поля по 118 — на новых блоках это уводило всё
   вправо на 22px против Figma. */
.wrap--grid8{
  --grid8-x: clamp(20px, 6.667vw, 96px);
  max-width: calc(1248px + var(--grid8-x) * 2);
  padding-left: var(--grid8-x);
  padding-right: var(--grid8-x);
}

.icon-sprite{ position: absolute; width: 0; height: 0; overflow: hidden; }

/* Одна иконка на весь сайт. Направлена вправо во всех состояниях —
   поворотов у неё нет ни в одном компоненте нового макета. */
.ic{
  flex: 0 0 auto;
  display: block;
  color: currentColor;
  transition: transform .18s var(--ease);
}

/* ---------- Inline link: «Подробнее», «Подробнее обо мне», «Открыть кейс» ----------
   Канонический компонент из Figma (108:24). Текст остаётся ink во всех
   состояниях; двигаются только стрелка и линия, и двигаются асинхронно. */
.ilink{
  display: inline-flex;
  flex-direction: column;
  align-items: stretch;
  width: max-content;
  color: var(--ink);
}
.ilink__row{
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 500;
  line-height: 21px;
  white-space: nowrap;
}
/* Стрелка выравнивается по оптической середине надписи, а не по середине
   строки. `align-items: center` ставит её по центру инлайнового бокса, то есть
   на 0.5px выше центра заглавных и на 1.7px выше центра строчных. Надписи здесь
   почти целиком строчные («Подробнее», «Открыть кейс»), поэтому глаз читает
   середину по ним. Сдвигаем на 1px вниз — ровно между двумя серединами.
   Через margin, а не transform: transform занят сдвигом стрелки на hover. */
.ilink .ic{ width: 18px; height: 18px; margin-top: 2px; }
/* линия рисуется на всю ширину строки, то есть до правого края стрелки */
/* Линия появляется только по наведению и выезжает слева направо. Постоянной
   серой подложки нет намеренно: на лаймовой плашке она смотрелась грязно. */
.ilink__rule{
  position: relative;
  height: 1px;
}
.ilink__rule::after{
  content: "";
  position: absolute;
  inset: 0;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .42s var(--ease) .04s;
}
.ilink:hover .ic,
.ilink:focus-visible .ic{ transform: translateX(2px); }
.ilink:hover .ilink__rule::after,
.ilink:focus-visible .ilink__rule::after{ transform: scaleX(1); }
.ilink:active .ic{ transform: translateX(1px); }
.ilink:active .ilink__rule::after{ opacity: .75; }
.ilink:focus-visible{ outline: 2px solid var(--ink); outline-offset: 4px; }

/* ---------- Первый экран главной ---------- */
.home-hero{
  display: grid;
  grid-template-columns: minmax(0, 760fr) minmax(0, 434fr);
  column-gap: clamp(24px, 3.75vw, 54px);
  /* 50px сверху и между рядами — решение 27.08: прежние 79/80 читались
     как слишком просторные. В адаптиве те же отступы равны 40px. */
  row-gap: 50px;
  /* 112px снизу — системный отступ между блоками: два соседних `.about-row`
     дают 56 + 56, столько же стоит снизу у самих «Направлений». */
  padding: 50px 0 112px;
}
/* вертикальная подпись слева от портрета: контейнер растянут ровно по
   высоте .author-copy — от верхней кромки блока автора до нижней кромки
   ссылки "Подробнее обо мне". .author-copy — ближайший позиционированный
   предок. */
.home-hero__spine{
  position: absolute;
  top: 0;
  bottom: 0;
  /* сдвиг влево на ширину портрета + тот же gap, что был между подписью
     и портретом в старой flex-раскладке — визуально подпись остаётся
     на прежнем месте */
  left: 0;
  right: auto;
  width: 36px;
  display: flex;
  align-items: stretch;
  justify-content: center;
}
/* Буквы разнесены по всей высоте контейнера, а не идут естественной длиной
   слова: раньше слово было длиннее блока и вылезало за верхнюю кромку.
   `text-align-last: justify` тут не работает — в слове нет пробелов, строку
   некуда разбивать, поэтому каждая буква вынесена отдельным span и
   раздвигается через `justify-content`. В `writing-mode: vertical-rl`
   главная ось строчного flex идет сверху вниз, поэтому распределение
   получается вертикальным; `height: 100%` дает flex определенную главную
   ось — без нее контейнер считает высоту по содержимому и растяжка не
   срабатывает. */
.home-hero__spine-text{
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  height: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-family: var(--font-display);
  /* Кегль взят чуть меньше точного вписывания: естественная длина стопки
     букв должна быть КОРОЧЕ контейнера, тогда остаток добирает
     `justify-content: space-between` и слово всегда заполняет высоту ровно.
     При большем кегле сжать нечем — space-between только раздвигает, и
     буквы вылезали за верхнюю кромку. Множитель vw повторяет тот, что задан
     портрету: высота контейнера равна высоте картинки, поэтому кегль
     обязан ехать вместе с ней. */
  font-size: clamp(20px, 1.8vw, 26px);
  font-weight: 500;
  /* в вертикальном письме интерлиньяж становится толщиной колонки:
     36 px держит ту же ширину подписи, что и в Figma, независимо от кегля */
  line-height: 36px;
  letter-spacing: normal;
  color: var(--muted);
  white-space: nowrap;
}
.home-hero__author{
  grid-column: 1;
  grid-row: 1;
  /* точка отсчета для вертикальной подписи: она встает по левому краю
     блока, а не отмеряется от текстовой колонки. Поэтому ширина портрета
     может меняться, подпись остается на месте. */
  position: relative;
  display: flex;
  gap: clamp(20px, 2.78vw, 40px);
  /* stretch внутри блока: текстовая колонка тянется на высоту портрета,
     и «Подробнее обо мне» встает по нижней кромке — на одну линию
     с низом портрета и вертикальной подписи */
  align-items: stretch;
  /* но сам блок не тянется на высоту ряда: ее задает блок метрик справа
     (224px), и без этого колонка растягивалась под него, а ссылка уезжала
     ниже портрета */
  /* тянемся на высоту ряда: ее задает блок метрик справа, и оба блока
     верхушки получают одинаковый габарит */
  align-self: stretch;
  /* левый край блока совпадает с левым краем превью под ним; место слева
     занимает вертикальная подпись */
  margin-left: 0;
  padding-left: calc(36px + clamp(6px, 0.8vw, 12px));
}
.home-hero__metrics{ grid-column: 2; grid-row: 1; }
.home-hero__featured{ grid-column: 1; grid-row: 2; }
.home-hero__index{ grid-column: 2; grid-row: 2; }

/* портрет и курсор */
.author-portrait{
  position: relative;
  flex: 0 0 auto;
  /* уменьшено 27.08: портрет был выше текстовой колонки и не сходился
     с ней по нижней кромке */
  /* Картинка квадратная и занимает 86.15% ширины блока, остаток справа
     держит место под пузырь «Hi!». Ширина подобрана так, чтобы высота
     картинки совпала с высотой всего блока автора — от верхней кромки
     до строки «Подробнее обо мне». */
  width: clamp(190px, 16vw, 230px);
  /* не растягивать вместе с колонкой: у пузыря позиция в процентах
     от высоты контейнера, при растяжении он уезжал бы вниз */
  align-self: flex-start;
}
.author-portrait__img{
  display: block;
  width: 86.15%;
  height: auto;
  aspect-ratio: 1;
  border-radius: var(--radius-lg);
  object-fit: cover;
}
/* Курсор с «Hi!» перенесён из V1 как есть: группа не пульсирует масштабом,
   а плавно уезжает по диагонали и возвращается — 12s, ease-in-out, ±14px.
   Сам курсор рисуется clip-path, а не svg, и наклонён на -14°, как там. */
.author-portrait__hi{
  position: absolute;
  left: 76.54%;
  top: 60.27%;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  pointer-events: none;
  animation: home-hi-float 12s cubic-bezier(.45, 0, .55, 1) infinite;
  will-change: transform;
}
.author-portrait__cursor{
  width: 19px;
  height: 20px;
  background: var(--ink);
  clip-path: polygon(0 0, 100% 40%, 44% 55%, 32% 100%);
  transform: rotate(-14deg);
  transform-origin: 50% 50%;
}
.author-portrait__label{
  display: inline-flex;
  align-items: center;
  min-height: 23px;
  padding: 5px 9px 6px;
  border-radius: 5px;
  background: var(--ink);
  color: var(--surface);
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0;
  white-space: nowrap;
}

/* текстовая колонка автора */
.author-copy{
  /* точкой отсчета для вертикальной подписи теперь служит сам блок автора,
     поэтому колонка больше не позиционированный предок */
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
/* ссылка прижата к низу колонки — по макету она стоит на одной линии
   с нижней кромкой портрета, а не сразу под описанием */
.author-copy > .ilink{ margin-top: auto; }
.author-copy__inner{ position: relative; display: flex; flex-direction: column; gap: 8px; }
.author-copy__eyebrow{
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 600;
  line-height: 18px;
  text-transform: uppercase;
  color: var(--muted);
}
.author-copy__role{
  font-family: var(--font-display);
  /* 40 px ровно на 1440 и пропорционально ниже: иначе «Дизайнер бренда»
     ломается на две строки, когда колонка сужается */
  font-size: clamp(33px, 2.78vw, 40px);
  font-weight: 500;
  line-height: 1.1;
  color: var(--ink);
}
.author-copy__about{
  font-size: 14px;
  line-height: 21px;
  color: var(--muted);
}
/* Заголовок сделан строчным внутри обёртки: лейблы дисциплин текут сразу за его
   последней строкой, оставаясь при этом снаружи h1 — доступное имя заголовка
   не засоряется. */
.author-copy__headline{
  display: block;
  /* та же метрика строки, что у заголовка: строка, на которую переносятся
     лейблы, должна быть той же высоты, иначе она наезжает на текст выше */
  font-size: clamp(33px, 2.78vw, 40px);
  line-height: 1.1;
}
.author-copy__headline .author-copy__role{ display: inline; }

/* Лейблы дисциплин текут за последней строкой заголовка, а не стоят абсолютом.
   Абсолют с фиксированным top держался ровно на одной ширине: стоило колонке
   сузиться, заголовок перерастал и они на него наезжали. В потоке они сами
   переносятся общей строкой под заголовок, когда места не остаётся, — ровно то
   поведение, что описано в спецификации для узкого экрана. */
.author-labels{
  display: inline-flex;
  gap: 12px;
  /* чуть дальше от последнего слова заголовка */
  margin-left: 9px;
  vertical-align: 12px;
  /* линия сверху висит не на контейнере, а на каждом лейбле отдельно —
     иначе она тянется сквозь промежуток между ними */
  /* сбрасываем наследование от 40-пиксельного заголовка */
  font-size: 10px;
  font-weight: 500;
  line-height: normal;
  white-space: nowrap;
}
/* padding-top равен gap: воздух над текстом и под ним одинаковый */
.author-labels__item{
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding-top: 3px;
  border-top: 1px solid var(--line);
}
.author-labels__item span{
  font-family: var(--font-display);
  font-size: 10px;
  font-weight: 500;
  color: var(--muted);
  white-space: nowrap;
}
.author-labels__item i{ display: block; height: 1px; background: var(--line); }

/* метрики: карточки с общей границей за счёт перекрытия в 1px */
.metrics{ display: flex; flex-direction: column; width: 100%; }
/* relative — точка отсчета для звезды: она садится на стык пары и полосы */
.metrics__pair{ position: relative; display: flex; margin-bottom: -1px; }
.metric{
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  /* Воздух сверху и снизу 20px по факту: 19px поля плюс пиксель рамки.
     Было 26px, пробовали 11px по нижним строкам — остановились на 20.
     Отдельная минимальная высота не нужна: плашка обнимает текст. */
  padding: 19px 24px;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface);
}
.metrics__pair .metric{ flex: 1 1 0; min-width: 0; }
.metrics__pair .metric:first-child{ margin-right: -1px; }
/* Две равные колонки вместо space-between: при space-between «до 16» уезжало
   к правому краю карточки и не вставало под «+25%». Горизонтальный padding
   снят с самой полосы и перенесен на колонки — тогда левый край второй
   колонки совпадает с левым краем второй карточки пары, и обе правые
   метрики стоят на одной вертикали. */
.metrics__band{
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  padding: 19px 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface);
}
.metrics__band > div{ display: flex; flex-direction: column; gap: 4px; padding: 0 24px; }
.metric__value,
.metrics__band b{
  font-family: var(--font-display);
  font-size: 30px;
  font-weight: 600;
  line-height: 36px;
  color: var(--ink);
}
.metric__label,
.metrics__band span{
  font-size: 14px;
  line-height: 21px;
  color: var(--muted);
}
/* Звезда сидит ровно на пересечении швов: по горизонтали — стык двух карточек
   пары (всегда 50%, карточки равны), по вертикали — нижняя кромка пары.
   Раньше стояли подобранные под одну ширину `left: 44.93%` и `top: 90px`:
   на другой ширине и при выросших по высоте карточках звезда уезжала.
   Смещение на половину размера сделано через margin, а не translate —
   transform занят пульсацией и затер бы сдвиг. */
.metrics__star{
  position: absolute;
  left: 50%;
  bottom: 0;
  margin-left: -21.5px;
  margin-bottom: -21.5px;
  width: 43px;
  height: 43px;
  color: var(--ink);
  animation: pulse 2400ms var(--ease) infinite;
}
@keyframes pulse{
  0%, 100%{ transform: scale(.98); }
  50%{ transform: scale(1.04); }
}

/* ---------- Большая карточка активного кейса ---------- */
.featured{
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 760 / 340;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--surface-soft);
  /* transform здесь занят нажатием (.995 за 120 мс), поэтому появление идёт
     только прозрачностью, а стартовый сдвиг из `.reveal` снят ниже — иначе
     карточка прыгала бы на месте в момент показа */
  transition: transform .12s var(--ease),
              opacity .8s var(--ease) calc(var(--i, 0) * 110ms);
}
.featured.reveal{ transform: none; }
.featured.reveal.is-visible{ transform: none; }
.featured__media{ position: absolute; inset: 0; }
.featured__img{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transform: scale(1.02);
  transition: opacity .32s var(--ease), transform .32s var(--ease);
}
.featured__img--top{ object-position: center top; transform-origin: center top; }
.featured__img.is-current{ opacity: 1; transform: scale(1); }
.featured__img.is-leaving{ opacity: 0; transform: scale(.99); }
.featured:hover .featured__img.is-current{ transform: scale(1.02); }
.featured:active{ transform: scale(.995); }

/* Три зоны, а не space-between: боковые колонки равной ширины (1fr) держат
   направление ровно по центру плашки независимо от длины названия работы.
   Номер и название лежат в одной ячейке и читаются как пара — при
   space-between название уезжало в середину свободного места и «отрывалось»
   от номера. */
.featured__caption{
  position: absolute;
  left: 24px;
  right: 24px;
  bottom: 24px;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 24px;
  height: 62px;
  /* было 16px — стрелка «Открыть кейс» упиралась в скругление */
  padding: 0 28px;
  border-radius: var(--radius-md);
  background: var(--surface);
  box-shadow: 0 18px 40px var(--shadow-soft);
  transition: transform .32s var(--ease);
}
/* baseline, а не center: цифра мельче названия, и по центру она вставала
   оптически выше его базовой линии */
.featured__head{
  display: flex;
  align-items: baseline;
  gap: 14px;
  min-width: 0;
}
.featured:hover .featured__caption{ transform: translateY(-6px); }
/* ширину не задаём: номер стоит вплотную к названию через gap родителя,
   как в строках списка справа */
.featured__num{
  flex: 0 0 auto;
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 600;
  line-height: 18px;
  color: var(--muted);
  transition: color .32s var(--ease);
}
.featured__title{
  min-width: 0;
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 500;
  line-height: 27px;
  color: var(--ink);
  white-space: nowrap;
}
/* auto-ширина: колонка центрируется сеткой, фиксированные 230px смещали
   направление вправо от настоящего центра плашки */
.featured__type{
  font-size: 12px;
  line-height: 18px;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--muted);
  transition: color .32s var(--ease);
}
.featured__caption .ilink{ justify-self: end; }
.featured:hover .featured__num,
.featured:hover .featured__type{ color: var(--ink); }
.featured:focus-visible{ outline: 2px solid var(--ink); outline-offset: 2px; }

/* ---------- Индекс избранных работ ---------- */
.cindex{ display: flex; flex-direction: column; gap: 12px; width: 100%; }
.cindex__eyebrow{
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 600;
  line-height: 18px;
  text-transform: uppercase;
  color: var(--muted);
}
.cindex__rows{ display: flex; flex-direction: column; gap: 8px; }

.crow{
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 70px;
  /* Отступы неравные по числу, но равные на глаз: слева край упирается
     в текст номера, справа — в круг 48px, внутри которого стрелка 22px,
     то есть ещё 13px собственного воздуха. При одинаковых 16px слева
     читалось 17px, справа — 30px. 24 и 11 дают ровно 24 с обеих сторон. */
  padding: 0 11px 0 24px;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--surface);
  transition: background .32s var(--ease), border-color .32s var(--ease),
              opacity .8s var(--ease) calc(var(--i, 0) * 110ms),
              transform .8s var(--ease) calc(var(--i, 0) * 110ms);
}
.crow__num{
  width: 24px;
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 600;
  line-height: 18px;
  color: var(--muted);
  transition: color .32s var(--ease);
}
.crow__title{
  /* Название может переноситься в тесной колонке; зазор до типа сохраняется. */
  flex: 1 1 auto;
  min-width: 0;
  margin-right: 16px;
  font-family: var(--font-display);
  /* На 1180–1400 строка кейса стоит в узкой правой колонке: длинное
     название ломалось на две строки, а короткие рядом оставались в одну —
     ряд разъезжался. Кегль идёт за шириной. */
  font-size: clamp(16px, 1.25vw, 18px);
  font-weight: 500;
  line-height: 27px;
  color: var(--ink);
}
.crow__type{
  /* Тип проекта занимает свою ширину без наложения на название. */
  flex: 0 0 auto;
  min-width: 0;
  white-space: nowrap;
  font-size: 12px;
  line-height: 18px;
  text-transform: uppercase;
  color: var(--muted);
  transition: color .32s var(--ease);
}
.crow__arrow{
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border-radius: var(--radius-pill);
  color: var(--ink);
  transition: background .32s var(--ease);
}
.crow__arrow .ic{ width: 22px; height: 22px; }
/* Единственный кликабельный элемент сайта, который раньше не отвечал вовсе */
.crow:hover .crow__arrow .ic{ transform: translateX(2px); }
/* выбранная строка: лаймовая заливка, вторичный текст уходит в ink */
.crow.is-selected{ background: var(--accent); border-color: var(--accent); }
.crow.is-selected .crow__num{ color: var(--ink); }
.crow.is-selected .crow__type{ color: var(--ink); }
.crow.is-selected .crow__arrow{ background: var(--accent); }
.crow:focus-visible{ outline: 2px solid var(--ink); outline-offset: 2px; }

/* ссылка в каталог */
.allworks{
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 62px;
  /* 11px внутреннего отступа строки кейса плюс её 1px границы: у CTA границы
     нет, поэтому её собственный отступ должен добрать этот пиксель. Тогда
     центр стрелки CTA стоит на той же вертикали, что центры стрелок трёх
     строк выше. Считаем по центрам стрелок, а не по краям кругов. */
  padding-right: 12px;
}
/* Текст отвечает на наведение той же линией, что и остальные ссылки сайта
   (.ilink): выезжает слева направо. Раньше реагировал только круг, и половина
   строки казалась неинтерактивной. */
.allworks__text{
  position: relative;
  padding-bottom: 4px;
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 500;
  line-height: 27px;
  color: var(--ink);
}
.allworks__text::after{
  content: "";
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  height: 1px;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .42s var(--ease) .04s;
}
.allworks:hover .allworks__text::after,
.allworks:focus-visible .allworks__text::after{ transform: scaleX(1); }
.allworks__circle{
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: var(--ink);
  transition: background .32s var(--ease), color .32s var(--ease), transform .32s var(--ease);
}
.allworks__circle .ic{ width: 22px; height: 22px; }
.allworks:hover .allworks__circle{ background: var(--ink); color: var(--accent); transform: scale(1.04); }
/* стрелка в круге доворачивается вверх, как у кнопок на обложках кейсов */
.allworks:hover .allworks__circle .ic{ transform: rotate(-45deg); }
.allworks:active .allworks__circle{ transform: scale(.96); }
.allworks:focus-visible{ outline: 2px solid var(--ink); outline-offset: 2px; }
/* Тот же акцентный CTA, что «Смотреть все работы», но внутри текстового
   блока: там он занимал колонку целиком и разносил текст и круг по краям.
   Здесь ширина по содержимому, круг сразу за надписью — читается кнопкой. */
.allworks--compact{
  width: max-content;
  max-width: 100%;
  justify-content: flex-start;
  gap: 20px;
  margin-top: 28px;
  padding-right: 0;
}

/* ---------- Направления ---------- */
.directions{ padding: 0 0 112px; }
.directions__head{ display: flex; flex-direction: column; gap: 20px; margin-bottom: 28px; }
.directions__title{
  font-family: var(--font-display);
  font-size: 34px;
  font-weight: 500;
  line-height: 1;
  color: var(--ink);
}
.directions__lead{ font-size: 18px; line-height: 1.4; color: var(--muted); }

.directions__grid{ position: relative; display: flex; }
.dcard{
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  flex: 1 1 0;
  min-width: 0;
  min-height: 400px;
  padding: 34px 24px 24px;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface);
  overflow: hidden;
  /* своя transition стирает ту, что задана в `.reveal`, поэтому появление
     перечислено здесь же — вместе с задержкой каскада */
  transition: background .32s var(--ease),
              opacity .8s var(--ease) calc(var(--i, 0) * 110ms),
              transform .8s var(--ease) calc(var(--i, 0) * 110ms);
}
/* соседние карточки делят границу: перекрытие в 1px, как в макете */
.dcard + .dcard{ margin-left: -1px; }
/* лаймовая зона растёт снизу вверх до 72px */
.dcard__fill{
  position: absolute;
  left: -1px;
  right: -1px;
  bottom: -1px;
  height: 0;
  background: var(--accent);
  transition: height .32s cubic-bezier(.22,1,.36,1);
  pointer-events: none;
}
.dcard:hover,
.dcard:focus-visible{ background: var(--tint-soft); }
.dcard:hover .dcard__fill,
.dcard:focus-visible .dcard__fill{ height: 72px; }
.dcard:focus-visible{
  outline: 2px solid var(--ink);
  outline-offset: -2px;
  background: var(--surface);
}
.dcard:focus-visible .dcard__fill{ height: 0; }
.dcard__title{
  font-family: var(--font-display);
  /* 26 px на широком экране; когда карточка сужается, кегль идёт следом —
     иначе заголовок из двух слов ломается на три-четыре строки */
  font-size: clamp(20px, 2.2vw, 26px);
  font-weight: 600;
  line-height: 1.23;
  color: var(--ink);
  /* Место под две строки держим всегда: «Бренд & коммуникация» переносится,
     остальные названия короче. Без резерва тексты в карточках начинались бы
     на разной высоте, и ряды не совпадали бы по горизонтали. */
  min-height: 2.46em;
  margin-bottom: 24px;
}
.dcard__row{
  display: flex;
  align-items: center;
  width: 100%;
  /* min-height, а не height: одной строки хватает всем пунктам, но если текст
     когда-нибудь перерастёт строку, он раздвинет ряд, а не наедет на линию */
  min-height: 56px;
  padding: 8px 0;
  border-bottom: 1px solid var(--line);
  font-size: 16px;
  line-height: 24px;
  color: var(--muted);
}
/* min-height, а не только flex-grow: на высокой карточке распорка и так
   растягивается, но когда карточка сжимается по содержимому (узкий экран),
   она схлопывается в ноль — и лаймовая заливка, которая всегда 72px от низа,
   наезжает на последнюю строку списка. Этот минимум держит воздух перед
   строкой действия при любой высоте карточки. */
.dcard__spacer{ flex: 1 1 auto; min-height: 28px; }
.dcard__action{
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  height: 24px;
  width: 100%;
}
/* звёзды сидят ровно на стыках карточек */
.directions__star{
  position: absolute;
  top: -22px;
  width: 43px;
  height: 43px;
  margin-left: -21.5px;
  color: var(--ink);
  animation: pulse 2400ms var(--ease) infinite;
  pointer-events: none;
}
.directions__star--one{ left: 33.33%; }
.directions__star--two{ left: 66.66%; }
/* на «Обо мне» карточек две, поэтому стык один — ровно посередине */
.directions__star--mid{ left: 50%; }/* На тач-экране наведения не бывает: браузер подставляет hover после тапа,
   и лаймовая заливка «залипает» на карточке, к тому же на сжатой карточке
   её фиксированные 72px наезжают на заголовок. Поэтому там её нет вовсе,
   а нажатие подтверждается подсветкой всей карточки. Кликабельность видна
   по строке «Подробнее» со стрелкой. */
@media (hover: none){
  .dcard__fill{ display: none; }
  .dcard:active{ background: var(--tint-soft); }
}/* 24px — левый внутренний отступ карточки: ссылка начинается по той же
   вертикали, что заголовок и «Подробнее» внутри плашки, а не по её краю */
.about-direction .link-arrow{
  margin-top: 20px;
  margin-left: 24px;
  align-self: start;
  /* по центру, а не по базовой линии: в строке рядом с текстом стоят чипс
     и стрелка — у них своя высота, и baseline поднимал стрелку над строкой */
  align-items: center;
  flex-wrap: wrap;
}
/* «CV» вынесено в чипс: это тип документа, а не часть названия роли.
   Мельче основного текста, чтобы не спорить с ним. */
.about-direction .link-arrow .chip{
  flex: 0 0 auto;
  font-size: 11px;
  letter-spacing: .04em;
  padding: 3px 10px;
}
/* формат и вес файла: по ссылке уходит PDF, и это стоит сказать до клика */
.link-arrow__meta{
  font-size: 12px;
  color: var(--muted);
  white-space: nowrap;
}/* ---------- Каталог «Портфолио» ---------- */
.portfolio__head{ padding-top: 73px; }
.portfolio__title{
  font-family: var(--font-display);
  font-size: 34px;
  font-weight: 500;
  line-height: 44px;
  color: var(--ink);
}
.portfolio__filters{
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 44px;
}
.pfilter{
  min-width: 150px;
  padding: 9px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 500;
  line-height: 22.5px;
  color: var(--muted);
  text-align: center;
  cursor: pointer;
  transition: color .3s var(--ease), border-color .3s var(--ease), background .3s var(--ease);
}
.pfilter:hover{ color: var(--ink); border-color: var(--ink); }
.pfilter.is-active{ background: var(--ink); border-color: var(--ink); color: var(--surface); }
.pfilter:focus-visible{ outline: 2px solid var(--ink); outline-offset: 2px; }
/* без скрипта фильтров нет, но сетка остаётся полной */
.portfolio__filters{ display: none; }
.js .portfolio__filters{ display: flex; }

.portfolio__grid{
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 76px 28px;
  margin-top: 49px;
  padding-bottom: 112px;
}
/* ряды кейсов на страницах направлений: заголовок дает about-row, нижний отступ — секция */
.work-cases__grid{ margin-top: 0; padding-bottom: 0; }
/* если над сеткой есть текст, отбиваем ее самым крупным шагом ряда */
.about-row__body > * + .work-cases__grid{ margin-top: 40px; }
/* Ссылка «ещё работы» под сеткой кейсов: тот же шаг, что у сетки, и тот же
   вид, что у «Подробнее» на карточках направлений. Раньше здесь стоял блок
   с главной — он растянут на всю ширину колонки, и стрелка уезжала от текста
   к правому краю. */
.direction-more{ margin-top: 40px; }
.portfolio__empty{
  margin-top: 52px;
  padding-bottom: 112px;
  font-size: 18px;
  line-height: 1.55;
  color: var(--muted);
}

/* карточка каталога: обложка 4:3, стрелка на изображении, подпись под ним */
.pcase{ display: flex; flex-direction: column; gap: 26px; }
.pcase[hidden]{ display: none; }
.pcase__cover{
  position: relative;
  aspect-ratio: 610 / 458;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--surface-soft);
}
.pcase__cover img{
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--media-zoom-dur) var(--ease);
}
.pcase:hover .pcase__cover img,
.pcase:focus-visible .pcase__cover img{ transform: scale(var(--media-zoom)); }

/* Механика с референса gocetinkaya.com. В покое кнопка — сплющенная и
   наклонённая капсула, стрелка внутри смотрит вверх-вправо под 45°. При
   наведении капсула распрямляется в полный круг, а стрелка доворачивается
   до горизонтали. Сплющивание живёт на ::before, а не на самой кнопке:
   иначе оно растянуло бы и стрелку, и та плыла бы всю анимацию. */
/* Кнопка на обложке кейса. Форма — обычный круг: капсула с наклоном
   существовала ровно здесь и выпадала из системы. Стрелка внутри круга при
   наведении доворачивается на 45° вверх, а не едет вправо: у круга есть свои
   границы, и движение внутрь них читается хуже поворота. Цвета прежние — в
   покое полупрозрачная подложка и белая стрелка, при наведении белый круг
   и черная стрелка. */
.pcase__go{
  position: absolute;
  left: 24px;
  bottom: 24px;
  display: grid;
  place-items: center;
  width: 60px;
  height: 60px;
  border-radius: var(--radius-pill);
  background: var(--scrim-soft);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: var(--surface);
  transition: background .35s var(--ease), color .35s var(--ease),
              transform .35s var(--ease),
              opacity .8s var(--ease) calc(var(--i, 0) * 110ms);
}
.pcase__go .ic{ width: 20px; height: 20px; }
.pcase:hover .pcase__go,
.pcase:focus-visible .pcase__go{ background: var(--surface); color: var(--ink); }
.pcase:hover .pcase__go .ic,
.pcase:focus-visible .pcase__go .ic{ transform: rotate(-45deg); }
.pcase:active .pcase__go{ transform: scale(.94); }
.pcase:focus-visible{ outline: 2px solid var(--ink); outline-offset: 2px; }

.pcase__caption{ display: flex; flex-direction: column; gap: 10px; }
.pcase__chips{ display: flex; flex-wrap: wrap; gap: 8px; }
.pcase__chips .chip{ background: var(--surface); }
.pcase__head{ display: flex; flex-direction: column; gap: 4px; }
.pcase__title{
  font-family: var(--font-display);
  font-size: 26px;
  font-weight: 600;
  line-height: 39px;
  color: var(--ink);
}
.pcase__desc{ font-size: 15px; line-height: 22.5px; color: var(--muted); }
.pcase__metric{ display: flex; align-items: flex-end; gap: 8px; }
.pcase__metric b{
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 300;
  line-height: 19.5px;
  color: var(--ink);
  opacity: .8;
}
.pcase__metric span{ font-size: 13px; line-height: 19.5px; color: var(--muted); }

/* ---------- Адаптив нового контура ---------- */
@media (max-width: 1180px){
  /* одна колонка — блоки идут стопкой, между ними и над первым по 40px */
  .home-hero{ grid-template-columns: 1fr; row-gap: 40px; padding-top: 40px; }
  .home-hero__spine{ display: none; }
  .home-hero__author{ margin-left: 0; padding-left: 0; align-self: start; }
  .home-hero__metrics,
  .home-hero__featured,
  .home-hero__index{ grid-column: 1; }
  .home-hero__metrics{ grid-row: 2; }
  .home-hero__featured{ grid-row: 3; }
  .home-hero__index{ grid-row: 4; }
  .metrics, .cindex{ width: 100%; }
  .featured{ width: 100%; height: auto; aspect-ratio: 760 / 340; }
  .directions__grid{ flex-wrap: wrap; }
}

@media (max-width: 720px){
  .home-hero{ padding: 40px 0 64px; }
  .home-hero__author{ flex-direction: column; gap: 24px; }
  .author-portrait{ width: 100%; height: auto; }
  .author-portrait__img{ width: min(224px, 60vw); height: auto; aspect-ratio: 1; }
  .author-portrait__hi{ left: min(199px, 52vw); }
  .author-portrait__hi{ left: min(199px, 52vw); top: 60%; }
  /* те же уменьшенные размеры, что в V1 на узком экране */
  .author-portrait__hi{ gap: 6px; }
  .author-portrait__cursor{ width: 17px; height: 18px; }
  .author-portrait__label{ min-height: 22px; padding: 5px 8px 6px; font-size: 11px; }
  .author-copy{ width: 100%; }
  .author-copy__role{ font-size: 32px; line-height: 38px; }
  /* На узком экране лейблы встают отдельной строкой, а не текут за заголовком:
     иначе они либо прилипают к последнему слову, либо переносятся со сдвигом в
     9px и не совпадают по левому краю с именем, заголовком, описанием и ссылкой.
     `display: flex` делает их блоком — строка своя при любой длине заголовка. */
  .author-labels{
    display: flex;
    margin-left: 0;
    margin-top: 12px;
    vertical-align: baseline;
  }

  .metrics__pair{ flex-direction: column; margin-bottom: 0; }
  .metrics__pair .metric{ width: 100%; margin-right: 0; margin-bottom: -1px; }
  /* полоса складывается в одну колонку; горизонтальный padding возвращается
     на саму полосу — выравнивать по второй карточке здесь нечего, карточки
     тоже стоят стопкой */
  /* «6+ лет» и «до 16» остаются в две колонки и на узком экране: вдвоем они
     коротки, а стопкой давали лишнюю высоту в и без того длинном первом
     экране. Горизонтальный padding здесь на самой полосе — карточки выше
     идут в одну колонку, выравнивать по второй из них нечего. */
  .metrics__band{ grid-template-columns: 1fr 1fr; align-items: center; gap: 16px; padding: 16px 24px; }
  .metrics__band > div{ padding: 0; }
  .metrics__star{ display: none; }

  /* Три колонки на узкий экран не помещаются. Не переносим их по строкам
     (тогда направление липнет к названию, а действие уезжает вправо), а
     ставим всё в столбик по левому краю — строки читаются сверху вниз. */
  /* Обложки кейсов квадратные, а рамка 760/340 — на узком экране от картинки
     оставалась горизонтальная полоса, которую плашка перекрывала целиком.
     4/3 ближе к исходному кадру: изображения видно заметно больше, при этом
     блок не вырастает в полный квадрат. */
  .featured{ aspect-ratio: 4 / 3; }

  .featured__caption{
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    /* Равный отступ от нижнего и боковых краев обложки. */
    top: auto;
    bottom: 24px;
    height: auto;
    margin-block: 0;
    padding: 14px 16px;
    gap: 6px;
  }
  .featured:hover .featured__caption{ transform: none; }
  .featured__num, .featured__title, .featured__type{ width: auto; }
  .featured__title, .featured__type{ white-space: normal; }
  .featured__caption .ilink{ margin-left: 0; margin-top: 2px; }

  /* Сетка вместо переноса строк: у длинного направления стрелка уезжала на
     вторую строку, у короткого оставалась на первой — строки списка стояли
     по-разному. Теперь номер с названием сверху, направление под ними,
     а стрелка держит правый край на всю высоту строки. */
  .crow{
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    height: auto;
    padding: 14px 11px 14px 24px;
    column-gap: 10px;
    row-gap: 2px;
  }
  .crow__num, .crow__title, .crow__type{ width: auto; }
  .crow__title{ grid-column: 1; grid-row: 1; margin-right: 0; }
  .crow__type{ grid-column: 1; grid-row: 2; }
  .crow__arrow{ grid-column: 2; grid-row: 1 / 3; margin-left: 0; }

  .directions__grid{ flex-direction: column; }
  /* В колонке flex-basis: 0 из базового правила меряется по высоте: карточки
     сжимались до padding (60 px) и прятали содержимое под overflow: hidden.
     По высоте они должны занимать столько, сколько занимает контент. */
  .dcard{ min-height: 0; flex: 0 0 auto; }
  .dcard + .dcard{ margin-left: 0; margin-top: -1px; }
  /* Звёзды с широкого экрана стоят на стыках колонок — в столбик стыков нет,
     поэтому исходные прячем, а вместо них каждая карточка получает свою:
     тот же знак открывает направление, но уже сверху, перед заголовком.
     Звезда нарисована фоном, чтобы не заводить её в разметку трёх страниц. */
  .directions__star{ display: none; }
  .dcard::before{
    content: "";
    display: block;
    width: 18px;
    height: 18px;
    margin-bottom: 16px;
    background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 44 44'%3E%3Cpath d='M22 0c1.4 11.2 10.4 20.2 21.6 21.6-11.2 1.4-20.2 10.4-21.6 21.6C20.6 32 11.6 23 .4 21.6 11.6 20.2 20.6 11.2 22 0z' fill='%230a0a0a'/%3E%3C/svg%3E") no-repeat center / contain;
  }

  .portfolio__grid{ grid-template-columns: 1fr; gap: 48px; }
  .pcase__go{ width: 52px; height: 52px; left: 18px; bottom: 18px; }
  .pcase__go .ic{ width: 18px; height: 18px; }
  .pfilter{ min-width: 0; }
}

/* ---------- Уважение к настройке «меньше движения» ---------- */
@media (prefers-reduced-motion: reduce){
  .author-portrait__hi{ transform: translate3d(0, 0, 0); }
  .author-portrait__hi,
  .metrics__star,
  .directions__star,
  .process-lead__diamond,
  .process-lead__wave,
  .live-link__dot{ animation: none; }
  .featured__img,
  .featured__caption,
  .pcase__cover img,
  .process-services__ph img,
  .dcard__fill,
  .ilink .ic,
  .ilink__rule::after,
  .cv-links .link-arrow > span:first-child::after,
  .link-arrow.about-more > span:first-child::after,
  .allworks__circle,
  .allworks__text::after{ transition: none; }
  .featured:hover .featured__img.is-current,
  .pcase:hover .pcase__cover img,
  .pcase:focus-visible .pcase__cover img,
  .process-services__item:hover .process-services__ph img,
  .process-services__item:focus-within .process-services__ph img{ transform: none; }
  /* на тач-экране сдвига стрелки нет: наведения не бывает */
  .pcase__go .ic{ transition: none; transform: none; }
  .pcase:hover .pcase__go .ic,
  .pcase:focus-visible .pcase__go .ic{ transform: none; }
  .featured:hover .featured__caption{ transform: none; }
  .ilink:hover .ic,
  .ilink:focus-visible .ic{ transform: none; }
  .ilink:hover .ilink__rule::after,
  .ilink:focus-visible .ilink__rule::after{ transform: scaleX(1); }
  .allworks:hover .allworks__circle{ transform: none; }
}

/* ---------- work grid filter ---------- */
/* hidden until the script announces itself: buttons that cannot do anything
   are worse than no buttons, so without JS the grid simply stays complete */
.filters{
  display: none;
  margin-bottom: 12px;
  flex-wrap: wrap;
  gap: 8px;
}
.js .filters{ display: flex; }.filters__btn.is-active{
  border-color: var(--ink);
  background: var(--ink);
  color: var(--surface);
}/* the count is for screen readers; sighted readers see the grid itself change */
.filters__status{
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
/* ---------- direction switch ----------
   Three ordinary links styled as one segmented control. They are separate
   pages, not tabs: direct URL, Back/Forward and keyboard focus all behave
   normally, and the whole thing works with JavaScript off.
   Styled to read as the same family as the .dcard "3 directions" blocks
   (shared borders between segments, accent fill for the active one)
   instead of a generic dark pill switch. */
.switch{
  /* три равные колонки на всю ширину контентной колонки: направления
     равноправны как маршруты, поэтому и весят в навигации одинаково,
     независимо от длины названия. Пустого хвоста после третьего пункта
     не остаётся. */
  display: grid;
  /* minmax(0, …), а не голый 1fr: 1fr не позволяет колонке стать уже
     своего содержимого, и длинное «Бренд & коммуникация» раздувало
     первую треть на узком экране */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--surface);
  overflow: hidden;
}
.switch__item{
  padding: 13px 18px;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 500;
  line-height: 1.2;
  text-align: center;
  color: var(--muted);
  /* Переносов по слогам нет намеренно. break-word оставлен только страховкой
     от переполнения на совсем узких экранах — в норме не срабатывает. */
  overflow-wrap: break-word;
  transition: color .3s var(--ease), background .3s var(--ease);
}
.switch__item + .switch__item{ border-left: 1px solid var(--line); }
.switch__item:hover{ color: var(--ink); background: var(--tint-soft); }
.switch__item.is-current{
  background: var(--accent);
  color: var(--ink);
}
.switch__item.is-current:hover{ background: var(--accent); }
.switch__item:focus-visible{
  position: relative;
  z-index: 1;
  outline: 2px solid var(--ink);
  outline-offset: -2px;
}.about-router__card:hover .icon-arrow-ne{ transform: rotate(45deg); }

/* ---------- «Подробнее» at the foot of a services column ---------- */
.services__more{
  margin-top: 16px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 500;
  color: var(--ink);
  transition: color .3s var(--ease);
}
.services__more .icon-arrow-ne{ width: 14px; height: 14px; }
.services__more:hover{ color: var(--muted); }
.services__more:hover .icon-arrow-ne{ transform: rotate(45deg); }

/* deliverable line under a process step: label in grey, content in the note tone */
.process-out{
  margin-top: 14px;
  max-width: 640px;
  font-size: 16px;
  line-height: 1.55;
  color: var(--muted);
}
.process-out span{
  margin-right: 8px;
  color: var(--muted);
}

/* short product flow: steps in a row, joined by arrows. On a narrow screen the
   row wraps and the arrows wrap with it, so the chain never runs off the edge. */
.flow{
  margin-top: 40px;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px 14px;
  max-width: 780px;
}/* two equal blocks side by side, set in body size */
.about-duo{
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 40px;
  max-width: 780px;
}.about-duo__title{
  display: flex;
  align-items: center;
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 600;
  line-height: 1.3;
  margin-bottom: 10px;
}
.about-duo__item p{
  font-size: 16px;
  line-height: 1.55;
  color: var(--muted);
  text-wrap: pretty;
}

/* small image that opens large on hover — used for the portrait and later
   for the embroidery / tea photos */
.pop-media{ position: relative; display: inline-block; }
.pop-media__big{
  position: absolute;
  left: 50%;
  /* sits a touch higher and laps over the small chip; still opens downward so
     it never slides under the sticky header */
  top: 32%;
  width: 240px;
  height: 240px;
  max-width: none;
  border-radius: 999px;
  object-fit: cover;
  object-position: 50% 32%;
  box-shadow: 0 18px 40px var(--shadow-soft);
  opacity: 0;
  transform: translate(-32%, -10px) scale(.94);
  transform-origin: 50% 0;
  pointer-events: none;
  z-index: 5;
  transition: opacity .3s var(--ease), transform .3s var(--ease);
}
.pop-media:hover .pop-media__big{
  opacity: 1;
  transform: translate(-32%, 0) scale(1);
}

/* chip variant: a standalone round thumbnail set in a heading line, sized in px
   so it does not shrink with the small 20px title */
.pop-media--chip{ vertical-align: middle; margin-right: 10px; }
.pop-media__chip{
  display: block;
  width: 44px;
  height: 44px;
  border-radius: 999px;
  object-fit: cover;
}
/* the chip is centred on its own big image, unlike the portrait in the headline */
.pop-media--chip .pop-media__big{ transform: translate(-40%, -10px) scale(.94); }
.pop-media--chip:hover .pop-media__big{ transform: translate(-40%, 0) scale(1); }

/* stack: circles overlap like a deck and fan apart when the group is hovered.
   Each circle keeps its own pop-media behaviour, so pointing at one of them
   opens that photo large. The ring is painted in the page background so the
   circles stay legible where they overlap. */
.pop-stack{
  display: inline-flex;
  align-items: center;
  margin-right: 10px;
}
.pop-stack .pop-media--chip{
  margin-right: 0;
  transition: margin-left .3s var(--ease);
}
.pop-stack .pop-media--chip + .pop-media--chip{ margin-left: -18px; }
.pop-stack:hover .pop-media--chip + .pop-media--chip{ margin-left: 6px; }
.pop-stack .pop-media__chip{ box-shadow: 0 0 0 2px var(--surface); }
/* first card sits on top of the deck, as in an avatar stack */
.pop-stack .pop-media--chip:nth-child(1){ z-index: 4; }
.pop-stack .pop-media--chip:nth-child(2){ z-index: 3; }
.pop-stack .pop-media--chip:nth-child(3){ z-index: 2; }
.pop-stack .pop-media--chip:nth-child(4){ z-index: 1; }
/* the one being pointed at comes forward, above its neighbours and its ring */
.pop-stack .pop-media--chip:hover{ z-index: 5; }

.about-more{ margin-top: 28px; display: inline-flex; }

/* У строки без лейбла тело попадало в первую колонку шириной 230 px и
   зажималось: текст переносился, стопка не помещалась. Ставим его в колонку
   контента, как у всех остальных строк. */
.about-row--plain .about-row__body{ grid-column: 2; }

/* ---------- переход в каталог: текст и лента обложек ---------- */
/* Одна ссылка на весь блок. Обложки идут бесконечной лентой слева направо и
   уходят за оба края экрана: блок показывает объём портфолио сам, без наведения. */
.teaser{
  --card-w: clamp(120px, 12.5vw, 180px);
  --row-gap: 20px;
  --bleed-l: calc(var(--page-x) + 270px);
  --bleed-r: var(--page-x);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  /* 40px — системный шаг, тот же, что между лидом и списком в `about-row__body` */
  gap: 40px;
  min-width: 0;
  color: var(--ink);
}
.teaser__text{
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 500;
  line-height: 1.4;
  box-shadow: inset 0 -1px 0 transparent;
  transition: box-shadow .3s var(--ease);
}
.teaser:hover .teaser__text{ box-shadow: inset 0 -1px 0 currentColor; }
.teaser__text .icon-arrow-ne{ width: 16px; height: 16px; flex: 0 0 auto; }

/* окно ленты во всю ширину экрана */
.teaser__stack{
  display: block;
  width: calc(100% + var(--bleed-l) + var(--bleed-r));
  flex: none;
  min-width: 0;
  margin-left: calc(-1 * var(--bleed-l));
  margin-right: calc(-1 * var(--bleed-r));
  overflow: hidden;
}
/* Набор обложек продублирован: лента едет на половину своей ширины и
   возвращается в начало, стык приходится ровно на границу наборов.
   Интервал задан через margin, а не gap — с gap половина ширины не совпала бы
   с длиной одного набора и лента дёргалась бы на каждом круге. */
.teaser__row{
  display: flex;
  width: max-content;
  animation: teaser-drift 90s linear infinite;
}
/* курсор на блоке — лента замирает, чтобы можно было рассмотреть и нажать */
.teaser:hover .teaser__row,
.teaser:focus-visible .teaser__row{ animation-play-state: paused; }
@keyframes teaser-drift{
  from{ transform: translateX(-50%); }
  to{ transform: translateX(0); }
}
.teaser__card{
  flex: 0 0 auto;
  width: var(--card-w);
  margin-right: var(--row-gap);
  aspect-ratio: 308 / 241;
  height: auto;
  border-radius: 10px;
  object-fit: cover;
  background: var(--surface-soft);
  box-shadow: 0 1px 5px var(--shadow-soft);
  user-select: none;
  -webkit-user-drag: none;
}
.teaser:focus-visible{
  outline: 2px solid var(--focus-ring);
  outline-offset: 6px;
  border-radius: 4px;
}

/* two CVs side by side; they wrap under each other on a narrow screen */
.cv-links{ margin-top: 28px; display: flex; flex-wrap: wrap; gap: 12px 32px; }
/* Линия под текстом — тот же жест, что у `.ilink__rule`: выезжает слева направо
   по наведению, постоянной подложки нет. Только под самой надписью: стрелка
   доворачивается на 45°, а вес файла — сноска, подчеркивать ее нечего. */
.cv-links .link-arrow > span:first-child,
.link-arrow.about-more > span:first-child{ position: relative; }
.cv-links .link-arrow > span:first-child::after,
.link-arrow.about-more > span:first-child::after{
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .42s var(--ease) .04s;
}
.cv-links .link-arrow:hover > span:first-child::after,
.cv-links .link-arrow:focus-visible > span:first-child::after,
.link-arrow.about-more:hover > span:first-child::after,
.link-arrow.about-more:focus-visible > span:first-child::after{ transform: scaleX(1); }

@media (max-width: 720px){
  .about-row{
    grid-template-columns: 1fr;
    gap: 20px;
    padding: 40px 0;
  }
  .about-row--first{ padding-top: 56px; }
  /* колонка одна: без сброса тело уезжает в неявную вторую и сужается */
  .about-row--plain .about-row__body{ grid-column: auto; }
  .teaser{
    --card-w: 132px;
    --bleed-l: var(--page-x);
    gap: 20px;
  }  .directions__star--mid{ display: none; }
  .about-list li{ grid-template-columns: 1fr; gap: 4px; }
  /* В столбик цифра и её текст должны читаться как одна пара, поэтому
     расстояние между парами заметно больше, чем внутри пары (20px).
     При прежних 24px между блоками оказывалось теснее, чем внутри них,
     и метрики сливались в сплошную ленту. */
  .about-facts{ grid-template-columns: 1fr; gap: 60px; }
  .about-duo{ grid-template-columns: 1fr; gap: 32px; }  /* the word plus two shapes do not fit across 390px, so the shapes drop to
     their own row instead of pushing the page sideways */
  .lockup{
    --lockup-word: clamp(58px, 16vw, 92px);
    --lockup-size: clamp(46px, 13vw, 72px);
    padding-bottom: 40px;
  }
  /* Раскладка та же, что на широком экране, — три равные колонки. На узком
     меняются только кегль и отступы, а длинные русские названия переносятся
     внутри своей колонки и не толкают страницу вбок. */
  .switch__item{
    /* боковые поля уже, чем на десктопе: длинному «коммуникация» нужна
       вся ширина ячейки, чтобы уместиться в одну строку без переноса */
    padding: 10px 8px;
    /* 14px везде, кроме совсем узких экранов: на 320px «коммуникация»
       в треть ширины не влезает, и кегль сам ужимается до 12.5px вместо
       того, чтобы рвать слово переносом */
    font-size: clamp(12px, 3.9vw, 14px);
    white-space: normal;
  }
  /* Переключатель на всю ширину экрана: боковые поля страницы гасим тем же
     токеном, которым они заданы. Полоса идёт от края до края, поэтому
     скругление и боковые границы сняты — они пришлись бы ровно на кромку. */
  .about-row--switch .about-row__body{
    margin-left: calc(-1 * var(--page-x));
    margin-right: calc(-1 * var(--page-x));
  }
  .about-row--switch .switch{
    border-radius: 0;
    border-left: none;
    border-right: none;
  }
  .expertise{ grid-template-columns: 1fr; gap: 28px; }
  .pop-media__big{ width: 180px; height: 180px; }
  .about-lead{ max-width: none; }
}

/* ---------- contacts page ----------
   Geometry taken from the reference /contact at 1280: eyebrow 18/500 #666,
   title 64/500, lead 24/500, gaps 24 / 24 / 64, left text column 400px,
   socials flush right at 300px, copy pill 36px tall with radius 50px. */
/* Wider side margins than the rest of the site, matching the reference
   /contact (80px at 1280 → content 1120). */
.contact-page{
  --page-x: clamp(20px, 6.25vw, 80px);
  padding-bottom: 96px;
}

.contact-intro{ padding-top: 96px; }
.contact-intro__eyebrow{
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 500;
  line-height: 1.4;
  color: var(--muted);
}
.contact-intro__title{
  /* Надзаголовка «Контакты» больше нет — он повторял пункт меню. Отступ,
     который отбивал заголовок от него, теперь не нужен: страница начинается
     с самого заголовка. */
  margin-top: 0;
  font-family: var(--font-display);
  font-size: var(--fs-footer-title);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: -0.01em;
}
/* Wider than the reference's 400px: Russian runs ~30% longer than English and
   at 400px the lead broke into a ragged column. */
.contact-intro__lead{
  margin-top: 24px;
  /* По замеру: 946 px — строка до тире, 997 px — весь остаток фразы.
     При 960 «на задачу.» уезжало третьей строкой в 119 px. 1010 держит
     текст в двух строках и оставляет тире в конце первой. */
  max-width: 1010px;
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 500;
  line-height: 1.4;
}

.contact-details{
  margin-top: 56px;
  display: grid;
  grid-template-columns: minmax(0, 620px) 1fr;
  gap: 40px;
  /* e-mail row sits on the same bottom line as the last social link */
  align-items: end;
}
.contact-details__label{
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 500;
  line-height: 1.4;
  color: var(--muted);
}
/* light-theme colours for every link-with-arrow on this page (socials + e-mail) */
.contact-details{
  --social-color: var(--ink);
  --social-hover: var(--muted);
}
.contact-details__social{
  justify-self: end;
  width: 100%;
  max-width: 300px;
}

.contact-email{
  margin-top: 16px;
  display: flex;
  align-items: center;
  gap: 10px;
}
/* Same as the social links: the label owns a fixed track and the arrow follows
   it 8px later, so the arrow sits away from the glyphs (reference: 307 + 8 + 16). */
.contact-email__link{ width: 331px; }
.contact-email__link > span{ flex: 1; }
.contact-email__copy{
  flex: 0 0 auto;
  background: var(--tint-soft);
  color: var(--muted);
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 400;
  line-height: 1;
  padding: 10px;
  border: none;
  border-radius: 50px;
  cursor: pointer;
  transition: background .3s var(--ease), color .3s var(--ease);
}
/* Hover changes only the label colour — the pill keeps its grey background. */
.contact-email__copy:hover{ color: var(--ink); }
.contact-email__copy.is-done{ color: var(--ink); }

.contact-copy{
  margin-top: 160px;
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 500;
  line-height: 1.4;
  color: var(--muted);
}

@media (max-width: 720px){
  .contact-intro{ padding-top: 56px; }
  .contact-details{
    margin-top: 56px;
    grid-template-columns: 1fr;
    gap: 40px;
    align-items: start;
  }
  .contact-details__social{ justify-self: stretch; max-width: none; }
  /* the 331px track is a desktop measurement from the reference; on a 390px
     screen it plus the Copy button overflows the page, so let it go fluid */
  .contact-email{ flex-wrap: wrap; }
  .contact-email__link{ width: auto; max-width: 100%; min-width: 0; }
  .contact-email__link > span{ flex: 0 1 auto; min-width: 0; overflow-wrap: anywhere; }
  .contact-copy{ margin-top: 80px; }
}

/* ---------- site footer (component: partials/site-footer.html) ---------- */

/* Scroll reveal: the footer is pinned to the bottom of the viewport and the
   page content slides up over it. `--footer-h` is measured in main.js and
   reserves the matching scroll distance below the content.
   `.no-footer-reveal` is set automatically when the footer is taller than the
   viewport (small phones), where pinning would clip it. */
.site-footer{
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 0;
  background: var(--footer);
  color: var(--surface);
  padding: 64px var(--page-x);
}
/* Opaque page layer that slides up over the pinned footer. It has to wrap the
   header too: the header itself is transparent, so without this layer the
   footer would show through behind it at the top of the page. */
.page{
  position: relative;
  z-index: 1;
  background: var(--surface);
  margin-bottom: var(--footer-h, 0px);
}
.no-footer-reveal .site-footer{ position: static; }
.no-footer-reveal .page{ margin-bottom: 0; }
.site-footer__inner{
  max-width: var(--grid-max);
  margin: 0 auto;
}
.site-footer__eyebrow{
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 500;
  line-height: 1.4;
  color: var(--surface);
}
.site-footer__title{
  margin-top: 24px;
  font-family: var(--font-display);
  font-size: var(--fs-footer-title);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--surface);
}
.site-footer__cta{
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 32px;
  background: var(--tint-solid);
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 500;
  line-height: 1.4;
  padding: 16px 32px;
  border-radius: 64px;
  box-shadow: inset 0 0 0 1px transparent;
  /* `transition` replaces the one from .reveal (same specificity, declared
     later), so the reveal properties must be repeated here or the button
     would snap into place instead of animating in with the rest. */
  transition:
    background .3s var(--ease),
    color .3s var(--ease),
    box-shadow .3s var(--ease),
    opacity .8s var(--ease),
    transform .8s var(--ease);
  /* the shorthand above also resets the stagger delay — put it back */
  transition-delay: calc(var(--i, 0) * 110ms);
}
.site-footer__cta:hover{
  background: var(--surface);
  color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--ink);
  /* hover must react at once, not after the entrance delay */
  transition-delay: 0s;
}

.icon-arrow-ne{
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
  transition: transform .3s var(--ease);
}
.site-footer__cta .icon-arrow-ne{
  width: 19px;
  height: 19px;
}
.site-footer__cta:hover .icon-arrow-ne{
  transform: rotate(45deg);
}

.site-footer__cols{
  margin-top: 50px;
  display: grid;
  /* три колонки: разделы сайта, направления, контакты */
  grid-template-columns: repeat(3, 1fr);
  gap: 40px;
}
.site-footer__nav{
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
}
/* Подзаголовок ставим над всеми тремя колонками, а не над одной: одиночный
   заголовок читался бы как случайная надпись и ломал бы ритм ряда.
   Тот же кегль и цвет, что у меток разделов на страницах. */
.site-footer__col{
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
}
/* Подзаголовок есть только у колонки направлений, но строку под него держат
   все три: пустая метка сохраняет высоту, и первые пункты колонок стоят
   на одном уровне — «Портфолио» ровно напротив «Бренд & коммуникация». */
.site-footer__col-title{
  margin-bottom: 4px;
  min-height: 20px;
  font-size: 13px;
  font-weight: 400;
  line-height: 20px;
  color: var(--footer-muted);
}
.site-footer__col-title:empty{ margin-bottom: 4px; }
.site-footer__nav a{
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 500;
  line-height: 1.4;
  color: var(--surface);
  transition: transform .3s var(--ease);
}
.site-footer__nav a:hover{
  transform: translateX(3px);
}

/* Inline external link inside running text: the label stays black against the
   grey paragraph, the arrow marks it as leaving the site. Only the last word and
   the arrow are kept on one line, so a long label can still wrap. */
.link-inline{
  color: var(--ink);
  font-weight: 500;
  transition: color .3s var(--ease);
}
.link-inline__tail{ white-space: nowrap; }
.link-inline .icon-arrow-ne{
  width: 14px;
  height: 14px;
  margin-left: 3px;
  vertical-align: -1px;
}
.link-inline:hover{ color: var(--muted); }
.link-inline:hover .icon-arrow-ne{ transform: rotate(45deg); }

/* Shared link-with-arrow behaviour: text dims and the arrow rotates from ↗ to →.
   Used by the social list (footer + contacts) and by the contacts e-mail link. */
.link-arrow{
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 500;
  line-height: 1.4;
  color: var(--social-color, var(--ink));
  transition: color .3s var(--ease);
}
.link-arrow:hover{ color: var(--social-hover, var(--muted)); }
.link-arrow:hover .icon-arrow-ne{ transform: rotate(45deg); }

/* Shared component: partials/social-links.html — used in the footer (dark) and
   on the contacts page (light). Colours come from --social-* set by the host. */
.social-list{
  display: flex;
  flex-direction: column;
  gap: 16px;
}
/* only in the list does the label stretch so the arrow sits at the far edge */
.social-list .link-arrow > span{ flex: 1; }

.site-footer{
  --social-color: var(--surface);
  --social-hover: var(--footer-muted);
}

.site-footer__copy{
  margin-top: 40px;
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 500;
  line-height: 1.4;
  color: var(--footer-muted);
}

@media (max-width: 720px){
  .site-footer{ padding: 48px var(--page-x); }
  .site-footer__cta{ margin-top: 28px; }
  .site-footer__cols{
    grid-template-columns: 1fr;
    gap: 32px;
    margin-top: 40px;
  }
  .site-footer__copy{ margin-top: 32px; }
}

/* ---------- reference-styled process blocks: gocetinkaya.com/process ---------- */
/* Заголовок двухцветный собран на существующем .about-lead + <b>: тот же
   приём, что в рефе (утверждение чёрным, продолжение серым), уже есть в
   системе — новый класс не нужен. */
/* Double Diamond рядом с описанием процесса: цвет — токен ink, а не чёрный
   из исходного файла (fill в svg заменён на currentColor). */
.process-lead{ display: flex; flex-direction: column; gap: 24px; }
.process-lead__icon{
  /* 88.9% прежнего размера: иконка стала уже ровно на ширину одного ромба
     (77.18 из 693 единиц viewBox = 11.14%), пропорции сохранены */
  width: clamp(114px, 14.2vw, 185px);
  height: auto;
  color: var(--ink);
}
.process-lead__text{ margin: 0; }

/* Иконка переехала в левую колонку, под лейбл «Как я работаю» — своя
   явная grid-раскладка только для этой секции, чтобы не трогать общий
   .about-row, который используется на всех остальных строках сайта.
   body растягивается на обе строки (grid-row: 1 / 3), поэтому его высота
   не завязана на высоту иконки — он идёт своим чередом рядом с обеими. */
.about-row--icon-label{
  grid-template-rows: auto 1fr;
}
.about-row--icon-label > .about-row__label{ grid-row: 1; grid-column: 1; }
.about-row--icon-label > .process-lead__icon{
  grid-row: 2;
  grid-column: 1;
  align-self: start;
  /* сдвинуто так, чтобы центр ромбов совпадал по высоте со 2-й строкой
     текста справа (измерено в браузере: getBoundingClientRect ромбов
     против getClientRects текста) */
  margin-top: -17px;
  /* не 100%, а 88.9%: уже на ширину одного ромба */
  width: 88.9%;
  max-width: none;
}
.about-row--icon-label > .about-row__body{ grid-row: 1 / 3; grid-column: 2; }

/* Два ромба пульсируют асинхронно. Поворот на 45° теперь сидит СТАТИЧНО на
   родительском <g> (XML-атрибут, CSS его не трогает и не может подменить).
   CSS-анимация трогает только сам <rect> и масштабирует его от СОБСТВЕННОГО
   геометрического центра (transform-box: fill-box; transform-origin: center —
   считается в локальных координатах rect, до применения поворота родителя).
   Раньше scale стоял на том же элементе, что и rotate(45, угол-квадрата) —
   тогда центром масштабирования был угол ромба, а не его середина, и ромб
   визуально «стекал» в сторону этого угла вместо того, чтобы дышать на месте. */
.process-lead__diamond{
  transform-box: fill-box;
  transform-origin: center;
}
.process-lead__diamond--a{ animation: process-diamond-pulse 2600ms var(--ease) infinite; }
/* отрицательная задержка стартует со середины цикла сразу при отрисовке —
   без неё асинхронность была бы заметна только после первой паузы */
.process-lead__diamond--b{ animation: process-diamond-pulse 2600ms var(--ease) -1300ms infinite; }
@keyframes process-diamond-pulse{
  0%, 100%{ transform: scale(.88); opacity: .82; }
  50%{ transform: scale(1.14); opacity: 1; }
}

/* Волна течёт слева направо, зациклена. Ровно один период (44px) за цикл:
   волна нарисована на 10 периодов вперёд, поэтому сдвиг на один период
   выглядит идентично исходному кадру — цикл бесшовный без дублирования
   разметки (сам путь уже избыточно длинный, в отличие от ленты обложек). */
.process-lead__wave{ animation: process-wave-drift 3200ms linear infinite; }
@keyframes process-wave-drift{
  from{ transform: translateX(0); }
  to{ transform: translateX(44px); }
}

/* <ol> без сброса маркера рисовал собственную нумерацию браузера рядом с
   нашими «01/02/03/04»: список превращался в «1 01», «2 02». */
.process-steps{
  list-style: none;
  margin: 56px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 40px;
  max-width: 780px;
}
.process-steps__item{ list-style: none; }
/* По референсу (gocetinkaya) число сидит на высоте середины заголовка, не
   по верху и не по бейзлайну — align-items: center, без подбора чисел под
   конкретный кегль. */
/* center годится, пока заголовок в одну строку: тогда номер стоит вровень
   с ним. Как только заголовок переносится, центр пары уходит вниз и номер
   повисает между строками — поэтому многострочный случай выравниваем
   по первой строке (см. медиазапрос ниже). */
.process-steps__row{ display: flex; align-items: center; gap: 16px; }
.process-steps__num{
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 400;
  color: var(--tone-soft);
}
.process-steps__title{
  margin: 0;
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: 500;
  line-height: 1.15;
  color: var(--ink);
}
.process-steps__desc{
  margin: 12px 0 0;
  max-width: 720px;
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--muted);
}

.process-services{
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 48px;
  max-width: 900px;
}
/* Три колонки — плейсхолдер, текст, чипы. flex-wrap вместо жёстких
   брейкпоинтов: когда ширины не хватает на все три в ряд, чипы (самый
   узкий и самый независимый по смыслу блок) сами уходят на новую строку —
   без отдельного media-правила под каждую промежуточную ширину. */
.process-services__item{ display: flex; flex-wrap: wrap; align-items: flex-start; gap: 24px 40px; }
.process-services__text{ flex: 1 1 260px; min-width: 200px; }
/* Рамка неподвижна, увеличивается только картинка внутри неё: overflow
   подрезает выход за скруглённые края. Раньше масштабировалась сама рамка —
   это было временно, пока вместо фото стояла заглушка. */
.process-services__ph{
  position: relative;
  flex: 0 0 220px;
  height: 170px;
  border-radius: var(--radius-md);
  background: var(--tint-soft);
  overflow: hidden;
}
.process-services__item:hover .process-services__ph img,
.process-services__item:focus-within .process-services__ph img{ transform: scale(var(--media-zoom)); }
/* «Подробнее» отзывается на наведение всего блока, а не только на себя:
   после удаления зелёной кнопки выход из блока остался один, поэтому
   реакция блока целиком указывает именно на него и ни с чем не спорит.
   Повторяем то же, что делает .ilink:hover — линия и сдвиг стрелки. */
.process-services__item:hover .process-services__more .ic{ transform: translateX(2px); }
.process-services__item:hover .process-services__more .ilink__rule::after{ transform: scaleX(1); }
.process-services__ph img{
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform var(--media-zoom-dur) var(--ease);
}
.process-services__title{
  margin: 0 0 8px;
  font-family: var(--font-display);
  font-size: 32px;
  font-weight: 500;
  color: var(--ink);
}
/* Заголовок встаёт по картинке высотой заглавной буквы, а не верхом строки.
   Строка оставляет над прописной ~0.387em воздуха (при line-height 1.5 и
   cap-height 0.727), из-за чего текстовая колонка проваливалась ниже кромки
   картинки на 12px. Тот же приём уже применён к парам «лейбл + лид»
   в about-строках. Картинка и чипсы не двигаются — только текст. */
@supports (text-box-trim: trim-start){
  .process-services__title{ text-box-trim: trim-start; text-box-edge: cap alphabetic; }
}
@supports not (text-box-trim: trim-start){
  /* в em, а не в px: работает и на узком экране, где кегль другой */
  .process-services__title{ margin-top: -0.387em; }
}
/* список через «/»: слэш — псевдоэлемент, не часть текста, чтобы контент
   можно было переставлять и редактировать без ручного слэша в разметке */
.process-services__list{
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
/* Вход в направление под списком услуг. Зелёная кнопка на изображении ведёт
   в каталог с фильтром — это «покажи работы»; здесь другое намерение,
   «расскажи, что ты умеешь в этом», поэтому ссылка отдельная и тихая. */
.process-services__more{ display: block; margin-top: 20px; }
.process-services__list li{
  font-size: var(--fs-body);
  line-height: 1.55;
  color: var(--muted);
}
.process-services__list li::before{ content: "/ "; color: var(--tone-soft); }
/* третья колонка: чипы вертикальным столбцом, тот же .chip, что у языков
   на «Обо мне». Без стрелок между ними — стрелка читалась в горизонтальном
   потоке, в столбце сам порядок сверху вниз уже читается как
   последовательность */
/* фиксированная ширина колонки чипов — иначе flex:0 0 auto подгоняется под
   САМЫЙ ДЛИННЫЙ чип каждой карточки отдельно, и колонки трёх карточек не
   стоят на одной вертикали (у Web & digital чипы короче, чем у остальных,
   и flow съезжал на 32px правее). 200px — с запасом от самого широкого
   чипа на странице (161px, «Концепция и айдентика» / «Исследование и анализ»). */
.process-services__flow{
  flex: 0 0 200px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}
/* обёртка чипов прозрачна для раскладки: на широком экране столбец чипов
   строится ровно так же, как строился без неё */
.process-services__chips{ display: contents; }
/* вертикальная подпись нужна только в мобильной раскладке */
.process-services__caption{ display: none; }
@media (max-width: 720px){
  .process-steps{ gap: 32px; margin-top: 40px; }
  .process-steps__title{ font-size: 22px; }
  /* на узком экране заголовки переносятся, поэтому номер садится на базовую
     линию первой строки, а не в центр всей пары */
  .process-steps__row{ align-items: baseline; }
  /* ---- мобильная раскладка блока услуг ----
     Порядок сверху вниз: заголовок с описанием → подпись процесса и чипы →
     картинка → кнопка. На широком экране те же элементы стоят в три колонки,
     поэтому переставляем их через order, не трогая разметку. */
  .process-services{ gap: 60px; margin-top: 50px; }
  .process-services__item{ flex-direction: column; gap: 24px; }
  .process-services__text{ order: 1; flex: 1 1 auto; }
  .process-services__flow{ order: 2; }
  .process-services__ph{ order: 3; }
  .process-services__title{ font-size: 24px; }

  /* подпись — обычный подзаголовок над чипами */
  .process-services__flow{
    flex: 1 1 auto;
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
  }
  .process-services__caption{
    display: block;
    font-size: 13px;
    line-height: 1.35;
    color: var(--muted);
  }
  .process-services__chips{
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }

  /* картинка перестаёт быть кадром с наведением: кнопка уходит под неё
     обычным блоком, потому что на тач-экране hover не случается */
  .process-services__ph{
    flex-basis: auto;
    max-width: 320px;
    height: auto;
    overflow: visible;
    background: none;
    transform: none;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
  }
  .process-services__item:hover .process-services__ph img,
  .process-services__item:focus-within .process-services__ph img{ transform: none; }
  .process-services__ph img{
    height: 200px;
    border-radius: var(--radius-md);
  }
  /* явные grid-row/column у --icon-label создают вторую колонку сами по
     себе, даже когда общий .about-row уже схлопнут в одну (браузер
     достраивает недостающий трек под явное размещение) — сбрасываем на
     обычный поток, как у всех строк на узком экране */
  .about-row--icon-label > .about-row__label,
  .about-row--icon-label > .process-lead__icon,
  .about-row--icon-label > .about-row__body{
    grid-row: auto;
    grid-column: auto;
  }
  .about-row--icon-label > .process-lead__icon{
    width: min(88.9%, 185px);
    margin-top: 16px;
  }
}.live-link{
  display: inline-flex;
  align-items: center;
  gap: 14px;
  width: fit-content;
  margin-top: 40px;
  padding: 10px 20px 10px 16px;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: var(--accent-ink);
  transition: background .3s var(--ease), color .3s var(--ease);
}
/* Ряд из нескольких кнопок: у кейса может быть больше одного живого адреса
   (у Togas это основной сайт и бутиковая линия). Правило для вложенной
   кнопки существовало давно, а самой раскладки ряда не было. */
.live-link-row{
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 40px;
}
/* Кнопки стоят в первом экране, на месте строки характеристик: у части
   кейсов там одно поле, и строка растягивалась пустотой на всю ширину.
   Отбивка та же, что у самой строки. */
.case-meta + .live-link-row{ margin-top: 32px; }
.live-link-row + .case-hero__media{ margin-top: 60px; }
.live-link-row .live-link{ margin-top: 0; }
.live-link:hover, .live-link:focus-visible{ background: var(--ink); color: var(--accent); outline: none; }
/* Кнопка ведёт на внешний сайт или в стор, поэтому стрелка диагональная
   и доворачивается до горизонтали — тем же жестом, что у `.link-arrow`. */
.live-link:hover .icon-arrow-ne,
.live-link:focus-visible .icon-arrow-ne{ transform: rotate(45deg); }
.live-link__badge{
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding-right: 14px;
  border-right: 1px solid currentColor;
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  opacity: .82;
}
/* точка того же цвета, что и текст (currentColor) — на лайме тёмная, на
   инверсии hover светлая; отдельный зелёный токен не заводим специально
   под статус-индикатор, того же приёма пульса, что у звёзд и ромбов */
.live-link__dot{
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
  animation: live-dot-pulse 1800ms var(--ease) infinite;
}
@keyframes live-dot-pulse{
  0%, 100%{ transform: scale(.82); opacity: .75; }
  50%{ transform: scale(1.15); opacity: 1; }
}
.live-link__text{
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 500;
}
.live-link .ic{ width: 16px; height: 16px; margin-top: 2px; }

/* ---------- embedded site preview: browser-frame mockup around a 1:1 replica
   of an external site's own hero (svitla.live), scaled to fit the frame via
   JS (see the inline script next to its markup). The chrome uses our tokens;
   everything inside .svitla-hero is a literal copy of that site's own CSS —
   different font, different red, on purpose. ---------- */
/* внешние отступы держит обёртка: сама рамка внутри неё должна прилегать
   вплотную, иначе кнопка, наложенная на шапку, съедет вместе с рамкой */
.site-preview-wrap{
  margin-top: 40px;
  /* padding, а не margin: со следующим блоком margin схлопывался бы
     (соседние вертикальные margin берут максимум, а не сумму), и вместо
     120px до линии «Другие проекты» оставалось 80px — на других страницах
     там padding секции, поэтому расхождение было только здесь */
  padding-bottom: 80px;
}
/* Копия сайта лежит внутри секции шапки, а не рядом с блоком текста,
   поэтому соседний селектор её не находил. Складывались нижний padding
   шапки и нижний padding самой копии — сверху выходило 160 против 80 снизу.
   Отбивку даёт копия, шапка своей не добавляет. */
.case-hero:has(.site-preview-wrap){ padding-bottom: 0; }

/* Секции уже отбивают себя снизу своим padding'ом. Собственный margin
   превью складывался с ним и давал 120px там, где сверху блока стоит 80px —
   один и тот же промежуток отбивали дважды. */
:is(.case-overview, .case-story, .case-gallery, .case-hero) + .site-preview-wrap{
  margin-top: 0;
}
.site-preview{
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--surface-soft);
}
.site-preview__chrome{
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--line);
}
.site-preview__dot{ width: 9px; height: 9px; border-radius: 50%; background: var(--line); }
.site-preview__url{
  margin-left: 12px;
  padding: 5px 14px;
  font-size: 12px;
  color: var(--muted);
  background: var(--surface);
  border-radius: var(--radius-pill);
}
/* Кнопка живёт вне рамки (в .site-preview-wrap), а на широком экране
   накладывается на шапку рамки справа. Так она может уехать НАД рамкой на
   узком экране — из шапки её было бы не вынести, overflow: hidden у рамки
   обрезал бы её по краю. */
.site-preview-wrap{ position: relative; }
.site-preview__cta{
  position: absolute;
  top: 8px;
  right: 16px;
  z-index: 2;
  margin-top: 0;
}
/* Порог по содержимому, а не по устройству: точки + адрес + кнопка требуют
   около 540px, и на более узкой шапке кнопка вылезала за край рамки.
   Ниже порога она встаёт обычным блоком над превью. Само превью при этом
   не перестраивается — оно показывает первый экран чужого сайта как есть. */
@media (max-width: 720px){
  .site-preview__cta{
    position: static;
    margin-bottom: 12px;
  }
}

/* Кнопка на самой картинке, в левом верхнем углу. Тот же приём, что у
   .site-preview__cta над рамкой превью, но с другой стороны: под кнопкой
   здесь не светлая шапка браузера, а тёмный кадр, и правый верхний угол
   на нём занят светлым скриншотом. Отдельно ряд под кнопку не нужен —
   раньше она забирала целую строку между метриками и картинкой.

   overflow: hidden у .case-hero__media кнопку не режет: она внутри
   границ, а не за ними. Ниже 720px отступ мельче — кадр сам уже. */
.case-hero__media--cta{ position: relative; }
.case-hero__media-cta{
  position: absolute;
  top: 16px;
  left: 16px;
  z-index: 2;
  margin-top: 0;
}
@media (max-width: 720px){
  .case-hero__media-cta{ top: 12px; left: 12px; }
}
/* height ставит JS по фактической высоте копии внутри.
   width: 100% обязателен: с aspect-ratio и заданной высотой браузер начинал
   выводить ШИРИНУ из высоты, скрипт считал масштаб от неё, получал меньшую
   высоту — и рамка схлопывалась по кругу. min-height держит вид, если скрипт
   почему-то не отработал. */
.site-preview__frame{
  position: relative;
  width: 100%;
  min-height: 120px;
  overflow: hidden;
  background: rgb(250, 248, 245);
}
/* содержимое рамки — картинка сайта, а не сам сайт: ни ховеров, ни переходов.
   Ссылки внутри копии ведут на чужой домен и по клику уводили бы с портфолио */
.site-preview__stage,
.site-preview__stage *{ pointer-events: none; }
.site-preview__stage{
  position: absolute;
  top: 0;
  left: 0;
  width: 1400px;
  /* без height: копия сама задаёт свою высоту, а скрипт по ней подгоняет рамку */
  transform-origin: top left;
}

/* ---------- svitla-hero: literal port of svitla.live's own hero ---------- */
.svitla-hero{
  --sh-red: #c8282a;
  --sh-red-soft: #e04040;
  --sh-red-dark: #8b1010;
  --sh-text: #2a2520;
  --sh-text-md: #5a534a;
  --sh-border: rgba(200,40,42,.12);
  width: 1400px;
  height: 800px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  background: rgb(250, 248, 245);
  font-family: "Inter", "Helvetica Neue", Arial, sans-serif;
  color: var(--sh-text);
}
.svitla-hero__left{ display: flex; flex-direction: column; justify-content: center; padding: 80px 64px; }
.svitla-hero__eyebrow{
  display: flex; align-items: center; gap: 16px;
  font-size: 10px; font-weight: 400; letter-spacing: 5px; text-transform: uppercase;
  color: var(--sh-red); margin: 0 0 36px;
  opacity: 0; transform: translateY(20px);
  animation: svitla-fadeUp .9s ease .2s 1 forwards;
}
.svitla-hero__eyebrow::after{ content: ""; width: 40px; height: 1px; background: var(--sh-red); opacity: .4; }
.svitla-hero__title{
  font-family: "Cormorant Garamond", serif;
  font-size: 92px; font-weight: 300; letter-spacing: 10px; line-height: 1;
  color: var(--sh-text); margin: 0;
  opacity: 0; transform: translateY(20px);
  animation: svitla-fadeUp .9s ease .4s 1 forwards;
}
.svitla-hero__title-sub{
  font-family: "Cormorant Garamond", serif; font-style: italic;
  font-size: 28px; font-weight: 300; color: var(--sh-red-soft); letter-spacing: 4px;
  margin: 8px 0 48px;
  opacity: 0; transform: translateY(20px);
  animation: svitla-fadeUp .9s ease .6s 1 forwards;
}
.svitla-hero__quote{
  font-family: "Cormorant Garamond", serif; font-style: italic;
  font-size: 18px; font-weight: 300; line-height: 1.7; color: var(--sh-text-md);
  max-width: 440px; margin: 0 0 52px;
  border-left: 2px solid var(--sh-border); padding-left: 24px;
  opacity: 0; transform: translateY(20px);
  animation: svitla-fadeUp .9s ease .8s 1 forwards;
}
.svitla-hero__actions{
  display: flex; gap: 20px; align-items: center;
  opacity: 0; transform: translateY(20px);
  animation: svitla-fadeUp .9s ease 1s 1 forwards;
}
.svitla-hero__btn-primary{
  display: inline-flex; align-items: center; gap: 10px;
  padding: 15px 44px;
  background: var(--sh-red); color: rgb(250,248,245);
  font-size: 11px; letter-spacing: 3px; text-transform: uppercase; font-weight: 400;
  text-decoration: none; border: 0; cursor: pointer;
  position: relative; overflow: hidden;
  transition: background .3s, transform .3s;
}
.svitla-hero__btn-primary::after{
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(135deg, transparent 30%, rgba(255,140,110,.45) 50%, transparent 70%) 0 0 / 300% 300%;
  animation: svitla-btnSweep 4s ease-in-out infinite;
}
.svitla-hero__btn-primary span{ position: relative; z-index: 1; }
.svitla-hero__btn-primary:hover{ background: var(--sh-red-dark); transform: translateY(-2px); }
.svitla-hero__btn-ghost{
  font-size: 11px; letter-spacing: 2px; text-transform: uppercase; color: var(--sh-red);
  text-decoration: none; padding-bottom: 2px; font-weight: 400; position: relative;
  transition: color .2s, opacity .2s;
}
.svitla-hero__btn-ghost::after{
  content: ""; position: absolute; bottom: 0; left: 0; width: 0; height: 1px;
  background: currentColor; transition: width .4s;
}
.svitla-hero__btn-ghost:hover::after{ width: 100%; }

.svitla-hero__right{
  background: transparent; display: flex; flex-direction: column;
  align-items: center; justify-content: center; position: relative; overflow: visible;
  opacity: 0;
  animation: svitla-fadeIn 1.2s ease .5s 1 forwards;
}
.svitla-hero__yantra-wrap{ width: 520px; height: 520px; position: relative; }
.svitla-hero__yantra-outer{ width: 100%; height: 100%; animation: svitla-slowRotate 40s linear infinite; }
.svitla-hero__yantra-inner{ position: absolute; inset: 15%; animation: svitla-slowRotate 25s linear infinite reverse; }
.svitla-hero__portal-blob,
.svitla-hero__portal-blob-2,
.svitla-hero__portal-blob-3,
.svitla-hero__portal-blob-4,
.svitla-hero__portal-blob-5{
  position: absolute; top: 50%; left: 50%; width: 110%; height: 110%;
  transform: translate(-50%,-50%);
  background: linear-gradient(160deg, rgb(237,231,223) 0%, rgb(232,226,218) 50%, rgb(223,217,208) 100%);
  opacity: .18; mix-blend-mode: multiply; pointer-events: none;
}
.svitla-hero__portal-blob{ z-index: 3; border-radius: 30% 70% 60% 40% / 55% 35% 65% 45%; animation: svitla-blobRotate 100s linear infinite; }
.svitla-hero__portal-blob-2{ z-index: 2; border-radius: 55% 45% 35% 65% / 40% 60% 40% 60%; animation: svitla-blobRotateReverse 100s linear infinite; }
.svitla-hero__portal-blob-3{ z-index: 1; border-radius: 65% 35% 45% 55% / 35% 55% 45% 65%; animation: svitla-blobRotate3 120s linear infinite; }
.svitla-hero__portal-blob-4{ z-index: 1; width: 108%; height: 108%; border-radius: 48% 52% 40% 60% / 62% 38% 55% 45%; animation: svitla-blobRotate4 75s linear infinite; }
.svitla-hero__portal-blob-5{ z-index: 1; width: 112%; height: 112%; border-radius: 38% 62% 52% 48% / 58% 42% 60% 40%; animation: svitla-blobRotate5 130s linear infinite; }
.svitla-hero__portal{
  position: absolute; top: 50%; left: 50%; width: 55%; height: 55%;
  transform: translate(-50%,-50%);
  border-radius: 50%; overflow: hidden; z-index: 5;
  mask-image: radial-gradient(circle, #000 60%, transparent 100%);
  -webkit-mask-image: radial-gradient(circle, #000 60%, transparent 100%);
}
.svitla-hero__portal img{
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  opacity: 0; animation: svitla-portalFade 30s ease-in-out infinite;
}
.svitla-hero__portal img:nth-child(1){ animation-delay: 0s; }
.svitla-hero__portal img:nth-child(2){ animation-delay: 6s; }
.svitla-hero__portal img:nth-child(3){ animation-delay: 12s; }
.svitla-hero__portal img:nth-child(4){ animation-delay: 18s; animation-name: svitla-portalFadeZoom; }
.svitla-hero__portal-ring{
  position: absolute; top: 50%; left: 50%; width: 55%; height: 55%;
  transform: translate(-50%,-50%); z-index: 6; pointer-events: none;
  animation: svitla-ringRotate 55s linear infinite;
}
.svitla-hero__portal-ring svg{ width: 100%; height: 100%; }

@keyframes svitla-fadeUp{ 100%{ opacity: 1; transform: translateY(0); } }
@keyframes svitla-fadeIn{ 100%{ opacity: 1; } }
@keyframes svitla-slowRotate{ 0%{ transform: rotate(0); } 100%{ transform: rotate(360deg); } }
@keyframes svitla-ringRotate{ 0%{ transform: translate(-50%,-50%) rotate(0); } 100%{ transform: translate(-50%,-50%) rotate(360deg); } }
@keyframes svitla-blobRotate{ 0%{ transform: translate(-50%,-50%) rotate(0); } 100%{ transform: translate(-50%,-50%) rotate(360deg); } }
@keyframes svitla-blobRotateReverse{ 0%{ transform: translate(-43%,-56%) rotate(0); } 100%{ transform: translate(-43%,-56%) rotate(-360deg); } }
@keyframes svitla-blobRotate3{ 0%{ transform: translate(-57%,-44%) rotate(0); } 100%{ transform: translate(-57%,-44%) rotate(360deg); } }
@keyframes svitla-blobRotate4{ 0%{ transform: translate(-57%,-56%) rotate(0); } 100%{ transform: translate(-57%,-56%) rotate(-360deg); } }
@keyframes svitla-blobRotate5{ 0%{ transform: translate(-43%,-44%) rotate(0); } 100%{ transform: translate(-43%,-44%) rotate(360deg); } }
@keyframes svitla-portalFade{
  0%{ opacity: 0; transform: scale(1.08); }
  3%{ opacity: 1; }
  20%{ opacity: 1; }
  23%{ opacity: 0; transform: scale(1); }
  100%{ opacity: 0; }
}
@keyframes svitla-portalFadeZoom{
  0%{ opacity: 0; transform: scale(1.2); }
  3%{ opacity: 1; transform: scale(1.2); }
  20%{ opacity: 1; transform: scale(1.2); }
  23%{ opacity: 0; transform: scale(1.2); }
  100%{ opacity: 0; }
}
@keyframes svitla-btnSweep{
  0%{ background-position: 100% 100%; }
  50%{ background-position: 0% 0%; }
  100%{ background-position: 100% 100%; }
}

/* ---------- mnp-hero: literal port of moving.marknpost.com's own hero ---------- */
/* высота НЕ фиксирована: экран обрезается ровно там, где кончается первый
   экран оригинала (под строкой «* Откроется в Telegram»), а рамка снаружи
   подгоняется под неё скриптом — иначе снизу оставалось пустое поле */
.mnp-hero{
  position: relative;
  width: 1400px;
  /* нижний отступ 72, а не 32: примечание «* Opens in Telegram» висело
     в 8px от кромки и выглядело зажатым (правка 27.08) */
  padding: 58px 110px 72px;
  box-sizing: border-box;
  background: rgb(245, 245, 247);
  font-family: "Inter", "Helvetica Neue", Arial, sans-serif;
  color: rgb(24, 24, 24);
}
/* Белая полоса снизу: на оригинале форма расчёта стоит на стыке двух секций
   разного тона — серый экран кончается ровно по её середине, нижняя половина
   формы уже лежит на белом фоне следующего блока.
   104px = padding-bottom (72) + половина высоты формы (64/2): полоса растет
   вместе с отступом, иначе стык уехал бы с середины формы. */
.mnp-hero::after{
  content: "";
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  height: 104px;
  background: #fff;
}
/* контент поднят над белой полосой, иначе она перекрыла бы форму */
.mnp-hero__grid,
.mnp-hero__quote{ position: relative; z-index: 1; }
.mnp-hero__grid{
  display: grid;
  grid-template-columns: 760px 404px;
  column-gap: 16px;
}
.mnp-hero__eyebrow{
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  color: rgb(8, 122, 153);
  margin: 0 0 14px;
}
.mnp-hero__title{
  font-size: 40px;
  font-weight: 700;
  line-height: 41.2px;
  color: rgb(24, 24, 24);
  margin: 0 0 30px;
}
.mnp-hero__lead{
  font-size: 16px;
  font-weight: 400;
  line-height: 24px;
  color: rgb(52, 52, 52);
  margin: 0 0 28px;
}
.mnp-hero__cta{
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: rgb(227, 6, 19);
  color: #fff;
  font-size: 16px;
  font-weight: 700;
  padding: 12px 18px;
  border-radius: 6px;
  text-decoration: none;
  margin-bottom: 24px;
}
/* Стрелки в реплике набраны иконками, а не символами. Текстовые глифы
   не подхватывают начертание 700-800: рядом с жирным заголовком и кнопкой
   они выглядели тонкими, не как на самом сайте. У символа в спрайте
   non-scaling-stroke, поэтому толщина держится 1.6px при любом размере. */
.mnp-arrow{
  display: inline-block;
  width: 1em;
  height: 1em;
  vertical-align: -0.13em;
  color: currentColor;
  /* толщина задана здесь, а не атрибутом: stroke-width наследуется внутрь
     path, и подобрать вес обеих стрелок можно в одном месте */
  stroke-width: 3;
}
.mnp-arrow--ne{ width: .85em; height: .85em; vertical-align: -0.02em; stroke-width: 2.35; }

.mnp-hero__ratings{ display: flex; align-items: center; gap: 14px; }
.mnp-hero__rating{ display: flex; align-items: center; gap: 8px; }
.mnp-hero__rating img{ display: block; height: 20px; width: auto; }
.mnp-hero__rating-score{ font-size: 14px; font-weight: 700; color: rgb(24, 24, 24); }
.mnp-hero__rating-star{ height: 12px !important; }
.mnp-hero__rating-count{ font-size: 10px; color: rgb(110, 110, 110); }
.mnp-hero__rating-divider{ width: 1px; height: 26px; background: rgb(216, 225, 230); }
/* Геометрия колонки и обоих её слоёв снята с оригинала напрямую
   (getBoundingClientRect на moving.marknpost.com). */
.mnp-hero__visual{ position: relative; width: 404px; height: 500px; }
/* Картинка лежит ПОВЕРХ голубой карточки: у людей вырезан фон (альфа-канал),
   поэтому коробка и руки выходят за верхнюю грань карточки, а сама грань
   проходит по обрезу одежды. Раньше карточка была выше по слою и срезала их. */
.mnp-hero__visual img{
  position: absolute;
  top: -13px;
  left: 20px;
  z-index: 3;
  display: block;
  width: 370px;
  height: 313.5px;
}
.mnp-hero__usp{
  position: absolute;
  /* шире своей колонки и сдвинута влево — как в оригинале */
  top: 276px;
  left: -24px;
  width: 428px;
  /* высота с оригинала: текст занимает не всю карточку, снизу остаётся воздух.
     Без неё карточка сжималась по тексту (118px вместо 154) и её нижний край
     подходил вплотную к форме расчёта */
  min-height: 154px;
  z-index: 1;
  box-sizing: border-box;
  background: rgba(211, 239, 247, .92);
  padding: 18px;
  border-radius: 8px;
}
.mnp-hero__usp p{
  margin: 0;
  font-size: 12px;
  font-weight: 800;
  text-transform: uppercase;
  color: rgb(8, 122, 153);
}
.mnp-hero__usp strong{
  display: block;
  margin-top: 4px;
  font-size: 28px;
  font-weight: 700;
  line-height: 30px;
  color: rgb(24, 24, 24);
}
.mnp-hero__quote{
  /* подъём формы на колонку с картинкой; значение подобрано так, чтобы под
     голубой карточкой остались те же 30px зазора, что и на оригинале */
  margin-top: -60px;
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr auto;
  background: rgb(216, 221, 226);
  border-radius: 6px;
  gap: 1px;
  padding: 1px;
  max-width: 1180px;
}
.mnp-hero__field{
  background: #fff;
  padding: 10px 16px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.mnp-hero__field:first-child{ border-radius: 6px 0 0 0; }
.mnp-hero__field label{ font-size: 12px; color: rgb(98, 98, 98); }
.mnp-hero__field span{ font-size: 15px; color: rgb(24, 24, 24); }
.mnp-hero__submit{
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgb(227, 6, 19);
  color: #fff;
  font-size: 15px;
  font-weight: 700;
  padding: 12px 18px;
  border-radius: 0 6px 6px 0;
  white-space: nowrap;
}
/* сноска висит под кнопкой расчёта у правого края формы, а не в общем потоке:
   в потоке она сдвигала форму вверх от стыка фонов */
.mnp-hero__note{
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  font-size: 13px;
  color: rgb(98, 98, 98);
}
.mnp-hero--georgia{ padding-top: 0; }
.mnp-site-header{
  min-height: 68px;
  margin: 0 -110px 48px;
  padding: 10px 32px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  background: #fff;
  border-bottom: 1px solid rgb(216, 221, 226);
}
.mnp-site-header__logo{ display: block; width: 220px; height: auto; flex: 0 0 auto; }
.mnp-site-header__nav{ display: flex; align-items: center; gap: 28px; color: rgb(98, 98, 98); font-size: 15px; white-space: nowrap; }
.mnp-hero--georgia .mnp-hero__title{ max-width: 650px; font-size: 56px; line-height: 1.06; margin-bottom: 24px; }
.mnp-hero--georgia .mnp-hero__lead{ max-width: 650px; font-size: 20px; line-height: 30px; margin-bottom: 24px; }
.mnp-hero--georgia .mnp-hero__cta{ gap: 10px; font-size: 20px; padding: 16px 22px; margin-bottom: 24px; }
.mnp-hero--georgia .mnp-hero__rating-score{ font-size: 16px; }
.mnp-hero--georgia .mnp-hero__rating-count{ font-size: 12px; }
.mnp-hero--georgia .mnp-hero__usp{ padding-bottom: 20px; min-height: 0; }
.mnp-hero--georgia .mnp-hero__usp{ padding-bottom: 20px; }
.mnp-hero--georgia .mnp-hero__usp{ top: 276px; }
.mnp-hero__field span{ color: rgb(145, 145, 145); }

/* Balkans preview: geometry measured on the published hero at 1400px.
   The circles sit behind the last letter; vertical-align:middle follows the
   lowercase x-height rather than the title line box or the descender of g. */
.mnp-hero--balkans{ padding-top: 0; background: #f5f7f8; line-height: 1.5; }
.mnp-hero--balkans .mnp-site-header{ height: 72px; margin-bottom: 38px; padding: 0 40px; }
.mnp-balkans-brand{ display: flex; align-items: center; gap: 14px; font-size: 20px; }
.mnp-balkans-brand .mnp-site-header__logo{ width: 48px; height: 48px; }
.mnp-hero--balkans .mnp-site-header__nav{ gap: 38px; color: #555; }
.mnp-hero--balkans .mnp-hero__eyebrow{ display: flex; align-items: center; gap: 5px; margin-bottom: 16px; font-weight: 750; line-height: 1.3; letter-spacing: .035em; }
.mnp-balkans-route-arrow{ display: block; flex: 0 0 16px; width: 16px; height: 16px; }
.mnp-hero--balkans .mnp-hero__title{ font-size: 64px; line-height: .99; letter-spacing: -.045em; margin-bottom: 12px; }
.mnp-balkans-title-end{ display: block; white-space: nowrap; isolation: isolate; }
.mnp-balkans-title-text{ position: relative; z-index: 2; }
.mnp-balkans-decoration{ display: inline-flex; align-items: center; vertical-align: middle; position: relative; z-index: 1; margin-left: -24px; font-size: 20px; font-weight: 400; line-height: 1; letter-spacing: 0; }
.mnp-balkans-countries{ flex: 0 0 auto; display: flex; align-items: center; position: relative; z-index: 1; }
.mnp-balkans-countries img{ display: block; width: 48px; height: 48px; border: 2px solid #fff; border-radius: 50%; object-fit: cover; }
.mnp-balkans-countries img + img{ margin-left: -16px; }
.mnp-balkans-reverse{ flex: 0 0 auto; padding: 7px 0 7px 26px; margin-left: -18px; background: linear-gradient(90deg, #d3eff7 65%, transparent); }
.mnp-hero--balkans .mnp-hero__lead{ max-width: 660px; font-size: 20px; line-height: 29px; margin-bottom: 28px; }
.mnp-hero--balkans .mnp-hero__cta{ gap: 16px; min-height: 50px; margin-bottom: 18px; padding: 12px 19px; font-size: 15px; line-height: 22.5px; }
.mnp-hero--balkans .mnp-hero__ratings{ height: 26px; }
.mnp-hero--balkans .mnp-hero__rating img:not(.mnp-hero__rating-star){ height: 22px; }
.mnp-hero--balkans .mnp-hero__visual{ height: 500px; transform: translateY(-34px); }
.mnp-hero--balkans .mnp-hero__visual > img{ top: -22px; left: -63.25px; width: 505.64px; max-width: none; height: auto; }
.mnp-hero--balkans .mnp-hero__usp{ top: 276px; left: -24px; width: 428px; height: 155px; padding: 24px; display: flex; flex-direction: column; justify-content: center; }
.mnp-hero--balkans .mnp-hero__usp p{ margin-bottom: 16px; line-height: 14.4px; text-transform: none; }
.mnp-hero--balkans .mnp-hero__usp strong{ margin: 0; font-size: 32px; line-height: 1.1; }
.mnp-hero--balkans .mnp-hero__quote{ margin-top: -73px; border: 1px solid #aeb8c2; padding: 0; grid-template-columns: repeat(4, minmax(0, 1fr)) 184px; box-shadow: 0 18px 38px rgba(24,24,24,.1); }
.mnp-hero--balkans .mnp-hero__field{ padding: 14px 16px; gap: 4px; }
.mnp-hero--balkans .mnp-hero__field label{ font-size: 13px; line-height: 16px; }
.mnp-hero--balkans .mnp-hero__field span{ font-size: 16px; line-height: 22px; }
.mnp-hero--balkans .mnp-hero__field:nth-child(3) span{ color: #181818; display: flex; align-items: center; justify-content: space-between; }
.mnp-hero--balkans .mnp-hero__field:nth-child(3) span::after{ content: ''; width: 10px; height: 10px; margin-right: 2px; border-right: 2px solid; border-bottom: 2px solid; transform: rotate(45deg) translateY(-3px); }
.mnp-hero--balkans .mnp-hero__field:nth-child(-n+2) span{ visibility: hidden; }
.mnp-hero--balkans::after{ height: 108px; }


@media (max-width: 640px){
  .case-meta{ grid-template-columns: 1fr; gap: 16px; }
  .case-overview{ grid-template-columns: 1fr; gap: 28px; }
  .case-gallery--two{ grid-template-columns: 1fr; }
  .case-story__grid,
  .case-story--journeys .case-story__grid{ grid-template-columns: 1fr; gap: 24px; }
  .insight-grid{ grid-template-columns: 1fr; gap: 28px; }
  .journeys{ max-width: none; grid-template-columns: 1fr; gap: 24px; }
  .metric-board{ grid-template-columns: repeat(2, 1fr); padding: 32px 24px; gap: 28px 20px; }
}

@media (max-width: 700px){
  .case-hero--mark-n-post .case-meta{ grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: 24px; }
}
@media (max-width: 640px){
  .case-hero--mark-n-post .case-meta{ grid-template-columns: 1fr; }
}

/* ─────────────────────────────────────────────────────────────────────────
   Контакты: строки-ссылки. Отдельный вид только для этой страницы — в подвале
   мелкие текстовые ссылки уместны, а здесь ссылка и есть цель страницы.
   Раньше все четыре набирались тем же кеглем, что абзац рядом, с одинаковой
   стрелкой на всех трёх сервисах: узнать нельзя, попасть пальцем трудно
   (высота строки была 25 px при рекомендованных 44).
   ───────────────────────────────────────────────────────────────────────── */
.contact-links{
  display: grid;
  gap: 0;
  margin: 48px 0 0;
  border-top: 1px solid var(--line);
  max-width: 560px;
}
.clink{
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 64px;
  padding: 14px 4px;
  border-bottom: 1px solid var(--line);
  color: var(--ink);
  text-decoration: none;
  transition: padding-left var(--dur, .25s) var(--ease, ease);
}
.clink__mark{
  flex: 0 0 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--surface-soft);
  transition: background var(--dur, .25s) var(--ease, ease);
}
.clink__mark svg{ width: 20px; height: 20px; }
.clink__body{ display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.clink__name{ font-size: 17px; font-weight: 600; line-height: 1.3; }
.clink__value{
  font-size: 14px;
  color: var(--muted);
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.clink__go{
  width: 16px; height: 16px;
  margin-left: auto;
  flex: 0 0 auto;
  color: var(--muted);
  transition: transform var(--dur, .25s) var(--ease, ease), color var(--dur, .25s) var(--ease, ease);
}
.clink:hover{ padding-left: 10px; }
.clink:hover .clink__mark{ background: var(--accent); }
.clink:hover .clink__go{ color: var(--ink); transform: translate(2px, -2px); }
.clink:focus-visible{ outline: 2px solid var(--ink); outline-offset: 2px; border-radius: 8px; }

@media (max-width: 700px){
  .contact-links{ margin-top: 32px; max-width: none; }
  .clink__value{ font-size: 13px; }
}


/* ─────────────────────────────────────────────────────────────────────────
   Второй ряд внимания в каталоге. Приём измерен у Pentagram: на одной
   странице две величины карточки при одной и той же пропорции — крупные
   924×616 и мелкие 456×304. Иерархию делает размер, а не заголовок и не
   слово «архив»: оно сказало бы «устарело», а нужно «менее важно».
   Обложки здесь берутся с Behance в их родном 818×639 — под 390 px это
   ровно двойная плотность.
   ───────────────────────────────────────────────────────────────────────── */
.portfolio__grid--small{
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 44px 24px;
  margin-top: 28px;
  padding-bottom: 112px;
}
.portfolio__more{
  margin: 0;
  padding-top: 56px;
  border-top: 1px solid var(--line);
}
.pcase--small .pcase__cover{ aspect-ratio: 818 / 639; }
.pcase--small .pcase__caption{ gap: 10px; }
.pcase--small .pcase__title{ font-size: 19px; line-height: 1.3; }
.pcase--small .pcase__chips .chip{ font-size: 11px; }

@media (max-width: 1000px){
  .portfolio__grid--small{ grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px){
  .portfolio__grid--small{ grid-template-columns: 1fr; gap: 32px; }
}


/* ─────────────────────────────────────────────────────────────────────────
   Сплошное полотно. Кейс, который на исходнике был одной высокой картинкой
   и разрезан на куски: скругления и зазоры между ними выдали бы шов там,
   где его в макете нет. Куски встают вплотную и читаются как одно целое.
   ───────────────────────────────────────────────────────────────────────── */
.case-gallery--seamless{ padding-bottom: 0; gap: 0; }
.case-gallery--seamless img{ border-radius: 0; display: block; }
/* Полотно — одно целое, но верхний край всё же край: скругляем только его,
   как у любой другой картинки на сайте. Низ и стыки остаются прямыми. */
.case-gallery--seamless-first img{
  border-top-left-radius: var(--radius-lg);
  border-top-right-radius: var(--radius-lg);
}
.case-gallery--seamless + .case-gallery--seamless{ margin-top: 0; }
/* нижний отступ возвращает последний кусок, иначе полотно упрётся в подвал */
.case-gallery--seamless-last{ padding-bottom: 80px; }

.case-hero__media--flat{ border-radius: 0; }


/* ─────────────────────────────────────────────────────────────────────────
   Копия первого экрана verbamayr.ru. Собрана разметкой, а не скриншотом:
   текст остаётся текстом и переводится вместе с сайтом. Шрифт, логотип
   и значки — их собственные. Clear Sans под Apache 2.0, хостить у себя можно.
   Взят только первый экран: без плашки куки, телефона, переключателя языка
   и плавающих иконок чата — к работе они отношения не имеют.
   ───────────────────────────────────────────────────────────────────────── */
/* Light их сайт не подключает, но шрифт открытый: взят из официального
   репозитория Intel под Apache 2.0 и урезан до латиницы — в копии экрана
   только английский текст. */
@font-face{
  font-family: 'Clear Sans';
  font-style: normal; font-weight: 300; font-display: swap;
  src: url('../fonts/clear-sans-300.woff2') format('woff2');
}
@font-face{
  font-family: 'Clear Sans';
  font-style: normal; font-weight: 400; font-display: swap;
  src: url('../fonts/clear-sans-400.woff') format('woff');
}
@font-face{
  font-family: 'Clear Sans';
  font-style: normal; font-weight: 500; font-display: swap;
  src: url('../fonts/clear-sans-500.woff') format('woff');
}
@font-face{
  font-family: 'Clear Sans';
  font-style: normal; font-weight: 700; font-display: swap;
  src: url('../fonts/clear-sans-700.woff') format('woff');
}

.vm-hero{
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  color: #fff;
  font-family: 'Clear Sans', 'Helvetica Neue', Arial, sans-serif;
  font-weight: 400;
}
.vm-hero__bg{ position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* Верх кадра светлый — стекло и зелень, — и белая строка меню на нём
   пропадала. Затемняющая подложка сверху и снизу: так делают на самом сайте,
   иначе шапка и кнопки читаются только на удачном кадре. */
.vm-hero::before{
  content: "";
  position: absolute; inset: 0;
  z-index: 0;
  background:
    linear-gradient(180deg, rgba(0,0,0,.42) 0%, rgba(0,0,0,.12) 18%, rgba(0,0,0,0) 34%),
    linear-gradient(0deg, rgba(0,0,0,.34) 0%, rgba(0,0,0,0) 26%);
}
/* z-index действует только на позиционированных элементах. Когда я убрал
   отсюда position, подложка легла поверх меню и иконок — их стало не видно.
   Позиционирование нужно, но абсолютным блокам его нельзя перебивать,
   поэтому они идут следом отдельным правилом. */
.vm-hero__bg{ z-index: 0; }
.vm-hero > :not(.vm-hero__bg){ position: relative; z-index: 1; }
/* Селектор через `>` — иначе правило выше специфичнее и возвращает relative,
   а блоки уезжают со своих мест. */
.vm-hero > .vm-hero__title,
.vm-hero > .vm-hero__facts,
.vm-hero > .vm-hero__actions{ position: absolute; }

.vm-hero__top{
  display: flex; align-items: center; gap: 34px;
  padding: 30px 46px 0;
  font-size: 17px;
}
.vm-hero__menu{ display: inline-flex; align-items: center; gap: 14px; }
.vm-hero__burger{
  width: 26px; height: 12px;
  border-top: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
}
.vm-hero__search svg{ width: 22px; height: 22px; display: block; }
.vm-hero__logo{ margin: 0 auto; width: 250px; height: auto; }
.vm-hero__soc{ display: inline-flex; gap: 12px; }
.vm-hero__soc svg{ width: 34px; height: 34px; display: block; }

.vm-hero__title{
  /* по высоте — на уровне головы человека в бассейне */
  top: 46%; left: 46px;
  margin: 0;
  max-width: 820px;
  /* На живом сайте заголовок 40 px при ширине окна около 1900. Сцена копии
     1400, поэтому пропорционально это ~38. Я ставил 54 — тот же вес при
     большем кегле читается заметно жирнее. Начертаний тоньше 400 у Clear Sans
     на их сайте нет. */
  font-size: 49px; font-weight: 300; line-height: 1.2; letter-spacing: -.005em;
}
/* Иконки с подписями стоят слева внизу, кнопки — справа внизу, как в макете.
   Обе группы прижаты к нижнему краю и не пересекаются по горизонтали. */
.vm-hero__facts{
  position: absolute; left: 46px; bottom: 40px;
  display: flex; gap: 62px;
  margin: 0; padding: 0; list-style: none;
  font-size: 17px;
  max-width: 60%;
}
.vm-hero__facts li{ display: flex; flex-direction: column; gap: 16px; }
.vm-hero__facts img{ width: 46px; height: 46px; }

.vm-hero__actions{
  position: absolute; right: 46px; bottom: 40px;
  display: flex; gap: 14px;
}
.vm-hero__btn{
  padding: 15px 34px;
  background: #fff; color: #1b1b1b;
  font-size: 14px; font-weight: 500; letter-spacing: .08em; text-transform: uppercase;
}
.vm-hero__btn--ghost{ background: transparent; color: #fff; border: 1px solid rgba(255,255,255,.7); }




/* ─────────────────────────────────────────────────────────────────────────
   Копия первого экрана collagenina.ru. Сайт собран на Tilda, шрифт —
   Helvetica Neue, он есть в системе, подключать нечего. Взят только первый
   экран: шапка со знаком Swiss Patents и логотипом LABO, кадр продукта
   и текст справа.
   ───────────────────────────────────────────────────────────────────────── */
.cg-hero{ background: #fff; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; }
.cg-hero__top{
  display: flex; align-items: center; gap: 40px;
  padding: 22px 60px; border-bottom: 1px solid #ececec;
}
.cg-hero__patents{ width: 200px; height: auto; }
.cg-hero__nav{
  display: flex; gap: 56px; margin: 0 auto;
  font-size: 15px; letter-spacing: .06em; color: #1c1c1c;
}
.cg-hero__logo{ width: 220px; height: auto; }
.cg-hero__stage{ position: relative; }
.cg-hero__shot{ display: block; width: 100%; height: auto; }
.cg-hero__copy{
  position: absolute; right: 7%; top: 50%; transform: translateY(-50%);
  max-width: 40%; color: #4a3b2a;
}
.cg-hero__title{ margin: 0; font-size: 58px; font-weight: 400; letter-spacing: -.01em; }
.cg-hero__lead{ margin: 18px 0 0; font-size: 19px; line-height: 1.5; }
