

/* Start:/local/components/zabotix/partner.affiliate.showcase/templates/.default/style.css?178784172850084*/
/* ============================================================
 * Витрина программ — pa-showcase
 * Дизайн: направление «2 · тёмная витрина» (Claude Design).
 * Плоские классы pa-showcase-*, data-js в стилях не участвуют.
 *
 * Все величины сведены в приватные --pa-* с фолбэками: наборы токенов в
 * контурах разные. В гостевом auth-shell (styles_frame/tokens.css) есть
 * spacing и font-size, но радиусы называются border-radius-*;
 * в кабинете (assets/tokens.css) есть radius-*, но нет ни spacing,
 * ни font-size, ни transition-base. Токена radius-pill не существует
 * нигде — без фолбэка точки-пилюли стали бы квадратными.
 * ЗВЁЗДОЧКА СО СЛЕШЕМ ВНУТРИ КОММЕНТАРИЯ ЗАКРЫВАЕТ ЕГО ДОСРОЧНО и съедает
 * следующий блок — поэтому имена токенов здесь пишутся без «*».
 * ============================================================ */

.pa-showcase {
  /* Палитра направления */
  /* Цвета сверены с фирменной палитрой темы (assets/tokens.css). Значения
     продублированы числами, а не взяты через var(): в гостевом auth-shell
     грузится styles_frame/tokens.css, где --accent и --additional отсутствуют,
     и витрина осталась бы без цвета. Пары «токен → число» держим синхронно. */
  --pa-bg: #0f1a2f;              /* --header-bg; была своя копия #10162e */
  --pa-title-color: #ffffff;
  --pa-text-color: rgba(237, 237, 242, 0.82);
  --pa-link-color: #f59e0b;      /* --warning; был жёлтый #ffd24a */
  --pa-marker-color: #d45b40;    /* --accent; был кричащий коралл #ff5a3c */
  --pa-dot-idle: rgba(255, 255, 255, 0.28);
  --pa-dot-on: #ffffff;
  /* Токена --color-orange не существует ни в одном контуре: правило всегда
     падало в фолбэк, а var() лишь маскировал это. Пишем цвет напрямую. */
  --pa-focus: #d45b40;

  /* Размеры и ритм */
  /* Радиусы заданы числом, а не токеном: одноимённые токены в контурах имеют
     разные значения (в кабинете --radius-md = 10px, в макете — 8px), и
     слайд выглядел бы по-разному на гостевой странице и в кабинете. */
  --pa-radius-sm: 4px;
  --pa-radius-pill: 50px;
  --pa-gap: var(--spacing-lg, 1.375rem);
  /* Отступы колонки и просвет до точек взяты из макета правой части
     авторизации (styles_frame/registration.css): padding var(--spacing-xxl)
     = 50 px, а .registration-image-text отделён от точек на 34 px. */
  --pa-gap-xxl: var(--spacing-xxl, 3.125rem);
  --pa-gap-dots: 2.125rem;
  --pa-gap-sm: var(--spacing-sm, 0.5rem);
  --pa-gap-m: var(--spacing-m, 0.75rem);
  --pa-gap-md: var(--spacing-md, 1rem);
  --pa-title-size: 32px;
  --pa-title-weight: var(--font-weight-bold, 700);
  --pa-text-size: var(--font-size-m, 1rem);
  --pa-text-size-s: var(--font-size-s, 0.875rem);
  --pa-dot-size: 8px;
  --pa-dot-gap: 6px;    /* просвет между соседними точками */
  --pa-dot-ext: 20px;   /* насколько пилюля длиннее точки: 8 + 20 = 28 */
  --pa-dot-fade: 0.28;  /* приглушённость неактивной точки */
  --pa-hit-y: 8px;      /* запас под палец сверху и снизу, в поток не идёт */
  --pa-anim: var(--transition-base, 0.3s ease);

  position: relative;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  /* Раскладка прежней правой части авторизации: контент прижат к низу колонки и
     к левому краю, точки — под ним, тоже слева (styles_frame/registration.css:
     .registration-image { justify-content: flex-end }). */
  justify-content: flex-end;
  align-items: flex-start;
  gap: var(--pa-gap-dots);
  /* Высота не задаётся: блок равен своему содержимому — самому высокому слайду
     плюс точки. На гостевых страницах колонку всё равно растягивает флекс
     родителя (align-items: stretch), и слайд встаёт по центру. Фиксированная
     высота давала «анкету»: пустое поле во весь экран. */
  /* Узкая колонка: отступы ужимаются, текст не превращается в столбик. */
  padding: clamp(var(--pa-gap), 5%, var(--pa-gap-xxl));
  background: var(--pa-bg);
  /* Декор (::before/::after) остаётся на месте: прокручивается только трек. */
  overflow: hidden;
}

/* Тема гостевых страниц объявляет .registration-image с padding:
   var(--spacing-xxl) — та же специфичность, что у .pa-showcase, но позже в
   каскаде, поэтому побеждала она и отступы оставались 50 px вместо 22 px.
   Двойной класс (0,2,0) — тот же элемент, специфичность выше. */
.registration-image.pa-showcase {
  padding: clamp(var(--pa-gap), 5%, var(--pa-gap-xxl));
}

/* Атмосферный слой: один эффект на ::after, поверх фонового робота, под
   контентом.

   Третья итерация палитры, и обе прежние отпали по одной причине — смешение.
   Оранжевый с синим (первая версия) давал «цвет грязи»: это комплементарные
   цвета, и градиент между ними обязан пройти через десатурированную серо-
   коричневую середину — оттенками это не лечится. Уход в холодную пару
   «индиго → бирюза» (вторая версия) грязь убрал, но бирюза #40d0e0 в теме
   сайта не существует, и владелец справедливо увидел, что витрина «уходит в
   зелёный» и выбивается из общей темы.

   Здесь смешиваются только соседи по синей ветви, все три — фирменные:
   --additional (#6471b2) → --header-bg (#0f1a2f) → --additional-light
   (#7e8ac4). Переход чистый, потому что цвета родственные, зелени нет вовсе.
   Тёмно-синий стоит средним стопом намеренно: владелец отмечал, что
   фирменного тёмно-синего в анимации «прям очень мало» — теперь он участвует
   в самом переливе, а не только лежит подложкой.

   Тёплый акцент (--pa-marker-color, --pa-link-color) в градиенте не участвует
   вообще: он работает точечно на маркерах и ссылках. Именно это разведение по
   ролям, а не подбор оттенков, и снимает проблему грязи. */
.pa-showcase::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    120deg,
    rgba(100, 113, 178, 0.48),
    rgba(15, 26, 47, 0.55) 45%,
    rgba(126, 138, 196, 0.3)
  );
  background-size: 260% 260%;
  animation: pa-shift 11s ease-in-out infinite alternate;
}

@keyframes pa-shift {
  from { background-position: 0% 0%; }
  to { background-position: 100% 100%; }
}

/* Фоновый робот — водяной знак в правом верхнем углу, как прежняя
   .registration-image-content (position: absolute; top: 0; right: 0). Робот
   векторный и целый, поэтому без отрицательных сдвигов: реплика чата должна
   помещаться в кадр, иначе от неё виден один хвостик. */
.pa-showcase-bot {
  position: absolute;
  top: 0;
  /* Отступ справа считается от ШИРИНЫ САМОГО БОТА, а не колонки. Проценты в
     right Bitrix-страница отдала бы от ширины колонки, и пара отступов держалась
     бы ровно на одной ширине экрана: при узкой колонке бот занимает свои 90% и
     всё сходится, а на широкой он упирается в потолок 600px, тогда как -15%
     колонки продолжают расти — замерено 45px сверху против 12px справа на
     колонке 970. Здесь же обе величины пропорциональны одному масштабу SVG.

     Арифметика: справа от уха внутри холста лежит поле в 16.25 единиц из 62.
     Прячем 10.25 из них за краем колонки, оставляя видимыми 6 — ровно столько,
     сколько отведено сверху (viewBox начинается с -6, см. _bot.php). Отсюда и
     пара «сверху = справа» на любой ширине.
     Дальше вправо не двигаем: там начинает обрезаться реплика чата, ради этого
     сдвига уже ужатая. */
  right: calc(var(--pa-bot-width) * -10.25 / 62);
  /* Размер выровнен по оригиналу боевой страницы: там .registration-image-content
     — PNG 600x611, выводимый в натуральную величину, без ограничения по ширине
     колонки. Прежние 25rem давали всего ~350px, потому что корневой шрифт этой
     страницы 14px, а не 16px, — бот усох почти вдвое, что владелец и заметил
     («голова этого бота тоже побольше»). Потолок задан в px именно поэтому:
     rem здесь врёт. Процент оставлен, чтобы на узкой колонке водяной знак не
     занимал её целиком. */
  --pa-bot-width: min(90%, 600px);
  width: var(--pa-bot-width);
  color: var(--pa-title-color);
  opacity: 0.13;
  pointer-events: none;
  /* Смещение зрачков приходит из скрипта переменными. Диапазон держим здесь,
     а не в JS: капсула глаза узкая, и допустимый ход зрачка — вопрос
     геометрии рисунка, а не логики слежения. */
  --pa-pupil-x: 0px;
  --pa-pupil-y: 0px;
}

.pa-showcase-bot-pupil {
  transform: translate(var(--pa-pupil-x), var(--pa-pupil-y));
  transition: transform 0.32s ease-out;
}

.pa-showcase-bot-svg {
  display: block;
  width: 100%;
  height: auto;
  animation: pa-bot-float 7s ease-in-out infinite alternate;
}

/* Анимация «живого» бота: голова покачивается, глаза моргают, снизу всплывает
   реплика чата с печатающимися точками. Всё на CSS-кадрах: библиотека
   (motion.dev и подобные) ради трёх деклараций тянула бы в Bitrix-страницу
   лишний скрипт, а сборщика фронта здесь нет. */
@keyframes pa-bot-float {
  from { transform: translateY(0); }
  to { transform: translateY(-3%); }
}

.pa-showcase-bot-eyes {
  transform-box: fill-box;
  transform-origin: center;
  animation: pa-bot-blink 6s ease-in-out infinite;
}

@keyframes pa-bot-blink {
  0%, 92%, 100% { transform: scaleY(1); }
  95% { transform: scaleY(0.08); }
}

/* Реплика чата не крутится по своему таймеру, а всплывает на смену слайда:
   робот «проговаривает» каждый экран витрины, и фоновая картинка оказывается
   связана с контентом, а не живёт отдельной жизнью. В покое пузыря нет. */
.pa-showcase-bot-chat {
  transform-box: fill-box;
  transform-origin: center;
  opacity: 0;
}

.pa-showcase-bot.is-reacting .pa-showcase-bot-chat,
.pa-showcase-bot.is-approving .pa-showcase-bot-chat { animation: pa-bot-chat 3.2s ease-in-out both; }

/* Отметили программу — робот кивает и вместо печатающихся точек рисует
   галочку: подтверждение выбора приходит оттуда же, где он «говорит». */
.pa-showcase-bot.is-approving .pa-showcase-bot-head {
  transform-box: fill-box;
  transform-origin: 50% 15%;
  animation: pa-bot-nod 0.8s ease-in-out;
}

@keyframes pa-bot-nod {
  0%, 100% { transform: rotate(0deg); }
  30% { transform: rotate(5deg); }
  65% { transform: rotate(-2deg); }
}

.pa-showcase-bot-check {
  stroke-dasharray: 15;
  stroke-dashoffset: 15;
  opacity: 0;
}

.pa-showcase-bot.is-approving .pa-showcase-bot-check {
  opacity: 1;
  animation: pa-bot-check 0.5s 0.25s ease-out forwards;
}

.pa-showcase-bot.is-approving .pa-showcase-bot-typing { opacity: 0; animation: none; }

@keyframes pa-bot-check {
  to { stroke-dashoffset: 0; }
}

@keyframes pa-bot-chat {
  0% { opacity: 0; transform: translateY(10%) scale(0.9); }
  14%, 78% { opacity: 1; transform: none; }
  100% { opacity: 0; transform: translateY(10%) scale(0.94); }
}

/* ── РУЧКИ НАПРАВЛЕНИЯ ВОЛН ─────────────────────────────────────────────────
   Куда летит веер и откуда выходит, задаётся только этими тремя числами.
   Единицы — единицы координат SVG (viewBox 0 -14 62 62), не экранные пиксели:
   вся голова робота шириной около 46 таких единиц.

   --pa-signal-angle  направление веера. 0deg — строго вправо (сейчас),
                      -45deg — вправо-вверх по диагонали, -90deg — вертикально
                      вверх, положительные значения кладут веер вниз.
   --pa-signal-x      сдвиг точки выхода вправо от кончика антенны (22.9, 0).
   --pa-signal-y      сдвиг точки выхода вниз от него же. Сейчас 3.5 / 3.5 —
                      правый край петли антенны, взятый чуть ниже её верха.
                      Именно чуть ниже: холст SVG ужат сверху до 3 единиц, чтобы
                      робот встал на своё место (см. _bot.php), и веер, поднятый
                      выше, срезался бы верхней кромкой кадра.

   Что важно знать, подбирая. Веер раскрыт на ±30° от своей оси, а правый край
   антенны лежит вплотную к голове (её контур проходит через x=27.6 при y=1),
   поэтому нижняя половина горизонтального веера идёт по линии головы: прогон
   точек дуг через body.isPointInFill даёт 61 касание при нынешних 0deg против
   нуля, если довернуть ось к -45deg. Голова нарисована контуром, а не залита,
   так что читается это как перекрестье тонких линий, а не как клякса.

   Чистый горизонтальный веер без касаний возможен только подъёмом точки выхода
   заметно выше макушки — но тогда волны отрываются от антенны, а верхнюю кромку
   кадра держит ужатый холст SVG. Если понадобится, третий путь — укоротить сами
   дуги в _bot.php: там и радиусы, и раствор. */
.pa-showcase-bot-signal {
  --pa-signal-angle: 0deg;
  --pa-signal-x: 3.5px;
  --pa-signal-y: 3.5px;
  /* Поворот считается вокруг кончика антенны, а не вокруг угла холста. */
  transform-origin: 22.9px 0;
  transform: translate(var(--pa-signal-x), var(--pa-signal-y)) rotate(var(--pa-signal-angle));
}

/* Волны сигнала от «уха» — робот на связи. Расходятся по очереди и медленно:
   на фоне это должно жить, а не мельтешить рядом с формой. */
.pa-showcase-bot-signal path {
  transform-box: fill-box;
  /* Волны уходят вправо от кончика антенны, поэтому точка роста — левый край
     дуги, ближний к антенне. Пока сигнал раскрывался вверх, здесь стояло
     bottom center; с ним развёрнутые дуги росли бы снизу вверх поперёк
     собственного хода. */
  transform-origin: left center;
  opacity: 0;
  animation: pa-bot-signal 3.4s ease-out infinite;
}

.pa-showcase-bot-signal path:nth-child(2) { animation-delay: 0.35s; }
.pa-showcase-bot-signal path:nth-child(3) { animation-delay: 0.7s; }

@keyframes pa-bot-signal {
  0% { opacity: 0; transform: scale(0.72); }
  22% { opacity: 0.85; }
  55% { opacity: 0; transform: scale(1); }
  100% { opacity: 0; transform: scale(1); }
}

.pa-showcase-bot-typing { animation: pa-bot-typing 1.2s ease-in-out infinite; }
.pa-showcase-bot-typing:nth-of-type(2) { animation-delay: 0.15s; }
.pa-showcase-bot-typing:nth-of-type(3) { animation-delay: 0.3s; }

@keyframes pa-bot-typing {
  0%, 60%, 100% { opacity: 0.35; }
  30% { opacity: 1; }
}

.pa-showcase-track,
.pa-showcase-dots {
  position: relative;
  z-index: 1;
}

/* Трек: слайды лежат в одной ячейке грида — высота по самому высокому,
   без absolute и без прыжков при переключении. */
.pa-showcase-track {
  display: grid;
  /* Все слайды в одной ячейке: высота трека равна самому высокому из них и не
     меняется при листании. Трек не растягивается по свободному месту — высота
     идёт от наполнения, а не от размера колонки.
     center, а не stretch: короткий слайд встаёт по центру ячейки, а не липнет
     к верху под пустотой в высоту самого длинного. */
  align-items: center;
  min-width: 0;
  min-height: 0;
  width: 100%;
  /* Ширина текстовой колонки прежней правой части (.registration-image-text):
     строка не растягивается на всю ширину и не наезжает на фонового робота. */
  max-width: 29.625rem;
  flex: 0 0 auto;
  container-type: inline-size;
}

/* Переход между слайдами по действию пользователя рисует браузер: имя
   участника нужно только треку, содержимое слайдов внутри него сводится
   кроссфейдом целиком. Правила ::view-transition-* браузером без поддержки
   API просто игнорируются. */
.pa-showcase-track { view-transition-name: pa-showcase-track; }

::view-transition-old(pa-showcase-track) { animation: pa-vt-out 0.2s ease both; }
::view-transition-new(pa-showcase-track) { animation: pa-vt-in 0.32s ease both; }

@keyframes pa-vt-out {
  to { opacity: 0; transform: translateY(-10px); }
}

@keyframes pa-vt-in {
  from { opacity: 0; transform: translateY(16px); }
}

/* Перелёт карточки программы в слайд («Подробнее»). Группа задаёт траекторию и
   темп движения, old/new — растворение карточки и проявление слайда. Дольше
   обычного переключения: движение через всю ширину экрана должно читаться
   глазом, а не мелькать. z-index поднимает летящий снимок над колонками. */
::view-transition-group(pa-showcase-fly) {
  animation-duration: 0.62s;
  animation-timing-function: cubic-bezier(0.22, 0.75, 0.2, 1);
  z-index: 20;
}

::view-transition-old(pa-showcase-fly) { animation: pa-vt-out 0.28s ease-in both; }
::view-transition-new(pa-showcase-fly) { animation: pa-vt-in 0.42s 0.16s ease-out both; }

/* «Подробнее» нажимают в левой колонке, а переключается правая — вспышка по
   контуру ставит точку в конце перелёта. */
.pa-showcase.is-pulse { animation: pa-pulse 0.9s ease-out; }

@keyframes pa-pulse {
  0% { box-shadow: inset 0 0 0 0 rgba(120, 170, 255, 0); }
  30% { box-shadow: inset 0 0 0 3px rgba(120, 170, 255, 0.55); }
  100% { box-shadow: inset 0 0 0 3px rgba(120, 170, 255, 0); }
}

.pa-showcase-slide {
  grid-area: 1 / 1;
  box-sizing: border-box;
  min-width: 0;
  min-height: 0;
  width: 100%;
  /* Слайд без собственной подложки: ни фона, ни рамки, ни отступов — контент
     лежит прямо на фоне витрины и центрируется ею (justify-content: center).
     Рамка внутри рамки читалась как «анкета» и съедала ширину. */
  overflow-wrap: break-word;
  color: var(--pa-text-color);
  font-size: var(--pa-text-size);
  line-height: var(--line-height-base, 1.5);
  text-wrap: pretty;
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity var(--pa-anim), transform var(--pa-anim), visibility var(--pa-anim);
}

.pa-showcase-slide.is-active {
  opacity: 1;
  visibility: visible;
  transform: none;
}

/* Содержимое слайда — произвольный HTML из визуального редактора.
   Никаких обязательных обёрток: селекторы по тегам.
   Префикс .pa-showcase обязателен: гостевая тема раздаёт собственные margin
   через p:not([class]), ul:not([class]) и подобные — специфичность (0,1,1)
   против (0,1,0) у голого «.pa-showcase-slide > *», и побеждала тема. Из-за
   этого список уезжал вправо на её margin-left: 24px, а вертикальный ритм
   слайда подменялся отступами темы (над списком выходил ноль). */
.pa-showcase .pa-showcase-slide > * { margin: 0; }
.pa-showcase .pa-showcase-slide > * + * { margin-top: var(--pa-gap-md); }

/* Селекторы заголовков и абзаца намеренно с префиксом .pa-showcase: тема
   кабинета объявляет h1..h4:not([class]) и p:not([class]) с color: var(--text).
   Специфичность у них такая же, как у «.pa-showcase-slide h2» (0,1,1), а в
   каскаде они идут позже — и перекрашивали текст слайда в тёмный по тёмному. */
.pa-showcase .pa-showcase-slide h1,
.pa-showcase .pa-showcase-slide h2,
.pa-showcase .pa-showcase-slide h3,
.pa-showcase .pa-showcase-slide h4 {
  /* Заголовок масштабируется по ширине колонки (контейнерные единицы). */
  font-size: clamp(var(--pa-text-size), 8cqw, var(--pa-title-size));
  font-weight: var(--pa-title-weight);
  line-height: var(--line-height-tight, 1.16);
  color: var(--pa-title-color);
}

.pa-showcase .pa-showcase-slide h3 { font-size: clamp(var(--pa-text-size-s), 6cqw, calc(var(--pa-title-size) * 0.74)); }
.pa-showcase .pa-showcase-slide h4 { font-size: clamp(var(--pa-text-size-s), 5cqw, calc(var(--pa-title-size) * 0.62)); }
.pa-showcase .pa-showcase-slide p { color: var(--pa-text-color); }

/* Префикс .pa-showcase — по той же причине, что у заголовков и абзаца выше:
   гостевая тема объявляет strong:not([class]), b:not([class]) с color: var(--text).
   Специфичность у неё такая же (0,1,1), а в каскаде она позже — и жирный текст
   слайда становился тёмно-синим по тёмно-синему фону. */
.pa-showcase .pa-showcase-slide strong,
.pa-showcase .pa-showcase-slide b {
  font-weight: var(--font-weight-medium, 500);
  color: var(--pa-title-color);
}

/* Префикс .pa-showcase — как у заголовков: гостевая тема сбрасывает спискам
   list-style и padding-left правилом той же специфичности, но позже в каскаде,
   и пункты оставались без маркеров.
   padding-left: 0 — текст пунктов встаёт по одной левой линии с заголовком и
   абзацем слайда, маркеры при list-style-position: outside уходят в отступ
   витрины. Ноль объявлен явно, а не выкинут: без декларации вернётся дефолт
   браузера (40px) либо сброс темы, то есть отступ снова уедет.
   Отступы самого списка (margin) сюда не дублируем — их снимает правило
   «.pa-showcase .pa-showcase-slide > *» выше. */
.pa-showcase .pa-showcase-slide ul,
.pa-showcase .pa-showcase-slide ol {
  padding-left: 0;
  display: grid;
  gap: var(--pa-gap-sm);
  list-style-position: outside;
}

.pa-showcase .pa-showcase-slide ul { list-style-type: disc; }
.pa-showcase .pa-showcase-slide ol { list-style-type: decimal; }
.pa-showcase-slide li::marker { color: var(--pa-marker-color); }

.pa-showcase-slide img {
  display: block;
  width: 100%;
  height: auto;
  /* contain, а не cover: ограничение высоты защищает вёрстку от больших
     картинок из редактора, но обрезать иллюстрацию по краям оно не должно. */
  max-height: 16rem;
  object-fit: contain;
  border-radius: var(--pa-radius-sm);
}

.pa-showcase-slide a {
  color: var(--pa-link-color);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.pa-showcase-slide a:hover { color: var(--pa-link-color); }

/* Кнопка-якорь к анкете. На десктопе форма и витрина видны одновременно —
   прокручивать некуда, кнопка не нужна; показывается только в списочном режиме
   (@media ≤1023px в конце файла).
   Тройной класс (0,3,0) обязателен: правило ссылок слайда выше
   («.pa-showcase .pa-showcase-slide a», 0,2,1) красит и подчёркивает любую
   ссылку внутри слайда, и кнопка получила бы жёлтый текст с подчёркиванием. */
.pa-showcase .pa-showcase-slide .pa-showcase-cta { display: none; }

.pa-showcase-dots {
  display: flex;
  justify-content: flex-start;
  /* Просвет задан не gap'ом, а половинками внутри бокса каждой точки: пилюля
     вылезает за свой бокс вправо и должна ложиться ровно в просвет, а gap
     флексбокса — внешний зазор, в него нельзя зайти содержимым. */
  gap: 0;
  /* Запас под пилюлю последней точки: её бокс шириной с точку, а нарисованное
     тело длиннее на --pa-dot-ext (см. ниже). Без запаса пилюля последнего
     слайда упёрлась бы в край колонки. */
  padding-right: var(--pa-dot-ext);
}

/* Геометрия точки-пилюли. Два решения, оба про «перетекание».

   1. Бокс точки шириной с ТОЧКУ, а не с пилюлю. Пилюля вылезает за свой бокс
      вправо, а точки правее неё сдвинуты на её длину. Значит место под пилюлю
      не зарезервировано заранее — оно реально освобождается уходящей и реально
      занимается приходящей. Ряд остаётся плотным, а суммарная ширина не
      меняется ни на кадр: сколько одна пилюля отдала, столько вторая взяла.
      Прежний бокс шириной с полную пилюлю освобождать было нечему — точки
      стояли редко, с дырами по 20px, и ничего никуда не перетекало.

   2. Пилюля собрана из ТРЁХ частей: неподвижный левый торец (::before),
      перемычка (.pa-showcase-dot-pill, тянется scaleX) и правый торец
      (::after, едет translateX). Оба торца — всегда круги 8×8 и никогда не
      масштабируются, поэтому капсула остаётся капсулой при любой длине, а при
      нулевой перемычке торцы совпадают и дают чистую точку.

      Так — а не «круг + растягиваемый хвост-капсула», как было: scaleX плющит
      и border-radius тоже, поэтому короткий хвост превращался в прямоугольник
      с плоскими торцами и вылезал из круга углами — в последнюю секунду цикла
      точка на миг становилась скруглённым квадратиком. Компенсировать радиусом
      в кадрах нельзя: border-radius не композитное свойство, и одна такая
      строка снимает анимацию с композитора на главный поток (проверено через
      getAnimations()).

   В кадрах — только transform, translate и opacity, то есть композитор. Ширину
   не анимируем принципиально: она layout-свойство, браузер снапит её к целому
   пикселю, и на диапазоне 20px за семь секунд это двадцать видимых ступеней —
   ровно то «тиканье», от которого уходили. */
.pa-showcase-dot {
  position: relative;
  box-sizing: content-box;
  width: calc(var(--pa-dot-size) + var(--pa-dot-gap));
  height: var(--pa-dot-size);
  /* Зона нажатия 14×24 без влияния на раскладку: padding растит бокс,
     отрицательный margin возвращает строке прежнюю высоту в 8px.
     Расширять зону по ГОРИЗОНТАЛИ тем же приёмом нельзя: боксы соседних точек
     начнут перекрываться на удвоенный запас, в перекрытии клик заберёт правый
     сосед, и нажатие рядом с кружком переключит не на тот слайд. */
  padding: var(--pa-hit-y) 0;
  margin: calc(var(--pa-hit-y) * -1) 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  /* Приглушённость неактивной точки задаётся прозрачностью КНОПКИ, а не цветом
     каждой части. Иначе на нахлёсте торцов и перемычки альфа складывается и
     стык проступает светлым пятном, а если развести части встык — между дугой
     круга и прямым краем перемычки открывается тёмный вырез. Прозрачность на
     общем родителе гасит обе беды разом: части рисуются непрозрачными, гасится
     результат. Побочно opacity, как и transform, композитное. */
  opacity: var(--pa-dot-fade);
  /* translate отдельным свойством от transform: точке правее пары одновременно
     нужны оба сдвига (уходящая освобождает место, приходящая занимает), и в
     одном transform они затирали бы друг друга. */
  transition: opacity var(--pa-anim), transform var(--pa-anim), translate var(--pa-anim);
}

/* Торцы. Оба лежат в одной точке; правый уезжает вправо на длину пилюли.
   Половина просвета слева — тот самый зазор между соседями. */
.pa-showcase-dot::before,
.pa-showcase-dot::after {
  content: '';
  position: absolute;
  top: var(--pa-hit-y);
  left: calc(var(--pa-dot-gap) / 2);
  width: var(--pa-dot-size);
  height: var(--pa-dot-size);
  border-radius: 50%;
  background: var(--pa-dot-on);
}

.pa-showcase-dot::after {
  transform: translateX(0);
  transition: transform var(--pa-anim);
}

/* Перемычка между торцами. Начинается в ЦЕНТРЕ левого торца и кончается в
   центре правого — оба стыка перекрыты кругами, поэтому её собственные плоские
   края не видны никогда. */
.pa-showcase-dot-pill {
  position: absolute;
  top: var(--pa-hit-y);
  left: calc(var(--pa-dot-gap) / 2 + var(--pa-dot-size) / 2);
  width: var(--pa-dot-ext);
  height: var(--pa-dot-size);
  background: var(--pa-dot-on);
  transform-origin: left center;
  transform: scaleX(0);
  transition: transform var(--pa-anim);
}

/* Статика: автолистания нет (reduced-motion, мобильный список, остановленный
   таймер). Активная точка — пилюля, и точки правее неё сдвинуты на её длину:
   место занято по-настоящему. */
.pa-showcase-dot.is-active {
  opacity: 1;
}

.pa-showcase-dot.is-active::after {
  transform: translateX(var(--pa-dot-ext));
}

.pa-showcase-dot.is-active .pa-showcase-dot-pill {
  transform: scaleX(1);
}

.pa-showcase-dot.is-active ~ .pa-showcase-dot {
  translate: var(--pa-dot-ext) 0;
}

/* Индикатор обратного отсчёта до смены слайда.
   Владелец на созвоне: «размер пилюли активного слайда уменьшается, при этом
   одновременно увеличивается размер пилюли следующего; когда размер текущего
   становится точкой, а следующего — пилюлей, переключается слайд». Цель по его
   же словам — «помочь людям увидеть, когда у них слайд переключится».

   Анимация живёт под .is-autoplaying, который вешает и снимает сам таймер, а не
   под .is-active. Это важно: там, где автолистания нет — мобильный лендинг,
   prefers-reduced-motion, остановленный таймер — индикатор обязан быть
   статичным, иначе он обещает переключение, которого не будет.

   Длительность приходит из JS (--pa-autoplay), а не записана здесь числом:
   AUTOPLAY_MS остаётся единственным источником истины, и анимация не может
   разъехаться с таймером при правке одного из двух мест. */
/* Общие параметры цикла. Имена анимаций назначаются ниже по роли точки —
   отдельными свойствами, а не шорткатом: одной точке нужно сразу две анимации
   (своя яркость плюс сдвиг от соседа), и шорткат затирал бы одну другой.
   Ход ровный и длиной во весь цикл: по длине пилюли в любой момент видно,
   сколько осталось до переключения. */
.pa-showcase.is-autoplaying .pa-showcase-dot,
.pa-showcase.is-autoplaying .pa-showcase-dot::after,
.pa-showcase.is-autoplaying .pa-showcase-dot-pill {
  animation-duration: var(--pa-autoplay, 7000ms);
  animation-timing-function: linear;
  animation-fill-mode: forwards;
}

/* Распределение анимаций по ролям.
   pa-dot-close (свойство translate)  — сдвиг точек правее активной:   E → 0
   pa-dot-open  (свойство transform)  — сдвиг точек правее следующей:  0 → E
   Точка правее обеих получает обе: E-a плюс E-b даёт E, то есть стоит
   неподвижно. Порядок правил учитывает и перескок с последнего слайда на
   первый, когда следующая точка стоит ЛЕВЕЕ активной. */
.pa-showcase.is-autoplaying .pa-showcase-dot.is-next ~ .pa-showcase-dot {
  animation-name: pa-dot-open;
}

.pa-showcase.is-autoplaying .pa-showcase-dot.is-active {
  animation-name: pa-dot-dim;
}

.pa-showcase.is-autoplaying .pa-showcase-dot.is-next {
  animation-name: pa-dot-lit;
}

.pa-showcase.is-autoplaying .pa-showcase-dot.is-next ~ .pa-showcase-dot.is-active {
  animation-name: pa-dot-dim, pa-dot-open;
}

.pa-showcase.is-autoplaying .pa-showcase-dot.is-active ~ .pa-showcase-dot.is-next {
  animation-name: pa-dot-lit, pa-dot-close;
}

.pa-showcase.is-autoplaying .pa-showcase-dot.is-active ~ .pa-showcase-dot.is-next ~ .pa-showcase-dot {
  animation-name: pa-dot-close, pa-dot-open;
}

/* Сама пара: уходящая укорачивается ровно на столько же, на сколько удлиняется
   приходящая, и обе меняют длину в каждом кадре одновременно. */
.pa-showcase.is-autoplaying .pa-showcase-dot.is-active::after {
  animation-name: pa-cap-in;
}

.pa-showcase.is-autoplaying .pa-showcase-dot.is-active .pa-showcase-dot-pill {
  animation-name: pa-bar-shrink;
}

.pa-showcase.is-autoplaying .pa-showcase-dot.is-next::after {
  animation-name: pa-cap-out;
}

.pa-showcase.is-autoplaying .pa-showcase-dot.is-next .pa-showcase-dot-pill {
  animation-name: pa-bar-grow;
}

/* Пауза чтения (курсор над витриной, фокус внутри, палец на экране) замирает
   на текущем кадре, а не сбрасывает отсчёт. Раньше пауза снимала
   is-autoplaying — анимация исчезала, и пилюля скачком возвращалась к
   статическим 28px. JS при возобновлении досчитывает ровно остаток этой
   анимации, поэтому картинка и таймер не расходятся. */
.pa-showcase.is-paused .pa-showcase-dot,
.pa-showcase.is-paused .pa-showcase-dot::after,
.pa-showcase.is-paused .pa-showcase-dot-pill {
  animation-play-state: paused;
}

/* В кадрах ТОЛЬКО композитные свойства: transform, translate, opacity.
   border-radius сюда добавлять нельзя — он не композитный, и одна такая строка
   снимает всю анимацию с композитора обратно на главный поток. Проверено через
   getAnimations(): с радиусом в кадрах Chrome отдаёт список свойств, где рядом
   с transform стоят четыре borderRadius, и композитинга нет. */
@keyframes pa-cap-in {
  from { transform: translateX(var(--pa-dot-ext)); }
  to { transform: translateX(0); }
}

@keyframes pa-cap-out {
  from { transform: translateX(0); }
  to { transform: translateX(var(--pa-dot-ext)); }
}

@keyframes pa-bar-shrink {
  from { transform: scaleX(1); }
  to { transform: scaleX(0); }
}

@keyframes pa-bar-grow {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

@keyframes pa-dot-close {
  from { translate: var(--pa-dot-ext) 0; }
  to { translate: 0 0; }
}

@keyframes pa-dot-open {
  from { transform: translateX(0); }
  to { transform: translateX(var(--pa-dot-ext)); }
}

/* Яркость едет вместе с длиной: короткая пилюля приглушённая, длинная белая.
   Раньше приходящая росла полупрозрачной и в момент переключения скачком
   становилась белой. */
@keyframes pa-dot-dim {
  from { opacity: 1; }
  to { opacity: var(--pa-dot-fade); }
}

@keyframes pa-dot-lit {
  from { opacity: var(--pa-dot-fade); }
  to { opacity: 1; }
}

.pa-showcase-dot:focus-visible {
  outline: 2px solid var(--pa-focus);
  outline-offset: 3px;
}

/* Fallback: слайдов нет. Раскладку не переопределяем — текст встаёт в левый
   нижний угол теми же правилами, что и контент со слайдами; своё только
   ограничение ширины строки и слой над фоновым сиянием. */
.pa-showcase-fallback-text {
  position: relative;
  z-index: 1;
  max-width: 29.625rem;
  color: var(--pa-title-color);
}

@media (prefers-reduced-motion: reduce) {
  .pa-showcase-slide {
    transition: none;
    transform: none;
  }

  .pa-showcase-dot,
  .pa-showcase-dot::before,
  .pa-showcase-dot::after,
  .pa-showcase-dot-pill { transition: none; }

  /* Индикатор обратного отсчёта — тоже движение, и здесь его быть не должно.
     Автоплей при reduceMotion и так не стартует, но правило оставлено явным:
     оно страхует случай, когда класс is-autoplaying окажется на элементе по
     другой причине. */
  .pa-showcase.is-autoplaying .pa-showcase-dot,
  .pa-showcase.is-autoplaying .pa-showcase-dot::after,
  .pa-showcase.is-autoplaying .pa-showcase-dot-pill { animation: none; }

  .pa-showcase::after,
  .pa-showcase.is-pulse,
  .pa-showcase-bot-svg,
  .pa-showcase-bot-eyes,
  .pa-showcase-bot.is-reacting .pa-showcase-bot-chat,
  .pa-showcase-bot.is-approving .pa-showcase-bot-chat,
  .pa-showcase-bot.is-approving .pa-showcase-bot-head,
  .pa-showcase-bot.is-approving .pa-showcase-bot-check,
  .pa-showcase-bot-signal path,
  .pa-showcase-bot-typing { animation: none; }

  .pa-showcase-bot-pupil { transition: none; }
}

/* ============================================================
 * Мобильный лендинг (≤1023px): витрина разворачивается в список
 * ============================================================
 * На телефоне карусель проигрывает списку: листать на узком экране неудобно, а
 * все программы всё равно должны быть на виду до анкеты. Разворот делается
 * чистым CSS — неактивные слайды спрятаны opacity/visibility, а не display:
 * none, поэтому достаточно вернуть им видимость и вынуть трек из грида. Классы
 * is-active скрипт продолжает переставлять, но здесь они ни на что не влияют:
 * правила ниже (0,2,0) стоят позже одноимённых по специфичности и побеждают в
 * обе стороны — видимы все слайды всегда.
 * Блок намеренно последний в файле: у медиазапроса своей специфичности нет,
 * побеждает он только порядком. */
@media (max-width: 1023px) {
  /* justify-content: flex-end у витрины прижимал единственный трек к низу.
     В списке контент задаёт высоту сам, и при overflow: hidden прижатие к
     низу срезало бы верх списка, если высоту чем-то ограничат. */
  .registration-image.pa-showcase {
    justify-content: flex-start;
  }

  /* Из грида в поток: слайды перестают лежать друг на друге.
     view-transition-name снимается — переключать нечего, а именованный
     участник перехода на статичном блоке только мешает. */
  .pa-showcase .pa-showcase-track {
    display: flex;
    flex-direction: column;
    gap: 1.75rem;
    view-transition-name: none;
  }

  /* (0,2,0) — ровно как у «.pa-showcase-slide.is-active», но позже в файле,
     поэтому видимость не зависит от того, какой слайд скрипт считает
     активным. */
  .pa-showcase .pa-showcase-slide {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition: none;
  }

  /* Волосяная линия между слайдами: без неё семь программ подряд читаются
     сплошным текстом, а не отдельными карточками. */
  .pa-showcase .pa-showcase-slide + .pa-showcase-slide {
    padding-top: 1.75rem;
    border-top: 1px solid rgba(255, 255, 255, 0.14);
  }

  /* Листать нечем — точки не нужны: на мобильном витрина развёрнута в
     вертикальный список, все слайды и так на экране. */
  .pa-showcase .pa-showcase-dots { display: none; }

  /* Кнопка призыва к действию. min-height 44px — минимальная комфортная цель
     для пальца. Именно px, а не rem: базовый шрифт страницы 14px, и 2.75rem
     дали бы 38.5px — замерено в браузере 13.08.
     Специфичность (0,3,0) — см. базовое правило выше: иначе ссылку слайда
     перекрасит и подчеркнёт «.pa-showcase .pa-showcase-slide a». */
  .pa-showcase .pa-showcase-slide .pa-showcase-cta {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    min-height: 44px;
    padding: 0.625rem 1.5rem;
    border-radius: var(--pa-radius-sm);
    background: var(--pa-marker-color);
    color: var(--pa-title-color);
    font-size: var(--pa-text-size);
    font-weight: var(--font-weight-medium, 500);
    line-height: 1.2;
    text-align: center;
    text-decoration: none;
  }

  .pa-showcase .pa-showcase-slide .pa-showcase-cta:focus-visible {
    outline: 2px solid var(--pa-focus);
    outline-offset: 3px;
  }
}

/* End */
/* /local/components/zabotix/partner.affiliate.showcase/templates/.default/style.css?178784172850084 */
