/* VIPER — лендинг терминала (viper.scalping.bar, templates/viper_landing.html):
   цвета и типографика из дизайна, панель стакана рисует настоящий
   chart-orderbook.css (подключён отдельно). */

:root {
  --vp-bg: #05070a;
  --vp-panel: #0a0f16;
  --vp-panel-2: #070a0f;
  --vp-line: #141b26;
  --vp-edge: #1c2431;
  --vp-edge-hi: #2c3a4d;
  --vp-ink: #f2f6fc;
  --vp-ink-2: #eef2f8;
  --vp-text: #d7dde8;
  --vp-muted: #778294;
  --vp-muted-2: #4e5867;
  --vp-dim: #3f4a53;
  --vp-green: #00c076;
  --vp-blue: #4aa3ff;
  --vp-amber: #f0b90b;
  --vp-red: #f6465d;
  --vp-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --vp-sans: "IBM Plex Sans", "Segoe UI", -apple-system, BlinkMacSystemFont, sans-serif;
  --vp-ease: cubic-bezier(.16, 1, .3, 1);
}

* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  scrollbar-width: thin;
  scrollbar-color: #243040 var(--vp-bg);
}

body {
  margin: 0;
  background:
    radial-gradient(1200px 700px at 50% -8%, rgba(0, 192, 118, .07), transparent 70%),
    var(--vp-bg);
  color: var(--vp-text);
  font-family: var(--vp-sans);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

a { color: var(--vp-blue); text-decoration: none; }
::selection { background: rgba(0, 192, 118, .28); }
:focus-visible { outline: 1px solid var(--vp-green); outline-offset: 3px; }

::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: var(--vp-bg); }
::-webkit-scrollbar-thumb { background: #243040; border: 3px solid var(--vp-bg); border-radius: 8px; }
::-webkit-scrollbar-thumb:hover { background: var(--vp-green); }
::-webkit-scrollbar-corner { background: var(--vp-bg); }

/* Язык: показываем только активную половину подписей. */
body.lang-ru [data-en-only],
body.lang-en [data-ru-only] { display: none; }

@keyframes vp-blink { 0%, 100% { opacity: 1 } 50% { opacity: .18 } }
@keyframes vp-marquee { from { transform: translate3d(0, 0, 0) } to { transform: translate3d(-50%, 0, 0) } }
@keyframes vp-breathe { 0%, 100% { opacity: .3 } 50% { opacity: .85 } }

/* ===================== КУРСОР ===================== */
.vp-cursor {
  position: fixed;
  left: 0; top: 0;
  width: 640px; height: 640px;
  margin: -320px 0 0 -320px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 1;
  background: radial-gradient(circle, rgba(0, 192, 118, .10), rgba(74, 163, 255, .05) 42%, transparent 68%);
  will-change: transform;
}

/* ===================== ТОПБАР ===================== */
.vp-topbar {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 11px 22px;
  background: rgba(5, 7, 10, .72);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-bottom: 1px solid var(--vp-line);
  transform: translateY(-101%);
  transition: transform .85s var(--vp-ease) .3s;
}

body.is-ready .vp-topbar { transform: none; }

.vp-topbar__prog {
  position: absolute;
  left: 0; bottom: -1px;
  height: 1px; width: 0;
  background: linear-gradient(90deg, rgba(0, 192, 118, .2), var(--vp-green));
  box-shadow: 0 0 12px rgba(0, 192, 118, .6);
}

.vp-topbar__left { display: flex; align-items: center; gap: 11px; min-width: 0; }
.vp-topbar__mark { width: 26px; height: 26px; object-fit: contain; display: block; flex: none; }

.vp-topbar__name {
  font: 600 13px/1 var(--vp-mono);
  letter-spacing: .34em;
  color: var(--vp-ink-2);
}

.vp-topbar__badge {
  font: 500 9.5px/1 var(--vp-mono);
  letter-spacing: .2em;
  color: var(--vp-muted-2);
  padding-left: 12px;
  border-left: 1px solid var(--vp-edge);
  white-space: nowrap;
}

.vp-topbar__right { display: flex; align-items: center; gap: 12px; flex: none; }

/* Сообщество в Telegram — круглая кнопка у переключателя языка. */
.vp-tg {
  position: relative;
  width: 32px; height: 32px;
  display: grid; place-items: center;
  border: 1px solid var(--vp-edge);
  border-radius: 50%;
  background: rgba(10, 15, 22, .6);
  color: var(--vp-muted);
  transition: color .2s, border-color .2s, background .2s;
}
.vp-tg:hover,
.vp-tg:focus-visible { color: #fff; border-color: rgba(42, 171, 238, .75); background: #229ed9; outline: none; }
.vp-tg svg { width: 16px; height: 16px; fill: currentColor; transform: translateX(-1px); }
.vp-tg__label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

.vp-lang {
  display: flex;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--vp-edge);
  border-radius: 999px;
  background: var(--vp-panel);
}

.vp-lang__btn {
  border: 0;
  cursor: pointer;
  text-decoration: none;   /* кнопки стали ссылками на /en и / — вид тот же */
  font: 600 10px var(--vp-mono);
  letter-spacing: .14em;
  padding: 5px 11px;
  border-radius: 999px;
  background: transparent;
  color: var(--vp-muted-2);
  transition: background .2s, color .2s;
}

.vp-lang__btn.is-active { background: #1b2431; color: var(--vp-ink-2); }

.vp-cta {
  font: 600 11px var(--vp-mono);
  letter-spacing: .12em;
  color: #04101e;
  background: var(--vp-green);
  padding: 9px 16px;
  border-radius: 8px;
  white-space: nowrap;
  box-shadow: 0 8px 30px rgba(0, 192, 118, .2);
  transition: filter .2s;
}

.vp-cta:hover { filter: brightness(1.12); color: #04101e; }

/* ===================== ГЕРОЙ ===================== */
/* Зона выросла с 440vh не ради более медленной анимации: хореография занимает
   первые VP_ANIM_SPAN зоны (см. app.js) и по абсолютной прокрутке идёт ровно как
   раньше. Прибавка — ДОК: участок, где сцена уже собрана, стоит и её можно
   трогать. До него живое окно было 301px, три щелчка колеса. */
.vp-zone { position: relative; height: 580vh; }

.vp-stage {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  display: grid;
  place-items: center;
  z-index: 2;
}

.vp-stage__grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(#0c121b 1px, transparent 1px),
    linear-gradient(90deg, #0c121b 1px, transparent 1px);
  background-size: 64px 64px;
  mask-image: radial-gradient(circle at 50% 45%, #000 28%, transparent 72%);
  -webkit-mask-image: radial-gradient(circle at 50% 45%, #000 28%, transparent 72%);
  opacity: 0;
  transition: opacity 1.8s ease .15s;
}

body.is-ready .vp-stage__grid { opacity: .75; }

.vp-word {
  position: absolute;
  z-index: 5;
  text-align: center;
  pointer-events: none;
  padding: 0 20px;
  will-change: transform, opacity;
}

.vp-word__mark {
  width: 96px; height: 96px;
  object-fit: contain;
  display: block;
  margin: 0 auto 16px;
  opacity: 0;
  transform: scale(.78);
  filter: blur(12px) drop-shadow(0 0 0 rgba(0, 192, 118, 0));
  transition: opacity .9s var(--vp-ease) .05s, transform 1.1s var(--vp-ease) .05s, filter 1.1s var(--vp-ease) .05s;
}

body.is-ready .vp-word__mark {
  opacity: 1;
  transform: none;
  filter: blur(0) drop-shadow(0 0 40px rgba(0, 192, 118, .35));
}

.vp-word__title {
  margin: 0;
  font: 700 clamp(44px, 11vw, 146px)/1 var(--vp-mono);
  letter-spacing: .28em;
  text-indent: .28em;
  color: var(--vp-ink);
}

/* Побуквенный подъём: буква приходит снизу, из размытия, с задержкой по
   индексу — от неё же считаются задержки всего, что ниже по герою. */
.vp-word__ch {
  display: inline-block;
  opacity: 0;
  transform: translateY(52px) scale(1.08);
  filter: blur(16px);
  transition:
    opacity .85s var(--vp-ease),
    transform 1.15s var(--vp-ease),
    filter .85s var(--vp-ease);
  transition-delay: calc(var(--i) * 72ms + 220ms);
}

body.is-ready .vp-word__ch { opacity: 1; transform: none; filter: blur(0); }

.vp-word__kicker {
  margin-top: 18px;
  font: 600 11.5px var(--vp-mono);
  letter-spacing: .34em;
  color: var(--vp-green);
  opacity: 0;
  transform: translateY(16px);
  transition: opacity .8s var(--vp-ease) .72s, transform .8s var(--vp-ease) .72s;
}

body.is-ready .vp-word__kicker { opacity: 1; transform: none; }

.vp-word__lead {
  margin: 22px auto 0;
  max-width: 520px;
  font-size: 16px;
  line-height: 1.6;
  color: var(--vp-muted);
  text-wrap: pretty;
  opacity: 0;
  transform: translateY(16px);
  transition: opacity .8s var(--vp-ease) .86s, transform .8s var(--vp-ease) .86s;
}

body.is-ready .vp-word__lead { opacity: 1; transform: none; }

.vp-word__scroll {
  margin-top: 32px;
  font: 500 10px var(--vp-mono);
  letter-spacing: .28em;
  color: #3a4453;
  opacity: 0;
}

/* Дыхание запускается только после появления: иначе анимация opacity
   перебивала бы вход и подсказка проступала бы вместе с заголовком. */
body.is-ready .vp-word__scroll {
  animation: vp-scroll-in .55s var(--vp-ease) 1.15s forwards, vp-breathe 2.4s ease-in-out 1.7s infinite;
}

@keyframes vp-scroll-in { to { opacity: .85; } }

/* ---------- Рига из трёх панелей ---------- */
.vp-rig {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  gap: 12px;
  align-items: stretch;
  opacity: 0;
  will-change: transform, opacity;
}

.vp-panel {
  display: flex;
  flex-direction: column;
  background: var(--vp-panel);
  border: 1px solid var(--vp-edge);
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 40px 90px rgba(0, 0, 0, .6);
}

.vp-panel--chart { flex: 1 1 0; min-width: 0; opacity: 0; }

.vp-panel--dom {
  width: 500px;
  flex: none;
  background: var(--vp-panel-2);
}

.vp-panel__head {
  flex: none;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 10px 13px;
  border-bottom: 1px solid var(--vp-line);
  background: #0c121b;
}

.vp-panel__sym { font: 600 12px var(--vp-mono); letter-spacing: .08em; color: var(--vp-ink-2); }
.vp-panel__chg { font: 500 11px var(--vp-mono); font-variant-numeric: tabular-nums; color: var(--vp-green); }
.vp-panel__body { position: relative; flex: 1; min-height: 0; }

.vp-tfs { display: flex; gap: 3px; margin-left: auto; }

.vp-tf {
  border: 0;
  background: transparent;
  cursor: pointer;
  font: 500 10px var(--vp-mono);
  color: var(--vp-muted-2);
  padding: 3px 7px;
  border-radius: 4px;
  transition: background .18s, color .18s;
}

.vp-tf:hover { color: var(--vp-text); }
.vp-tf.is-active { color: #04101e; background: var(--vp-green); }

.vp-chart { position: absolute; inset: 0; }

/* Логотип TradingView: lightweight-charts рисует его отдельным элементом поверх
   канваса (#tv-attr-logo), и в левом нижнем углу он перехватывает клики. Правило
   повторяет то, что уже стоит в парном терминале (pair-terminal.css). */
.vp-chart #tv-attr-logo,
.vp-chart a[href*="tradingview"] { display: none !important; }

/* Прелоадер графика — тот же язык, что у оверлея загрузки стакана
   (.book-loading-* в chart-orderbook.css): график и панель должны говорить
   одинаково. Лежит поверх старых свечей: при смене ТФ прежний график живёт до
   прихода новых данных, и подложка честно показывает, что идёт замена. */
.vp-chart__loader {
  position: absolute;
  inset: 0;
  z-index: 6;
  display: grid;
  place-items: center;
  background:
    linear-gradient(180deg, rgba(5, 7, 10, .84), rgba(5, 7, 10, .72)),
    radial-gradient(circle at 50% 46%, rgba(74, 163, 255, .12), transparent 42%);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  animation: vp-chart-loader-in .18s ease-out;
}

.vp-chart__loader[hidden] { display: none !important; }

@keyframes vp-chart-loader-in { from { opacity: 0; } to { opacity: 1; } }

.vp-chart__loader-card {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-width: 168px;
  height: 38px;
  padding: 0 14px;
  border: 1px solid rgba(120, 170, 230, .24);
  border-radius: 6px;
  background: rgba(7, 11, 17, .92);
  box-shadow: 0 10px 28px rgba(0, 0, 0, .34);
}

.vp-chart__loader-spinner {
  width: 16px;
  height: 16px;
  flex: none;
  border: 2px solid rgba(74, 163, 255, .18);
  border-top-color: var(--vp-blue);
  border-radius: 50%;
  animation: vp-chart-loader-spin 760ms linear infinite;
}

@keyframes vp-chart-loader-spin { to { transform: rotate(360deg); } }

.vp-chart__loader-text {
  font: 800 11px var(--vp-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: .02em;
  color: var(--vp-text);
  white-space: nowrap;
}

.vp-chart__note {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  max-width: 78%;
  text-align: center;
  font: 500 11.5px/1.6 var(--vp-mono);
  letter-spacing: .04em;
  color: var(--vp-muted);
  background: rgba(7, 10, 15, .86);
  border: 1px solid var(--vp-edge);
  border-radius: 10px;
  padding: 14px 18px;
}

.vp-chart__note[hidden] { display: none; }
.vp-chart__note b { color: var(--vp-text); font-weight: 600; }

/* ---------- Хост настоящей панели стакана ---------- */
.vp-panel--dom .chart-dom-orderbook {
  width: 100%;
  min-width: 0;
  height: 100%;
  flex: 1;
  min-height: 0;
  background: transparent;
}

/* Шестерёнка открывает модалку настроек, которой на лендинге нет. */
.vp-panel--dom #settingsButton { display: none; }

/* Колесо над стаканом двигает ЦЕНОВУЮ ОСЬ (модуль гасит событие), поэтому
   панель ловит указатель только после того, как рига собралась — иначе
   курсор, случайно оказавшийся над ней, останавливал бы прокрутку страницы
   в середине истории. */
.vp-panel--dom { pointer-events: none; }
.vp-rig.is-live .vp-panel--dom { pointer-events: auto; }

/* ============================================================
   СБОРКА НА СТАПЕЛЕ
   Живые колонки НЕ размываются: слой блюра инвалидировался бы на каждом тике
   вебсокета. Размытие живёт только на призраках — пустых прямоугольниках без
   живого содержимого.
   Глубина боевых узлов пишется perspective() ВНУТРИ строки transform.
   Свойством perspective объявлено только на .vp-jig — узле лендинга без
   position:fixed потомков. Иначе #clusterMenu и #compressionMenu (fixed, дети
   .chart-dom-orderbook) получили бы новый containing block.
   ============================================================ */

.vp-panel--dom #clustersPanel,
.vp-panel--dom #tapeStage,
.vp-panel--dom #bookPanel,
.vp-panel--dom .chart-dom-orderbook,
.vp-panel--dom .chart-dom-head { will-change: transform, opacity; }

/* Единственное новое позиционирование в боевом поддереве: контейнер кожуха.
   #clustersPanel и #tapeStage уже position:relative в боевом CSS. */
.vp-panel--dom #bookPanel { position: relative; }

/* Боевой #layout залит цветом шва (padding:1px поверх фона и даёт рамку). Пока
   колонки ещё не сели, этот фон виден целиком, и пустое шасси читается светлым
   прямоугольником вместо тёмного корпуса. Рамку отдаём внутренней тенью — на
   собранной панели результат неотличим от боевого. */
.vp-panel--dom #layout {
  background: var(--panel-2, #070a0f);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .08);
}

.vp-panel--dom .chart-dom-head   { transform-origin: 14px 50%; }
.vp-panel--dom #clustersPanel    { transform-origin: 100% 50%; }
.vp-panel--dom #tapeStage        { transform-origin: 50% 0%; }
.vp-panel--dom #bookPanel        { transform-origin: 0% 50%; }
.vp-panel--dom .column-resizer   { transform-origin: 50% 0%; will-change: transform, opacity; }
.vp-panel--dom #clusterFooter    { transform-origin: 50% 100%; }
.vp-panel--dom #stageStepValue   { transform-origin: 0 50%; }
.vp-panel--dom #tapeSpeedValue   { transform-origin: 0 50%; }
.vp-panel--dom #volumeModeButton { transform-origin: 100% 0; }

/* ---------- СТАПЕЛЬ: рельс = выносная линия = подпись подсистемы ----------
   Живёт в .vp-rig, у которой нет overflow вообще: .vp-panel,
   .chart-dom-orderbook и #layout — три вложенных overflow:hidden, изнутри
   «прилететь снаружи» невозможно. Бокс ставит measure() по offsetLeft панели. */
.vp-jig {
  position: absolute;
  pointer-events: none;
  z-index: 4;
  perspective: 1400px;
  perspective-origin: 50% 44%;
  will-change: transform, opacity;
}

.vp-jig[hidden] { display: none; }

.vp-rail { position: absolute; opacity: 0; will-change: transform, opacity; }

.vp-rail::after {
  content: attr(data-name);
  position: absolute;
  font: 900 9px/1 var(--vp-mono);
  letter-spacing: .22em;
  color: rgba(120, 170, 230, .58);
  opacity: var(--vp-rail-label, 0);
  white-space: nowrap;
}

.vp-rail--l, .vp-rail--r {
  top: 42%;
  width: 360px;
  height: 1px;
  background: linear-gradient(90deg, rgba(120, 170, 230, 0), rgba(120, 170, 230, .42));
}

.vp-rail--l { right: 100%; transform-origin: right center; }

.vp-rail--r {
  left: 100%;
  transform-origin: left center;
  background: linear-gradient(270deg, rgba(120, 170, 230, 0), rgba(120, 170, 230, .42));
}

.vp-rail--l::after { left: 0; bottom: 6px; }
.vp-rail--r::after { right: 0; bottom: 6px; }

.vp-rail--b {
  top: 100%;
  left: 46%;
  width: 1px;
  height: 330px;
  transform-origin: center top;
  background: linear-gradient(180deg, rgba(120, 170, 230, .42), rgba(120, 170, 230, 0));
}

.vp-rail--b::after { bottom: 0; left: 8px; }

/* ---------- ПРИЗРАКИ ----------
   Бокс каждого — измеренный бокс его колонки. Содержимого нет намеренно:
   подрисованное «содержимое» разошлось бы с настоящей колонкой в момент подмены. */
.vp-ghost {
  position: absolute;
  left: 0; top: 0;
  width: 0; height: 0;
  opacity: 0;
  border-radius: 3px;
  background: linear-gradient(180deg, rgba(18, 26, 38, .96), rgba(9, 13, 20, .98));
  box-shadow: inset 0 0 0 1px rgba(120, 170, 230, .16), 0 34px 80px rgba(0, 0, 0, .58);
  will-change: transform, opacity, filter;
  backface-visibility: hidden;
}

.vp-ghost[hidden] { display: none; }

.vp-ghost::before {
  content: "";
  position: absolute;
  inset: 7px 5px;
  background: repeating-linear-gradient(180deg, rgba(150, 190, 235, .09) 0 1px, transparent 1px 15px);
}

/* Ведущая кромка — та, которой деталь встанет в гнездо. */
.vp-ghost::after {
  content: "";
  position: absolute;
  background: rgba(0, 192, 118, .75);
  box-shadow: 0 0 16px rgba(0, 192, 118, .45);
}

.vp-ghost[data-ghost="clusters"]::after { top: 0; bottom: 0; right: 0; width: 2px; }
.vp-ghost[data-ghost="book"]::after     { top: 0; bottom: 0; left: 0;  width: 2px; }
.vp-ghost[data-ghost="tape"]::after     { left: 0; right: 0; top: 0;   height: 2px; }

/* ---------- КОЖУХИ: единственный механизм сокрытия живых данных ----------
   Абсолютный ребёнок grid-контейнера выпадает из потока → неявного трека не
   создаёт, и ни один из четырёх ResizeObserver'ов модуля не будится.
   Маска мягкого края СТАТИЧНА: растрируется один раз вместе со слоем,
   покадрово меняется только transform. */
.vp-cover {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}

.vp-cover[hidden] { display: none; }

.vp-panel--dom #clustersPanel > .vp-cover { z-index: 85; } /* выше подноса итогов */
.vp-panel--dom #tapeStage > .vp-cover,
.vp-panel--dom #bookPanel > .vp-cover { z-index: 30; }

.vp-cover__pane {
  position: absolute;
  left: 0; right: 0;
  background: linear-gradient(180deg, #0c121b, #070a0f 62%);
  box-shadow: inset 0 0 0 1px rgba(120, 170, 230, .06);
  will-change: transform;
}

.vp-cover__pane::after { content: ""; position: absolute; background: rgba(120, 190, 255, .55); }

.vp-cover--clusters .vp-cover__pane {
  top: 0; bottom: 0;
  -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 26px), transparent 100%);
          mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 26px), transparent 100%);
}

.vp-cover--clusters .vp-cover__pane::after { top: 0; bottom: 0; right: 0; width: 1px; }

.vp-cover--tape .vp-cover__pane {
  top: 0; bottom: 0;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 26px, #000 100%);
          mask-image: linear-gradient(180deg, transparent 0, #000 26px, #000 100%);
}

.vp-cover--tape .vp-cover__pane::after { left: 0; right: 0; top: 0; height: 1px; }

.vp-cover--book .vp-cover__half { height: 50%; }

.vp-cover--book .vp-cover__half--t {
  top: 0;
  -webkit-mask-image: linear-gradient(180deg, #000 0, #000 calc(100% - 26px), transparent 100%);
          mask-image: linear-gradient(180deg, #000 0, #000 calc(100% - 26px), transparent 100%);
}

.vp-cover--book .vp-cover__half--t::after { left: 0; right: 0; bottom: 0; height: 1px; }

.vp-cover--book .vp-cover__half--b {
  bottom: 0;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 26px, #000 100%);
          mask-image: linear-gradient(180deg, transparent 0, #000 26px, #000 100%);
}

.vp-cover--book .vp-cover__half--b::after { left: 0; right: 0; top: 0; height: 1px; }

.vp-cover__mid {
  position: absolute;
  left: 0; right: 0;
  top: 50%;
  height: 1px;
  margin-top: -.5px;
  opacity: 0;
  will-change: transform, opacity;
  background: linear-gradient(90deg, transparent, #9fd0ff, transparent);
}

/* ---------- Бесплатные детали самой панели ----------
   .chart-dom-head__spacer — голая flex-распорка, а .stage-grid прозрачна;
   ни та, ни другая в orderbook-dom.js не упомянуты ни разу. */
.vp-panel--dom .chart-dom-head__spacer {
  align-self: center;
  height: 1px;
  margin: 0 8px;
  transform: scaleX(var(--vp-rule, 1));
  transform-origin: left center;
  opacity: var(--vp-rule-a, 0);
  background: repeating-linear-gradient(90deg, rgba(120, 170, 230, .45) 0 4px, transparent 4px 9px);
}

/* ---------- Лента как в SB-TERMINAL ----------
   Принты нанизаны на видимую нить. Полилинию рисует сам модуль (syncTapeLinks),
   слой связей лежит ПОД кружками (z 2 против 3) — нить и должна уходить за них.
   В боевом CSS она rgba(...,.24) в 1px и на тёмном фоне почти не читается. */
.vp-panel--dom .tape-link {
  stroke: rgba(154, 184, 219, .58);
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Заливка плоская. В боевом CSS у кружка глянцевый блик — белое пятно
   radial-gradient в левом верхнем углу плюс светлая рамка; в терминале этого
   нет, принт читается как плотная метка, а не как стеклянный шарик.
   Селекторы длиннее боевых намеренно: перебиваем специфичностью, а не порядком
   подключения файлов. Всё ограничено лендингом, /chart не меняется. */
.vp-panel--dom .chart-dom-orderbook .tape-bubble {
  border-color: rgba(0, 0, 0, .3);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .24);
  /* Принты непрозрачные: модуль гасит их по возрасту, и на перекрытии кружки
     просвечивали друг сквозь друга. !important обязателен — модуль пишет ИНЛАЙН
     переменную --opacity, а само свойство приходит из таблицы стилей, так что
     перебивается именно оно. */
  opacity: 1 !important;
}

.vp-panel--dom .chart-dom-orderbook .tape-bubble.buy { background: #8fbfff; }
.vp-panel--dom .chart-dom-orderbook .tape-bubble.sell { background: #ff737f; }

/* У точек своя подсветка (0 0 8px белым) — тоже убираем. */
.vp-panel--dom .chart-dom-orderbook .tape-bubble.tape-dot {
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .34);
}

/* ---------- Круглые уровни как в SB-TERMINAL ----------
   Какие строки круглые, решает модуль (roundMarks: "terminal" в index.html).
   Оформление — роли тёмной темы терминала: RoundMarkInk #778294, линия в ленте
   96/255, подложка строки 16/255 (DomTheme.RoundMarkLine / RoundMarkBackground).
   Линия живёт только в ленте: в лестнице она легла бы поперёк цифр цены, там
   уровень держат подложка и цена, осветлённая к белому на 45% / 40%. */
.vp-panel--dom .chart-dom-orderbook .price-guide {
  background: rgba(119, 130, 148, .376);
}

.vp-panel--dom .chart-dom-orderbook .ladder-row.round {
  background: rgba(119, 130, 148, .063);
  box-shadow: none;
}

.vp-panel--dom .chart-dom-orderbook .ladder-row.round .price { text-shadow: none; }
.vp-panel--dom .chart-dom-orderbook .ladder-row.round.ask .price { color: #ffc0c7; }
.vp-panel--dom .chart-dom-orderbook .ladder-row.round.bid .price { color: #c5e6ff; }

/* ---------- Разовые акценты ---------- */
@keyframes vp-seat {
  0%   { box-shadow: inset 0 0 0 1px rgba(0, 192, 118, .55), 0 0 26px rgba(0, 192, 118, .18); }
  55%  { box-shadow: inset 0 0 0 1px rgba(0, 192, 118, .22), 0 0 10px rgba(0, 192, 118, .07); }
  100% { box-shadow: inset 0 0 0 1px rgba(0, 192, 118, 0),   0 0 0 rgba(0, 192, 118, 0); }
}

.vp-panel--dom .vp-seat { animation: vp-seat 520ms cubic-bezier(.16, 1, .3, 1); }

/* Только box-shadow: background резайзера несёт background-blend-mode в боевом
   CSS, переписывать его нельзя. */
@keyframes vp-seam-lit {
  0%   { box-shadow: inset 1px 0 rgba(74, 163, 255, .95), inset -1px 0 rgba(215, 221, 232, .35), 0 0 14px rgba(74, 163, 255, .42); }
  100% { box-shadow: inset 1px 0 rgba(74, 163, 255, .26), inset -1px 0 rgba(215, 221, 232, .09), 0 0 0 rgba(74, 163, 255, 0); }
}

.vp-panel--dom .vp-seam-lit { animation: vp-seam-lit 380ms ease-out; }

@keyframes vp-chip-lit {
  0%   { box-shadow: 0 0 0 1px rgba(169, 207, 252, .85), 0 0 12px rgba(169, 207, 252, .35); }
  100% { box-shadow: 0 0 0 1px rgba(169, 207, 252, 0),   0 0 0 rgba(169, 207, 252, 0); }
}

.vp-panel--dom .vp-chip-lit { animation: vp-chip-lit 260ms ease-out; }

@keyframes vp-registered {
  0%   { box-shadow: inset 0 0 0 1px rgba(0, 192, 118, .7), 0 0 46px rgba(0, 192, 118, .2); }
  100% { box-shadow: inset 0 0 0 1px rgba(0, 192, 118, 0),  0 0 0 rgba(0, 192, 118, 0); }
}

.vp-panel--dom.vp-registered { animation: vp-registered 620ms cubic-bezier(.16, .84, .34, 1); }

/* ---------- Сборка завершена: снимаем слои ---------- */
.vp-rig.vp-assembled .vp-panel--dom #clustersPanel,
.vp-rig.vp-assembled .vp-panel--dom #tapeStage,
.vp-rig.vp-assembled .vp-panel--dom #bookPanel,
.vp-rig.vp-assembled .vp-panel--dom .chart-dom-orderbook,
.vp-rig.vp-assembled .vp-panel--dom .chart-dom-head,
.vp-rig.vp-assembled .vp-panel--dom .column-resizer { will-change: auto; }

.vp-rig.vp-assembled .vp-jig,
.vp-rig.vp-assembled .vp-cover { display: none !important; }

/* ---------- Боковые карточки ---------- */
/* 320px: скринеру плотностей нужны пять колонок панели «СТАКАН» (у скринера она 336px). */
.vp-side { width: 320px; flex: none; display: flex; flex-direction: column; gap: 12px; opacity: 0; }
.vp-side__card { flex: 1 1 0; min-height: 0; }
.vp-side__card:first-child { flex-grow: 1.1; }

.vp-side__head {
  flex: none;
  padding: 10px 13px;
  border-bottom: 1px solid var(--vp-line);
  background: #0c121b;
  font: 600 10px var(--vp-mono);
  letter-spacing: .2em;
  color: var(--vp-muted);
}

.vp-side__head--row { display: flex; align-items: center; justify-content: space-between; }
.vp-side__flag { font: 500 9px var(--vp-mono); letter-spacing: .1em; color: var(--vp-amber); }

.vp-scr, .vp-news { flex: 1; min-height: 0; overflow: hidden; }
.vp-news { padding: 3px 0; }

/* Скринер плотностей — вид «Стакан» панели «СТАКАН» основного скринера
   (style.css, body.screener-page .volume-depth-*): те же колонки, дорожки
   сетки, цвета сторон, шрифт Inter, пунктиры 1%/2% и линия «0». */
/* Карточка чуть уже панели скринера (320 против 336px), поэтому колонке
   времени отдано больше: «⏱ 13м 38с» иначе обрезалось. */
.vp-depth__head,
.vp-depth__row {
  display: grid;
  grid-template-columns: minmax(72px, 1.05fr) minmax(44px, .78fr) minmax(42px, .72fr) minmax(38px, .56fr) minmax(54px, .86fr);
}
.vp-depth__head {
  flex: none;
  align-items: center;
  margin: 4px 6px 4px;
  padding: 3px 4px;
  border-bottom: 1px solid rgba(150, 178, 212, .18);
}
.vp-depth__head > span {
  min-width: 0;
  padding: 0 6px;
  overflow: hidden;
  font: 760 8.5px Inter, var(--vp-sans);
  letter-spacing: .04em;
  text-transform: uppercase;
  white-space: nowrap;
  color: rgba(170, 186, 210, .62);
}
.vp-depth__head > span + span { text-align: center; border-left: 1px solid rgba(150, 178, 212, .12); }

.vp-depth { padding: 0 6px 4px; font-family: Inter, var(--vp-sans); }
.vp-depth__side { display: flex; flex-direction: column; gap: 2px; }
.vp-depth__row {
  position: relative;
  align-items: stretch;
  min-height: 22px;
  padding: 2px 4px;
  border: 1px solid transparent;
  border-radius: 5px;
  overflow: hidden;
  font-variant-numeric: tabular-nums;
  opacity: 0;
  transition: background .14s ease, border-color .14s ease;
}
.is-asks .vp-depth__row:hover { background: rgba(224, 82, 95, .10); border-color: rgba(224, 82, 95, .28); }
.is-bids .vp-depth__row:hover { background: rgba(53, 201, 146, .10); border-color: rgba(53, 201, 146, .28); }
.vp-depth__fill {
  position: absolute;
  top: 0; bottom: 0; left: 0;
  z-index: 0;
  opacity: .9;
  transform-origin: left center;
  transform: scaleX(0);
}
.is-asks .vp-depth__fill { background: linear-gradient(90deg, rgba(224, 82, 95, .30), rgba(224, 82, 95, .05)); }
.is-bids .vp-depth__fill { background: linear-gradient(90deg, rgba(53, 201, 146, .30), rgba(53, 201, 146, .05)); }
.vp-depth__row.is-hot .vp-depth__fill { filter: saturate(1.25) brightness(1.12); }
.vp-depth__row.is-cool .vp-depth__fill { filter: saturate(.7) brightness(.88); }
.vp-depth__row > span:not(.vp-depth__fill) {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  padding: 0 4px;
  overflow: hidden;
  white-space: nowrap;
}
.vp-depth__row > span:not(.vp-depth__fill) + span:not(.vp-depth__fill) { border-left: 1px solid rgba(150, 178, 212, .12); }
.vp-depth__row > .vp-depth__ticker { justify-content: flex-start; font-size: 10px; font-weight: 800; color: rgba(239, 247, 255, .96); }
.vp-depth__name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.vp-depth__row.is-round .vp-depth__ticker::before { content: "★"; margin-right: 3px; font-size: 8px; color: rgba(225, 180, 90, .95); }
.vp-depth__mkt {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  gap: 3px;
  margin-left: 4px;
  padding: 1px 3px;
  border: 1px solid rgba(120, 150, 190, .18);
  border-radius: 3px;
  background: rgba(100, 130, 170, .08);
  font-size: 9.5px;
  font-weight: 800;
  line-height: 1;
  color: rgba(170, 190, 220, .6);
}
.vp-depth__mkt i {
  width: 13px; height: 13px;
  border-radius: 3px;
  background: url("../img/exchanges/binance-square.png") center / contain no-repeat;
}
.vp-depth__price { font-size: 9.5px; font-weight: 600; color: rgba(214, 228, 248, .9); }
.vp-depth__vol { font-size: 9.5px; font-weight: 600; color: rgba(220, 232, 250, .8); }
.vp-depth__dist { font-size: 9.5px; font-weight: 800; }
.is-asks .vp-depth__dist { color: rgba(255, 196, 202, .86); }
.is-bids .vp-depth__dist { color: rgba(183, 244, 224, .86); }
.vp-depth__row > .vp-depth__time { padding: 0 3px; font-size: 8px; font-weight: 600; color: rgba(170, 186, 210, .56); }
.vp-depth__line,
.vp-depth__zero { position: relative; height: 0; }
.vp-depth__line { margin: 5px 0; border-top: 1px dashed rgba(150, 178, 212, .22); }
.vp-depth__zero { margin: 7px 0; border-top: 2px solid rgba(150, 178, 212, .5); }
.vp-depth__line span,
.vp-depth__zero span {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  background: var(--vp-panel);
  line-height: 1;
}
.vp-depth__line span { right: 4px; padding: 0 4px; font: 700 8.5px Inter, var(--vp-sans); letter-spacing: .04em; color: rgba(170, 186, 210, .62); }
.vp-depth__zero span { left: 50%; transform: translate(-50%, -50%); padding: 0 8px; font: 800 9px Inter, var(--vp-sans); letter-spacing: .08em; color: rgba(220, 232, 250, .86); }

/* Карточка новости — та же, что в ленте /news: .news-message с .nm-head /
   .nm-chips / .nm-text и классами влияния из classifyMarketImpact. */
.vp-news {
  --nw-panel: rgba(10, 15, 23, .72);
  --nw-panel-hover: rgba(12, 18, 27, .88);
  --nw-border: rgba(120, 150, 190, .12);
  --nw-border-mid: rgba(120, 150, 190, .20);
  --nw-text: rgba(240, 247, 255, .92);
  --nw-soft: rgba(190, 205, 230, .40);
  --nw-green: #4ade80;
  --nw-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Consolas, monospace;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px;
  overflow: hidden;
  /* Свежая строка приходит снизу, поэтому лента прижата к нижнему краю, а
     уходящая наверх обязана растворяться: обрез по краю читается как поломка. */
  justify-content: flex-end;
  mask-image: linear-gradient(transparent 0%, #000 20%);
  -webkit-mask-image: linear-gradient(transparent 0%, #000 20%);
}

.vp-news .news-message {
  flex: none;
  padding: 7px 9px 8px;
  border: 1px solid var(--nw-border);
  border-radius: 9px;
  background: var(--nw-panel);
  transition: border-color 160ms ease, background 160ms ease;
}

.vp-news .news-message:hover { border-color: rgba(130, 180, 240, .26); background: var(--nw-panel-hover); }

@keyframes nwCardIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
@keyframes nwCardFlash {
  0% { border-color: rgba(130, 180, 240, .75); box-shadow: 0 0 0 3px rgba(75, 159, 234, .20); }
  100% { border-color: var(--nw-border); box-shadow: none; }
}

.vp-news .news-message.new-message { animation: nwCardIn 260ms ease, nwCardFlash 3.2s ease; }

.vp-news .nm-head { display: flex; align-items: center; gap: 7px; margin-bottom: 5px; }
.vp-news .nm-head-spacer { flex: 1; }

.vp-news .nm-time {
  font-family: var(--nw-mono);
  font-size: 10px;
  font-weight: 500;
  color: var(--nw-soft);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.vp-news .nm-impact-badge {
  min-width: 26px;
  padding: 1px 6px;
  border: 1px solid var(--nw-border-mid);
  border-radius: 5px;
  background: rgba(120, 150, 190, .10);
  color: rgba(226, 238, 255, .90);
  font-family: var(--nw-mono);
  font-size: 9.5px;
  font-weight: 600;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.vp-news .nm-impact-badge.impact-very-positive,
.vp-news .nm-impact-badge.impact-positive {
  color: var(--nw-green);
  background: rgba(34, 197, 94, .12);
  border-color: rgba(34, 197, 94, .38);
}

.vp-news .nm-impact-badge.impact-low-positive {
  color: #a3e635;
  background: rgba(132, 204, 22, .10);
  border-color: rgba(132, 204, 22, .30);
}

.vp-news .nm-impact-badge.impact-very-negative,
.vp-news .nm-impact-badge.impact-negative {
  color: #f87171;
  background: rgba(220, 38, 38, .12);
  border-color: rgba(220, 38, 38, .38);
}

.vp-news .nm-impact-badge.impact-low-negative {
  color: #fb923c;
  background: rgba(249, 115, 22, .10);
  border-color: rgba(249, 115, 22, .30);
}

.vp-news .nm-impact-badge.impact-very-positive { box-shadow: 0 0 8px rgba(34, 197, 94, .18); }
.vp-news .nm-impact-badge.impact-very-negative { box-shadow: 0 0 8px rgba(220, 38, 38, .18); }

.vp-news .nm-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 5px; }

.vp-news .ticker-chip {
  padding: 2px 7px;
  border: 1px solid rgba(34, 197, 94, .35);
  border-radius: 5px;
  background: rgba(34, 197, 94, .10);
  color: var(--nw-green);
  font-family: var(--nw-mono);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: .3px;
}

.vp-news .nm-text {
  color: var(--nw-text);
  font-size: 11.5px;
  line-height: 1.45;
  word-wrap: break-word;
  overflow-wrap: anywhere;
}

.vp-news .nm-clamp {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ---------- Линк: номер окна и демо новостей ----------
   Номер линка — как в терминале: одно число в шапке графика, в колонке ленты
   стакана и в шапке новостей значит одну связку. Горит, когда демо связывает. */
.vp-side__title { display: inline-flex; align-items: center; gap: 8px; }

.vp-link {
  display: inline-grid;
  place-items: center;
  min-width: 22px;
  height: 16px;
  padding: 0 5px;
  border: 1px solid rgba(74, 163, 255, .4);
  border-radius: 4px;
  background: rgba(74, 163, 255, .12);
  color: #4aa3ff;
  font: 700 10px var(--vp-mono);
  letter-spacing: .04em;
  font-variant-numeric: tabular-nums;
}
.vp-link[hidden] { display: none; }
.vp-link.is-lit { animation: vp-link-lit .9s var(--vp-ease); }
@keyframes vp-link-lit {
  0%   { opacity: 0; transform: scale(.55); box-shadow: 0 0 0 0 rgba(74, 163, 255, .55); }
  45%  { opacity: 1; transform: scale(1.14); }
  100% { transform: none; box-shadow: 0 0 0 9px rgba(74, 163, 255, 0); }
}

/* Под темпом ленты (.tape-speed-value: top 20px, высота 16px). */
.vp-panel--dom .vp-dom-link { position: absolute; top: 40px; left: 4px; z-index: 6; pointer-events: none; }

/* Фокус на стакан: кольцо сходится и гаснет. Тень панели повторена в кадрах —
   анимация box-shadow подменяет её целиком. */
.vp-panel--dom:focus { outline: none; }
.vp-panel--dom.vp-focus { animation: vp-focus-ring 1.7s var(--vp-ease); }
@keyframes vp-focus-ring {
  0%   { box-shadow: 0 0 0 14px rgba(0, 192, 118, 0), 0 40px 90px rgba(0, 0, 0, .6); }
  30%  { box-shadow: 0 0 0 2px rgba(0, 192, 118, .7), 0 0 46px rgba(0, 192, 118, .22), 0 40px 90px rgba(0, 0, 0, .6); }
  100% { box-shadow: 0 0 0 1px rgba(0, 192, 118, 0), 0 0 0 rgba(0, 192, 118, 0), 0 40px 90px rgba(0, 0, 0, .6); }
}

/* Тикер сменился — подпись вспыхивает в шапке графика и стакана. */
.vp-sym-flash { animation: vp-sym-flash 1.3s ease; }
@keyframes vp-sym-flash {
  0%, 18% { color: #fff; text-shadow: 0 0 14px rgba(74, 163, 255, .95); }
  100%    { text-shadow: 0 0 0 rgba(74, 163, 255, 0); }
}

/* Новость, по которой уехал стакан: синяя вспышка вместо обычной, чип монеты
   пульсирует — видно, ЧТО именно переключило окна. */
.vp-news .news-message.is-link-hit { border-color: rgba(74, 163, 255, .45); }
.vp-news .news-message.new-message.is-link-hit { animation: nwCardIn 260ms ease, vp-news-hit 3.4s ease; }
@keyframes vp-news-hit {
  0%, 30% { border-color: rgba(74, 163, 255, .9); box-shadow: 0 0 0 3px rgba(74, 163, 255, .24); }
  100%    { border-color: rgba(74, 163, 255, .45); box-shadow: none; }
}
.vp-news .ticker-chip.is-hot { animation: vp-chip-hot 1.1s ease 2; }
@keyframes vp-chip-hot {
  50% { background: rgba(74, 222, 128, .28); box-shadow: 0 0 10px rgba(74, 222, 128, .35); }
}

/* Плашка новости на узких экранах: колонка новостей там скрыта. */
.vp-news.vp-flash {
  position: absolute;
  left: 50%;
  top: 62px;
  z-index: 8;
  width: min(360px, calc(100vw - 32px));
  padding: 0;
  overflow: visible;
  mask-image: none;
  -webkit-mask-image: none;
  opacity: 0;
  transform: translate(-50%, -12px);
  transition: opacity .35s var(--vp-ease), transform .35s var(--vp-ease);
  pointer-events: none;
}
.vp-news.vp-flash.is-on { opacity: 1; transform: translate(-50%, 0); }
.vp-news.vp-flash .news-message { box-shadow: 0 18px 50px rgba(0, 0, 0, .6); }

@media (prefers-reduced-motion: reduce) {
  .vp-link.is-lit,
  .vp-panel--dom.vp-focus,
  .vp-sym-flash,
  .vp-news .ticker-chip.is-hot,
  .vp-try.is-running::before { animation: none; }
  .vp-news .news-message.new-message.is-link-hit { animation: none; }
  .vp-news.vp-flash { transition: none; }
}

/* ---------- Подписи и точки ---------- */
.vp-caps {
  position: absolute;
  left: 0; right: 0; bottom: 26px;
  display: flex;
  justify-content: center;
  pointer-events: none;
  z-index: 6;
  padding: 0 20px;
}

.vp-caps { height: 44px; }

.vp-cap {
  position: absolute;
  left: 20px; right: 20px; top: 0;
  opacity: 0;
  text-align: center;
  font: 600 12.5px var(--vp-mono);
  letter-spacing: .14em;
  color: #8b97a9;
  text-transform: uppercase;
  transition: opacity .5s ease, transform .5s var(--vp-ease);
  will-change: transform, opacity;
}

/* ---------- Подсказка живого терминала ----------
   Сменяет строку подписей ровно в тот момент, когда панель стала интерактивной:
   у одного места на экране одна роль за раз. Селектор через соседа — .vp-live
   стоит в разметке после .vp-rig, класс is-live вешает хореография. */
.vp-live {
  position: absolute;
  left: 0; right: 0;
  bottom: 24px;
  z-index: 7;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 0 20px;
  opacity: 0;
  transform: translateY(10px);
  pointer-events: none;
  transition: opacity .45s var(--vp-ease), transform .45s var(--vp-ease);
}

.vp-rig.is-live ~ .vp-live { opacity: 1; transform: none; pointer-events: auto; }
.vp-rig.is-live ~ .vp-caps { opacity: 0; transition: opacity .3s ease; }

/* ---------- Фраза над собранным терминалом ----------
   Занимает полосу между шапкой и терминалом (--vp-rig-top ставит layout()
   сцены) и появляется вместе с «ДАЛЬШЕ»: по словам, из размытия. Кегль — не
   больше половины полосы; где полоса ниже MOTTO_MIN_BAND (app.js), фразы нет. */
.vp-motto {
  position: absolute;
  left: 0; right: 0; top: 58px;
  height: max(0px, calc(var(--vp-rig-top, 0px) - 58px));
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 24px;
  overflow: hidden;
  pointer-events: none;
  transition: opacity .35s ease;
}
body.is-coaching .vp-motto { opacity: 0; }
/* Моноширинный капс с разрядкой — тот же голос, что у слова VIPER на первом
   экране (выбор владельца 30.09 на стенде motto-fonts.html, вариант 12).
   text-indent равен разрядке: иначе хвостовой пробел последней буквы сдвигал
   бы строку влево от центра. */
.vp-motto__line {
  margin: 0;
  font: 700 min(clamp(20px, 2.1vw, 38px), calc((var(--vp-rig-top, 0px) - 58px) * .42))/1.1 var(--vp-mono);
  letter-spacing: .14em;
  text-indent: .14em;
  text-transform: uppercase;
  color: var(--vp-ink-2);
  text-align: center;
  white-space: nowrap;
}
.vp-motto__line span {
  display: inline-block;
  opacity: 0;
  transform: translateY(22px);
  filter: blur(10px);
  transition: opacity .8s var(--vp-ease), transform .8s var(--vp-ease), filter .8s var(--vp-ease);
  transition-delay: calc(var(--i) * 110ms);
}
.vp-rig.is-live ~ .vp-motto .vp-motto__line span { opacity: 1; transform: none; filter: none; }
.vp-motto__line .is-accent {
  background: linear-gradient(100deg, #00c076 0%, #7dffc4 45%, #00c076 60%, #00c076 100%);
  background-size: 220% 100%;
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
}
.vp-rig.is-live ~ .vp-motto .is-accent { animation: vp-motto-shine 3.6s ease-in-out 1s infinite; }
@keyframes vp-motto-shine { 0% { background-position: 100% 0; } 55%, 100% { background-position: 0 0; } }
.is-motto-off .vp-motto { display: none; }
/* Телефон: в одну строку фраза не помещается даже нижним кеглем (33 знака
   моно с разрядкой — 24.6em, на 20px это 490px), и по центру её обрезало с
   обоих краёв. Здесь она встаёт в две строки с переносом после тире (тире
   сидит в одном блоке со словом перед ним: между inline-block перенос возможен
   всегда, и неразрывный пробел его не держит), а кегль считается от ширины:
   самая длинная строка «СДЕЛАН ТРЕЙДЕРАМИ —» — 19 знаков, замер в браузере
   .756em на знак с разрядкой, ≈14.5em с отступом; делитель 15.4 — запас на
   округление. По высоте — не больше четверти полосы: две строки с
   интерлиньяжем занимают её меньше чем на две трети. */
.vp-motto__line .vp-motto__br { display: none; }
@media (max-width: 599px) {
  .vp-motto { padding: 0 16px; }
  .vp-motto__line {
    white-space: normal;
    font-size: min(calc((100vw - 32px) / 15.4), calc((var(--vp-rig-top, 0px) - 58px) * .24));
    line-height: 1.25;
  }
  .vp-motto__line .vp-motto__br { display: block; }
}
@media (prefers-reduced-motion: reduce) {
  .vp-motto__line span { transition: none; }
  .vp-rig.is-live ~ .vp-motto .is-accent { animation: none; }
}

.vp-live__next {
  border: 1px solid var(--vp-edge);
  background: rgba(10, 15, 22, .8);
  color: var(--vp-text);
  cursor: pointer;
  font: 600 10px var(--vp-mono);
  letter-spacing: .16em;
  padding: 7px 13px;
  border-radius: 999px;
  transition: border-color .2s, color .2s, background .2s;
}

.vp-live__next:hover {
  border-color: var(--vp-green);
  color: var(--vp-ink-2);
  background: rgba(0, 192, 118, .1);
}

.vp-dots {
  position: absolute;
  right: 20px; top: 50%;
  transform: translateY(-50%);
  z-index: 6;
  display: flex;
  flex-direction: column;
  gap: 7px;
  pointer-events: none;
}

.vp-dot {
  width: 3px; height: 22px;
  border-radius: 2px;
  background: var(--vp-edge);
  transition: background .3s, height .3s;
}

/* ===================== БЕГУЩАЯ СТРОКА ===================== */
.vp-marquee {
  position: relative;
  z-index: 3;
  border-top: 1px solid var(--vp-line);
  border-bottom: 1px solid var(--vp-line);
  background: var(--vp-panel-2);
  overflow: hidden;
  padding: 13px 0;
}

.vp-marquee__track { display: flex; width: max-content; animation: vp-marquee 46s linear infinite; }

.vp-marquee__item {
  display: flex;
  align-items: center;
  gap: 24px;
  padding: 0 24px;
  font: 500 11px var(--vp-mono);
  letter-spacing: .2em;
  color: var(--vp-dim);
  white-space: nowrap;
}

.vp-marquee__item::after {
  content: "";
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--vp-edge);
  flex: none;
}

/* ===================== ЧТО ВНУТРИ ===================== */
.vp-feats { position: relative; z-index: 3; max-width: 1180px; margin: 0 auto; padding: 118px 22px 20px; }

.vp-kicker { font: 600 10.5px var(--vp-mono); letter-spacing: .28em; color: var(--vp-green); margin-bottom: 20px; }

.vp-h2 {
  margin: 0;
  max-width: 20ch;
  font: 700 clamp(34px, 5.4vw, 62px)/1.04 var(--vp-sans);
  letter-spacing: -.03em;
  color: var(--vp-ink);
  text-wrap: balance;
}

.vp-h2--sm { max-width: none; font-size: clamp(30px, 4.4vw, 50px); line-height: 1.06; }

.vp-lead { margin: 22px 0 0; max-width: 56ch; font-size: 16.5px; line-height: 1.65; color: var(--vp-muted); text-wrap: pretty; }

/* ---------- ЭКОСИСТЕМА ----------
   Слово на поле живых стаканов (IBM Plex Sans Bold — выбор владельца
   30.09.2026 на стенде eco-variants.html). Рисует один холст (initEco): поле
   данных тускло во всю ширину, буквы — полупрозрачная тёмная толща (сквозь неё
   проступает размытое поле) с чётким белым контуром. Ширина — СТРАНИЦЫ, а не
   колонки: --vp-page-w ставит JS
   (clientWidth без полосы прокрутки; 100vw её включает). Края полосы данных
   растворяются маской, чтобы поле не читалось вырезанным прямоугольником. */
.vp-eco {
  position: relative;
  width: var(--vp-page-w, 100vw);
  margin: 0 0 46px calc(50% - var(--vp-page-w, 100vw) / 2);
  line-height: 0;
}

.vp-eco__canvas {
  display: block;
  width: 100%;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 16%, #000 84%, transparent 100%);
          mask-image: linear-gradient(180deg, transparent 0, #000 16%, #000 84%, transparent 100%);
}

.vp-eco__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ===================== ПЛИТКИ =====================
   Раскладка — именованными областями: у плиток разные размеры (тренажёр 2×1 в
   своей пропорции, «другие биржи» 2×1 — текст слева, запись справа, запись
   экрана и новости широкие), и только явная карта даёт сетку без дыр на каждой
   ширине. Порядок карточек в разметке — порядок чтения всех раскладок.
   Мини-сцена в текстовой плитке растягивается на высоту ряда (flex: 1), так
   что соседи тренажёра получают больше сцены, а не пустоту под текстом. */
.vp-cards {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-template-areas:
    "tr    tr    jr    risk"
    "walls walls rec   rec"
    "scr   news  news  chart"
    "tune  oi    tg    dens";
  align-items: stretch;
  gap: 14px;
  margin-top: 54px;
}

.vp-card[data-area="tr"]    { grid-area: tr; }
.vp-card[data-area="jr"]    { grid-area: jr; }
.vp-card[data-area="risk"]  { grid-area: risk; }
.vp-card[data-area="walls"] { grid-area: walls; }
.vp-card[data-area="rec"]   { grid-area: rec; }
.vp-card[data-area="scr"]   { grid-area: scr; }
.vp-card[data-area="news"]  { grid-area: news; }
.vp-card[data-area="chart"] { grid-area: chart; }
.vp-card[data-area="tune"]  { grid-area: tune; }
.vp-card[data-area="oi"]    { grid-area: oi; }
.vp-card[data-area="tg"]    { grid-area: tg; }
.vp-card[data-area="dens"]  { grid-area: dens; }

@media (max-width: 1159px) {
  .vp-cards {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-template-areas:
      "tr    tr    jr"
      "risk  walls walls"
      "rec   rec   scr"
      "news  news  chart"
      "tune  oi    tg"
      "dens  dens  dens";
  }
}

@media (max-width: 819px) {
  .vp-cards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-areas:
      "tr    tr"
      "jr    risk"
      "walls walls"
      "rec   rec"
      "scr   news"
      "chart tune"
      "oi    tg"
      "dens  dens";
  }
}

@media (max-width: 559px) {
  .vp-cards { grid-template-columns: minmax(0, 1fr); grid-template-areas: none; }
  .vp-card[data-area] { grid-area: auto; }
}

/* ---------- Карточка ----------
   Рамка подсвечивается за курсором (--mx/--my ставит initCards, один
   pointermove на всю сетку), под курсором — мягкое свечение фона. Приподнятие
   на наведении — только после появления (is-in), иначе спорит с ним. */
.vp-card {
  --mx: -600px;
  --my: -600px;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
  padding: 12px 12px 20px;
  border-radius: 18px;
  border: 1px solid rgba(36, 47, 63, .8);
  background:
    radial-gradient(520px circle at var(--mx) var(--my), rgba(0, 192, 118, .065), transparent 42%),
    linear-gradient(180deg, #0c121a, #080c12);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .035), 0 26px 60px -36px rgba(0, 0, 0, .95);
  overflow: hidden;
  isolation: isolate;
  transition: opacity .85s var(--vp-ease), transform .6s var(--vp-ease), border-color .3s;
}
.vp-card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  border-radius: inherit;
  padding: 1px;
  background: radial-gradient(340px circle at var(--mx) var(--my), rgba(0, 192, 118, .75), rgba(74, 163, 255, .28) 38%, transparent 70%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  opacity: 0;
  transition: opacity .35s ease;
  pointer-events: none;
}
.vp-cards:hover .vp-card::before { opacity: 1; }
/* Селектор длиннее [data-reveal] намеренно: правило появления стоит в файле
   ниже и иначе забрало бы переход рамки. */
.vp-cards > .vp-card { transition: opacity .85s var(--vp-ease), transform .6s var(--vp-ease), border-color .3s; }
.vp-card.is-in:hover { transform: translateY(-4px); border-color: rgba(58, 76, 99, .9); }

.vp-card__body { display: flex; flex-direction: column; gap: 10px; padding: 0 8px; }
.vp-card__top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.vp-card__no { font: 600 10px var(--vp-mono); letter-spacing: .2em; color: var(--vp-dim); }
.vp-card__tag {
  font: 500 9.5px var(--vp-mono);
  letter-spacing: .14em;
  padding: 3px 9px;
  border-radius: 999px;
  white-space: nowrap;
  border: 1px solid var(--tone-edge);
  background: var(--tone-wash);
  color: var(--tone-ink);
}
.tone-green { --tone-ink: #00c076; --tone-edge: rgba(0, 192, 118, .35); --tone-wash: rgba(0, 192, 118, .09); }
.tone-blue { --tone-ink: #4aa3ff; --tone-edge: rgba(74, 163, 255, .35); --tone-wash: rgba(74, 163, 255, .09); }
.tone-amber { --tone-ink: #f0b90b; --tone-edge: rgba(240, 185, 11, .32); --tone-wash: rgba(240, 185, 11, .08); }
.tone-red { --tone-ink: #f6465d; --tone-edge: rgba(246, 70, 93, .32); --tone-wash: rgba(246, 70, 93, .08); }
.vp-card__title { margin: 0; font: 600 18.5px/1.25 var(--vp-sans); letter-spacing: -.015em; color: var(--vp-ink-2); text-wrap: pretty; }
.vp-card__desc { margin: 0; font-size: 14.2px; line-height: 1.6; color: var(--vp-muted); text-wrap: pretty; }

/* ---------- Записи в плитках ---------- */
.vp-card__slot {
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  border: 1px solid rgba(30, 40, 54, .9);
  border-radius: 12px;
  background: #000;
  overflow: hidden;
  cursor: zoom-in;
  font: inherit;
  color: inherit;
  transition: border-color .3s;
}
.vp-card__slot:hover,
.vp-card__slot:focus-visible { border-color: var(--vp-edge-hi); outline: none; }
.vp-card__slot:focus-visible { box-shadow: 0 0 0 2px rgba(0, 192, 118, .45); }
.vp-card__slot--video { aspect-ratio: 1930 / 1438; flex: none; }
.vp-card__video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% 30%;
  display: block;
  transition: transform .8s var(--vp-ease);
}
.vp-card__slot:hover .vp-card__video { transform: scale(1.015); }
.vp-card__watch {
  position: absolute; right: 10px; bottom: 10px;
  z-index: 3;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 10px;
  border: 1px solid rgba(255, 255, 255, .09);
  border-radius: 999px;
  background: rgba(5, 7, 10, .72);
  -webkit-backdrop-filter: blur(6px);
          backdrop-filter: blur(6px);
  font: 600 10px var(--vp-mono);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--vp-text);
  transition: background .25s, color .25s;
}
.vp-card__watch svg {
  width: 12px; height: 12px;
  fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round;
}
.vp-card__slot:hover .vp-card__watch { background: rgba(0, 192, 118, .9); color: #03130c; }

/* «Другие биржи»: текст слева, вертикальная запись справа во всю высоту
   плитки. Обрезка — снизу: шапка стакана с тикером остаётся в кадре. */
.vp-card--split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, .9fr);
  align-items: stretch;
  gap: 16px;
  padding: 12px;
}
.vp-card--split .vp-card__body { justify-content: center; padding: 10px 4px 10px 10px; }
/* Колонка текста узкая: тег справа отрывался от номера и прилипал к записи. */
.vp-card--split .vp-card__top { justify-content: flex-start; }
.vp-card--split .vp-card__slot--portrait { height: 100%; min-height: 320px; }
.vp-card__slot--portrait .vp-card__video { object-fit: cover; object-position: 50% 0; }

@media (max-width: 559px) {
  .vp-card--split { display: flex; flex-direction: column; }
  .vp-card--split .vp-card__slot--portrait { order: -1; height: auto; min-height: 0; aspect-ratio: 492 / 662; max-height: 78vh; }
  .vp-card__slot--portrait .vp-card__video { object-fit: contain; }
}

/* ---------- Мини-сцены ----------
   Код дизайна страницы: цвета стакана /chart, моно-подписи, зелёный акцент.
   Сцена работает, только пока плитка в кадре: без is-live (его ставит
   initCards) CSS-анимации внутри стоят. Списки сцен (сделки, заявки,
   сообщения, клипы) — с contain: size: высоту ряда сетки задают тексты и
   соседи, а не число строк, иначе каждая новая строка растила плитку. Сколько
   строк видно, решает высота, которую плитка получила от ряда. */
.vz {
  position: relative;
  flex: 1 1 auto;
  min-height: 164px;
  border-radius: 12px;
  border: 1px solid rgba(30, 40, 54, .85);
  background:
    radial-gradient(120% 100% at 50% 0%, rgba(22, 31, 44, .55), transparent 70%),
    #070a0f;
  overflow: hidden;
  font: 600 10.5px/1.2 var(--vp-mono);
  font-variant-numeric: tabular-nums;
  color: var(--vp-text);
}
.vz:not(.is-live) *,
.vz:not(.is-live) *::before,
.vz:not(.is-live) *::after { animation-play-state: paused !important; }
.vz svg { display: block; }

/* журнал: VIPER → ДНЕВНИК */
.vz--journal { display: flex; flex-direction: column; gap: 10px; padding: 12px; }
.vzj__flow { display: flex; align-items: center; gap: 8px; }
.vzj__node {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 9px;
  border-radius: 8px;
  border: 1px solid rgba(0, 192, 118, .35);
  background: rgba(0, 192, 118, .08);
  color: var(--vp-green);
  font-size: 10px;
  letter-spacing: .12em;
  white-space: nowrap;
}
.vzj__node img { width: 12px; height: 12px; }
.vzj__node svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.vzj__node--diary { border-color: rgba(74, 163, 255, .35); background: rgba(74, 163, 255, .08); color: #8fc3ff; }
.vzj__wire { position: relative; flex: 1; height: 1px; background: linear-gradient(90deg, rgba(0, 192, 118, .55), rgba(74, 163, 255, .55)); }
.vzj__wire i {
  position: absolute; top: -3px; left: 0;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: #7dffc4;
  box-shadow: 0 0 10px rgba(0, 192, 118, .9);
  opacity: 0;
}
.vzj__wire.is-pulse i { animation: vzj-packet .9s var(--vp-ease); }
@keyframes vzj-packet { 0% { left: 0; opacity: 1; } 85% { opacity: 1; } 100% { left: calc(100% - 7px); opacity: 0; } }
.vzj__rows {
  flex: 1;
  min-height: 180px;
  contain: size;
  display: flex; flex-direction: column; gap: 4px;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, #000 72%, transparent);
          mask-image: linear-gradient(180deg, #000 72%, transparent);
}
.vzj__row {
  flex: none;
  display: grid;
  grid-template-columns: 36px minmax(0, 1fr) auto auto;
  gap: 8px;
  align-items: center;
  padding: 6px 8px;
  border-radius: 7px;
  background: rgba(255, 255, 255, .025);
  border: 1px solid rgba(255, 255, 255, .03);
}
.vzj__row .t { color: #4e5867; }
.vzj__row .s { color: var(--vp-ink-2); overflow: hidden; text-overflow: ellipsis; }
.vzj__row .d { font-size: 9px; letter-spacing: .1em; padding: 1px 5px; border-radius: 4px; }
.vzj__row .d.up { color: var(--vp-green); background: rgba(0, 192, 118, .1); }
.vzj__row .d.down { color: #ff7b88; background: rgba(246, 70, 93, .1); }
.vzj__row .p.up { color: var(--vp-green); }
.vzj__row .p.down { color: #ff7b88; }
.vzj__row.is-new { animation: vz-row-in .6s var(--vp-ease); }
@keyframes vz-row-in {
  from { opacity: 0; transform: translateY(-10px); background: rgba(0, 192, 118, .18); }
  to   { opacity: 1; transform: none; }
}
.vzj__foot { display: inline-flex; align-items: center; gap: 7px; color: var(--vp-muted); font-size: 10px; letter-spacing: .04em; }
.vzj__foot svg { width: 14px; height: 14px; flex: none; fill: none; stroke: var(--vp-green); stroke-width: 1.4; stroke-linecap: round; }

/* риск: просадка → лимит → замок */
.vz--risk { display: flex; flex-direction: column; gap: 10px; padding: 12px; }
.vzr__head { display: flex; justify-content: space-between; align-items: baseline; color: var(--vp-muted); letter-spacing: .12em; text-transform: uppercase; font-size: 9.5px; }
.vzr__dd { font: 700 20px var(--vp-mono); letter-spacing: 0; color: #ff7b88; }
.vzr__track { position: relative; height: 8px; margin-bottom: 14px; border-radius: 99px; background: rgba(255, 255, 255, .06); }
.vzr__track::after { content: ""; position: absolute; right: 0; top: -4px; bottom: -4px; width: 2px; border-radius: 1px; background: #f6465d; }
.vzr__fill {
  position: absolute; inset: 0;
  border-radius: inherit;
  transform-origin: left center;
  transform: scaleX(0);
  background: linear-gradient(90deg, #f0b90b, #f6465d);
  transition: transform .5s var(--vp-ease), box-shadow .4s;
}
.vzr__limit { position: absolute; right: 0; top: 12px; font-size: 9px; letter-spacing: .08em; color: #4e5867; }
.vzr__plot { position: relative; flex: 1; min-height: 56px; }
.vzr__curve { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.vzr__curve polyline { fill: none; stroke: #ff7b88; stroke-width: 1.8; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.vzr__lim { stroke: rgba(246, 70, 93, .55); stroke-width: 1; stroke-dasharray: 4 4; vector-effect: non-scaling-stroke; }
.vzr__lock {
  position: absolute; left: 50%; top: 50%;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 12px;
  border-radius: 10px;
  border: 1px solid rgba(246, 70, 93, .55);
  background: rgba(40, 10, 16, .82);
  -webkit-backdrop-filter: blur(6px);
          backdrop-filter: blur(6px);
  color: #ffb3bb;
  font-size: 9.5px;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0;
  transform: translate(-50%, -50%) scale(.86);
  transition: opacity .35s, transform .45s var(--vp-ease);
}
.vzr__lock svg { width: 14px; height: 14px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.6; }
.vzr__lock-t { display: flex; flex-direction: column; gap: 3px; }
.vzr__lock small { font-size: 8.5px; letter-spacing: .1em; color: rgba(255, 179, 187, .65); }
.vz--risk.is-locked .vzr__fill { box-shadow: 0 0 16px rgba(246, 70, 93, .55); }
.vz--risk.is-locked .vzr__lock { opacity: 1; transform: translate(-50%, -50%) scale(1); }

/* запись экрана: таймлайн, отрезки сделок, файлы клипов */
.vz--rec { display: flex; flex-direction: column; gap: 12px; padding: 12px 14px; }
.vzc__head { display: flex; align-items: center; gap: 12px; }
.vzc__rec { display: inline-flex; align-items: center; gap: 6px; color: #ff7b88; letter-spacing: .16em; }
.vzc__rec i { width: 8px; height: 8px; border-radius: 50%; background: #f6465d; box-shadow: 0 0 10px rgba(246, 70, 93, .8); animation: vp-blink 1.2s ease-in-out infinite; }
.vzc__codec { margin-left: auto; color: #4e5867; letter-spacing: .12em; }
.vzc__track {
  position: relative;
  height: 36px;
  border-radius: 8px;
  border: 1px solid rgba(255, 255, 255, .05);
  background: repeating-linear-gradient(90deg, rgba(255, 255, 255, .05) 0 1px, transparent 1px 22px), rgba(255, 255, 255, .02);
}
.vzc__seg { position: absolute; top: 6px; bottom: 6px; border-radius: 5px; }
.vzc__seg.up { background: linear-gradient(180deg, rgba(0, 192, 118, .55), rgba(0, 192, 118, .28)); box-shadow: inset 0 0 0 1px rgba(0, 192, 118, .7); }
.vzc__seg.down { background: linear-gradient(180deg, rgba(246, 70, 93, .5), rgba(246, 70, 93, .26)); box-shadow: inset 0 0 0 1px rgba(246, 70, 93, .65); }
.vzc__playhead { position: absolute; top: -5px; bottom: -5px; width: 2px; margin-left: -1px; border-radius: 1px; background: #f2f6fc; box-shadow: 0 0 10px rgba(242, 246, 252, .6); }
.vzc__files { flex: 1; min-height: 88px; contain: size; display: flex; flex-direction: column; gap: 5px; overflow: hidden; }
.vzc__file {
  flex: none;
  display: flex; align-items: center; gap: 8px;
  padding: 6px 8px;
  border-radius: 7px;
  background: rgba(255, 255, 255, .03);
  border-left: 2px solid var(--vp-green);
  white-space: nowrap;
  overflow: hidden;
  animation: vz-row-in .5s var(--vp-ease);
}
.vzc__file.down { border-left-color: #f6465d; }
.vzc__file span { overflow: hidden; text-overflow: ellipsis; }
.vzc__file svg { width: 13px; height: 13px; flex: none; fill: none; stroke: #778294; stroke-width: 1.3; }

/* скринер: сводный список крупных заявок */
.vz--depth { display: flex; flex-direction: column; gap: 6px; padding: 10px; }
.vzd__head, .vzd__row { display: grid; grid-template-columns: 1.35fr .9fr .9fr .8fr; gap: 6px; align-items: center; }
.vzd__head { padding: 0 8px; color: #4e5867; font-size: 8.5px; letter-spacing: .06em; text-transform: uppercase; white-space: nowrap; }
.vzd__head span:not(:first-child),
.vzd__row span:not(:first-child) { text-align: right; }
.vzd__rows {
  flex: 1;
  min-height: 210px;
  contain: size;
  display: flex; flex-direction: column; gap: 4px;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, #000 80%, transparent);
          mask-image: linear-gradient(180deg, #000 80%, transparent);
}
.vzd__row { position: relative; flex: none; padding: 7px 8px; border-radius: 6px; overflow: hidden; }
.vzd__row > i { position: absolute; left: 0; top: 0; bottom: 0; width: 100%; transform-origin: left center; z-index: 0; }
.vzd__row.ask > i { background: linear-gradient(90deg, rgba(255, 118, 76, .42), rgba(255, 118, 76, .1)); }
.vzd__row.bid > i { background: linear-gradient(90deg, rgba(84, 166, 255, .4), rgba(84, 166, 255, .08)); }
.vzd__row span { position: relative; z-index: 1; white-space: nowrap; }
.vzd__row .sym { color: var(--vp-ink-2); overflow: hidden; text-overflow: ellipsis; }
.vzd__row.ask .dist { color: #ff8c9a; }
.vzd__row.bid .dist { color: #9ed6ff; }
.vzd__row .age { color: var(--vp-muted); }
.vzd__row.is-new { animation: vzd-new 1.2s var(--vp-ease); }
@keyframes vzd-new {
  0%   { opacity: 0; transform: translateX(-12px); box-shadow: inset 0 0 0 1px rgba(242, 246, 252, .6); }
  30%  { opacity: 1; transform: none; }
  100% { box-shadow: inset 0 0 0 1px rgba(242, 246, 252, 0); }
}

/* новости: новость → линк → стакан */
.vz--news { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(24px, .3fr) minmax(0, 1fr); align-items: center; padding: 14px; }
.vzn__news {
  padding: 10px 11px;
  border-radius: 9px;
  border: 1px solid rgba(120, 150, 190, .18);
  background: rgba(10, 15, 23, .85);
  opacity: 0;
  transform: translateY(12px);
  transition: opacity .45s, transform .55s var(--vp-ease), border-color .4s, box-shadow .4s;
}
.vz--news.is-news .vzn__news { opacity: 1; transform: none; }
.vz--news.is-linked .vzn__news { border-color: rgba(74, 163, 255, .7); box-shadow: 0 0 0 3px rgba(74, 163, 255, .14); }
.vzn__meta { display: flex; align-items: center; gap: 6px; margin-bottom: 7px; }
.vzn__time { color: #4e5867; }
.vzn__chip { padding: 1px 6px; border-radius: 4px; color: #4ade80; background: rgba(34, 197, 94, .1); border: 1px solid rgba(34, 197, 94, .35); }
.vzn__impact { margin-left: auto; padding: 1px 6px; border-radius: 4px; color: #f87171; background: rgba(220, 38, 38, .12); border: 1px solid rgba(220, 38, 38, .38); }
.vzn__text { font: 500 12px/1.35 var(--vp-sans); color: rgba(240, 247, 255, .92); }
.vzn__wire { width: 100%; height: 20px; overflow: visible; }
.vzn__wire path { fill: none; stroke: #4aa3ff; stroke-width: 1.6; vector-effect: non-scaling-stroke; stroke-dasharray: 1; stroke-dashoffset: 1; }
.vz--news.is-linked .vzn__wire path { stroke-dashoffset: 0; transition: stroke-dashoffset .45s var(--vp-ease); filter: drop-shadow(0 0 4px rgba(74, 163, 255, .85)); }
.vzn__ladder { border-radius: 9px; border: 1px solid rgba(38, 50, 67, .9); background: #05080c; overflow: hidden; }
.vzn__lh { display: flex; align-items: center; gap: 6px; padding: 6px 8px; border-bottom: 1px solid rgba(255, 255, 255, .05); }
.vzn__lh i { width: 6px; height: 6px; border-radius: 50%; background: var(--vp-green); }
.vzn__lh b { color: var(--vp-ink-2); letter-spacing: .04em; }
.vzn__link { margin-left: auto; padding: 0 5px; border-radius: 4px; color: #4aa3ff; background: rgba(74, 163, 255, .12); border: 1px solid rgba(74, 163, 255, .4); font-size: 9.5px; }
.vzn__ladder.is-switched .vzn__lh b { animation: vp-sym-flash 1.2s ease; }
.vzn__row { position: relative; display: flex; justify-content: flex-end; padding: 2px 8px; font-size: 10px; }
.vzn__row i { position: absolute; left: 0; top: 1px; bottom: 1px; }
.vzn__row span { position: relative; }
.vzn__row.ask { color: #ff8c9a; }
.vzn__row.ask i { background: rgba(255, 118, 76, .5); }
.vzn__row.bid { color: #9ed6ff; }
.vzn__row.bid i { background: rgba(84, 166, 255, .45); }
.vzn__ladder.is-switched .vzn__row { animation: vz-row-in .5s var(--vp-ease); }

/* графики: живые свечи */
.vzg__svg { position: absolute; left: 10px; top: 12px; width: calc(100% - 64px); height: calc(100% - 24px); overflow: visible; }
.vzg__svg .w { stroke-width: 1; }
.vzg__svg .up { fill: #26a69a; stroke: #26a69a; }
.vzg__svg .down { fill: #ef5350; stroke: #ef5350; }
.vzg__svg .pl { stroke: rgba(242, 246, 252, .35); stroke-dasharray: 3 3; }
.vzg__price { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); padding: 2px 5px; border-radius: 4px; background: #26a69a; color: #03130c; font-size: 9.5px; transition: background .3s; }
.vzg__price.down { background: #ef5350; color: #fff; }

/* автонастройка: шаг стакана меняется, строки пересобираются */
.vz--tune { display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; }
.vzt__head { display: flex; align-items: center; gap: 8px; color: var(--vp-muted); letter-spacing: .1em; text-transform: uppercase; font-size: 9.5px; }
.vzt__head b { color: var(--vp-ink-2); font-size: 12px; letter-spacing: 0; }
.vzt__wheel { width: 16px; height: 16px; fill: none; stroke: var(--vp-green); stroke-width: 1.3; stroke-linecap: round; }
.vzt__auto { margin-left: auto; padding: 2px 6px; border-radius: 4px; color: var(--vp-green); background: rgba(0, 192, 118, .1); border: 1px solid rgba(0, 192, 118, .35); }
.vzt__rows { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 2px; }
.vzt__row { position: relative; display: flex; justify-content: flex-end; padding: 2px 8px; font-size: 10.5px; border-radius: 3px; }
.vzt__row i { position: absolute; left: 0; top: 1px; bottom: 1px; width: 72%; border-radius: 2px; transform-origin: left center; transition: transform .6s var(--vp-ease); }
.vzt__row span { position: relative; }
.vzt__row.ask { color: #ff8c9a; }
.vzt__row.ask i { background: rgba(255, 118, 76, .3); }
.vzt__row.bid { color: #9ed6ff; }
.vzt__row.bid i { background: rgba(84, 166, 255, .26); }
/* Строки выше автопорога — горят; порог двигается вместе с шагом. */
.vzt__row.is-big.ask i { background: rgba(255, 94, 66, .92); box-shadow: 0 0 10px rgba(255, 94, 66, .4); }
.vzt__row.is-big.bid i { background: rgba(70, 154, 255, .88); box-shadow: 0 0 10px rgba(70, 154, 255, .4); }
.vzt__row.is-big span { color: #f2f6fc; }
.vzt__row.best { box-shadow: inset 0 -1px 0 rgba(242, 246, 252, .28); }
.vz--tune.is-step .vzt__row span { animation: vzt-step .6s ease; }
.vz--tune.is-step .vzt__head b { animation: vzt-flash .8s ease; }
.vz--tune.is-step .vzt__notch { animation: vzt-roll .6s ease; }
@keyframes vzt-step { from { opacity: .2; } to { opacity: 1; } }
@keyframes vzt-flash { 0% { color: var(--vp-green); } 100% { color: var(--vp-ink-2); } }
@keyframes vzt-roll { 0% { transform: translateY(0); } 50% { transform: translateY(3px); opacity: .3; } 100% { transform: translateY(0); } }

/* ОИ: столбик на каждые 10 секунд */
.vz--oi { display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; }
.vzo__head { display: flex; justify-content: space-between; align-items: baseline; color: var(--vp-muted); letter-spacing: .1em; font-size: 9.5px; text-transform: uppercase; }
.vzo__head b { font-size: 14px; letter-spacing: 0; color: var(--vp-green); }
.vzo__head b.down { color: #ff7b88; }
.vzo__bars { position: relative; flex: 1; overflow: hidden; }
/* Лента на 30 шагов: столбик — тридцатая часть ширины за вычетом 29 зазоров.
   Сдвиг на шаг — (ширина + зазор) / 30 от ширины самой ленты. */
.vzo__track { position: absolute; inset: 0; display: flex; gap: 3px; }
.vzo__track.is-moving { transform: translateX(calc((-100% - 3px) / 30)); transition: transform .6s var(--vp-ease); }
.vzo__zero { position: absolute; left: 0; right: 0; top: 50%; height: 1px; background: rgba(255, 255, 255, .12); }
.vzo__bar { position: relative; flex: 0 0 calc((100% - 87px) / 30); }
.vzo__bar i { position: absolute; left: 0; right: 0; border-radius: 2px; transition: height .45s var(--vp-ease); }
.vzo__bar.up i { bottom: 50%; background: linear-gradient(0deg, rgba(0, 192, 118, .3), rgba(0, 192, 118, .9)); }
.vzo__bar.down i { top: 50%; background: linear-gradient(180deg, rgba(246, 70, 93, .3), rgba(246, 70, 93, .9)); }
.vzo__bar:last-child i { box-shadow: 0 0 10px rgba(242, 246, 252, .35); }

/* Telegram: сообщения приходят, терминал закрыт */
.vz--tg { display: flex; flex-direction: column; gap: 10px; padding: 12px; }
.vzm__stack {
  flex: 1;
  min-height: 128px;
  contain: size;
  display: flex; flex-direction: column; justify-content: flex-end; gap: 8px;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 32%);
          mask-image: linear-gradient(180deg, transparent, #000 32%);
}
.vzm__msg { flex: none; display: flex; align-items: flex-end; gap: 8px; animation: vzm-in .6s var(--vp-ease); }
@keyframes vzm-in { from { opacity: 0; transform: translateY(14px) scale(.96); } to { opacity: 1; transform: none; } }
.vzm__ava { flex: none; width: 26px; height: 26px; display: grid; place-items: center; border-radius: 50%; background: linear-gradient(180deg, #2aabee, #229ed9); }
.vzm__ava img { width: 14px; height: 14px; }
.vzm__bubble { min-width: 0; padding: 7px 10px 8px; border-radius: 12px 12px 12px 4px; background: #182533; font: 500 11.5px/1.35 var(--vp-sans); color: #e8f1fb; }
.vzm__from { display: flex; gap: 6px; margin-bottom: 2px; font: 600 10px var(--vp-sans); color: #6ab3f3; }
.vzm__from span { font-weight: 400; color: #6d7f94; }
.vzm__sub { font-size: 10.5px; color: #8fa2b8; }
.vzm__foot { display: inline-flex; align-items: center; gap: 6px; color: #4e5867; font-size: 9px; letter-spacing: .1em; text-transform: uppercase; }
.vzm__foot i { width: 6px; height: 6px; border-radius: 50%; background: #4e5867; }

/* слежение за плотностью: держат → съедают → переставили → сняли */
.vz--track { display: flex; flex-direction: column; gap: 8px; padding: 10px 12px; }
.vzk__rows { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 2px; }
.vzk__row { position: relative; display: flex; justify-content: space-between; padding: 3px 8px; border-radius: 4px; font-size: 10.5px; color: #ff8c9a; }
.vzk__row i { position: absolute; left: 0; top: 1px; bottom: 1px; width: 100%; border-radius: 3px; transform-origin: left center; background: rgba(255, 118, 76, .32); transition: transform .8s var(--vp-ease); }
.vzk__row span { position: relative; }
.vzk__row.is-wall { color: #fff; }
.vzk__row.is-wall i { background: linear-gradient(90deg, rgba(255, 94, 66, .95), rgba(255, 94, 66, .55)); box-shadow: 0 0 18px rgba(255, 94, 66, .35); }
.vzk__row.is-gone i { transform: scaleX(0) !important; }
.vzk__status { display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: 8px; background: rgba(255, 255, 255, .03); font-size: 10px; letter-spacing: .12em; }
.vzk__status i { width: 7px; height: 7px; border-radius: 50%; background: var(--st, var(--vp-green)); box-shadow: 0 0 8px var(--st, var(--vp-green)); transition: background .3s; }
.vzk__status span { color: var(--st, var(--vp-green)); transition: color .3s; }
.vzk__status b { margin-left: auto; font-weight: 600; color: var(--vp-muted); }

@media (prefers-reduced-motion: reduce) {
  .vp-card, .vp-card::before { transition: none; }
  .vp-card.is-in:hover { transform: none; }
  .vz *, .vz *::before, .vz *::after { animation: none !important; transition: none !important; }
}

/* ---------- Карточка новостей: кнопка демо линка ---------- */
.vp-card__actions {
  margin-top: auto;
  padding-top: 4px;
  display: flex;
  align-items: center;
  gap: 12px;
}

.vp-try {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 9px 16px 9px 13px;
  border: 1px solid rgba(0, 192, 118, .45);
  border-radius: 999px;
  background: rgba(0, 192, 118, .08);
  color: var(--vp-green);
  font: 600 10.5px var(--vp-mono);
  letter-spacing: .16em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background .25s, color .25s, border-color .25s, box-shadow .25s;
}
.vp-try:hover,
.vp-try:focus-visible {
  background: var(--vp-green);
  border-color: var(--vp-green);
  color: #03130c;
  box-shadow: 0 0 0 4px rgba(0, 192, 118, .14);
  outline: none;
}
.vp-try__icon { width: 11px; height: 11px; fill: currentColor; flex: none; }

/* Без колонки графика демо показывать нечего (NEWS_DEMO_MIN_WIDTH в app.js). */
@media (max-width: 999px) { .vp-try { display: none; } }

/* ---------- Подсказки демо линка ----------
   Рамка вокруг цели притемняет всё остальное (тень в размер экрана), плашка
   с номером шага стоит над целью или под ней. Координаты — от окна: сцена
   закреплена, а цель пересчитывается каждый кадр. */
.vp-coach {
  position: fixed;
  inset: 0;
  z-index: 80;
  pointer-events: none;
  opacity: 0;
  transition: opacity .35s ease;
}
.vp-coach.is-on { opacity: 1; }
.vp-coach.is-away { opacity: 0; }
.vp-coach__ring {
  position: absolute;
  border-radius: 16px;
  box-shadow:
    0 0 0 1.5px rgba(0, 192, 118, .95),
    0 0 30px rgba(0, 192, 118, .4),
    0 0 0 200vmax rgba(2, 4, 7, .56);
  transition: left .55s var(--vp-ease), top .55s var(--vp-ease), width .55s var(--vp-ease), height .55s var(--vp-ease);
}
.vp-coach__ring::after {
  content: "";
  position: absolute;
  inset: -7px;
  border-radius: 21px;
  border: 1px solid rgba(0, 192, 118, .55);
  animation: vp-coach-pulse 1.5s ease-out infinite;
}
@keyframes vp-coach-pulse { from { opacity: .9; transform: scale(1); } to { opacity: 0; transform: scale(1.035); } }
.vp-coach__tip {
  position: absolute;
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: min(380px, calc(100vw - 24px));
  padding: 10px 14px;
  border: 1px solid rgba(0, 192, 118, .45);
  border-radius: 12px;
  background: rgb(8, 13, 19);
  box-shadow: 0 18px 50px rgba(0, 0, 0, .6);
  font: 500 13.5px/1.35 var(--vp-sans);
  color: var(--vp-ink-2);
  transition: left .55s var(--vp-ease), top .55s var(--vp-ease);
}
.vp-coach__tip.is-new { animation: vp-coach-tip .5s var(--vp-ease); }
@keyframes vp-coach-tip { from { opacity: 0; } to { opacity: 1; } }
.vp-coach__step {
  flex: none;
  padding: 3px 7px;
  border-radius: 999px;
  background: var(--vp-green);
  font: 700 10px var(--vp-mono);
  letter-spacing: .1em;
  color: #03130c;
}
.vp-coach__arrow {
  position: absolute;
  top: 100%;
  width: 11px;
  height: 11px;
  margin: -6px 0 0 -6px;
  background: rgb(8, 13, 19);
  border-right: 1px solid rgba(0, 192, 118, .45);
  border-bottom: 1px solid rgba(0, 192, 118, .45);
  transform: rotate(45deg);
}
.vp-coach__tip.is-below .vp-coach__arrow { top: 0; transform: rotate(225deg); }
@media (prefers-reduced-motion: reduce) {
  .vp-coach__ring, .vp-coach__tip { transition: none; }
  .vp-coach__ring::after, .vp-coach__tip.is-new { animation: none; }
}

/* Пока идёт демо — кнопка не нажимается, вместо треугольника дышит точка. */
.vp-try.is-running {
  pointer-events: none;
  background: transparent;
  border-color: var(--vp-edge-hi);
  color: var(--vp-muted);
  box-shadow: none;
}
.vp-try.is-running .vp-try__icon { display: none; }
.vp-try.is-running::before {
  content: "";
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--vp-green);
  animation: vp-try-dot 1s ease-in-out infinite;
}
@keyframes vp-try-dot { 50% { opacity: .25; transform: scale(.7); } }

/* ---------- Прелоадер записи ----------
   Висит, пока видео попросили играть, а первого кадра ещё нет, и когда
   воспроизведение встало за буфером. Процент — доля файла, которую браузер
   уже держит: запись весит мегабайты, и честная цифра объясняет паузу лучше
   одного крутящегося кольца. Полоска внизу — та же доля. */
.vp-vload {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 12px;
  background:
    radial-gradient(circle at 50% 46%, rgba(0, 192, 118, .10), transparent 46%),
    rgba(5, 7, 10, .62);
  -webkit-backdrop-filter: blur(3px);
          backdrop-filter: blur(3px);
  opacity: 0;
  visibility: hidden;
  transition: opacity .3s ease, visibility 0s linear .3s;
  pointer-events: none;
}
.vp-vload.is-on { opacity: 1; visibility: visible; transition: opacity .2s ease; }

.vp-vload__ring {
  width: 30px;
  height: 30px;
  border: 2px solid rgba(0, 192, 118, .18);
  border-top-color: var(--vp-green);
  border-radius: 50%;
  animation: vp-chart-loader-spin 760ms linear infinite;
}
.vp-vload__text {
  font: 700 10px var(--vp-mono);
  letter-spacing: .16em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  color: var(--vp-text);
  white-space: nowrap;
}
.vp-vload__bar {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  background: rgba(255, 255, 255, .06);
}
.vp-vload__bar > span {
  display: block;
  height: 100%;
  width: 100%;
  transform-origin: left center;
  transform: scaleX(0);
  background: var(--vp-green);
  box-shadow: 0 0 10px rgba(0, 192, 118, .6);
  transition: transform .25s linear;
}
.vp-vload.is-error .vp-vload__ring { display: none; }
.vp-vload.is-error .vp-vload__text { color: var(--vp-red); }

@media (prefers-reduced-motion: reduce) {
  .vp-vload__ring { animation-duration: 2.4s; }
}

/* ---------- Окно просмотра записи ---------- */
html.vp-viewer-open { overflow: hidden; }

/* Ширина окна следует за пропорцией записи (--ar из VIDEO_SOURCES), иначе
   ограниченная по высоте запись стоит в окне с чёрными полями по бокам.
   --vw-max не даёт растянуть маленькую запись больше чем в полтора раза: мелкий
   текст стакана при сильном увеличении расплывается. */
.vp-viewer {
  width: min(1480px, 94vw, calc((92vh - 54px) * var(--ar, 1.342)), var(--vw-max, 1480px));
  max-width: none; max-height: none;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--vp-text);
  overflow: visible;
}
.vp-viewer::backdrop {
  background: rgba(3, 5, 8, .82);
  -webkit-backdrop-filter: blur(4px);
          backdrop-filter: blur(4px);
}
.vp-viewer[open] { animation: vp-viewer-in .32s var(--vp-ease); }
@keyframes vp-viewer-in {
  from { opacity: 0; transform: translateY(12px) scale(.985); }
  to   { opacity: 1; transform: none; }
}

.vp-viewer__frame {
  border: 1px solid var(--vp-edge-hi);
  border-radius: 14px;
  background: var(--vp-panel);
  overflow: hidden;
  box-shadow: 0 30px 90px rgba(0, 0, 0, .7);
}

.vp-viewer__bar {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 10px 10px 10px 18px;
  border-bottom: 1px solid var(--vp-edge);
}
.vp-viewer__title {
  font: 600 11px var(--vp-mono);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--vp-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.vp-viewer__close {
  flex: none;
  display: grid; place-items: center;
  width: 32px; height: 32px;
  border: 1px solid var(--vp-edge);
  border-radius: 8px;
  background: transparent;
  color: var(--vp-muted);
  cursor: pointer;
  transition: color .2s, border-color .2s;
}
.vp-viewer__close:hover, .vp-viewer__close:focus-visible { color: var(--vp-ink); border-color: var(--vp-edge-hi); outline: none; }
.vp-viewer__close svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }

/* Запись экрана с мелким текстом: только contain, обрезать нельзя. Высота
   ограничена окном — иначе на широком мониторе нижняя панель уйдёт за край. */
.vp-viewer__stage { position: relative; }

.vp-viewer__video {
  display: block;
  width: 100%;
  height: auto;
  max-height: calc(92vh - 54px);
  background: #000;
  object-fit: contain;
}

@media (prefers-reduced-motion: reduce) {
  .vp-viewer[open] { animation: none; }
}

/* ===================== ПОДКЛЮЧЕНИЯ — ЛЕНТА ===================== */
/* Заменяет .vp-conn__rail / __track / __card / __logo / __name целиком. */

.vp-conn { position: relative; z-index: 3; padding: 108px 0 20px; }
.vp-conn__intro { max-width: 1180px; margin: 0 auto; padding: 0 22px; }

/* --- сам рельс: полоса во всю ширину между двумя волосяными линиями --- */
.vp-tape {
  --tape-h: 196px;
  --tape-wire: 84px;   /* y провода внутри рельса */
  position: relative;
  margin-top: 40px;
  height: var(--tape-h);
  border-top: 1px solid var(--vp-line);
  border-bottom: 1px solid var(--vp-line);
  background: linear-gradient(180deg, rgba(10,15,22,.55), rgba(7,10,15,.85));
}

/* Провод-основание кончается ТАМ ЖЕ, где цепочка, — на свежем принте, и его конец
   прячется под непрозрачным диском. Раньше он шёл до края экрана («трасса идёт
   дальше»), но у ленты дальше ничего нет: справа от последней сделки будущее, а
   его не рисуют. Слева провод растворяется — там прошлое, оно уходит за кадр. */
.vp-tape__wire {
  position: absolute; left: 0; right: var(--tape-inset, 48px);
  top: var(--tape-wire); height: 1px;
  background: linear-gradient(90deg, transparent,
    rgba(210,216,226,.10) 6%, rgba(210,216,226,.10) 100%);
  pointer-events: none;
}

/* Считывающая головка. Неподвижна: не лента стоит, а площадки в неё приезжают. */
.vp-tape__head {
  position: absolute; left: calc(100% - var(--tape-inset, 48px)); top: 0; bottom: 0; width: 0;
  border-left: 1px solid rgba(120,170,230,.09);
  pointer-events: none;
}
.vp-tape__head::before, .vp-tape__head::after {
  content: ""; position: absolute; left: -3px; width: 7px; height: 1px;
  background: rgba(120,170,230,.40);
}
.vp-tape__head::before { top: 8px; }
.vp-tape__head::after  { top: 14px; opacity: .5; }

.vp-tape__rail {
  position: absolute; inset: 0; overflow: hidden;
  /* Маска НЕСИММЕТРИЧНА, и это не стиль, а смысл.
     Справа её НЕТ: там нечего прятать. Следующий принт лежит за краем рельса и
     снимается overflow'ом — у ленты не бывает будущих сделок.
     Слева — короткое растворение в один шаг (--tape-lead ставит JS): без него
     уходящий диск обрезало бы пополам краем рельса. Затухания по возрасту здесь
     нет: логотип в полсилы читается как плохо отрисованный, а не как давний. */
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 var(--tape-lead, 116px));
  mask-image: linear-gradient(90deg, transparent 0, #000 var(--tape-lead, 116px));
}

/* Единственный анимируемый узел на всю секцию. --tape-w и --tape-snap ставит JS. */
.vp-tape__track {
  position: absolute; top: 0; left: 0; height: 100%;
  width: var(--tape-w, 200%);
  transform: translate3d(0, 0, 0);
}

/* Перехода НЕТ намеренно. У боевой ленты .tape-bubble стоит на
   transitionDuration 0s: принт не переезжает, он ПОЯВЛЯЕТСЯ на новом слоте, а
   весь ряд мгновенно сдвигается. Любой tween здесь — уже не лента, а карусель. */
@media (prefers-reduced-motion: no-preference) {
  .vp-tape__track { will-change: transform; }
}

/* --- геометрия ленты --- */
.vp-tape__svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; z-index: 1; }

/* Ровно .tape-link из chart-orderbook.css: одна ломаная на всю цепочку. */
.vp-tape__link {
  fill: none;
  /* Заметнее, чем в боевой ленте: там нить фон, а здесь она несёт всю структуру —
     без неё принты рассыпаются в случайно расставленные кружки. */
  stroke: rgba(170,190,215,.42);
  stroke-width: 1.2;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
/* Отсутствующий канал не пропускается молча — он ПОМЕЧЕН. Спецификация обязана
   называть пустую графу, иначе её нельзя проверить. */

/* Принт биржи: диск — константа, марка — переменная внутри него. */
.vp-tape__print {
  position: absolute; top: calc(var(--tape-wire) + var(--y, 0px)); left: var(--x);
  width: var(--disc, 44px); height: var(--disc, 44px);
  margin: calc(var(--disc, 44px) / -2) 0 0 calc(var(--disc, 44px) / -2);
  border-radius: 50%;
  background: #0b1119;
  box-shadow: inset 0 0 0 1px var(--vp-edge), 0 6px 18px rgba(0,0,0,.55);
  display: grid; place-items: center;
  z-index: 2;
}

.vp-tape__print img {
  display: block;
  height: var(--m, 22px);
  width: var(--mw, auto); max-width: calc(var(--disc, 44px) - 10px);
  object-fit: contain;
  border-radius: var(--r, 0);
  opacity: var(--o, 1);
  box-shadow: 0 0 0 1px var(--halo, transparent);
  transform: translateY(var(--dy, 0));
}

/* Подпись ПОД диском, а не сбоку. Сбоку колонка стоила «диск + зазор + текст»,
   и при шаге 116 увеличить можно было только что-то одно; под диском она стоит
   максимум из двух, и растут оба. */
.vp-tape__name {
  position: absolute;
  top: calc(var(--tape-wire) + var(--y, 0px) + var(--disc, 56px) / 2 + 7px);
  left: var(--x);
  transform: translateX(-50%);
  padding: 2px 6px; border-radius: 3px;
  background: rgba(7,10,15,.92);
  font: 600 10.5px var(--vp-mono); letter-spacing: .1em;
  color: var(--vp-text); white-space: nowrap;
  z-index: 2;
}

/* Подпись под головкой — единственное, что тут меняет содержание, а не позицию. */
.vp-tape__readout {
  position: absolute; right: 18px; bottom: 9px; max-width: calc(100% - 36px);
  margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  text-align: right; pointer-events: none;
  font: 500 9.5px var(--vp-mono); letter-spacing: .2em; color: var(--vp-muted-2);
  transition: opacity .3s var(--vp-ease);
}

/* --- все подключения списком ---
   Карточка площадки: марка в диске (те же --m/--mw/--dy/--r/--halo, что у
   принта ленты), имя и только отличающие её возможности. На широком экране
   пять в ряд (два ряда по пять), имя над чипами; уже — по две и по одной, всё
   в одну строку. */
.vp-venues {
  list-style: none;
  margin: 34px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 10px;
}
.vp-venue {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-rows: auto auto;
  column-gap: 11px;
  row-gap: 6px;
  align-items: center;
  min-width: 0;
  padding: 11px 12px;
  border: 1px solid rgba(36, 47, 63, .8);
  border-radius: 12px;
  background: linear-gradient(180deg, #0c121a, #080c12);
  transition: border-color .25s;
}
.vp-venue:hover { border-color: var(--vp-edge-hi); }
.vp-venue__logo {
  grid-row: 1 / span 2;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: #0b1119;
  box-shadow: inset 0 0 0 1px var(--vp-edge);
  display: grid;
  place-items: center;
}
.vp-venue__logo img {
  display: block;
  height: var(--m, 18px);
  width: var(--mw, auto);
  max-width: 30px;
  object-fit: contain;
  border-radius: var(--r, 0);
  box-shadow: 0 0 0 1px var(--halo, transparent);
  transform: translateY(var(--dy, 0));
}
.vp-venue__name {
  align-self: end;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font: 600 14.5px var(--vp-sans);
  color: var(--vp-ink-2);
}
.vp-venue__caps { align-self: start; display: flex; flex-wrap: wrap; gap: 4px; }
.vp-venue__cap {
  padding: 2px 7px;
  border-radius: 999px;
  border: 1px solid var(--cap-edge);
  background: var(--cap-wash);
  font: 600 8.5px var(--vp-mono);
  letter-spacing: .1em;
  white-space: nowrap;
  color: var(--cap-ink);
}
.vp-venue__cap.is-trade { --cap-ink: #00c076; --cap-edge: rgba(0, 192, 118, .35); --cap-wash: rgba(0, 192, 118, .08); }
.vp-venue__cap.is-view  { --cap-ink: #8b97a9; --cap-edge: rgba(139, 151, 169, .3); --cap-wash: rgba(139, 151, 169, .06); }
.vp-venue__cap.is-extra { --cap-ink: #4aa3ff; --cap-edge: rgba(74, 163, 255, .35); --cap-wash: rgba(74, 163, 255, .08); }

@media (max-width: 1099px) {
  .vp-venues { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .vp-venue { grid-template-columns: auto minmax(0, 1fr) auto; grid-template-rows: auto; }
  .vp-venue__logo { grid-row: auto; }
  .vp-venue__name, .vp-venue__caps { align-self: center; }
  .vp-venue__caps { justify-content: flex-end; }
}
@media (max-width: 559px) {
  .vp-venues { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 760px) {
  .vp-conn { padding-top: 76px; }
  .vp-tape { --tape-h: 152px; --tape-wire: 62px; }
  .vp-tape__name { font-size: 9.5px; letter-spacing: .1em; padding: 2px 5px; }
}

/* Сокращённая моторика: не обрубок, а управляемый список (приём Vercel).
   Дорожка стоит на translate 0 и показывает первую половину, которая ПО
   ПОСТРОЕНИЮ перекрывает экран — состояние полное и читаемое, а не случайно
   уцелевшее. Маска снимается, чтобы ничего не было срезано. */
@media (prefers-reduced-motion: reduce) {
  .vp-tape__track { transform: none; will-change: auto; }
  .vp-tape__rail {
    overflow-x: auto; overflow-y: hidden;
    -webkit-mask-image: none; mask-image: none;
    scrollbar-width: thin;
  }
  .vp-tape__head, .vp-tape__readout { display: none; }
}

/* ===================== ЛИСТ ОЖИДАНИЯ ===================== */
.vp-wait { position: relative; z-index: 3; max-width: 1180px; margin: 0 auto; padding: 126px 22px 118px; }

.vp-wait__box {
  position: relative;
  border: 1px solid var(--vp-edge);
  border-radius: 20px;
  background: linear-gradient(180deg, #0b1118, var(--vp-panel-2));
  overflow: hidden;
  padding: clamp(28px, 5vw, 60px);
}

.vp-wait__glow {
  position: absolute;
  inset: 0;
  background: radial-gradient(700px 320px at 12% 0%, rgba(0, 192, 118, .12), transparent 70%);
  pointer-events: none;
}

/* min(300px, 100%): на телефоне внутри рамки меньше 300px, и колонка с жёстким
   минимумом вылезала за неё — форма и текст обрезались по правому краю. */
.vp-wait__grid {
  position: relative;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: 44px;
  align-items: start;
}

.vp-wait .vp-lead { max-width: 46ch; font-size: 16px; margin-top: 20px; }

/* Сообщество под формой: карточка-ссылка в цвете Telegram. */
.vp-community {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 22px;
  padding: 14px 16px;
  border: 1px solid var(--vp-edge);
  border-radius: 14px;
  background: rgba(8, 13, 19, .7);
  color: inherit;
  text-decoration: none;
  transition: border-color .25s, background .25s;
}
.vp-community:hover,
.vp-community:focus-visible { border-color: rgba(42, 171, 238, .6); background: rgba(42, 171, 238, .06); outline: none; }
.vp-community__icon {
  flex: none;
  width: 40px; height: 40px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: linear-gradient(180deg, #2aabee, #229ed9);
  box-shadow: 0 6px 18px rgba(34, 158, 217, .35);
}
.vp-community__icon svg { width: 20px; height: 20px; fill: #fff; transform: translateX(-1px); }
.vp-community__text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.vp-community__title { font: 600 15px var(--vp-sans); color: var(--vp-ink-2); }
.vp-community__sub { font-size: 13px; color: var(--vp-muted); }
.vp-community__go { margin-left: auto; font: 600 10.5px var(--vp-mono); letter-spacing: .08em; color: #6ab3f3; white-space: nowrap; }
@media (max-width: 420px) { .vp-community__go { display: none; } }
.vp-wait .vp-kicker { margin-bottom: 18px; }

.vp-form { display: flex; flex-direction: column; gap: 12px; }
.vp-form__row { display: flex; gap: 10px; flex-wrap: wrap; }

.vp-form__input {
  flex: 1 1 210px;
  min-width: 0;
  background: var(--vp-bg);
  border: 1px solid #263143;
  border-radius: 10px;
  padding: 15px 16px;
  font: 500 15px var(--vp-mono);
  color: var(--vp-ink-2);
  outline: none;
  transition: border-color .2s;
}

.vp-form__input::placeholder { color: var(--vp-muted-2); }
.vp-form__input:focus { border-color: var(--vp-green); }

.vp-form__btn {
  flex: none;
  border: 0;
  cursor: pointer;
  font: 600 12px var(--vp-mono);
  letter-spacing: .14em;
  color: #04101e;
  background: var(--vp-green);
  padding: 15px 24px;
  border-radius: 10px;
  box-shadow: 0 10px 34px rgba(0, 192, 118, .22);
  transition: filter .2s;
}

.vp-form__btn:hover { filter: brightness(1.12); }
.vp-form__btn:disabled { cursor: progress; filter: saturate(.55) brightness(.85); }

/* Ловушка для ботов: поле, которое человек не видит и не заполняет. Сдвинуто
   за край, а не display:none — часть ботов пропускает скрытые поля. */
.vp-form__trap {
  position: absolute;
  left: -10000px;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.vp-form__hint {
  min-height: 16px;
  font: 500 11px var(--vp-mono);
  letter-spacing: .08em;
  color: var(--vp-muted-2);
}

.vp-form__hint.is-bad { color: var(--vp-red); }

.vp-done {
  display: flex;
  align-items: center;
  gap: 14px;
  border: 1px solid rgba(0, 192, 118, .4);
  background: rgba(0, 192, 118, .08);
  border-radius: 12px;
  padding: 20px;
}

.vp-done[hidden] { display: none; }

.vp-done__tick {
  width: 34px; height: 34px;
  flex: none;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--vp-green);
  color: #04101e;
  font: 700 15px var(--vp-mono);
}

.vp-done__title { font: 600 14.5px var(--vp-sans); color: var(--vp-ink-2); }
.vp-done__mail { margin-top: 4px; font: 500 11.5px var(--vp-mono); color: var(--vp-muted); overflow-wrap: anywhere; }

/* ===================== ПОДВАЛ ===================== */
.vp-footer { position: relative; z-index: 3; border-top: 1px solid var(--vp-line); padding: 28px 22px 44px; }

.vp-footer__in {
  max-width: 1180px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  flex-wrap: wrap;
}

.vp-footer__brand { display: flex; align-items: center; gap: 10px; }
.vp-footer__brand img { width: 22px; height: 22px; object-fit: contain; display: block; flex: none; opacity: .75; }
.vp-footer__brand span { font: 600 11px var(--vp-mono); letter-spacing: .3em; color: var(--vp-muted-2); }
.vp-footer__meta { font: 500 10.5px var(--vp-mono); letter-spacing: .16em; color: #333c49; }

/* ===================== ПОЯВЛЕНИЕ ПРИ СКРОЛЛЕ ===================== */
[data-reveal] {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity .85s var(--vp-ease), transform .85s var(--vp-ease);
}

[data-reveal].is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  [data-reveal] { opacity: 1 !important; transform: none !important; }
  .vp-marquee__track { animation: none; }
  .vp-topbar,
  .vp-word__ch,
  .vp-word__mark,
  .vp-word__kicker,
  .vp-word__lead {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    transition: none !important;
  }
  .vp-stage__grid { opacity: .75 !important; transition: none !important; }
  body.is-ready .vp-word__scroll { animation: none; opacity: .85; }
  /* Главная страховка — ранний выход в assembly(): при сокращённой моторике
     туда подставляется p = 1, каждый бит уходит в ветку очистки. Медиазапрос
     не перебивает инлайн-стиль без !important на каждом свойстве, поэтому
     здесь снимается только то, что живёт в самой таблице стилей. */
  .vp-jig, .vp-cover { display: none !important; }
  .vp-panel--dom .chart-dom-head__spacer { opacity: 0; transform: none; }
  .vp-panel--dom .vp-seat,
  .vp-panel--dom .vp-seam-lit,
  .vp-panel--dom .vp-chip-lit,
  .vp-panel--dom.vp-registered { animation: none !important; }
}

/* ===================== АДАПТИВ ===================== */
@media (max-width: 760px) {
  .vp-topbar { padding: 10px 14px; }
  .vp-topbar__badge { display: none; }
  .vp-feats { padding-top: 84px; }
  .vp-dots { display: none; }
  .vp-cap { font-size: 10.5px; letter-spacing: .1em; }
}
/* Телефон: правая группа шапки (Telegram, RU/EN, кнопка) не сжимается, и на
   390px она наезжала на «VIPER». Здесь ужаты промежутки и кегли, а там, где
   не хватает и этого, слово уходит — знак V остаётся, имя крупно стоит на
   первом экране. */
@media (max-width: 440px) {
  .vp-topbar { gap: 10px; padding: 10px 12px; }
  .vp-topbar__left { gap: 8px; }
  .vp-topbar__name { letter-spacing: .22em; }
  .vp-topbar__right { gap: 8px; }
  .vp-tg { width: 30px; height: 30px; }
  .vp-lang__btn { padding: 5px 8px; }
  .vp-cta { font-size: 10px; letter-spacing: .08em; padding: 8px 11px; }
}
@media (max-width: 370px) {
  .vp-topbar__name { display: none; }
}
/* Телефон лёжа: первый экран выше экрана — знак уходил под шапку. Знак и слово
   ужимаются по высоте; сам терминал ниже вписывает layout() (STAGE_EDGE). */
@media (max-height: 520px) {
  .vp-word__mark { width: 56px; height: 56px; margin-bottom: 10px; }
  .vp-word__title { font-size: clamp(40px, 15vh, 96px); }
  .vp-word__kicker { margin-top: 12px; }
  .vp-word__lead { margin-top: 14px; }
  .vp-word__scroll { margin-top: 18px; }
}
