:root {
  --black: #000;
  --white: #fff;
  --orange: #fc6030;
  --red: #ff3c00;
  --gray: #555;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* фон белый только у html (canvas/overscroll): body прозрачен, чтобы
   не накрывать слой z-index:-1, которым js/sides.js красит бока */
html { background: var(--white); }

body {
  overflow-x: hidden;
}

#page {
  width: 1280px;
}

#page-inner {
  width: 1280px;
  transform-origin: 0 0;
}

.sec {
  position: relative;
  width: 1280px;
  height: 832px;
  overflow: hidden;
}

.sec-white { background: var(--white); color: var(--black); }
.sec-dark  { background: var(--black); color: var(--white); }
.sec-dark .body16, .sec-dark .lead20 { color: var(--white); }

/* ---------- typography ---------- */

.mono { font-family: 'IBM Plex Mono', monospace; }

.sec {
  font-family: 'IBM Plex Mono', monospace;
}

.sec p { font-family: 'Arsenal', serif; }

.h40 {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 40px;
  font-weight: 400;
  line-height: 110%;
}
.med { font-weight: 500; }
.caps { text-transform: uppercase; line-height: 130%; }

.lead20 { font-size: 20px; line-height: 125%; color: var(--black); }
.lead18 { font-size: 18px; line-height: 125%; color: var(--black); }

.body16 {
  font-family: 'Arsenal', serif;
  font-size: 16px;
  line-height: 125%;
  color: var(--black);
}

/* ---------- primitives ---------- */

.rule {
  border: none;
  border-top: 1px solid var(--black);
  position: absolute;
}

.divider {
  border: none;
  border-top: 2px solid var(--black);
  position: absolute;
  left: 100px;
  width: 1080px;
}

.orange-rule {
  border: none;
  border-top: 2px solid var(--orange);
  position: absolute;
  left: 100px;
  width: 1080px;
}

.dot {
  position: absolute;
  width: 18px; height: 18px;
  background: var(--black);
  border-radius: 50%;
}
.dot-white   { background: var(--white); width: 21.38px; height: 21.38px; }
.circle-dot   { background: var(--white); width: 21.38px; height: 21.38px; transition: opacity 0.45s ease; opacity: 0; }
.dot-orange  { background: var(--orange); width: 20px; height: 20px; }

.ann {
  position: absolute;
  background: var(--black);
  height: 1px;
  transform-origin: 0 0;
}
.ann.o { background: var(--orange); }
.ann.v {
  width: 1px;
}

.pill {
  display: inline-block;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  line-height: 8px;
  color: var(--gray);
  border: 1px solid var(--gray);
  border-radius: 120px;
  padding: 7px 10px;
  margin-right: 10px;
  margin-bottom: 10px;
  white-space: nowrap;
}

.corner-dot {
  position: absolute;
  width: 20px; height: 20px;
  background: var(--black);
  border-radius: 10px;
}

/* ---------- widgets (chat) ---------- */

.widget {
  position: absolute;
  width: 340px;
  padding: 15px 16px;
  z-index: 1;
}
.widget-head {
  display: flex;
  justify-content: space-between;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 16px;
  font-weight: 300;
  margin-bottom: 12px;
}
.widget-x {
  font-size: 20px;
  font-weight: 300;
  line-height: 1;
}
.wx { flex: none; }
.widget-note {
  font-family: 'Arsenal', serif;
  font-size: 20px;
  line-height: 110%;
}
.w-orange { background: var(--orange); color: var(--white); }
.w-gray   { background: var(--gray);   color: var(--white); }
.w-white  { background: var(--white);  color: var(--black); border: 1px solid var(--black); }

/* =========================================================
   1. HERO
========================================================= */

.sec-hero { padding: 50px 100px 0; }

.hero-title {
  font-size: 100px;
  font-weight: 400;
  line-height: 90%;
  letter-spacing: 0;
  text-transform: uppercase;
  color: var(--black);
  width: 1080px;
}

.hero-sub {
  position: absolute;
  left: 840px; top: 196px;
  width: 340px;            /* правый край = 1180, как в макете */
  font-family: 'IBM Plex Mono', monospace;
  font-size: 16px; font-weight: 500;
  text-align: right;
  line-height: 130%;
  color: var(--red);
}

.hero-grid {
  position: absolute;
  left: 100px; top: 473px;
  display: grid;
  grid-template-columns: 340px 340px 340px;
  column-gap: 30px;
}
.hero-col { position: relative; }
.hero-num {
  font-size: 64px;
  color: var(--orange);
  margin-bottom: 22px;
}
.hero-col .rule { position: static; margin: 0; }
.hero-q {
  font-size: 20px;
  margin: 30px 0 14px;
  min-height: 92px;
}
.hero-tags { margin-top: 37px; }

/* жёсткая привязка линий и декора к координатам макета */
.hero-col .rule { position: absolute; width: 337px; left: 0; }
.hero-col:nth-child(2) .rule { width: 334px; left: 3px; }
.hero-col .rule.r1 { top: 84px; }   /* 556 - 473 + 3 */
.hero-col .rule.r2 { top: 219px; }  /* 692 - 473 */

/* =========================================================
   2/5. DARK STATEMENTS
========================================================= */

.statement-40 {
  position: absolute;
  /* top выверен так, чтобы шарик (центр 417.69 = 407 + 21.38/2) стоял по
     оптическому центру строки. Метрики IBM Plex Mono (hhea): ascent 1025,
     descent 275, lineGap 0 → при 40px normal line-height = 52px и
     baseline = top + 41 (полулидер 0). Чернила строки: верх — бревис «й»
     (768/1000·40 = 30.72px над baseline), низ — «у»/«р» (−200/1000·40 = 8px)
     → центр чернил = baseline − (30.72 − 8)/2 = baseline − 11.36px.
     Итог: baseline = 417.69 + 11.36 = 429.05 → top = 429.05 − 41 = 388.05
     (прежний top 403 давал baseline 444 — шарик стоял у верха букв).
     Экран 5 (.sec-statement2) перекрывает top своим значением — не тронут */
  left: 526px; top: 388.05px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 40px;
  width: 720px;
}
.sec-statement .statement-40 {
  width: auto; white-space: nowrap;
  /* буквы растворяются, уходя ЛЕВЕЕ шарика (его левая кромка стоит на 322.16px
     страничных координат с момента контакта и до конца пина — см. keyframes
     stDot: transform заморожен на -147.84px, правый край шарика = 470-147.84+21.38).
     Маска в локальных координатах текста: полоса растворения 60px (как прежний
     fade) стоит влево от этой кромки → позиция маски = -263.84 - tx (tx = сдвиг
     текста в stText). Размер 4000px > ширины текста, чтобы чёрная часть градиента
     всегда накрывала текст справа, а всё левее полосы оставалось скрытым.
     Положение маски едет в tl-ветке через stTextMask, в no-tl — из hero.js */
  -webkit-mask-image: linear-gradient(to right, rgba(0,0,0,0) 0, #000 60px, #000 4000px);
  -webkit-mask-size: 4000px 100%;
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-position: -917.84px 0;
  mask-image: linear-gradient(to right, rgba(0,0,0,0) 0, #000 60px, #000 4000px);
  mask-size: 4000px 100%;
  mask-repeat: no-repeat;
  mask-position: -917.84px 0;
}
.sec-statement .dot-white { left: 470px; top: 407px; }

/* скролл-скраб: элементы скрабятся по
   сближение -> столкновение -> осколки по окружности -> текст по центру ->
   текст улетает влево, буквы растворяются на маске влево от левой кромки
   шарика (322.16px), растут 12 спиц (финальный кадр макета).
   PIN 2700: последние 900px отданы финальной фазе; старые фазы сохраняют
   абсолютную длину в px скролла, поэтому их проценты пересчитаны (px/2700).
   Диапазон анимации ниже задан в процентах как запасной вариант: hero.js
   пересчитывает его в точные px на scroll(root)-таймлайне (Chromium меряет
   view-timeline по layout-боксу без учёта scale — из-за этого процентные
   границы плывут на вьюпортах с высотой != 832·scale).
   Без поддержки timeline прежние keyframe-анимации отключаются. */
.statement-pin {
  position: relative;
  height: 3532px; /* 2700 (PIN) + 832 (экран) */
  view-timeline-name: --statement;
  /* чёрный фон обёртки: пока экран приколот transform'ом, бока страницы
     (слой js/sides.js) читают диапазон всей обёртки, а не только экрана.
     Обнажаемые сверху/снизу области обёртки не видны: пин начинается до
     того, как зазор под экраном доходит до нижней кромки вьюпорта */
  background: var(--black);
}
.statement-pin .sec-statement {
  position: relative;
  top: 0;
  z-index: 5;
}
.statement-pin.tl .sec-statement {
  animation: stPin linear both;
  animation-timeline: --statement;
  animation-range: cover 19.065% cover 80.935%;
}
@keyframes stPin {
  from { transform: translateY(0); }
  to   { transform: translateY(2700px); }
}

.statement-pin.no-tl .sec-statement .dot-white:not(.dot-piece) { transition: opacity 0.25s ease; opacity: 0; }
.statement-pin.no-tl .sec-statement .statement-40 { transition: opacity 0.25s ease; opacity: 0; }
.statement-pin.no-tl .sec-statement .dot-piece { transition: opacity 0.25s ease; opacity: 0; }
.statement-pin.no-tl .sec-statement .statement-question { transition: opacity 0.25s ease; opacity: 0; }
.statement-pin.no-tl .sec-statement .circle-dot { transition: opacity 0.25s ease; opacity: 0; }

.statement-pin.tl .sec-statement .dot-white:not(.dot-piece) {
  animation: stDot linear both;
  animation-timeline: --statement;
  animation-range: cover 19.065% cover 80.935%;
}
/* шарик раздваивается в момент ПЕРВОГО касания буквы: правый край шарика
   (центр 480.69 + tx + 10.69) доходит до левого края текста (526 + tx текста)
   при k≈0.966 прежнего подлёта → 521.6px скролла (19.32% от 2700).
   Шарик замирает в точке контакта (tx −147.84) и там гаснет; длины прочих
   фаз в px сохранены: окно расщепления 521.6–575.6, прилёт осколков 756px */
@keyframes stDot {
  0%     { transform: translateX(-370px); opacity: 1; }
  19.32% { transform: translateX(-147.84px); opacity: 1; }
  21.31%, 100% { transform: translateX(-147.84px); opacity: 0; }
}

.statement-pin.tl .sec-statement .statement-40 {
  animation: stText linear both, stTextMask linear both;
  animation-timeline: --statement;
  animation-range: cover 19.065% cover 80.935%;
}
@keyframes stText {
  0%     { transform: translateX(654px); }
  19.32% { transform: translateX(-182.47px); } /* первое касание буквы */
  21.31% { transform: translateX(-182.47px); } /* держится, пока шарик гаснет */
  /* движение прежнее: правый край текста доезжает до левой кромки окружности
     (56.17%, tx = -1313.31) и дальше до 66.67% — но виден он только до
     левой кромки шарика: растворение теперь делает маска stTextMask,
     а не opacity (буквы исчезают, уходя левее шарика) */
  56.17% { transform: translateX(-1313.31px); }
  66.67%, 100% { transform: translateX(-1654px); }
}

/* позиция маски растворения: полоса 60px стоит влево от левой кромки шарика
   (322.16px страничных координат = локальная -203.84 - tx) → позиция = -263.84 - tx.
   Те же стопы, что и в stText, — обе анимации линейны на одних участках, поэтому
   синхронны на каждом кадре. Значение на 0% (-917.84px) также стоит в базовом
   правиле .sec-statement .statement-40 — до старта анимации маска ничего не скрывает */
@keyframes stTextMask {
  0%            { -webkit-mask-position: -917.84px 0; mask-position: -917.84px 0; }
  19.32%, 21.31% { -webkit-mask-position: -81.37px 0; mask-position: -81.37px 0; }
  56.17%        { -webkit-mask-position: 1049.47px 0; mask-position: 1049.47px 0; }
  66.67%, 100%  { -webkit-mask-position: 1390.16px 0; mask-position: 1390.16px 0; }
}

/* осколки стартуют там, где шарик замер при контакте с буквой:
   центр шарика в контакте (332.85, 417.69) → left 322.16, top 407 */
.sec-statement .dot-piece {
  left: 322.16px;
  top: 407px;
  opacity: 0;
  pointer-events: none;
}
.statement-pin.tl .sec-statement .p1 {
  animation: stP1 linear both;
  animation-timeline: --statement;
  animation-range: cover 19.065% cover 80.935%;
}
/* фазы осколков в % от PIN=2700: проявление 521.6–575.6px (19.32–21.31%),
   прилёт на окружность 756px (28%).
   Конечная точка осколка — позиция на окружности (210°), центр (380.79,266.35):
   от старта (322.16,407) это translate(47.94,-151.34) */
@keyframes stP1 {
  0%, 19.32% { transform: translate(0,0); opacity: 0; }
  21.31%     { transform: translate(0,0); opacity: 1; }
  28%        { transform: translate(47.94px,-151.34px); opacity: 1; }
  100%       { transform: translate(47.94px,-151.34px); opacity: 1; }
}
.statement-pin.tl .sec-statement .p2 {
  animation: stP2 linear both;
  animation-timeline: --statement;
  animation-range: cover 19.065% cover 80.935%;
}
/* зеркальный осколок — позиция 150°, центр (380.79,565.65):
   от старта (322.16,407) это translate(47.94,147.97) */
@keyframes stP2 {
  0%, 19.32% { transform: translate(0,0); opacity: 0; }
  21.31%     { transform: translate(0,0); opacity: 1; }
  28%        { transform: translate(47.94px,147.97px); opacity: 1; }
  100%       { transform: translate(47.94px,147.97px); opacity: 1; }
}

.statement-question {
  position: absolute;
  left: 314px;
  top: 364px;
  width: 651px;
  text-align: center;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 40px;
  line-height: 130%;
  opacity: 0;
  pointer-events: none;
}
.statement-pin.tl .sec-statement .statement-question {
  animation: stQuestion linear both;
  animation-timeline: --statement;
  animation-range: cover 19.065% cover 80.935%;
}
@keyframes stQuestion {
  /* вопрос появляется (1656–1728px), держится и исчезает в финале пина —
     остаётся только кольцо точек со спицами (кадр 65 макета) */
  0%, 61.33% { opacity: 0; }
  64%, 70%   { opacity: 1; }
  76%, 100%  { opacity: 0; }
}

/* финальный кадр: 12 радиальных спиц вытягиваются от кружков к центру
   (dashoffset 275 → 0 по 1944–2322px), пока вопрос исчезает.
   В no-tl ветке dashoffset рулит hero.js */
.st-spokes {
  position: absolute;
  left: 0;
  top: 0;
  width: 1280px;
  height: 832px;
  pointer-events: none;
}
.st-spokes line {
  stroke: var(--white);
  stroke-width: 1;
  stroke-dasharray: 275;
  stroke-dashoffset: 275;
}
.statement-pin.tl .st-spokes line {
  animation: stSpoke linear both;
  animation-timeline: --statement;
  animation-range: cover 19.065% cover 80.935%;
}
@keyframes stSpoke {
  0%, 72%   { stroke-dashoffset: 275; }
  86%, 100% { stroke-dashoffset: 0; }
}

/* попарное проявление оставшихся 10 кружков после остановки осколков.
   Порядок пар — слева направо, по x левого кружка пары:
   pair1(479.65) → pair3(479.65) → pair2(629.31) → pair4(778.97),
   пара на экваторе (pair5, x=330/929, y≈405) — последней.
   У pair1a и pair3b левый кружок на одной вертикали (x=479.65) —
   их очерёдность сохранена прежней.
   Окна пар по 180px скролла (как раньше): 810–1710px → 30–63.33% от 2700. */
.statement-pin.tl .sec-statement .circle-dot {
  opacity: 0;
  animation-timeline: --statement;
}
.statement-pin.tl .sec-statement .pair1a,
.statement-pin.tl .sec-statement .pair1b {
  animation: stPair1 linear both;
  animation-timeline: --statement;
  animation-range: cover 19.065% cover 80.935%;
}
.statement-pin.tl .sec-statement .pair3a,
.statement-pin.tl .sec-statement .pair3b {
  animation: stPair2 linear both;
  animation-timeline: --statement;
  animation-range: cover 19.065% cover 80.935%;
}
.statement-pin.tl .sec-statement .pair2a,
.statement-pin.tl .sec-statement .pair2b {
  animation: stPair3 linear both;
  animation-timeline: --statement;
  animation-range: cover 19.065% cover 80.935%;
}
.statement-pin.tl .sec-statement .pair4a,
.statement-pin.tl .sec-statement .pair4b {
  animation: stPair4 linear both;
  animation-timeline: --statement;
  animation-range: cover 19.065% cover 80.935%;
}
.statement-pin.tl .sec-statement .pair5a,
.statement-pin.tl .sec-statement .pair5b {
  animation: stPair5 linear both;
  animation-timeline: --statement;
  animation-range: cover 19.065% cover 80.935%;
}
@keyframes stPair1 { 0%,30%    { opacity: 0; } 36.67%,100% { opacity: 1; } }
@keyframes stPair2 { 0%,36.67% { opacity: 0; } 43.33%,100% { opacity: 1; } }
@keyframes stPair3 { 0%,43.33% { opacity: 0; } 50%,100%    { opacity: 1; } }
@keyframes stPair4 { 0%,50%    { opacity: 0; } 56.67%,100% { opacity: 1; } }
@keyframes stPair5 { 0%,56.67% { opacity: 0; } 63.33%,100% { opacity: 1; } }
.sec-statement2 .statement-40 {
  left: 193px; top: 364px;
  width: 894px;
  text-align: center;
  /* фраза раскрывается ИЗ СЕРЕДИНЫ, между разъезжающимися скобками: видима
     полоса между двумя ножницами — левый край едет за правым краем чернил
     левой скобки, правый — за левым краем чернил правой. Сомкнуты скобки
     чернилами в центре экрана (точка 640): обе вставки по 447 = щель
     нулевой ширины ровно в точке смыкания (193 + 447 = 1087 − 447 = 640),
     раскрыты — по 17: видима полоса 210..1070 между чернилами скобок.
     Ход строго линейный и одновременный со скобками (все 0.8s linear, разбег
     скобок и ход ножниц — ровно 430px), поэтому края ножниц совпадают
     с чернилами скобок в каждый момент. Старым браузерам без clip-path фраза
     просто видна всегда — скобки едут поверх (лучше статика, чем навсегда
     скрытый текст) */
  -webkit-clip-path: inset(0 447px 0 447px);
          clip-path: inset(0 447px 0 447px);
  transition: clip-path 0.8s linear, -webkit-clip-path 0.8s linear;
}
.sec-statement2.in .statement-40 {
  -webkit-clip-path: inset(0 17px 0 17px);
          clip-path: inset(0 17px 0 17px);
}
/* Скобки-тикер экрана 5 (мокап 1779-928): белые [ ] в Roboto Mono ExtraLight
   200 (начертание из макета — поэтому в подключении шрифтов добавлен вес 200).
   Механика — как у гигант-лого финала (.giant-ctx), но раскрытие из центра:
   базовое состояние — скобки сомкнуты ЧЕРНИЛАМИ в центре экрана («[]» в
   точке 640), по .in на секции разъезжаются в обе стороны 0.8s linear, фраза
   раскрывается тем же ходом. Чернила к чернилам (а не боксами, как у финала):
   иначе между сомкнутыми штрихами осталась бы щель, в которой проглядывал бы
   центр фразы.
   Геометрия выверена по экспорту макета (чернильный бокс скобок):
   левая 191..210, правая 1070..1089, верх/низ 358..481. left/top ниже ставят
   бокс глифа: чернила внутри бокса Roboto Mono 200@128px сидят со смещением
   ox=29px у «[», 27px у «]», oy=8px (line-height:1) — вымерено на живом
   шрифте в headless Chrome и посажено точно на координаты макета */
.st2-br {
  position: absolute;
  top: 350px;
  font-family: 'Roboto Mono', monospace;
  font-weight: 200;
  font-size: 128px;
  line-height: 1;
  color: var(--white);
  /* ход скобки строго линейный, как у тикера чек-листа и финала:
     синхрон с проявлением фразы (тоже 0.8s linear) */
  transition: transform 0.8s linear;
}
.st2-br-l {
  left: 162px;
  /* сомкнутое состояние: правый край чернил «[» (бокс + 29 + 19) встаёт в
     точку смыкания 640 → сдвиг 430 = 640 − (162 + 48); по .in скобка
     возвращается на своё место макета (left 162) */
  transform: translateX(430px);
}
.st2-br-r {
  left: 1043px;
  /* зеркально: левый край чернил «]» (бокс + 27) встаёт в ту же точку 640 →
     сдвиг −430 = (640 − 27) − 1043. Разбег обеих скобок ровно 430px —
     как у ножниц фразы, поэтому край клипа не отстаёт от чернил */
  transform: translateX(-430px);
}
/* в раскрытом состоянии обе скобки на местах макета */
.sec-statement2.in .st2-br-l,
.sec-statement2.in .st2-br-r { transform: translateX(0); }

/* =========================================================
   3. CHECK SECTION
========================================================= */

  .sec-check .h40 { position: absolute; left: 100px; top: 80px; width: 540px; }
.sec-check .lead20 { position: absolute; left: 100px; top: 198px; width: 600px; }

/* =========================================================
   4. BENEFITS
========================================================= */

.sec-benefits .h40 { position: absolute; left: 100px; top: 40px; }

.benefit-cell { position: absolute; }
.benefit-cell:hover { background: var(--orange); }
.benefit-cell:hover + .benefit { color: var(--black); }
.benefit-cell:hover + .benefit .benefit-num { color: var(--white); }

.benefit { position: absolute; width: 340px; pointer-events: none; }
/* метрики из макета (1779-817): номер top+93 → заголовок top+60 → текст.
   У заголовка letter-spacing −1% как в макете — иначе «СОХРАНЯТЬ ДОВЕРИЕ
   К НАУКЕ» (25 знаков ≈ 345px) переносится и текст 06 вылезает за экран */
.benefit-num {
  font-size: 64px;
  line-height: 130%;
  color: var(--orange);
  margin-bottom: 10px;
}
.benefit-h {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 23px; font-weight: 500;
  line-height: 130%;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  margin: 0 0 30px;
}
.benefit-p { font-size: 18px; line-height: 125%; }

/* =========================================================
   6. CARDS: пин-контейнер + фиксированная фото-рука
========================================================= */

.cards-pin { position: relative; }

/* рука с лупой стоит на месте, пока карточки уезжают лентой:
   position:sticky не подходит (лента двигает transform),
   поэтому слой живёт внутри пин-обёртки и не участвует в ленте */
.cards-photo {
  position: absolute;
  left: 0; top: 0;
  width: 1280px; height: 832px;
  pointer-events: none;
  overflow: hidden;
  /* ЛУПА ВРЕМЕННО СКРЫТА (запрос «убери с экранов 01-04»): слой не рисуется,
     но остаётся в layout и в логике — photoPin двигает transform, on-stage
     переключается, dy4 считается. Вернуть — убрать visibility:hidden. */
  visibility: hidden;
}
.cards-photo img {
  position: absolute;
  left: 433px; top: 291px;
  width: 446px; height: 561px;
  /* стекло лупы прозрачное: вырезаем круг (центр 134,132, r≈112) в слое руки */
  -webkit-mask-image: radial-gradient(circle at 134px 132px, transparent 0 102px, #000 110px);
  mask-image: radial-gradient(circle at 134px 132px, transparent 0 102px, #000 110px);
}
.cards-photo .card-circle {
  left: 456px; top: 310px;
}

/* =========================================================
   6a. CARD
========================================================= */

.card-frame {
  position: absolute;
  left: 285px; top: 181px;
  width: 711px; height: 470px;
  border: 1px solid var(--orange);
}
.corner {
  position: absolute;
  width: 20px; height: 20px;
  background: var(--orange);
  border-radius: 60px;
}
.c-tl { left: 275px; top: 171px; }
.c-tr { left: 986px; top: 171px; }
.c-bl { left: 275px; top: 641px; }
.c-br { left: 986px; top: 641px; }

.card-photo {
  position: absolute;
  left: 433px; top: 291px;
  width: 446px; height: 561px;
  object-fit: cover;
}
.card-circle {
  position: absolute;
  left: 456px; top: 310px;
  width: 223px; height: 225px;
  border-radius: 50%;
  background: var(--white);
  opacity: 0.35;
  mix-blend-mode: overlay;
}

/* фото видно только пока карточки в зоне пина; скрытие быстрое,
   чтобы рука не «плыла» на соседних экранах */
.cards-photo { opacity: 0; transition: opacity 0.15s ease; z-index: 2; }
.cards-pin.on-stage .cards-photo { opacity: 1; }

.card-num {
  position: absolute;
  left: 334px; top: 291px;
  font-size: 128px;
  color: var(--white);
  mix-blend-mode: difference;
}
.card-mini {
  position: absolute;
  left: 575px; top: 328px;
  display: flex;
  align-items: baseline;
  font-size: 12px;
  color: var(--gray);
  letter-spacing: 10%;
}
.card-mini .br {
  font-family: 'Roboto Mono', monospace;
  font-size: 10px;
  color: var(--orange);
}
.card-h {
  position: absolute;
  left: 575px; top: 389px;
  font-size: 32px; font-weight: 400;
  text-transform: uppercase;
}
.card-p {
  position: absolute;
  left: 575px; top: 461px;
  width: 460px;
  font-size: 16px;
  font-family: 'Arsenal', serif;
  color: var(--white);
}

/* лента карточек 01-04 (и вход/выход через стейтмент) */
.sec.ribbon {
  transition: transform 620ms cubic-bezier(.77,0,.18,1);
  will-change: transform;
}

/* =========================================================
   7. SCIENTISTS
========================================================= */

/* ---- переходы карточка 04 ↔ «Учёные доказали» ↔ разбор поста ----
   Fade-гейты через белую вуаль, как герой → «Не спешите верить заголовку»
   (js/hero.js) и стыки разбора поста (js/tdgates.js): жест (колесо/клавиши)
   на стоянке карточки 04 или в зоне ниже играет вуаль 250 мс → прыжок на
   верх .sci-pin → reveal 400 мс (js/fades.js, Fades.fade); симметричный
   гейт выхода из экрана учёных вниз (в разбор поста) устроен так же —
   зона [zoneEnd, tdTop] в хвосте .sci-pin (режим sci-flat, разворот
   маски выключен). Запускает js/cards.js:
   .sci-on (на .sci-pin) — экран учёных в кадре: от стоянки (zoneEnd)
   до конца зоны выхода (tdTop), под вуалью прыжка переключается мгновенно;
   .td-on (на .td-pin) — разбор показан (со стоянки tdTop), зеркально;
   .sci-gate/.td-gate — JS-режимы видимости, ставятся при инициализации.
   Зоны — по одному экрану скролла, нативный запас гейта, как слайды
   tdgates: входная [cardTop 04, cardTop 04 + 832·scale] с приколотой
   карточкой 04 (translateY(+dy), fadePin в js/cards.js) и скрытым экраном
   учёных; выходная — с приколотым scrub'ом экраном учёных
   (js/scientists.js) и скрытым разбором. Не-колёсный вход в зону
   (скроллбар, инерция) ловит fallback на scroll: мгновенная вуаль и прыжок
   за зону. Числа FADE=832 (вход) и EXIT=832 (выход) держать синхронными
   в js/cards.js и js/scientists.js. */
.sci-pin {
  position: relative;
  /* 832 экран + 832 зона триггера разворота (порог — её середина) +
     832 стоянки на фулскрине. Хвост пина — отдельный экран из макета
     (1836:934): скролл только ПЕРЕКЛЮЧАЕТ состояние разворота, сам
     разворот маски-панели играет фиксированные 620 мс (твин --p в
     js/scientists.js), секцию на это время прикалывает вручную
     transform (см. scrub там же): position:sticky тут нельзя —
     body с overflow-x:hidden остаётся scroll-контейнером (overflow-y
     считается auto) и sticky прицепляется к нему, а не к окну */
  /* СЕЙЧАС ВЫКЛЮЧЕНО (временно): разворот маски погашен флагом EXPAND
     в js/scientists.js — там же высота обёртки режется до 1664px
     (экран + зона fade-гейта выхода вниз, стык с разбором поста);
     это значение остаётся эталоном включённого состояния */
  height: 2496px;
}
/* поверх руки-лупы (z-index 2) и карточки 04: экран закрывает их целиком */
.sci-pin .sec-scientists { position: relative; z-index: 5; }
/* подложка хвоста пина: в режиме вписывания (вьюпорт выше 832·scale) под
   приколотой секцией видна обёртка. Красим её в чёрный только когда маска
   накрыла больше половины экрана (класс ставит js/scientists.js) — иначе
   она вспыхнула бы под fade-переходом с карточки 04 */
.sci-pin.sciexp-dark { background: var(--black); }

/* видимость секции: режим включает .sci-gate (ставит cards.js при
   инициализации) — вне «кадра» экрана (.sci-on = y в [zoneEnd, tdTop):
   выше стоянки и за концом зоны выхода) секция скрыта: под карточкой 04
   в режиме вписывания виднелся бы её верхний край, в зоне перехода она
   не должна «подглядывать» из-под вуали, а за зоной выхода её закрывает
   разбор поста. Без JS классов нет и секция остаётся видимой по геометрии
   потока (native-слайд как деградация) */
.sci-pin.sci-gate .sec-scientists { opacity: 0; visibility: hidden; }
.sci-pin.sci-gate.sci-on .sec-scientists { opacity: 1; visibility: visible; }

.sci-title {
  position: absolute;
  left: 100px; top: 54px;
  font-size: 42px; font-weight: 500;
  line-height: 62px;
  letter-spacing: 0.113em;
  text-transform: uppercase;
}
.lines-svg { position: absolute; left: 0; top: 0; pointer-events: none; z-index: 0; }

.sci-pills { position: absolute; left: 100px; top: 286px; width: 420px; }
.sci-body {
  position: absolute;
  left: 466px; top: 283px;
  width: 712px;
  font-size: 17px;
  line-height: 169%;
}
.sci-body .orange { color: var(--orange); font-family: 'Arsenal', serif; }
.sci-body b { font-weight: 700; }

.sci-panel {
  position: absolute;
  /* чёрная поверхность панели; при растяжении (--p ставится на .sci-pin,
     js/scientists.js) растёт СИНХРОННО с маской — на фулскрин-экране
     (1836:934) она и есть его чёрный фон. Без синхронного роста текст
     маски остался бы белым на белом вне панели */
  left: calc(100px - 100px * var(--p, 0));
  top: calc(433px - 433px * var(--p, 0));
  width: calc(1080px + 200px * var(--p, 0));
  height: calc(350px + 482px * var(--p, 0));
  background: var(--black);
  border: 2px solid var(--black);
  /* над декоративными svg секции (z 0), но под маской: маска позже в DOM */
  z-index: 1;
}
/* типовые кружки макета (1779:721, Rectangle 34–37): круги 20×20 центром
   в углах панели. Дети панели — при развёртке едут вместе с её углами
   и гаснут от --p: на фулскрин-экране (1836:934) кружков в макете нет */
.sci-dot {
  position: absolute;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--black);
  opacity: calc(1 - var(--p, 0));
}
/* -12, а не -10: абсолютный ребёнок позиционируется от padding-box,
   у панели граница 2px (глобальный border-box) — компенсируем её,
   чтобы кружок стоял центром ровно на углу панели */
.sci-dot.tl { left: -12px; top: -12px; }
.sci-dot.tr { right: -12px; top: -12px; }
.sci-dot.bl { left: -12px; bottom: -12px; }
.sci-dot.br { right: -12px; bottom: -12px; }
/* пятно фонарика: позиция курсора над тёмной панелью (js/scientists.js);
   дефолт 226/177 — центр пятна из макета (при p=0), дальше его доезжает
   твин вместе с растяжкой. Круг 140px = эллипс 280 из макета, кромка
   добита блюром 61: ядро 100% до 66px, 30% на радиусе 140, ноль к 205px.
   --p (0..1) — прогресс растяжения маски из панели (100/433, 1080×350)
   в фулскрин-экран (0/0, 1280×832, макет 1836:934): вся геометрия маски
   и текста внутри — линейная интерполяция от p, ставит его твином
   состояния js/scientists.js (скролл только переключает разворот).
   Fallback 0 в var() — на случай выключенного JS
   и браузеров без @property (тогда --p просто токен) */
@property --mx { syntax: '<length-percentage>'; inherits: false; initial-value: 226px; }
@property --my { syntax: '<length-percentage>'; inherits: false; initial-value: 177px; }
@property --p { syntax: '<number>'; inherits: true; initial-value: 0; }
.sci-mask {
  --mx: 226px; --my: 177px;
  position: absolute;
  left: calc(100px - 100px * var(--p, 0));
  top: calc(433px - 433px * var(--p, 0));
  width: calc(1080px + 200px * var(--p, 0));
  height: calc(350px + 482px * var(--p, 0));
  overflow: hidden;
  z-index: 1; /* над панелью (тоже z 1, но маска позже в DOM) */
  -webkit-mask-image: radial-gradient(circle 205px at var(--mx) var(--my), rgba(0,0,0,1) 0 66px, rgba(0,0,0,0.3) 140px, rgba(0,0,0,0) 205px);
  mask-image: radial-gradient(circle 205px at var(--mx) var(--my), rgba(0,0,0,1) 0 66px, rgba(0,0,0,0.3) 140px, rgba(0,0,0,0) 205px);
}
.sci-mask.returning { transition: --mx 0.6s ease, --my 0.6s ease; }
.sci-questions {
  position: absolute;
  /* позиция текста относительно маски: панель (96;55, интерлиньяж 59) →
     фулскрин (193;233.76, интерлиньяж 90 = 200% из макета 1836:934) */
  left: calc(96px + 97px * var(--p, 0));
  top: calc(55px + 178.76px * var(--p, 0));
  font-family: 'IBM Plex Mono', monospace;
  font-size: 45px;
  line-height: calc(59px + 31px * var(--p, 0));
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--white);
  white-space: nowrap;
  z-index: 2;
}

/* =========================================================
   8. TEARDOWN
========================================================= */

/* overflow:visible — чёрная панель .td-left выезжает в боковое поле окна
   (--td-bleed ставит js/teardown.js): на широких экранах колонка центрируется
   с белыми полями, и без вылета панель «повисала» в отрыве от левого края
   экрана. Единственный ребёнок, которому нельзя рисовать за краем холста, —
   оранжевый слой вердикта: он укрыт обёрткой .td-vd-clip */
.sec-teardown { background: var(--white); overflow: visible; }

.td-bar {
  position: absolute;
  /* тёмный заголовок тянется на всю ширину окна: вылет в оба боковых поля
     (--td-bleed ставит js/teardown.js); текст остаётся по центру экрана */
  left: calc(-1 * var(--td-bleed, 0px)); top: 0;
  width: calc(1280px + 2 * var(--td-bleed, 0px)); height: 70px;
  background: var(--black);
  color: var(--white);
  font-size: 32px; font-weight: 500;
  letter-spacing: 35%;
  text-align: center;
  line-height: 70px;
}

.td-left {
  position: absolute;
  /* вылет в боковое поле: панель доезжает до настоящего левого края окна
     (--td-bleed — ширина поля в px макета, 0 на вписанных по ширине окнах) */
  left: calc(-1 * var(--td-bleed, 0px)); top: 70px;
  width: calc(413px + var(--td-bleed, 0px)); height: 762px;
  background: var(--black);
}
.td-post-title {
  position: absolute;
  /* контент центрируется в ВИДИМОЙ части панели: её начало уехало влево на
     вылет, поэтому внутри панели контент сдвигается вправо на вылет/2 */
  left: calc(40px + var(--td-bleed, 0px) / 2); top: 40px;
  width: 333px;
  font-size: 20px;
  line-height: 130%;
  color: var(--white);
}
.td-img {
  position: absolute;
  left: calc(40px + var(--td-bleed, 0px) / 2); top: 160px;
  width: 334px; height: 552px;
  border: 1px solid var(--gray);
  object-fit: cover;
}
.td-lead {
  position: absolute;
  /* левый край текста = левый край .td-article-img ниже (макет 1982:808:
     оба на 491); картинка центрируется в окне таба (495.5+bleed/2) — текст следует за ней */
  left: calc(495.5px + var(--td-bleed, 0px) / 2); top: 110px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 20px;
  line-height: 130%;
}

/* пост с метками — SVG-экспорт слоя публикации (Group 492): вектор,
   кратен любому масштабу страницы; метки вшиты в сам файл.
   Центрируется в видимом окне таба между полосой «ПУБЛИКАЦИЯ» (правая
   кромка 413+45=458, вылет не берёт) и припаркованными справа полосами
   (кромка 1138+bleed): 458 + (680+bleed−605)/2 = 495.5 + bleed/2 —
   на вписанных по ширине окнах (bleed=0) зазоры по 37.5 с обеих сторон,
   на широких картинка следует за правой стенкой окна */
.td-article-img {
  position: absolute;
  left: calc(495.5px + var(--td-bleed, 0px) / 2); top: 242px;
  width: 605px; height: 299px;
}
.td-tabs { position: absolute; left: 0; top: 0; width: 100%; height: 100%; }
.td-tab {
  position: absolute;
  top: 250px;
  width: 20px;
  height: 210px;
}
.tab-sq {
  position: absolute;
  left: 0; top: 0;
  display: block;
  width: 14px; height: 14px;
  border: 1px solid var(--orange);
  border-radius: 50%;
}
.tab-sq.active { background: var(--orange); }
.tab-label {
  position: absolute;
  /* колонка метки — ровно над кружком (x кружка): rotate(-90deg) вокруг
     верхнего левого угла строки гонит текст вверх, бокс 14px после поворота
     занимает x∈[left, left+14] — колонка кружка (origin 0 100% давал бы
     [left-14, left] — на кружок шире). Низ строки на top = 250-14 = 236, как
     в макете (1982:894/1982:847: метка и кружок на одном x) */
  left: 0;
  top: -14px;
  line-height: 14px;
  transform: rotate(-90deg);
  transform-origin: 0 0;
  font-size: 20px;
  color: var(--black);
  white-space: nowrap;
}

.td-strip {
  position: absolute;
  top: 70px;
  width: 45px; height: 762px;
  border: 1px solid var(--black);
  border-right: none;
}

/* ---------- 8b/8c. КОНТЕКСТ и ПЕРВОИСТОЧНИК ---------- */

.td2-h {
  position: absolute;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 20px;
  font-weight: 400;
  line-height: 130%;
  color: var(--black);
}
.td2-p {
  position: absolute;
  font-family: 'Arsenal', serif;
  font-size: 16px;
  line-height: 125%;
  color: var(--black);
}
.td2-p b { font-weight: 700; }
.td2-small { font-size: 14px; }
.td2-img { position: absolute; object-fit: cover; }

/* ---------- 8. пин табов с доводкой ----------
   Экран пинится на 3200px скролла (3 перехода по 800 + 800 запаса на
   вердикте), но скролл больше не скрабит анимацию: он только выбирает
   состояние s0..s3 (пороги — середины переходов, их проставляет
   js/teardown.js), а каждый переход всегда играет фиксированные 0.8 с —
   скоростью скролла управлять нельзя.
   Публикация → контекст: полоса «контекст» съезжает (1138 → 459),
   → первоисточник: «первоисточник» (1184 → 504), → вердикт: все полосы
   доезжают до левого края (0/45/90), «вердикт» — на 135, оранжевый слой
   проявляется. На вердикте на широких окнах весь стек табов доезжает до
   настоящего левого края окна (доп. сдвиг на вылет --td-bleed), а оранжевый
   заливает окно от края до края; на вписанных по ширине окнах вылет 0 и
   геометрия как в макете.
   Контент меняется перекрёстно: уход в первой половине
   перехода, приход во второй. Границы диапазона пина проставляет
   js/teardown.js; значения ниже — статичный запас на случай
   отключённого JS. */

.td-pin {
  position: relative;
  height: 4032px;              /* 832 экран + 3200px пина (3 × 800 перехода + 800 запас на вердикте) */
}
.td-pin .sec-teardown { position: relative; z-index: 5; }
/* видимость секции — зеркало .sci-gate/.sci-on (см. секцию 7): JS-режим
   включает .td-gate (ставит cards.js), стоянку — .td-on (y ≥ tdTop). В зоне
   fade-гейта выхода из экрана учёных разбор скрыт: иначе в режиме
   вписывания он «подглядывал» бы в зазоре под приколотым экраном и из-под
   вуали прыжка. Без JS классов нет — нативный слайд как деградация */
.td-pin.td-gate .sec-teardown { opacity: 0; visibility: hidden; }
.td-pin.td-gate.td-on .sec-teardown { opacity: 1; visibility: visible; }
.td-pin.tl .sec-teardown {
  animation: tdPin linear both;
  animation-timeline: scroll(root);
  animation-range: 51.3% 67.5%;
}
@keyframes tdPin {
  /* translateY догоняет скролл весь диапазон — экран приколот и держится
     на вердикте лишние 800px; дальше анимация замирает на 3200px и секция
     уезжает вместе со страницей, стыкуясь с чек-листом */
  from { transform: translateY(0); }
  to   { transform: translateY(3200px); }
}

.td-view { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
/* окно вердикта: оранжевый слой — единственный с непрозрачным фоном, его
   сдвиг ±60px при переходах рисовал бы за правым краем холста (секция теперь
   overflow:visible ради вылета чёрной панели в боковое поле).
   На вердикте (s3) окно расширяется на вылет в ОБЕ стороны: оранжевый
   заливает экран от края до края любого окна, а слой растягивается вместе
   с клипом (он inset:0 от клипа) — контент слоя лево-якорный и не двигается.
   Расширение анимируется вслед за fade слоя (0.4s ease), чтобы на выходе
   из s3 боковые поля не мигнули */
.td-vd-clip {
  position: absolute; inset: 0; overflow: hidden; z-index: 1; pointer-events: none;
  transition: left 0.4s ease, right 0.4s ease;
}
.td-pin.s3 .td-vd-clip {
  left: calc(-1 * var(--td-bleed, 0px));
  right: calc(-1 * var(--td-bleed, 0px));
}
.td-left { z-index: 2; }
.td-strip { z-index: 3; background: var(--white); }
.td-tabs { z-index: 4; }  /* над полосами: кружки и подписи табов не затираются «ластиком» */
.td-bar { z-index: 4; }

/* ---- центр контента слоёв в видимом окне таба ----
   Стенки окна едут с вылетом по-разному, и контенту нужен свой добор.
   КОНТЕКСТ/ПЕРВОИСТОЧНИК: слева активная полоса канво-якорна (+bleed),
   справа припаркованные полосы прижаты к краю ОКНА (+2·bleed) — центр
   окна уезжает на +1.5·bleed, а канво-якорный контент сам едет только
   на +bleed: добор полвылета. Группы у дизайнера уже центрированы в окне
   с точностью до 0.5px — им не хватает только вылета.
   ВЕРДИКТ: слой якорен к клипу, который на s3 сам прижат к настоящим
   краям окна и растянут на вылет в обе стороны — без добора контент
   (лево-якорный, координаты в px холста) уехал бы влево на вылет вместе
   с клипом; +bleed возвращает канво-якорность. Композиция центрирована
   на 708 (как в макете 1982:847: «Выводы…» 348..1068, цепочка 570..846 —
   центр поля ПОСЛЕ ПОЛОС [136..1280]), а не в поле за стеком табов —
   попытка добора +22px до центра [180..1280] расходилась с макетом и
   отменена. Сдвиг детьми слоя, а не слоем: transform слоя занят
   fade-переходами (±60px) */
.td-ctx > *, .td-src > * { transform: translateX(calc(var(--td-bleed, 0px) / 2)); }
.td-vd > * { transform: translateX(var(--td-bleed, 0px)); }

/* ---- доводка переходов с фиксированной скоростью ----
   Состояние выбирает скролл (s0/s1/s2), анимацию делает transition:
   полосы и табы всегда едут 0.8 с, слои контента меняются перекрёстно
   (уход — сразу, приход — с задержкой 0.4 с, во второй половине). */

.td-strip, .td-tab { transition: transform 0.8s cubic-bezier(0.76, 0, 0.24, 1); }

/* правые табы (и их полосы) прижимаются к настоящему правому краю окна:
   базовый сдвиг вправо на вылет. Целевые позиции переходов ниже — в
   координатах холста, поэтому вылет в них НЕ вычитается: целевой
   transform полностью заменяет базовый (не складывается с ним), так что
   стыковка всегда к краю чёрной панели в координатах холста. Таб
   «ПУБЛИКАЦИЯ» живёт у края панели и не смещается */
.strip-ctx, .strip-src, .strip-vd,
.tab-ctx, .tab-src, .tab-vd { transform: translateX(var(--td-bleed, 0px)); }

/* целевые положения полос и табов по состояниям */
.td-pin.s1 .strip-ctx, .td-pin.s2 .strip-ctx { transform: translateX(-679px); }
.td-pin.s1 .tab-ctx, .td-pin.s2 .tab-ctx { transform: translateX(-680px); }
.td-pin.s2 .strip-src { transform: translateX(-680px); }
.td-pin.s2 .tab-src { transform: translateX(-681px); }

/* состояние s3 (вердикт): полосы доезжают до левого края,
   подложка таба «вердикт» гаснет — таб остаётся на оранжевом.
   Стек табов уезжает на вылет влево и прижимается к НАСТОЯЩЕМУ левому
   краю окна — как чёрная панель, которая уходит за край ровно на вылет
   (её правая кромка встаёт на −bleed). Окно в координатах холста —
   [−bleed, 1280+bleed], поэтому весь стек (165px: полосы 0..135 + таб
   «вердикт» до 165) помещается при любом вылете: метки едут вместе с
   полосами и остаются видимыми, а таб «вердикт» встаёт на 153 − вылет
   от края экрана — как в макете (153 от левого края) */
.td-pin.s3 .strip-pub, .td-pin.s3 .tab-pub { transform: translateX(calc(-413px - var(--td-bleed, 0px))); }
.td-pin.s3 .strip-ctx, .td-pin.s3 .tab-ctx { transform: translateX(calc(-1093px - var(--td-bleed, 0px))); }
.td-pin.s3 .strip-src, .td-pin.s3 .tab-src { transform: translateX(calc(-1094px - var(--td-bleed, 0px))); }
.td-pin.s3 .tab-vd { transform: translateX(calc(-1095px - var(--td-bleed, 0px))); }
.td-pin.s3 .strip-vd {
  transform: translateX(calc(-1095px - var(--td-bleed, 0px)));
  opacity: 0;
  transition: transform 0.8s cubic-bezier(0.76, 0, 0.24, 1), opacity 0.4s ease;
}

.td-ctx, .td-src, .td-vd { opacity: 0; transform: translateX(60px); }
.td-view {
  transition: opacity 0.4s ease, transform 0.4s ease;
  transition-delay: 0s;               /* уход — сразу */
}
.td-pub { transition-delay: 0.4s; }   /* возврат публикации — во второй половине */

/* левая панель с постом: уезжает влево вместе с полосами на вердикте;
   на вылет в боковое поле тоже — иначе в поле осталась бы чёрная полоса */
.td-left { transition: transform 0.8s cubic-bezier(0.76, 0, 0.24, 1); }

/* состояние s1: контекст */
.td-pin.s1 .td-pub {
  opacity: 0;
  transform: translateX(-60px);
  transition-delay: 0s;
}
.td-pin.s1 .td-ctx {
  opacity: 1;
  transform: translateX(0);
  transition-delay: 0.4s;
}

/* состояние s2: первоисточник */
.td-pin.s2 .td-pub {
  opacity: 0;
  transform: translateX(-60px);
  transition-delay: 0s;
}
.td-pin.s2 .td-ctx {
  opacity: 0;
  transform: translateX(-60px);
  transition-delay: 0s;
}
.td-pin.s2 .td-src {
  opacity: 1;
  transform: translateX(0);
  transition-delay: 0.4s;
}

/* состояние s3: вердикт */
.td-pin.s3 .td-left { transform: translateX(calc(-413px - var(--td-bleed, 0px))); }
.td-pin.s3 .td-pub {
  opacity: 0;
  transform: translateX(-60px);
  transition-delay: 0s;
}
.td-pin.s3 .td-ctx, .td-pin.s3 .td-src {
  opacity: 0;
  transform: translateX(-60px);
  transition-delay: 0s;
}
.td-pin.s3 .td-vd {
  opacity: 1;
  transform: translateX(0);
  transition-delay: 0.4s;
}

/* активная точка таба — дискретно, по ближайшему состоянию;
   на вердикте таб стоит на оранжевом — белый квадрат и белая подпись */
.td-pin.s0 .tab-pub .tab-sq,
.td-pin.s1 .tab-ctx .tab-sq,
.td-pin.s2 .tab-src .tab-sq { background: var(--orange); }
.td-pin.s3 .tab-vd .tab-sq { background: var(--white); border-color: transparent; }
.td-pin.s3 .tab-vd .tab-label { color: var(--white); }

/* =========================================================
   9. VERDICT — слой пина (s3)
========================================================= */

/* оранжевый слой — ребёнок .td-vd-clip (inset:0 ОТ КЛИПА): расширение
   клипа на вылет в обе стороны на вердикте растягивает и слой — оранжевый
   заливает окно от края до края. Контент слоя лево-якорный (пилюли цепочки
   от left холста), поэтому не смещается при растяжении */
.td-vd { background: var(--orange); }

.vd-main {
  position: absolute;
  left: 348px; top: 152px;
  width: 720px;
  text-align: center;
  font-family: 'IBM Plex Mono', monospace !important; /* .sec p (0,1,1) перекрывал .vd-main (0,1,0) */
  font-size: 40px;
  color: var(--white);
}

/* цепочка под заголовком (мокап 1982:873): пилюли на оранжевом — белые и
   чёрные обводки, заливка только у «ПОСТ»; коннектор — линия 1px, точка
   (⌀5) сидит на его нижнем конце, до следующей пилюли остаётся зазор */
.vd-node {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  border: 1px solid var(--white);
  border-radius: 120px;
  font-family: 'IBM Plex Mono', monospace;
  line-height: 120%;
  color: var(--white);
}
.vd-node-ink { border-color: var(--black); color: var(--black); }
.vd-node-fill { background: var(--white); border-color: var(--orange); color: var(--orange); }
.vd-link {
  position: absolute;
  width: 1px;
  background: var(--white);
}
.vd-link::after {
  content: "";
  position: absolute;
  left: -2px; bottom: -2.5px;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--white);
}
.vd-link-ink { background: var(--black); }
.vd-link-ink::after { background: var(--black); }

/* =========================================================
   10. CHECKLIST
========================================================= */

.sec-checklist {
  background: var(--white);
  height: 3903px;
}

.cl-ticker {
  position: absolute;
  left: 100px; top: 118px;
  width: 1080px;
  font-size: 44px; font-weight: 500;
  line-height: 130%;
  white-space: nowrap;
}
/* тикер-строка чек-листа: правая скобка в сомкнутом состоянии наезжает на
   зафиксированную левую; по классу .in (вешает js/checklist.js при входе
   в кадр) скобка отъезжает вправо и «печатает» буквы «КОНТЕКСТ» одну за
   другой. Буквы всегда занимают место в потоке (анимируется только opacity),
   чтобы перенос строки не прыгал при переходе */
.ctx-inline {
  display: inline-flex;
  align-items: baseline;
}
.ctx-inline .br {
  font-family: 'Roboto Mono', monospace;
  font-size: 40px;
  color: var(--orange);
  /* ход скобки строго линейный: 8 букв за 0.8 с = ровно 0.1 с на букву.
     Плавный ease здесь ломал синхрон: середина слова проезжалась бы
     мгновенно (буквы вспыхивали бы пачкой), а края — с заметным
     опозданием, и задержки букв не совпадали с краем скобки */
  transition: transform 0.8s linear;
}
/* левая скобка зафиксирована: всегда на финальном месте */
.ctx-inline .br-l { transform: translateX(0); }
/* правая скобка в сомкнутом состоянии наезжает на левую (сдвиг влево на
   всю ширину слова — задаёт js/checklist.js по реально измеренной ширине,
   --ctx-shift); fallback на случай, если скрипт не успел измерить шрифт */
.ctx-inline .br-r { transform: translateX(calc(var(--ctx-shift, 210px) * -1)); }
/* в раскрытом состоянии правая скобка возвращается на своё место */
.cl-ticker.in .br-r { transform: translateX(0); }
.ctx-word {
  display: inline-block;
}
/* буквы проявляются по одной. Скобка проезжает слово за 0.8 с линейно —
   каждая буква ровно 0.1 с. Раскрытие: k-я буква начинает проявляться,
   когда скобка доезжает до её левого края (0.1s·(k−1)), и становится
   видимой ровно в момент, когда скобка её проехала */
.ctx-word .ch {
  opacity: 0;
  transition: opacity 0.1s linear;
}
/* сжатие (базовое состояние): скобка едет справа налево и «съедает» буквы —
   k-я буква прячется, когда скобка наезжает на её правый край (0.8s − 0.1s·k),
   и гаснет ровно к моменту, когда скобка её проехала */
.ctx-word .ch:nth-child(1) { transition-delay: 0.7s; }
.ctx-word .ch:nth-child(2) { transition-delay: 0.6s; }
.ctx-word .ch:nth-child(3) { transition-delay: 0.5s; }
.ctx-word .ch:nth-child(4) { transition-delay: 0.4s; }
.ctx-word .ch:nth-child(5) { transition-delay: 0.3s; }
.ctx-word .ch:nth-child(6) { transition-delay: 0.2s; }
.ctx-word .ch:nth-child(7) { transition-delay: 0.1s; }
.ctx-word .ch:nth-child(8) { transition-delay: 0s; }
.cl-ticker.in .ctx-word .ch { opacity: 1; }
/* при раскрытии — слева направо, синхронно со скобкой */
.cl-ticker.in .ctx-word .ch:nth-child(1) { transition-delay: 0s; }
.cl-ticker.in .ctx-word .ch:nth-child(2) { transition-delay: 0.1s; }
.cl-ticker.in .ctx-word .ch:nth-child(3) { transition-delay: 0.2s; }
.cl-ticker.in .ctx-word .ch:nth-child(4) { transition-delay: 0.3s; }
.cl-ticker.in .ctx-word .ch:nth-child(5) { transition-delay: 0.4s; }
.cl-ticker.in .ctx-word .ch:nth-child(6) { transition-delay: 0.5s; }
.cl-ticker.in .ctx-word .ch:nth-child(7) { transition-delay: 0.6s; }
.cl-ticker.in .ctx-word .ch:nth-child(8) { transition-delay: 0.7s; }

.cl-title {
  position: absolute;
  left: 100px; top: 300px;
  font-size: 36px; font-weight: 500;
  line-height: 130%;
  width: 463px;
}

.cl-intro { position: absolute; left: 100px; top: 424px; width: 463px; }

.cl-item { position: absolute; width: 463px; }
.cl-num {
  font-size: 80px;
  line-height: 1;
  margin-top: -14px;
  color: var(--orange);
}
.cl-h {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 29px; font-weight: 500;
  line-height: 125%;
  margin: 59px 0 0;
}
.cl-quote-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-top: 28px;
}
.cl-quote-mark {
  font-family: 'IBM Plex Mono', monospace;
  font-style: italic;
  font-size: 30px;
  line-height: 1;
  color: var(--orange);
  transform: translateY(2px);
}
.cl-quote {
  font-style: italic;
  font-size: 20px;
  line-height: 130%;
  color: var(--orange);
}
.cl-body {
  font-size: 20px;
  line-height: 125%;
  margin-top: 30px;
}

.cl-blackband {
  position: absolute;
  left: 0; bottom: 0;
  width: 1280px; height: 832px;
  background: var(--black);
}

/* катыш чек-листа: шарик катится по основной линии-зигзагу коннекторов.
   Путь и границу проявления svg считает js/checklist.js по скроллу,
   clip-path на img тоже инлайновый — без js svg полностью виден */
.cl-ball {
  position: absolute;
  left: 0; top: 0;
  /* размер узловых кружков checklist.svg (r=10): шарик — та же «бусина»,
     что и точки на линии, поэтому в узлах совпадает с ними один в один */
  width: 20px; height: 20px;
  /* transform из js кладёт в точку пути левый верхний угол бокса, поэтому
     сдвигаем на половину размера: в точке пути оказывается центр шарика */
  margin: -10px 0 0 -10px;
  border-radius: 50%;
  /* чёрный — как узловые точки-кружки на линии: шарик читается «бусиной»,
     едущей по тому же рисунку, а не цветным акцентом поверх него */
  background: var(--black);
  /* один уровень с коннекторами (lines-svg, z-index: 0), но позже в DOM —
     шарик поверх чернил линии. Виджеты (z-index: 1) его перекрывают: на
     старте он спрятан под оранжевым «Краткий чек-лист…», а в пути ныряет
     под белый — ровно там, где сама линия уже уходит за виджеты */
  z-index: 0;
  pointer-events: none;
}

/* =========================================================
   11. DECOR (наука стала декорацией)
========================================================= */

.sec-decor .h40 { position: absolute; left: 100px; top: 80px; }
.sec-decor .lead20 { position: absolute; left: 100px; top: 154px; width: 500px; }
.sec-decor .hero-tags { margin-top: 0; }

/* катыш тёмного экрана: белый — как линия decor_dark.svg и её узловые
   кружки, шарик читается той же «бусиной» (в чек-листе он чёрный по тому
   же принципу). Путь считает js/decor.js */
.sec-decor .cl-ball { background: var(--white); }

/* =========================================================
   12. FINALE
========================================================= */

/* Пин хвоста финала: обёртка выше экрана на недостающий скролл — столько,
   чтобы чёрный шарик доехал до конца хребта на константных 2/3 ровно к
   последнему px страницы. Высоту в px выставляет js/decor.js (syncPin),
   ниже 832px — фолбэк без JS: пина нет, svg полностью виден. Сам экран
   прикалывает transform из js (sticky нельзя: body с overflow-x:hidden
   остаётся scroll-контейнером — см. sci-pin выше), как у td-pin/sci-pin */
.fin-pin { position: relative; height: 832px; }

.fin-lead {
  position: absolute;
  left: 100px; top: 70px;
  width: 463px;
}
.fin-right {
  position: absolute;
  left: 717px; top: 491px;
  width: 463px;
  text-align: right;
}

.giant-ctx {
  position: absolute;
  left: 100px; top: 560px;
  width: 1080px;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 145px;
  font-weight: 400;
  line-height: 130%;
  letter-spacing: 10%;
}
.giant-ctx .br {
  font-family: 'Roboto Mono', monospace;
  font-size: 128px;
  color: var(--orange);
  /* ход скобки строго линейный, как у тикера чек-листа: 8 букв за 0.8 с =
     0.1 с на букву. Плавный ease ломал бы синхрон с задержками букв */
  transition: transform 0.8s linear;
}
/* Логотип-тикер финала: та же механика, что у тикера чек-листа (.cl-ticker):
   правая скобка в сомкнутом состоянии наезжает на левую; по классу .in
   (вешает js/decor.js при входе лого в кадр) отъезжает вправо, буквы
   «печатаются» одна за другой. Буквы всегда занимают место в потоке
   (анимируется только opacity). Отличие от чек-листа: буквы — прямые
   флекс-элементы .giant-ctx (space-between разводит их по ширине строки),
   поэтому nth-child считается по всем детям — скобки занимают слоты 1 и 10,
   буквам достаются 2–9 */
.giant-ctx .br-r { transform: translateX(calc(var(--ctx-shift, 900px) * -1)); }
/* в раскрытом состоянии правая скобка возвращается на своё место */
.giant-ctx.in .br-r { transform: translateX(0); }
.giant-ctx .ch {
  opacity: 0;
  transition: opacity 0.1s linear;
}
/* сжатие (базовое состояние): скобка едет справа налево и «съедает» буквы —
   k-я буква (слот k+1) прячется, когда скобка наезжает на её правый край
   (0.8s − 0.1s·k) */
.giant-ctx .ch:nth-child(2) { transition-delay: 0.7s; }
.giant-ctx .ch:nth-child(3) { transition-delay: 0.6s; }
.giant-ctx .ch:nth-child(4) { transition-delay: 0.5s; }
.giant-ctx .ch:nth-child(5) { transition-delay: 0.4s; }
.giant-ctx .ch:nth-child(6) { transition-delay: 0.3s; }
.giant-ctx .ch:nth-child(7) { transition-delay: 0.2s; }
.giant-ctx .ch:nth-child(8) { transition-delay: 0.1s; }
.giant-ctx .ch:nth-child(9) { transition-delay: 0s; }
.giant-ctx.in .ch { opacity: 1; }
/* при раскрытии — слева направо, синхронно со скобкой */
.giant-ctx.in .ch:nth-child(2) { transition-delay: 0s; }
.giant-ctx.in .ch:nth-child(3) { transition-delay: 0.1s; }
.giant-ctx.in .ch:nth-child(4) { transition-delay: 0.2s; }
.giant-ctx.in .ch:nth-child(5) { transition-delay: 0.3s; }
.giant-ctx.in .ch:nth-child(6) { transition-delay: 0.4s; }
.giant-ctx.in .ch:nth-child(7) { transition-delay: 0.5s; }
.giant-ctx.in .ch:nth-child(8) { transition-delay: 0.6s; }
.giant-ctx.in .ch:nth-child(9) { transition-delay: 0.7s; }

/* =========================================================
   11b. ВЫВОД (orange) + 11c. ВЫВОД (white detail)
========================================================= */

.sec-conclusion { background: var(--orange); color: var(--white); }
.sec-concl2 { background: var(--white); }

.concl-frame {
  position: absolute;
  left: 274px; top: 281px;
  width: 711px; height: 250px;
  border: 1px solid var(--white);
}
/* центры кружков — строго в углах рамки. Смещение -1px в HTML компенсирует
   рамку 1px (offset'ы считаются от padding-бокса). Направление translate
   своё у каждого угла: единый translate(-50%,-50%) у right/bottom-углов
   тянул кружок от угла, и центр уезжал на 20px внутрь рамки */
.cf-dot {
  position: absolute;
  width: 20px; height: 20px;
  background: var(--white);
  border-radius: 50%;
  transform: translate(-50%, -50%);
}
.cf-dot:nth-of-type(2) { transform: translate(50%, -50%); }
.cf-dot:nth-of-type(3) { transform: translate(-50%, 50%); }
.cf-dot:nth-of-type(4) { transform: translate(50%, 50%); }
/* мокап 1779:1029: 30px / lh 140% (42px), центр текста на оси рамки (640).
   top 91.2 — компенсация полулидера+ascent−capHeight ((42−39)/2 + 32 − 21 = 10.2):
   cap-топ первой строки встаёт на y=385 макета (тайт-баунды плагина = cap-топ) */
.concl-title {
  position: absolute;
  left: 120px; top: 91.2px;
  width: 500px;
  font-family: 'IBM Plex Mono', monospace !important;
  font-size: 30px;
  line-height: 140%;
  color: var(--white);
  white-space: nowrap;
}
.concl-pill {
  position: absolute;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 20px;
  line-height: 14px;
  color: var(--white);
  background: var(--orange);
  border: 1px solid var(--white);
  border-radius: 120px;
  padding: 8px 10px;
  white-space: nowrap;
}
.concl-pill.inv {
  color: var(--orange);
  background: var(--white);
  border-color: var(--orange);
}

.cl-line { position: absolute; left: 666px; top: 0; }
.concl-quote {
  position: absolute;
  font-family: 'Arsenal', serif;
  font-style: italic;
  font-size: 20px;
  line-height: 125%;
  color: var(--orange);
}

/* ---------- hero intro story ---------- */

.hero-glass {
  position: absolute;
  inset: 0;
  z-index: 10;
  background: rgba(255, 255, 255, 0.1);
  opacity: 0;
  transition: opacity 0.6s ease;
  pointer-events: none;
}
.sec-hero.s1 .hero-glass { opacity: 1; }

.hero-content {
  position: absolute;
  inset: 0;
  padding: 50px 100px 0;
  filter: blur(0);
  transition: filter 0.6s ease;
}
.sec-hero.s1 .hero-content { filter: blur(4px); }

.hero-widget {
  position: absolute;
  width: 340px;
  padding: 15px 16px;
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.45s ease, transform 0.45s ease;
  pointer-events: none;
}
.hero-widget .w-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
}
.hero-widget .w-title {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 16px;
  font-weight: 300;
  line-height: 120%;
  letter-spacing: 0.15em;
}
.hero-widget .w-title.wide { letter-spacing: 0.17em; }
.hero-widget .w-close {
  flex: 0 0 auto;
  margin: 1px -4px -4px;
  padding: 4px;
  box-sizing: content-box;
  cursor: pointer;
}
.hero-widget .w-text {
  margin-top: 16px;
  font-family: 'Arsenal', serif;
  font-size: 20px;
  line-height: 110%;
}
.w1 { z-index: 11; }
.w2 { z-index: 12; }
.w3 { z-index: 13; }
.w4 { z-index: 14; }
.sec-hero.s1 .w1, .sec-hero.s2 .w2, .sec-hero.s3 .w3, .sec-hero.s4 .w4 {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.sec-hero .hero-widget.off {
  opacity: 0;
  transform: translateY(18px);
  pointer-events: none;
}
.sec-hero.clear .hero-content { filter: blur(0); }
.sec-hero.clear .hero-glass { opacity: 0; }
.w-orange { background: var(--orange); border: 1px solid var(--orange); color: var(--white); }
.w-white  { background: var(--white);  border: 1px solid var(--black);  color: var(--black); }
.w-gray   { background: var(--gray);   border: 1px solid var(--gray);   color: var(--white); }
.w-black  { background: var(--black);  border: 1px solid var(--black);  color: var(--white); }

.sec-hero.no-anim, .sec-hero.no-anim * { transition: none !important; }
