/* ---------- Шрифты ---------- */
/* Asgard Number: в наличии Regular (400) и Xbold (800).
   Логотип в макете помечен как Medium 500 — по метрикам это ровно Regular
   (ширина «Burger» 307.7px против 308.3px в эталоне), поэтому 500 отдаём
   на Regular, а 700+ на Xbold. */
@font-face {
  font-family: "Asgard";
  src: url("/app/assets/fonts/Asgard-Regular.woff2") format("woff2");
  font-weight: 400 500;
  font-display: swap;
}

@font-face {
  font-family: "Asgard";
  src: url("/app/assets/fonts/Asgard-Xbold.woff2") format("woff2");
  font-weight: 600 900;
  font-display: swap;
}

/* Asgard Number — цифровое начертание Asgard, для крупных сумм. */
@font-face {
  font-family: "Asgard Number";
  src: url("/app/assets/fonts/AsgardNumber-Regular.woff2") format("woff2");
  font-weight: 400 500;
  font-display: swap;
}

@font-face {
  font-family: "Asgard Number";
  src: url("/app/assets/fonts/AsgardNumber-Xbold.woff2") format("woff2");
  font-weight: 600 900;
  font-display: swap;
}

@font-face {
  font-family: "Neue Haas Unica";
  src: url("/app/assets/fonts/NeueHaasUnica-Regular.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: "Neue Haas Unica";
  src: url("/app/assets/fonts/NeueHaasUnica-Medium.woff2") format("woff2");
  font-weight: 500 700;
  font-display: swap;
}

/* ---------- Переменные ---------- */
:root {
  --bg: #E4E4E4;
  --ink: #000;
  --paper: #fff;
  /* Силуэт для аватарки, у которой нет ни фото, ни имени (см.
     .avatar--letter[data-letter=""]). Инлайном: отдельный файл — лишний
     запрос ради случая, когда и показывать-то нечего. */
  --avatar-person: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><circle cx="12" cy="8" r="4"/><path d="M4 21c0-4.4 3.6-7 8-7s8 2.6 8 7z"/></svg>');
  --tg: #86DFFF;
  --tg-deep: #7FDFFE;

  /* Макет 440px: всё внутри масштабируется от ширины экрана */
  --w: 440;
  --h: 700;
  --backdrop: #8A8A8A;
  /* Ширина сцены и шаг сетки считаются из одного значения */
  --stage: min(100vw, 440px);
  --u: calc(var(--stage) / var(--w));
  --font-display: "Asgard", "Helvetica Neue", Arial, system-ui, sans-serif;
  --font-text: "Neue Haas Unica", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-number: "Asgard Number", "Asgard", Arial, sans-serif;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  background: var(--backdrop);
  font-family: var(--font-text);
  -webkit-font-smoothing: antialiased;
}

/* Макет 440x1000 по центру окна; на узких экранах прижимается к верху,
   чтобы низ не уезжал под обрез. */
body {
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}

/* Экран с навигацией занимает всё окно — центрировать нечего, а от
   центрирования низ сцены уезжал вверх и панель отрывалась от края. */
body:has(.tabbar) {
  align-items: stretch;
}

/* Если окно ниже макета — прижимаем к верху, иначе низ уедет за обрез. */
@media (max-height: 700px) {
  body {
    align-items: flex-start;
  }
}

/* ---------- Экран ---------- */
.stage {
  position: relative;
  width: var(--stage);
  margin: 0 auto;
  height: 850px;
}

/* Экран с навигацией тянем на всю высоту окна: панель прибита к низу
   окна, и на короткой сцене она висела бы в фоне страницы, оторванная
   от мини-аппа. Отступа снизу у сцены быть не должно — в нём просвечивал
   бы фон страницы; запас под панель даёт сам экран. */
.stage:has(.tabbar) {
  min-height: 100vh;
  min-height: 100dvh;
  /* Жёсткие 850px из .stage выше окна телефона (844 у iPhone 14) и
     давали лишние 6px прокрутки даже после правки box-sizing. Высоту
     задаёт min-height, а не фиксированное число. */
  height: auto;
}

/* Фон экрана доходит до самого низа окна, а содержимое не уезжает под
   панель: её высота отведена внутренним отступом. */
.stage:has(.tabbar) .screen {
  min-height: 100%;
  padding-bottom: calc(135 * var(--u));
  box-sizing: border-box;
}

/* Внутри Telegram окно выше макета — тянем экран на всю его высоту. */
.is-telegram .screen {
  height: 100%;
}

/* Правка 25.10.2026 (Матвей: «дай возможность скролла»).

   Исключение для «Друзей»: там содержимое БОЛЬШЕ окна, а height: 100%
   обрезал его по краю — блок денежной программы с кнопкой «Вывести»
   уходил под панель разделов (на Telegram Desktop 450x780 — на 94px,
   на 420x700 — на 134px, измерено). Отдаём экрану его собственную
   высоту, и до низа доводит прокрутка страницы; min-height оставляет
   фон до края окна на высоком экране. */

/* Правка 27.10.2026 (Матвей: «не работает скролл, поэтому кнопка оплаты
   практически недоступна»). Та же беда на тарифах: своя высота у
   .screen--tariffs была, но height: 100% ниже по файлу её перебивал —
   экран обрезался по окну, и «К оплате» уходила под панель разделов
   (на 450x780 — на 65px, на 420x700 — на 13px, измерено).

   877 = низ кнопки (732) + панель (135) + воздух. Панель складываем
   вручную: padding-bottom из .stage:has(.tabbar) .screen при border-box
   съел бы высоту изнутри — ровно та ловушка, о которой предупреждает
   комментарий у .screen--tariffs. */
.is-telegram .screen--tariffs {
  height: calc(897 * var(--u));
  min-height: 100%;
}
.is-telegram .screen--friends {
  /* 621 — низ ссылки «Получать деньги» в режиме дней, плюс воздух и
     135 на панель разделов. */
  height: calc(775 * var(--u));
  min-height: 100%;
}

/* В денежном режиме ниже стоит блок с балансом и кнопкой «Вывести»:
   его низ — 739, и экрану нужно на столько же больше. Класс ставит
   friends.js, когда показывает блок. */
.is-telegram .screen--friends.has-money {
  height: calc(895 * var(--u));
}

/* Пока проверяем, знаком ли нам пользователь, стартовый экран не
   показываем: у своих он иначе мелькнул бы перед уходом в кабинет.
   Фон остаётся, поэтому выглядит как обычная загрузка. */
.is-checking .stage {
  visibility: hidden;
}

.screen {
  position: relative;
  width: 100%;
  /* Фиксированная высота макета: 440x1000. */
  height: calc(var(--h) * var(--u));
  margin: 0 auto;
  overflow: hidden;
  background: var(--bg);
  isolation: isolate;
}

/* ---------- Логотип ---------- */
.hero {
  margin: 0;
}

.hero__title {
  position: absolute;
  left: calc(62 * var(--u));
  top: calc(99 * var(--u));
  width: calc(315 * var(--u));
  height: calc(54 * var(--u));
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: calc(77 * var(--u));
  line-height: .9;
  letter-spacing: -.03em;
  color: var(--ink);
}

/* Значок VPN */
.badge {
  position: absolute;
  /* Увеличено в 2.95 раза от макета: «VPN» набран тем же кеглем 77px,
     что и логотип, поэтому плашка и звезда выросли пропорционально. */
  left: calc(260 * var(--u));
  top: calc(100 * var(--u));
  width: 100px;
  height: 20px;
  transform: rotate(15deg);
  z-index: 2;
}

.badge__star {
  position: absolute;
  width: 65px;
  height: 65px;
  top: -20px;
  left: 15px;
  /* Девятиконечная звезда из макета (Star 21). Заливка, обводка и белые
     блики по краю уже запечены в картинке, поэтому здесь только фон. */
  background: url("/app/assets/icons/star.png") no-repeat center / contain;
}

.hero__tagline {
  position: absolute;
  left: calc(91 * var(--u));
  top: calc(175 * var(--u));
  width: calc(259 * var(--u));
  margin: 0;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(25 * var(--u));
  line-height: 1.1;
  letter-spacing: -.04em;
  color: rgba(0, 0, 0, .4);
}

/* ---------- Кнопки ---------- */
.actions {
  display: contents;
}

.btn,
.tg {
  -webkit-appearance: none;
  appearance: none;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.btn {
  position: absolute;
  left: calc(44 * var(--u));
  width: calc(352 * var(--u));
  height: calc(86 * var(--u));
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: calc(30 * var(--u));
  border: calc(2 * var(--u)) solid transparent;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(22 * var(--u));
  line-height: 1;
  text-decoration: none;
  text-align: center;
  /* Градиентная обводка из макета */
  background-origin: border-box;
  background-clip: padding-box, border-box;
  transition: transform .18s ease, filter .18s ease;
}

/* Наведение: кнопка чуть приподнимается и подсвечивается. */
@media (hover: hover) {
  .btn:hover {
    transform: translateY(calc(-2 * var(--u)));
    filter: brightness(1.08);
  }

  .btn--light:hover {
    filter: brightness(1.02);
  }

  .tg:hover {
    filter: brightness(1.05) drop-shadow(0 calc(5.47 * var(--u)) calc(4 * var(--u)) rgba(6, 118, 159, .1));
  }

  /* Круг «Добавьте фото»: слегка увеличивается и подсвечивается. */
  .avatar:hover {
    transform: scale(1.03);
    filter: brightness(1.04);
  }

  /* Кнопка «Создать профиль»: центрирование держится на translateX(-50%),
     поэтому подъём дописываем к нему, иначе кнопка прыгнет вправо. */
  .submit__btn:hover {
    transform: translateX(-50%) translateY(calc(-3 * var(--u)));
    filter: brightness(1.04);
  }
}

/* Форма готова к отправке — кнопка меняется на активный вариант. Готовность:
   на регистрации все поля заполнены И выбрано фото, на входе — только поля.
   Два background-image анимировать нельзя, поэтому активная картинка лежит
   отдельным слоем и плавно проявляется поверх обычной. Её холст 440×328
   против 605×318 у базовой, так что размеры задаём явно. */
.submit__btn::after {
  content: "";
  position: absolute;
  /* Активный холст 440x328, пилюля в нём — в точке 81;221. */
  left: calc(-81 * var(--u));
  top: calc(-221 * var(--u));
  width: calc(440 * var(--u));
  height: calc(328 * var(--u));
  background: url("/app/assets/icons/create_profile_active.png") no-repeat center / contain;
  opacity: 0;
  transition: opacity .45s ease;
  pointer-events: none;
}

.screen.is-ready .submit__btn::after {
  opacity: 1;
}

/* Базовая картинка лежит в ::before и гаснет так же плавно, как проявляется
   активная — background-image сам по себе не анимируется. */
.submit__btn::before {
  content: "";
  position: absolute;
  /* Холст PNG больше пилюли: 605x318, сама пилюля в нём — 281x72
     в точке 162;214. Отсюда сдвиги. */
  left: calc(-162 * var(--u));
  top: calc(-214 * var(--u));
  width: calc(605 * var(--u));
  height: calc(318 * var(--u));
  background: url("/app/assets/icons/create_profile.png") no-repeat center / contain;
  opacity: 1;
  transition: opacity .45s ease;
  pointer-events: none;
}

.screen.is-ready .submit__btn::before {
  opacity: 0;
}

/* Нажатие: лёгкое сжатие вместо подъёма. */
.avatar:active {
  transform: scale(.98);
}

.submit__btn:active {
  transform: translateX(-50%) scale(.985);
}

.btn:active {
  transform: scale(.985);
  filter: brightness(.97);
}

/* Центрирование держится на translateX(-50%), поэтому сжатие при нажатии
   дописываем к нему, а не заменяем — иначе кнопка прыгнет вправо. */
.tg:active {
  transform: translateX(-50%) scale(.98);
}

.btn:focus-visible,
.tg:focus-visible {
  outline: calc(3 * var(--u)) solid #2AABEE;
  outline-offset: calc(3 * var(--u));
}

.btn--dark {
  top: calc(222 * var(--u));
  color: var(--paper);
  background-image:
    linear-gradient(#000, #000),
    linear-gradient(43deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, .7) 26%,
      rgba(255, 255, 255, .3) 97%,
      rgba(255, 255, 255, .2) 100%);
  box-shadow:
    0 calc(25 * var(--u)) calc(20 * var(--u)) calc(-30 * var(--u)) rgba(0, 0, 0, .4),
    inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(16.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .7),
    inset calc(-2.5 * var(--u)) calc(-6.25 * var(--u)) calc(17.5 * var(--u)) calc(-5.5 * var(--u)) rgba(255, 64, 157, .6),
    inset calc(1.25 * var(--u)) calc(1.25 * var(--u)) calc(60 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .2),
    inset calc(-8 * var(--u)) calc(-9.25 * var(--u)) calc(15 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .2);
}

.btn--light {
  top: calc(323 * var(--u));
  color: var(--ink);
  background-image:
    linear-gradient(180deg, #fff 15%, #E4E4E4 95%),
    linear-gradient(43deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, .7) 26%,
      rgba(255, 255, 255, .3) 97%,
      rgba(255, 255, 255, .2) 100%);
  box-shadow:
    0 calc(25 * var(--u)) calc(20 * var(--u)) calc(-30 * var(--u)) rgba(0, 0, 0, .3),
    inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(16.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .7),
    inset calc(1.25 * var(--u)) calc(1.25 * var(--u)) calc(60 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .2),
    inset calc(-8 * var(--u)) calc(-9.25 * var(--u)) calc(15 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .2);
}

/* ---------- Вход через телеграм ---------- */
/* Весь блок — одна картинка 237×56 (стрелка, логотип и подпись уже в ней).
   Ширина берётся из макета, высота считается по пропорции файла. */
.tg {
  position: absolute;
  /* По центру сцены: середина минус половина ширины — не зависит от того,
     как поменяется ширина картинки. */
  left: 50%;
  transform: translateX(-50%);
  top: calc(434 * var(--u));
  width: calc(237 * var(--u));
  height: calc(56 * var(--u));
  display: block;
  filter: drop-shadow(0 calc(5.47 * var(--u)) calc(4 * var(--u)) rgba(6, 118, 159, .1));
  transition: transform .18s ease;
}

.tg__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* Пока проверяется подпись телеграма — кнопка приглушена и не ловит
   повторные нажатия. */
.tg.is-busy {
  opacity: .6;
  pointer-events: none;
}

/* ---------- Бургер ---------- */
.burger {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(497 * var(--u));
  bottom: 0;
  overflow: hidden;
  /* Свой контекст наложения: backdrop-filter у .burger__fade размывает
     только то, что внутри этого блока (картинку бургера), и не дотягивается
     до копирайта, который лежит выше по z-index. */
  isolation: isolate;
  z-index: 1;
}

/* Картинка шире экрана и уходит за края, как в макете. */
.burger__img {
  position: absolute;
  left: 50%;
  top: 5%;
  width: 110%;
  height: 100%;
  transform: translateX(-50%);
  object-fit: cover;
  object-position: top center;
}

/* Размытие низа — под подпись копирайта. Без затемнения: картинка бургера
   уходит в расфокус, а не в чёрный. Сам backdrop-filter применяется ко
   всему блоку сразу, поэтому плавность даёт маска — блюр набирает силу
   сверху вниз вместе с непрозрачностью маски. */
.burger__fade {
  position: absolute;
  left: 0;
  right: 0;
  /* Блок .burger уходит за нижний край экрана, поэтому bottom:0 увёл бы
     размытие за обрез — прижимаем полосу к видимому низу. */
  bottom: calc(101 * var(--u));
  height: calc(250 * var(--u));
  /* Радиус вдвое меньше прежнего: стоимость размытия растёт с радиусом,
     а под маской разница почти не видна. contain ограничивает
     перерисовку самим элементом — без него браузер на каждый кадр
     прокрутки пересобирает всё, что под полосой. */
  contain: paint;
  backdrop-filter: blur(calc(5 * var(--u)));
  -webkit-backdrop-filter: blur(calc(5 * var(--u)));
  mask: linear-gradient(180deg,
      rgba(0, 0, 0, 0) 0%,
      rgba(0, 0, 0, .35) 40%,
      rgba(0, 0, 0, 1) 75%,
      rgba(0, 0, 0, 1) 100%);
  -webkit-mask: linear-gradient(180deg,
      rgba(0, 0, 0, 0) 0%,
      rgba(0, 0, 0, .35) 40%,
      rgba(0, 0, 0, 1) 75%,
      rgba(0, 0, 0, 1) 100%);
  pointer-events: none;
}

/* На главной размытие идёт от самого низа блока — отступ, который нужен
   профилю, здесь задирает полосу над картинкой. */
.screen:not(.screen--profile) .burger__fade {
  bottom: 0;
}

/* ---------- Подвал ---------- */
/* Копирайт лежит поверх размытия. Одного z-index мало: backdrop-filter у
   .burger__fade захватывает в свой фон всё, что отрисовано под ним, и
   соседний футер туда попадал. Собственный слой композитора (transform +
   will-change) выводит текст из-под фильтра — он остаётся резким. */
.footer {
  position: absolute;
  left: calc(87 * var(--u));
  width: calc(265 * var(--u));
  bottom: calc(40 * var(--u));
  margin: 0;
  z-index: 2;
  transform: translateZ(0);
  will-change: transform;
}

.footer__text {
  margin: 0;
  text-align: center;
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(14 * var(--u));
  line-height: 1.15;
  letter-spacing: -.0286em;
  color: rgba(255, 255, 255, .8);
}

/* ==================================================================
   Страница регистрации (макет 920:16949, та же сетка 440×956)
   ================================================================== */

/* ---------- Переключатель Регистрация / Вход ---------- */
.seg {
  position: absolute;
  /* Ширина контейнера в макете — по содержимому (hug), а оно разное на
     вкладках «Регистрация» и «Вход». Поэтому центрируем, а не прибиваем
     к left: иначе блок уезжает вбок и обрезается. */
  left: 50%;
  transform: translateX(-50%);
  top: calc(85 * var(--u));
  height: calc(46 * var(--u));
  display: flex;
  align-items: center;
  padding: calc(2 * var(--u)) calc(4 * var(--u));
  border-radius: calc(15 * var(--u));
  /* Обводка-градиент из макета поверх полупрозрачной заливки */
  border: calc(1 * var(--u)) solid transparent;
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    linear-gradient(rgba(0, 0, 0, .1), rgba(0, 0, 0, .1)),
    linear-gradient(180deg, rgba(0, 0, 0, .05) 17%, rgba(0, 0, 0, .15) 100%);
}

.seg__item {
  -webkit-appearance: none;
  appearance: none;
  display: flex;
  align-items: center;
  justify-content: center;
  height: calc(38 * var(--u));
  /* Ширина по содержимому + горизонтальный padding из макета. «Вход» ниже
     получает минимум 84px — столько ему отведено в макете. */
  padding: 0 calc(24 * var(--u));
  border: 0;
  border-radius: calc(11 * var(--u));
  background: none;
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(11 * var(--u));
  line-height: 1;
  letter-spacing: -.0364em;
  text-align: center;
  color: var(--ink);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  /* Плавный переход между вкладками: цвет, фон и тень меняются не скачком. */
  transition: color .22s ease, background-image .22s ease, box-shadow .22s ease;
}

/* «Вход» в макете занимает 84px (layout_0Y57HQ) — и активным, и нет,
   иначе тёмная таблетка получается уже своей ячейки и жмётся к краю. */
.seg__item[data-tab="login"] {
  min-width: calc(84 * var(--u));
}

/* Активный сегмент — тёмная «таблетка» со стеклянной подсветкой */
.seg__item.is-active {
  color: var(--paper);
  border: calc(.5 * var(--u)) solid transparent;
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    linear-gradient(#000, #000),
    linear-gradient(180deg, rgba(0, 0, 0, .05) 17%, rgba(0, 0, 0, .15) 100%);
  box-shadow:
    0 calc(6 * var(--u)) calc(6 * var(--u)) calc(-4 * var(--u)) rgba(0, 0, 0, .3),
    inset calc(3 * var(--u)) calc(3 * var(--u)) calc(10 * var(--u)) calc(-1 * var(--u)) rgba(255, 255, 255, .8),
    inset calc(-2.5 * var(--u)) calc(-2.5 * var(--u)) calc(5 * var(--u)) calc(-1 * var(--u)) rgba(255, 255, 255, .6);
}

/* Выбранное фото затягивает круг целиком: подпись и плюс прячем. */
/* Фото выбрано: показываем картинку кругом на месте SVG-заглушки. */
.avatar.has-photo {
  height: calc(156 * var(--u));
  border-radius: 50%;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/* Аватарки на входе нет — поднимаем форму на её место (160px вверх),
   чтобы не оставалось пустоты под переключателем. */
.screen--login .field--name {
  top: calc(160 * var(--u));
}

.screen--login .field--email {
  top: calc(232 * var(--u));
}

.screen--login .field--password {
  top: calc(304 * var(--u));
}

.screen--login .submit {
  top: calc(378 * var(--u));
}

.screen--login .consent {
  top: calc(480 * var(--u));
}

.screen--login .tg--reg {
  top: calc(560 * var(--u));
}

/* ---------- Аватар ---------- */
/* Круг «Добавьте фото» целиком в SVG: градиент, обводки, подпись по дуге,
   плюс и тень. Холст 156×194 — снизу запас под тень, поэтому высота больше
   ширины, а сам круг занимает верхние 156px. */
.avatar {
  position: absolute;
  z-index: 1;
  left: calc(142 * var(--u));
  top: calc(152 * var(--u));
  width: calc(156 * var(--u));
  height: calc(194 * var(--u));
  padding: 0;
  border: 0;
  background: url("/app/assets/icons/add-photo.png") no-repeat center top / contain;
  cursor: pointer;
  transition: transform .2s ease, filter .2s ease;
}

/* ---------- Поля ---------- */
.reg-form {
  margin: 0;
}

.field {
  position: absolute;
  z-index: 1;
  left: calc(44 * var(--u));
  width: calc(352 * var(--u));
  height: calc(65 * var(--u));
  /* Содержимое по центру и по горизонтали, и по вертикали. */
  display: flex;
  align-items: center;
  border-radius: calc(14 * var(--u));
}

.field--name {
  top: calc(312 * var(--u));
}

.field--email {
  top: calc(384 * var(--u));
}

.field--password {
  top: calc(456 * var(--u));
  padding-right: calc(25 * var(--u));
}

/* Текст пароля не должен заезжать под глазок */
.field--password .field__input {
  padding-right: 0;
}

.field__input {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  /* Высоту не тянем на 100%: тогда flex-центрирование родителя работает,
     и текст стоит ровно по вертикали поля. */
  /* Высота во всё поле + line-height равен ей: глиф встаёт ровно по центру.
     При line-height .9 текст уезжал вверх — это и был перекос. */
  height: 100%;
  padding: 0 calc(34 * var(--u));
  border: 0;
  border-radius: inherit;
  background: none;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(32 * var(--u));
  line-height: calc(65 * var(--u));
  letter-spacing: -.03em;
  text-align: center;
  color: var(--ink);
}

.field__input::placeholder {
  color: rgba(0, 0, 0, .2);
  opacity: 1;
}

.field__input:focus {
  outline: none;
}

/* Точки-маркеры по краям поля */
/* Полукруги по краям поля: половина ширины, скруглены только с одной
   стороны — плоской гранью наружу, к краю поля. */
.field__dot {
  position: absolute;
  top: calc(24 * var(--u));
  width: calc(9.5 * var(--u));
  height: calc(19 * var(--u));
  background: rgba(0, 0, 0, .2);
  pointer-events: none;
  transition: background-color .2s ease;
}

/* Поле заполнено — метки по краям чернеют. :placeholder-shown истинно, пока
   поле пустое, поэтому берём отрицание. Селектор смотрит вперёд по дереву,
   а .field__dot--left стоит ДО инпута, поэтому для него используем :has(). */
.field:has(.field__input:not(:placeholder-shown)) .field__dot {
  background: var(--ink);
}

.field__dot--left {
  left: calc(1 * var(--u));
  border-radius: 0 calc(9.5 * var(--u)) calc(9.5 * var(--u)) 0;
}

.field__dot--right {
  left: calc(341.5 * var(--u));
  border-radius: calc(9.5 * var(--u)) 0 0 calc(9.5 * var(--u));
}

/* Глазок у пароля: в макете 392/470 от экрана, поле стоит в 44/452 */
/* Кнопка-«глаз» — полуовал: вытянутая по горизонтали таблетка,
   скруглённая по половине высоты. */
.field__eye {
  position: absolute;
  z-index: 2;
  left: calc(356 * var(--u));
  top: calc(17 * var(--u));
  width: calc(36 * var(--u));
  height: calc(36 * var(--u));
  padding: 0;
  border: 0;
  /* Иконка из макета: подложка, обводка и тень уже внутри SVG. */
  background: url("/app/assets/icons/eye-off.svg") no-repeat center / contain;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* Пароль показан — перечёркиваем глаз диагональной линией. */
/* Пароль показан — иконка из макета со «зрачком» вместо перечёркнутой. */
.field__eye.is-on {
  background-image: url("/app/assets/icons/eye-on.svg");
}

/* ---------- Кнопка «Создать профиль» ---------- */
.submit {
  position: absolute;
  z-index: 0;
  left: 0;
  right: 0;
  /* Форма кнопки — SVG 281×72 из макета; высота обёртки под неё.
     Стоит между паролем (низ 527) и согласием (632) — чуть выше него. */
  top: calc(530 * var(--u));
  height: calc(72 * var(--u));
  pointer-events: none;
}

/* Кнопка — вытянутый эллипс со стеклянными inset-тенями (Ellipse 1664).
   Подпись у нижней дуги, как в макете (текст на 354..575). */
/* Кнопка «Создать профиль» целиком в SVG (605×318): форма, inner-тени,
   размытая тень под ней и сам текст. Видимая часть — x 154..445, y 205..288,
   поэтому холст шире и выше кнопки; лишнее прозрачно. */
.submit__btn {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  /* Кнопка — ровно пилюля из макета (281x72); картинки-холсты лежат
     в ::before/::after и выходят за неё, не перехватывая клики. */
  top: 0;
  width: calc(281 * var(--u));
  height: calc(72 * var(--u));
  padding: 0;
  border: 0;
  -webkit-appearance: none;
  appearance: none;
  background: none;
  cursor: pointer;
  pointer-events: auto;
  transition: transform .2s ease, filter .2s ease;
}

/* Пока форма не готова, кнопка не реагирует на нажатия. */
.screen:not(.is-ready) .submit__btn {
  cursor: default;
  pointer-events: none;
}

/* Профиль уже создаётся — второе нажатие завело бы ещё один запрос. */
.screen.is-busy .submit__btn {
  cursor: progress;
  pointer-events: none;
  filter: grayscale(1);
}

/* ---------- Согласие ---------- */
.consent {
  position: absolute;
  z-index: 1;
  left: calc(94 * var(--u));
  top: calc(646 * var(--u));
  display: flex;
  align-items: center;
  gap: calc(8 * var(--u));
}

/* Причина, по которой форма не отправилась. Браузерная подсказка
   молчит про галочку согласия и не видна на десктопе. */
.form-error {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  /* Прижимаем к низу экрана: при фиксированной координате сообщение
     обрезалось нижним краем на невысоких окнах. */
  bottom: calc(10 * var(--u));
  margin: 0;
  padding: 0 calc(24 * var(--u));
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(14 * var(--u));
  line-height: 1.2;
  text-align: center;
  color: #BF2121;
}

/* Та же строка, но это подсказка, а не сбой: «ждём подтверждения»
   красным читается как ошибка. */
.form-error--hint {
  color: rgba(0, 0, 0, .55);
}

/* Причина, по которой автовход не состоялся (стартовый экран).
   В потоке, а не absolute как .form-error: этот экран прокручивается,
   и прижатое к низу сообщение уехало бы под кнопки. */
.auth-problem {
  margin: calc(14 * var(--u)) calc(24 * var(--u)) 0;
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(14 * var(--u));
  line-height: 1.25;
  text-align: center;
  color: #BF2121;
}

/* «Вы вышли из профиля» — состояние, а не сбой: тот же размер, но
   спокойный цвет, чтобы человек не искал несуществующую ошибку. */
.auth-problem--calm {
  color: rgba(0, 0, 0, .6);
}

.consent__box {
  flex: 0 0 auto;
  width: calc(25 * var(--u));
  height: calc(24 * var(--u));
  padding: 0;
  border: 0;
  /* По умолчанию — «полный» вид (как раньше при нажатии), галочка внутри
     появляется только когда согласие отмечено. */
  background: url("/app/assets/icons/check-box.svg") no-repeat center / contain;
  opacity: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  position: relative;
  transition: opacity .15s ease, background-image .15s ease;
}

/* Галочка отмеченного состояния. */
/* Отмечено — меняем иконку на активную (чёрный кружок с галочкой). */
.consent__box[aria-checked="true"] {
  background-image: url("/app/assets/icons/check-box-active.svg");
}

.consent__text {
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(12 * var(--u));
  line-height: 1.15;
  letter-spacing: -.0337em;
  color: rgba(0, 0, 0, .2);
}

/* ---------- «Взять данные из телеграма» ---------- */
.tg--reg {
  top: calc(711 * var(--u));
  width: calc(237.9 * var(--u));
  height: calc(56.2 * var(--u));
  filter: drop-shadow(0 calc(5.47 * var(--u)) calc(6.83 * var(--u)) rgba(6, 118, 159, .15));
}

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

  .btn,
  .avatar,
  .submit__btn,
  .consent__box {
    transition: none;
  }
}

/* ---------- Текст по дуге (<curved-text>) ---------- */
curved-text {
  display: block;
  line-height: 0;
  pointer-events: none;
}

.curved-text__svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

curved-text text {
  font-family: var(--font-display);
}

/* ==========================================================================
   Личный кабинет (account.html) — экран залогиненного пользователя.
   Макет 946:8980. Координаты и размеры — как в Figma, в единицах --u.
   ========================================================================== */

/* ---------- Карточка тарифа ---------- */
.plan {
  position: absolute;
  left: calc(20 * var(--u));
  top: calc(108 * var(--u));
  width: calc(400 * var(--u));
  height: calc(187 * var(--u));
  /* Размеры и координаты — из макета (Frame 1171277000, 400x187).
     Тариф задаётся data-plan на .plan, окончание подписки — классом is-expired. */
  border-radius: calc(45 * var(--u));
  border: calc(3 * var(--u)) solid transparent;
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    linear-gradient(var(--plan-bg), var(--plan-bg)),
    linear-gradient(43deg,
      rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, .7) 26%,
      rgba(255, 255, 255, .3) 97%, rgba(255, 255, 255, .2) 100%);
  box-shadow:
    0 calc(31 * var(--u)) calc(21 * var(--u)) calc(-30 * var(--u)) var(--plan-shadow),
    inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(16.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .7),
    inset calc(1.25 * var(--u)) calc(1.25 * var(--u)) calc(30 * var(--u)) calc(-2.5 * var(--u)) #fff,
    inset calc(-2.5 * var(--u)) calc(-6.25 * var(--u)) calc(17.5 * var(--u)) calc(-5.5 * var(--u)) var(--plan-glow);
  overflow: hidden;
}

/* ---------- Темы тарифов ----------
   Цвета, тени и градиенты каждого тарифа взяты из макета. Значение по
   умолчанию — «Продвинутый», остальные переопределяют переменные. */
.plan,
.plan[data-plan="advanced"] {
  --plan-bg: #000;
  --plan-shadow: rgba(0, 0, 0, .3);
  --plan-glow: rgba(144, 137, 246, .6);
  --plan-accent: #fff;
  --plan-count: #000;
  --plan-stroke: #fff;
  --plan-name: linear-gradient(30deg, #F7DED7 0%, #B6C9D7 36%, #B4C2F3 70%, #E2CEEA 100%);
  --plan-fill: linear-gradient(30deg, #F7DED7 0%, #B6C9D7 36%, #B4C2F3 70%, #E2CEEA 100%);
  --plan-muted: rgba(255, 255, 255, .3);
  --plan-track: rgba(255, 255, 255, .3);
  --plan-used: #fff;
}

/* Личный — зелёная карточка. */
.plan[data-plan="personal"] {
  --plan-bg: #27E593;
  --plan-shadow: rgba(15, 160, 97, .3);
  --plan-glow: rgba(226, 246, 137, .6);
  --plan-accent: #32D890;
  --plan-count: #32D890;
  --plan-stroke: #fff;
  --plan-name: linear-gradient(32deg, #F2F2F2 0%, #D7FFA2 55%, #F2FFD5 100%);
  --plan-fill: linear-gradient(32deg, #F2F2F2 0%, #D7FFA2 55%, #F2FFD5 100%);
  --plan-muted: rgba(255, 255, 255, .6);
  --plan-track: rgba(255, 255, 255, .3);
  --plan-used: #fff;
}

/* Семья — розовая карточка. */
.plan[data-plan="family"] {
  --plan-bg: #F5197B;
  --plan-shadow: rgba(178, 6, 83, .3);
  --plan-glow: rgba(246, 188, 137, .6);
  --plan-accent: #FF2486;
  --plan-count: #FF2486;
  --plan-stroke: #fff;
  --plan-name: linear-gradient(34deg, #F2F2F2 22%, #FFD2A2 85%, #C4FFE6 100%);
  --plan-fill: linear-gradient(90deg, #F2F2F2 15%, #FFD2A2 35%, #C4FFE6 79%);
  --plan-muted: rgba(255, 255, 255, .6);
  --plan-track: rgba(255, 255, 255, .3);
  --plan-used: #fff;
}

/* Конструктор — фиолетовая карточка. */
.plan[data-plan="custom"] {
  --plan-bg: #8523C6;
  --plan-shadow: rgba(113, 19, 176, .5);
  --plan-glow: rgba(175, 255, 25, .6);
  --plan-accent: #8523C6;
  --plan-count: #8523C6;
  --plan-stroke: #fff;
  --plan-name: linear-gradient(30deg, #F7EED7 0%, #FFB3E4 36%, #EADECE 100%);
  --plan-fill: linear-gradient(90deg, #F7EED7 8%, #FFB3E4 36%, #EADECE 79%, #E5FFB4 100%);
  --plan-muted: rgba(255, 255, 255, .6);
  --plan-track: rgba(255, 255, 255, .3);
  --plan-used: #fff;
}

/* Подписка закончилась — светлая карточка, всё приглушено. */
.plan.is-expired {
  --plan-bg: #E4E4E4;
  --plan-shadow: rgba(0, 0, 0, .3);
  --plan-glow: rgba(0, 0, 0, .1);
  --plan-accent: #E4E3E3;
  --plan-count: #fff;
  --plan-stroke: #000;
  --plan-name: linear-gradient(rgba(0, 0, 0, .4), rgba(0, 0, 0, .4));
  --plan-fill: linear-gradient(rgba(0, 0, 0, .3), rgba(0, 0, 0, .3));
  --plan-muted: rgba(0, 0, 0, .4);
  --plan-track: rgba(0, 0, 0, .1);
  --plan-used: rgba(0, 0, 0, .6);
}

/* Даже погасшая карточка сохраняет отсвет своего тарифа: в макете у
   каждого из четырёх истёкших вариантов свой цвет внутренней тени. */
.plan.is-expired[data-plan="advanced"] {
  --plan-glow: rgba(137, 186, 246, .6);
}

.plan.is-expired[data-plan="personal"] {
  --plan-glow: rgba(226, 246, 137, .6);
  --plan-shadow: rgba(15, 160, 97, .3);
}

.plan.is-expired[data-plan="family"] {
  --plan-glow: rgba(245, 25, 123, .6);
  --plan-shadow: rgba(245, 25, 123, .2);
}

.plan.is-expired[data-plan="custom"] {
  --plan-glow: rgba(113, 19, 176, .6);
  --plan-shadow: rgba(113, 19, 176, .5);
}

/* ---------- Название тарифа (39px, 34;32) ---------- */
.plan__name {
  position: absolute;
  left: calc(34 * var(--u));
  /* Правка 13.10.2026 (Мария): «в названии тарифа буквы обрезаются по
     нижнему краю». Та же причина, что у .plan-card__name на экране
     тарифов (её чинили 12.10.2026): фиксированная height: 27px при
     шрифте 39px, а название красится через background-clip: text —
     градиент обрезается ровно по блоку, и хвосты «р», «у», «ц» теряют
     низ. Высоту задаём минимальной, блок растёт под строку; верх
     поднимаем на половину прибавки, чтобы текст остался на месте. */
  top: calc(26 * var(--u));
  width: calc(332 * var(--u));
  min-height: calc(39 * var(--u));
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(39 * var(--u));
  line-height: .9;
  letter-spacing: -.03em;
  white-space: nowrap;
  background-image: var(--plan-name);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* ---------- Строка трафика ---------- */
/* Точки-маркеры по краям (34;79 и 359;79, диаметр 7). */
.plan__dot {
  position: absolute;
  top: calc(79 * var(--u));
  width: calc(7 * var(--u));
  height: calc(7 * var(--u));
  border-radius: 50%;
  background: var(--plan-muted);
}

.plan__dot--left {
  left: calc(34 * var(--u));
}

.plan__dot--right {
  left: calc(359 * var(--u));
}

.plan__traffic-label,
.plan__traffic-used,
.plan__traffic-total {
  position: absolute;
  top: calc(77 * var(--u));
  height: calc(9 * var(--u));
  display: flex;
  align-items: center;
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(12 * var(--u));
  line-height: .9;
  letter-spacing: -.06em;
  color: var(--plan-muted);
}

.plan__traffic-label {
  left: calc(45 * var(--u));
  width: calc(98 * var(--u));
}

/* Израсходовано — ярче остального (в макете белым на цветной карточке). */
.plan__traffic-used {
  left: calc(297 * var(--u));
  width: calc(20 * var(--u));
  justify-content: flex-end;
  color: var(--plan-used);
}

.plan__traffic-total {
  left: calc(317 * var(--u));
  width: calc(38 * var(--u));
  justify-content: flex-end;
}

/* ---------- Полоса трафика (332x18 в 34;94, радиус 6) ---------- */
.plan__bar {
  position: absolute;
  left: calc(34 * var(--u));
  top: calc(94 * var(--u));
  width: calc(332 * var(--u));
  height: calc(18 * var(--u));
  border-radius: calc(6 * var(--u));
  background: var(--plan-track);
  overflow: hidden;
}

.plan__bar-fill {
  height: 100%;
  border-radius: inherit;
  background-image: var(--plan-fill);
}

/* ---------- Цена и дата (ряд в 36;137, промежуток 15) ----------
   Ряд упирается в кружки устройств (они начинаются с 287), поэтому
   ширину ограничиваем: «Подписка истекла» длиннее даты и иначе
   заезжает под счётчик. */
.plan__meta {
  position: absolute;
  left: calc(36 * var(--u));
  top: calc(137 * var(--u));
  max-width: calc(245 * var(--u));
  display: flex;
  align-items: center;
  gap: calc(15 * var(--u));
}

.plan__price,
.plan__until {
  margin: 0;
  font-family: var(--font-text);
  font-weight: 700;
  font-size: calc(18 * var(--u));
  line-height: .9;
  letter-spacing: -.06em;
  white-space: nowrap;
  /* В макете у строки нет заливки — только обводка 2px цветом фона. */
  color: transparent;
  -webkit-text-stroke: calc(1 * var(--u)) var(--plan-stroke);
  paint-order: stroke fill;
}

/* «Подписка истекла» набрана с более мягким трекингом, чем дата. */
.plan__until--note {
  letter-spacing: -.083em;
}

/* ---------- Устройства (кружки 35x35 в ряд, y=126) ----------
   Группа прижата к правому краю: сколько бы кружков ни было, последний
   стоит на месте. В макете у одного устройства счётчик начинается с
   307, у двух — с 287; разница ровно в один кружок со сдвигом. */
.plan__devices {
  position: absolute;
  top: calc(126 * var(--u));
  right: calc(33 * var(--u));
  height: calc(35 * var(--u));
  display: flex;
  align-items: center;
}

/* Кружки перекрывают друг друга и счётчик: device--1 поверх device--2,
   а тот — поверх счётчика. Порядок в разметке обратный, поэтому
   каждый следующий подтягивается влево. */
.plan__device {
  order: 1;
}

.plan__device--1 {
  order: 2;
}

/* Скрытый кружок не должен занимать место в ряду. */
.plan__device[hidden] {
  display: none;
}

/* Счётчик — белый круг с обводкой цвета тарифа. */
.plan__devices-count {
  position: relative;
  z-index: 3;
  flex: 0 0 auto;
  width: calc(35 * var(--u));
  height: calc(35 * var(--u));
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: calc(20 * var(--u));
  border: calc(1.5 * var(--u)) solid var(--plan-accent);
  background: #fff;
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(18 * var(--u));
  line-height: 1;
  letter-spacing: -.0167em;
  color: var(--plan-count);
}

/* На истёкшей карточке счётчик инвертирован: чёрный круг, белая цифра. */
.plan.is-expired .plan__devices-count {
  background: #000;
  color: #fff;
}

/* Кружки с иконками устройств; шаг 21/24 из макета даёт наложение. */
.plan__device {
  flex: 0 0 auto;
  width: calc(35 * var(--u));
  height: calc(35 * var(--u));
  margin-left: calc(-14 * var(--u));
  border-radius: calc(50 * var(--u));
  border: calc(1.5 * var(--u)) solid var(--plan-bg);
  background-image:
    radial-gradient(circle at 50% 0%,
      rgba(215, 215, 215, 1) 0%, rgba(175, 175, 175, .7) 17%,
      rgba(89, 89, 89, .9) 34%, rgba(154, 154, 154, .05) 49%);
  background-color: rgba(0, 0, 0, .5);
}

.plan.is-expired .plan__device {
  background-color: rgba(110, 110, 110, .1);
}

.plan__device--1 {
  z-index: 2;
}

.plan__device--2 {
  z-index: 1;
}

/* Сама картинка устройства поверх кружка. */
.plan__device::before {
  content: "";
  display: block;
  width: 100%;
  height: 100%;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
}

.plan__device--1::before {
  background-image: url("/app/assets/icons/plan-device-b.png");
}

.plan__device--2::before {
  background-image: url("/app/assets/icons/plan-device-a.png");
}

/* Бейдж «+ 150гб докуплено» поверх карточки. */
.traffic-badge {
  position: absolute;
  left: calc(135 * var(--u));
  top: calc(265 * var(--u));
  width: calc(162 * var(--u));
  height: calc(55 * var(--u));
  background: url("/app/assets/icons/traffic-badge.png") no-repeat center / contain;
  transform: rotate(-6deg);
  pointer-events: none;
}

/* ---------- Имя пользователя ---------- */
.account-user {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(79 * var(--u));
  margin: 0;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(20 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
}

/* Юзернейм в шапке не показываем — осталось только имя, поэтому
   display:inline (он ставил имя и ник в одну строку) больше не нужен. */
.account-user__name {
  margin: 0;
  color: var(--ink);
}

/* ---------- Кнопка «Открыть в Happ» ---------- */
.happ {
  position: absolute;
  left: 50%;
  top: calc(330 * var(--u));
  width: calc(295 * var(--u));
  height: calc(100.5 * var(--u));
  padding: 0;
  border: 0;
  -webkit-appearance: none;
  appearance: none;
  transform: translateX(-50%);
  background: url("/app/assets/icons/happ-btn.png") no-repeat center / contain;
  cursor: pointer;
  transition: transform .2s ease, filter .2s ease;
}

/* ---------- Плитки «Тарифы» и «Трафик» ---------- */
.tiles {
  display: contents;
}

.tile {
  position: absolute;
  top: calc(475 * var(--u));
  width: calc(195 * var(--u));
  height: calc(116 * var(--u));
  padding: 0;
  border: 0;
  -webkit-appearance: none;
  appearance: none;
  border-radius: calc(30 * var(--u));
  background: var(--paper);
  cursor: pointer;
  transition: transform .2s ease, filter .2s ease;
}

.tile--tariff {
  left: calc(20 * var(--u));
}

.tile--traffic {
  left: calc(225 * var(--u));
}

.tile__title,
.tile__hint {
  position: absolute;
  left: 0;
  right: 0;
  text-align: center;
}

.tile__title {
  top: calc(55 * var(--u));
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(28 * var(--u));
  line-height: .9;
  letter-spacing: -.03em;
  color: var(--ink);
}

.tile__hint {
  top: calc(84 * var(--u));
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(12 * var(--u));
  line-height: 1.1;
  letter-spacing: -.0167em;
  color: rgba(0, 0, 0, .4);
}

/* Розовые звёзды над плитками — декор из макета, вместе с иконкой внутри. */
.tile::before {
  content: "";
  position: absolute;
  left: 50%;
  top: calc(-60 * var(--u));
  width: calc(127 * var(--u));
  height: calc(126 * var(--u));
  transform: translateX(-50%);
  pointer-events: none;
}

/* ВРЕМЕННО: иконка тарифов — копия трафика, нужен отдельный SVG. */
.tile--tariff::before {
  background: url("/app/assets/icons/tile-tariff.svg") no-repeat center / contain;
}

.tile--traffic::before {
  background: url("/app/assets/icons/icon-traffic.svg") no-repeat center / contain;
}

/* ---------- Инструкция ---------- */
.instruction {
  position: absolute;
  left: calc(40 * var(--u));
  top: calc(625 * var(--u));
  width: calc(355 * var(--u));
  height: calc(69 * var(--u));
  padding: 0;
  border: 0;
  -webkit-appearance: none;
  appearance: none;
  background: url("/app/assets/icons/instruction-btn.png") no-repeat left center / contain;
  cursor: pointer;
  transition: transform .2s ease, filter .2s ease;
}

/* ---------- Нижняя панель ----------
   Прибита к низу окна, а не к координате макета: страницы длиннее экрана,
   и панель, лежащая в потоке, уезжала вверх вместе с содержимым — под ней
   открывалась пустота. fixed держит её на месте при любой прокрутке. */
/* Панель не ездит со страницей — прибита к низу окна. Сцена тянется на
   всю высоту окна (см. .stage:has(.tabbar)), поэтому низ окна и низ
   мини-аппа совпадают, и панель стоит у края экрана, а не в фоне. */
/* ---------- Всплывающее уведомление ----------
   Короткое подтверждение действия (скопировали ссылку). Висит над
   панелью навигации, нажатия не перехватывает. */
.toast {
  position: fixed;
  z-index: 8;
  left: 50%;
  bottom: calc(150 * var(--u));
  margin: 0;
  padding: calc(14 * var(--u)) calc(24 * var(--u));
  max-width: calc(var(--stage) - 48 * var(--u));
  border-radius: calc(24 * var(--u));
  background: rgba(0, 0, 0, .85);
  box-shadow: 0 calc(8 * var(--u)) calc(24 * var(--u)) calc(-8 * var(--u)) rgba(0, 0, 0, .45);
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(16 * var(--u));
  line-height: 1.2;
  letter-spacing: -.02em;
  text-align: center;
  color: #fff;
  pointer-events: none;
  /* Появляется снизу вверх; стартовое положение — чуть ниже. */
  transform: translate(-50%, calc(12 * var(--u)));
  opacity: 0;
  transition: opacity .2s ease, transform .2s ease;
}

.toast.is-shown {
  transform: translate(-50%, 0);
  opacity: 1;
}

.tabbar {
  position: fixed;
  z-index: 5;
  left: 50%;
  transform: translateX(-50%);
  bottom: 0;
  width: var(--stage);
  height: calc(135 * var(--u));
  /* Правка 18.10.2026: панель без значка. В tabbar.png значок VPN с
     надписью был вшит в картинку, и свой значок не мог его перекрыть.
     tabbar-plain.png — та же панель, из неё вырезан значок и ореол. */
  background: url("/app/assets/icons/tabbar-plain.png") no-repeat center top / contain;
}

.tabbar__item {
  position: absolute;
  top: calc(30 * var(--u));
  width: calc(59 * var(--u));
  height: calc(75 * var(--u));
  padding: 0;
  border: 0;
  -webkit-appearance: none;
  appearance: none;
  background: none;
  cursor: pointer;
  transition: transform .2s ease;
}

.tabbar__item--friends {
  left: calc(113 * var(--u));
}

.tabbar__item--profile {
  left: calc(268 * var(--u));
}

/* Значок VPN: белый «цветок», внутри иконка питания. Розовая в своём
   разделе, чёрная в чужом — меняется только она (макет 1007:11841).

   Правка 18.10.2026 (Матвей: «вот так должно быть»). Раньше значок брали
   из tabbar.png и накрывали tabbar-vpn-idle.png, но в обеих картинках
   внутри нарисована надпись «VPN», а в макете там иконка питания —
   перекрытием это не лечилось. Теперь значок целиком свой: форма,
   объём и иконка собраны в SVG по макету, поэтому состояние видно
   сразу и надпись не выглядывает.

   Раздел VPN это account, devices (туда ведёт кнопка «VPN») и tariffs,
   которые открываются из devices. */
.tabbar__item--vpn {
  left: calc(166 * var(--u));
  top: calc(2 * var(--u));
  width: calc(107 * var(--u));
  height: calc(107 * var(--u));
  border-radius: 50%;
  background: url("/app/assets/icons/tabbar-vpn-off.svg") no-repeat center / contain;
  /* Значок круглый, а кнопка — квадрат 107x107: её нижние углы
     заходят на подписи «Друзья» и «Профиль» (по ~6 единиц с каждой
     стороны на высоте подписи), и там нажатие по краю подписи
     уходило в VPN, хотя значка в этом месте не видно (Матвей,
     26.10.2026: «ничего, что находит одно на другое?»).

     Обрезаем область нажатия по кругу — она совпадает с тем, что
     человек видит. Соседние кнопки лежат НИЖЕ по z-порядку только
     частично: «Профиль» идёт в разметке после VPN и перекрывал бы
     его сам, так что чинить порядком нельзя — нужна форма. */
  clip-path: circle(50%);
}

.screen--account .tabbar__item--vpn,
.screen--devices .tabbar__item--vpn,
.screen--tariffs .tabbar__item--vpn {
  background-image: url("/app/assets/icons/tabbar-vpn-on.svg");
}

/* Подписи в панели уже нарисованы в картинке — прячем, оставляя
   доступными для скринридеров. */
/* Правка 18.10.2026: подписи рисует CSS. Раньше они были нарисованы в
   tabbar.png серым, подпись активной вкладки шла поверх, и под неё
   приходилось класть подложку — а панель там с градиентом, одним цветом
   не попасть: виден прямоугольник (Матвей: «какие-то кусочки, как будто
   вырезана из бумаги»). Теперь в картинке подписей нет, подложка не
   нужна, а активная отличается только цветом. */
.tabbar__label {
  position: absolute;
  left: 0;
  bottom: calc(13 * var(--u));
  width: 100%;
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(9 * var(--u));
  line-height: 1;
  letter-spacing: -.0333em;
  text-align: center;
  white-space: nowrap;
  color: #9A9A9E;
}

/* У VPN подпись не показываем: значок крупный и приподнят, текст лёг бы
   на него. Для скринридеров он остаётся в разметке. */
.tabbar__item--vpn .tabbar__label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

@media (hover: hover) {

  .happ:hover {
    transform: translateX(-50%) translateY(calc(-2 * var(--u)));
    filter: brightness(1.04);
  }

  .tile:hover,
  .instruction:hover {
    transform: translateY(calc(-2 * var(--u)));
    filter: brightness(1.04);
  }

  .tabbar__item:hover {
    transform: scale(1.06);
  }
}

/* Центрирование Happ держится на translateX(-50%) — дописываем к нему. */
.happ:active {
  transform: translateX(-50%) scale(.985);
}

.tile:active,
.instruction:active {
  transform: scale(.985);
}

.tabbar__item:active {
  transform: scale(.94);
}

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

  .happ,
  .tile,
  .instruction,
  .tabbar__item {
    transition: none;
  }
}

/* ==================================================================
   Экран «Выберите тариф» (макет 962:9209, сетка 440×956)
   ================================================================== */

.screen--tariffs {
  /* Экран длиннее окна: 782 = низ кнопки «К оплате» + отступ.
     Правка 15.10.2026 (Евгений, скриншот): снизу появилась панель
     разделов (ТЗ п. 8). Общее правило .stage:has(.tabbar) .screen даёт
     ей padding-bottom, но при border-box этот отступ съедал высоту
     изнутри — кнопка уезжала под панель. Тут контент размечен
     абсолютно от верха, поэтому высота считается без padding, а отступ
     прибавляется снизу: кнопка остаётся над панелью, и до неё можно
     долистать. */
  /* Низ кнопки «К оплате» — 732 (646+86), плюс немного воздуха.
     Было 810 под раскладку, где кнопка стояла на 696. */
  height: calc(764 * var(--u));
}

/* Правка 13.10.2026 (Мария): «на десктопе внизу серое пространство».
   Высота задана по макету, а окно браузера выше — снизу просвечивал фон
   страницы (--backdrop). Экранов с нижней панелью это не касалось: для
   них правило .stage:has(.tabbar) уже тянет сцену на всю высоту окна, а
   у тарифов и трафика панели нет. */
.stage:has(.screen--tariffs),
.stage:has(.screen--traffic) {
  min-height: 100vh;
  min-height: 100dvh;
}

.stage:has(.screen--tariffs) .screen--tariffs,
.stage:has(.screen--traffic) .screen--traffic {
  min-height: 100vh;
  min-height: 100dvh;
}

/* С панелью разделов «на всю высоту окна» мало: при border-box её 135
   единиц отводятся ВНУТРИ этой высоты, и содержимому остаётся
   «окно − 135». Кнопка «К оплате» размечена абсолютно и стоит ниже —
   панель ложилась прямо на неё, а прокрутки не возникало, потому что
   экран ровно по окну (Матвей, 29.10.2026: «скролл дальше не
   прокручивает, кнопка К оплате недоступна»; измерено: закрыта на
   19-94px на четырёх размерах из восьми).

   Поэтому к высоте окна прибавляем панель — но не всегда: на высоком
   окне содержимое и так помещается, и безусловная прибавка дала бы
   лишние 135px прокрутки там, где её не было. Включаем запас только
   когда экран со счётчиком в окно не влезает.

   Порог: раскрытый счётчик ставит кнопку на 701 с высотой 86, итого
   787 единиц, плюс панель 135 = 922. Окно ниже — нужна прокрутка. */
@media (max-height: 922px) {
  .stage:has(.tabbar) .screen--tariffs.has-counter {
    min-height: calc(100vh + 135 * var(--u));
    min-height: calc(100dvh + 135 * var(--u));
  }
}

/* Правка 17.10.2026 (Мария): «кнопку оплаты не видно на остальных
   страницах, и не всегда понятно, что надо прокрутить».

   Экраны тарифов и трафика размечены по макету 844px: кнопка стоит на
   фиксированных 696px от верха. На окне пониже (650 и меньше — обычное
   дело для вебвью с клавиатурой или на невысоком телефоне) она просто
   за кадром, а подсказки прокрутить нет. Измерено: при 650px до неё
   оставалось 43px прокрутки, при 560 — 133px.

   Прижимаем кнопку к нижнему краю окна, когда она туда не помещается.
   position: fixed не годится — сцена центрирована и уже 440px, fixed
   увёл бы кнопку за её край на десктопе (та же причина, по которой у
   .paybar выбран margin-top: auto). */
/* Правка 17.10.2026. Кнопку «К оплате» я прижимал к низу ОКНА
   (position: fixed), чтобы на невысоком экране её не приходилось искать
   прокруткой — у .screen стоит overflow: hidden, своей прокрутки нет.

   Это породило две поломки подряд: сперва из-под кнопки торчал значок
   панели разделов, потом кнопка легла прямо на карточку «Конструктор»
   (измерено: на окне 560px перекрытие 67px). Причина общая — карточки
   размечены АБСОЛЮТНО от верха экрана и за кнопкой не двигаются,
   сколько ни добавляй padding.

   Прижимать к окну больше не пытаемся: кнопка остаётся на своём месте
   в потоке, а до неё доводит прокрутка страницы (не экрана — страница
   прокручивается, высота экрана 810 больше окна). Вместо этого даём
   понять, что ниже что-то есть: на невысоком окне экран чуть
   укорачивается, и край кнопки попадает в видимую область. */
@media (max-height: 760px) {

  /* Низ кнопки «К оплате» — 732. Оставляем её и небольшой хвост в
     пределах прокрутки, чтобы она не оказывалась ровно у границы.
     У экрана трафика своя раскладка — ему прежняя высота. */
  .screen--tariffs {
    height: calc(760 * var(--u));
  }

  .screen--traffic {
    height: calc(800 * var(--u));
  }
}

/* Правка 15.10.2026 (Евгений, скриншот): панель разделов накрыла кнопку
   «К оплате».

   Общее правило .stage:has(.tabbar) .screen отводит панели место
   внутренним отступом при border-box. Для экранов, размеченных
   абсолютно от верха, это не работает: отступ съедает высоту изнутри, а
   координаты элементов не сдвигаются — кнопка на 696 оказывается под
   панелью. Здесь высота считается по контенту, а отступ прибавляется
   снизу, и до кнопки можно долистать. */
/* Правка 24.10.2026 (Матвей: «нужно чтобы выбор тарифа и Период
   вмещался на экран без скрола»).

   Вот откуда бралась прокрутка, и дело было не в раскладке. Стояло
   content-box: к высоте экрана (min-height: 100% от сцены, то есть всё
   окно) сверху прибавлялись 135px отступа под панель разделов — экран
   получался выше окна ровно на панель. Измерено: 970 при окне 844,
   отсюда и 126px прокрутки.

   Возвращаем border-box: панель занимает место ВНУТРИ высоты окна.
   Содержимому это не мешает — оно размечено абсолютными координатами
   от верха и padding его не двигает, а низ раскладки (кнопка на 722)
   теперь с запасом помещается над панелью. */
.stage:has(.tabbar) .screen--tariffs {
  box-sizing: border-box;
}

/* ---------- Стрелка «назад» ---------- */
.tariffs__back {
  position: absolute;
  left: calc(20 * var(--u));
  top: calc(74 * var(--u));
  width: calc(26 * var(--u));
  height: calc(20 * var(--u));
  padding: 0;
  border: 0;
  background: url("/app/assets/icons/back-arrow.svg") no-repeat center / contain;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

/* Сама стрелка 26x20 — в неё трудно попасть пальцем (минимум для
   касания 44x44). Расширяем область нажатия невидимым слоем, вид
   стрелки при этом не меняется. */
.tariffs__back::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(48 * var(--u));
  height: calc(48 * var(--u));
  transform: translate(-50%, -50%);
}

.tariffs__back:active {
  transform: scale(.9);
}

/* ---------- Заголовки секций ---------- */
.tariffs__title {
  position: absolute;
  left: calc(73.5 * var(--u));
  top: calc(72 * var(--u));
  display: flex;
  align-items: center;
  gap: calc(5 * var(--u));
}

.tariffs__title--period {
  left: calc(68 * var(--u));
  /* Правка 24.10.2026 (Матвей: «есть сверху и после тарифов пустое
     пространство»). Было 592 при карточках, кончающихся на 493, —
     99px пустоты. Теперь карточки кончаются на 476, под ними ссылка
     пробного периода, а заголовок встаёт сразу за ней.

     Правка 28.10.2026 (Матвей: «давай здесь сделаем отделение
     пустотой, чтобы после пробного периода визуально было видно
     отделение»). Было 546: от ссылки оставалось 6-16px — меньше, чем
     от карточек до самой ссылки (11-24px), и ссылка читалась как
     часть блока «Период подписки», а не как конец списка тарифов.
     566 даёт 26-36px, вдвое больше верхнего зазора. */
  top: calc(566 * var(--u));
}

.tariffs__title-badge {
  flex: 0 0 auto;
  width: calc(24 * var(--u));
  height: calc(24 * var(--u));
  background: url("/app/assets/icons/tariff-badge.svg") no-repeat center / contain;
}

/* У «Периода подписки» свой значок — календарь */
.tariffs__title--period .tariffs__title-badge {
  background-image: url("/app/assets/icons/period-badge.svg");
}

.tariffs__title-text {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(26 * var(--u));
  line-height: .9;
  letter-spacing: -.03em;
  color: var(--ink);
}

/* ---------- Карточки тарифов ---------- */
.plans {
  display: contents;
}

.plan-card {
  position: absolute;
  left: calc(20 * var(--u));
  width: calc(400 * var(--u));
  height: calc(86 * var(--u));
  padding: 0;
  text-align: left;
  border-radius: calc(25 * var(--u));
  border: calc(2 * var(--u)) solid transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  /* Неактивная карточка: полупрозрачная заливка + светлая обводка-градиент */
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    /* В макете заливка 10% чёрного, но поверх #E4E4E4 карточка выходит
       почти в цвет фона — берём плотнее, чтобы читалась как на макете. */
    linear-gradient(rgba(0, 0, 0, .18), rgba(0, 0, 0, .18)),
    linear-gradient(43deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, .7) 26%,
      rgba(255, 255, 255, .3) 97%,
      rgba(255, 255, 255, .2) 100%);
  transition: transform .18s ease;
}

/* Порядок из макета: Личный, Продвинутый, Семья, Конструктор */
.plan-card {
  z-index: 1;
}

.plan-card.is-active {
  z-index: 2;
}

.plan-card[data-plan="personal"] {
  top: calc(108 * var(--u));
}

.plan-card[data-plan="advanced"] {
  top: calc(202 * var(--u));
}

.plan-card[data-plan="family"] {
  top: calc(296 * var(--u));
}

.plan-card[data-plan="custom"] {
  top: calc(390 * var(--u));
}

/* ---------- Пробный период — ссылкой под карточками ----------

   Правка 24.10.2026 (Матвей): «нужно чтобы выбор тарифа и Период
   вмещался на экран без скрола… давай перенесем пробный тариф с блока
   на текст: Попробовать 3 дня бесплатно (подчеркнутый снизу текст)».

   Карточка занимала целый слот (98px) и сдвигала вниз период с кнопкой:
   на iPhone 14 экран прокручивался на 126px, на 360x640 — на 320px, и
   «К оплате» оказывалась за кадром. Ссылка занимает 20px вместо 98.

   Скрытую ссылку (триал уже брали) из потока убираем полностью, иначе
   под карточками остаётся её отступ. */
.trial-link {
  position: absolute;
  left: 50%;
  top: calc(500 * var(--u));
  transform: translateX(-50%);
  padding: calc(6 * var(--u)) calc(10 * var(--u));
  border: 0;
  background: none;
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(15 * var(--u));
  line-height: 1.2;
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: calc(3 * var(--u));
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  white-space: nowrap;
  transition: opacity .18s ease;
}

.trial-link[hidden] {
  display: none;
}

.trial-link:active {
  opacity: .6;
}

/* Раскрытый счётчик «Конструктора» занимает 453..520 — ровно то место,
   где стоит ссылка: она оказывалась под панелью и переставала
   нажиматься. Опускаем её под счётчик вместе с периодом и кнопкой
   (их сдвиг — в .has-counter ниже). */
.screen--tariffs.has-counter .trial-link {
  top: calc(563 * var(--u));
}

/* Триала нет — период и кнопка поднимаются на место ссылки. */
.screen--tariffs:not(.has-trial) .tariffs__title--period {
  top: calc(524 * var(--u));
}

.screen--tariffs:not(.has-trial) .periods {
  top: calc(557 * var(--u));
}

.screen--tariffs:not(.has-trial) .checkout {
  top: calc(624 * var(--u));
}

.plan-card:active {
  transform: scale(.99);
}

/* Выбранная карточка — чёрная, с цветной внутренней подсветкой */
.plan-card.is-active {
  background-image:
    linear-gradient(#000, #000),
    linear-gradient(43deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, .7) 26%,
      rgba(255, 255, 255, .3) 97%,
      rgba(255, 255, 255, .2) 100%);
  box-shadow:
    0 calc(32 * var(--u)) calc(22 * var(--u)) calc(-30 * var(--u)) rgba(0, 0, 0, .45),
    inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(16.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .7),
    inset calc(-2.5 * var(--u)) calc(-6.25 * var(--u)) calc(17.5 * var(--u)) calc(-5.5 * var(--u)) rgba(144, 137, 246, .6),
    inset calc(-8 * var(--u)) calc(-9.25 * var(--u)) calc(15 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .2);
}

/* ---------- Цвет выбранной карточки по тарифу ----------
   В макете каждый тариф свой: «Личный» зелёный, «Продвинутый» чёрный,
   «Семья» розовая, «Конструктор» фиолетовый. Меняются заливка,
   цвет падающей тени и нижняя внутренняя подсветка. */

/* «Личный» — зелёный */
.plan-card[data-plan="personal"].is-active {
  background-image:
    linear-gradient(#27E593, #27E593),
    linear-gradient(43deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, .7) 26%,
      rgba(255, 255, 255, .3) 97%,
      rgba(255, 255, 255, .2) 100%);
  box-shadow:
    0 calc(32 * var(--u)) calc(22 * var(--u)) calc(-30 * var(--u)) rgba(15, 165, 99, .3),
    inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(16.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .7),
    inset calc(-2.5 * var(--u)) calc(-6.25 * var(--u)) calc(17.5 * var(--u)) calc(-5.5 * var(--u)) rgba(226, 246, 137, .6),
    inset calc(-8 * var(--u)) calc(-9.25 * var(--u)) calc(15 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .2);
}

/* «Семья» — розовая */
.plan-card[data-plan="family"].is-active {
  background-image:
    linear-gradient(#F5197B, #F5197B),
    linear-gradient(43deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, .7) 26%,
      rgba(255, 255, 255, .3) 97%,
      rgba(255, 255, 255, .2) 100%);
  box-shadow:
    0 calc(32 * var(--u)) calc(22 * var(--u)) calc(-30 * var(--u)) rgba(143, 12, 70, .5),
    inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(16.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .7),
    inset calc(-2.5 * var(--u)) calc(-6.25 * var(--u)) calc(17.5 * var(--u)) calc(-5.5 * var(--u)) rgba(246, 188, 137, .6),
    inset calc(-8 * var(--u)) calc(-9.25 * var(--u)) calc(15 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .2);
}

/* «Конструктор» — фиолетовый */
.plan-card[data-plan="custom"].is-active {
  background-image:
    linear-gradient(#8523C6, #8523C6),
    linear-gradient(43deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, .7) 26%,
      rgba(255, 255, 255, .3) 97%,
      rgba(255, 255, 255, .2) 100%);
  box-shadow:
    0 calc(32 * var(--u)) calc(22 * var(--u)) calc(-30 * var(--u)) rgba(142, 35, 215, .6),
    inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(16.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .7),
    inset calc(-2.5 * var(--u)) calc(-6.25 * var(--u)) calc(17.5 * var(--u)) calc(-5.5 * var(--u)) rgba(144, 137, 246, .6),
    inset calc(-8 * var(--u)) calc(-9.25 * var(--u)) calc(15 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .2);
}

.plan-card__name {
  position: absolute;
  /* Минус 2px рамки: left считается от padding-box. */
  left: calc(23 * var(--u));
  top: calc(24 * var(--u));
  /* Правка 12.10.2026 (Мария): «обрезается часть букв снизу при смене
     цвета». Была фиксированная height: 14px при шрифте 20px — обычному
     тексту это сходило, а у выбранной карточки название красится через
     background-clip: text, и градиент обрезается ровно по блоку: буквы
     с хвостами (у, р, ц) теряли низ. Высоту задаём минимальной — блок
     растёт под строку, верхняя граница остаётся на месте. */
  min-height: calc(14 * var(--u));
  display: flex;
  align-items: center;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(20 * var(--u));
  /* Ниже 1 межстрочный интервал прижимал хвосты букв к краю блока. */
  line-height: 1.1;
  letter-spacing: -.03em;
  color: rgba(0, 0, 0, .3);
}

/* У выбранной карточки название — перламутровый градиент,
   свой для каждого тарифа */
.plan-card.is-active .plan-card__name {
  background-image: linear-gradient(30deg,
      #F7DED7 0%, #B6C9D7 36%, #B4C2F3 70%, #E2CEEA 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.plan-card[data-plan="personal"].is-active .plan-card__name {
  background-image: linear-gradient(32deg,
      #F2F2F2 0%, #D7FFA2 55%, #F2FFD5 100%);
}

.plan-card[data-plan="family"].is-active .plan-card__name {
  background-image: linear-gradient(34deg,
      #F2F2F2 22%, #FFD2A2 85%, #C4FFE6 100%);
}

.plan-card[data-plan="custom"].is-active .plan-card__name {
  background-image: linear-gradient(30deg,
      #F7EED7 0%, #FFB3E4 36%, #F3B4B5 70%, #EADECE 100%);
}

.plan-card__devices {
  position: absolute;
  left: calc(23 * var(--u));
  top: calc(49 * var(--u));
  height: calc(10 * var(--u));
  display: flex;
  align-items: center;
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(14 * var(--u));
  line-height: .9;
  letter-spacing: -.04em;
  color: rgba(0, 0, 0, .3);
}

.plan-card.is-active .plan-card__devices {
  color: rgba(255, 255, 255, .6);
}

/* Плашка с ценой справа */
.plan-card__price {
  position: absolute;
  /* left/top у absolute-потомка отсчитываются от padding-box, а координаты
     макета — от края карточки, поэтому вычитаем 2px рамки. */
  left: calc(239 * var(--u));
  top: calc(14 * var(--u));
  width: calc(144 * var(--u));
  height: calc(54 * var(--u));
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(4 * var(--u));
  border-radius: calc(14 * var(--u));
  border: calc(1 * var(--u)) solid transparent;
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(13 * var(--u));
  letter-spacing: -.03em;
  color: rgba(1, 1, 1, .3);
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    radial-gradient(51.78% 51.78% at 50% 50.03%,
      rgba(255, 255, 255, 0) 91.47%, rgba(255, 255, 255, .01) 100%),
    linear-gradient(rgba(255, 255, 255, .1), rgba(255, 255, 255, .1));
  box-shadow: inset calc(3 * var(--u)) calc(3 * var(--u)) calc(17 * var(--u)) calc(-3 * var(--u)) rgba(255, 255, 255, .8);
}

/* Кегль чуть меньше макетного: четырёхзначные суммы (и «₽» следом)
   не помещались в плашку и выпирали за её край. */
.plan-card__sum {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(17 * var(--u));
  line-height: 1;
  letter-spacing: -.0357em;
  white-space: nowrap;
}

/* Плашка выбранной карточки — тёмная, цифры белые */
.plan-card.is-active .plan-card__price {
  color: var(--paper);
  border-color: transparent;
  background-image:
    radial-gradient(circle at 50% 50%, rgba(255, 255, 255, .01) 91%, rgba(255, 255, 255, 1) 100%),
    linear-gradient(rgba(255, 255, 255, .1), rgba(255, 255, 255, .1));
  box-shadow:
    inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(16.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .8),
    inset calc(1.25 * var(--u)) calc(1.25 * var(--u)) calc(20 * var(--u)) calc(-2.5 * var(--u)) #fff,
    inset calc(1.25 * var(--u)) calc(1.25 * var(--u)) calc(20 * var(--u)) calc(-2.5 * var(--u)) #fff;
}

/* ---------- Плашки «Хит» и скидок ----------
   Скотч: форму и наклон берём из SVG-экспорта Figma как маску (у него
   рваные края в альфе), а цвет задаём здесь — экспорт Figma опирается
   на смешивание слоёв, которое браузер внутри <img> не воспроизводит.
   Надпись остаётся обычным HTML поверх плёнки. */
.pill {
  position: absolute;
  isolation: isolate;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.0383em;
  pointer-events: none;
}

.pill::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-color: var(--pill-color);
  -webkit-mask: var(--pill-tape) no-repeat center / 100% 100%;
  mask: var(--pill-tape) no-repeat center / 100% 100%;
}

/* «Хит» — на карточке «Продвинутый», левый верхний угол.
   В отличие от скидок это готовая цветная картинка с уже напечатанной
   надписью: кладём её фоном, а не маской. Пропорции 77x52. */
.pill--hit {
  left: calc(-14 * var(--u));
  top: calc(-22 * var(--u));
  width: calc(71 * var(--u));
  height: calc(48 * var(--u));
  background: url("/app/assets/icons/hit.png") no-repeat center / contain;
  /* Надпись уже есть на картинке — HTML-текст прячем,
     но оставляем в дереве доступности. */
  font-size: 0;
  color: transparent;
  z-index: 2;
}

/* Плёнка-маска не нужна: у «Хита» своя картинка. */
.pill--hit::before {
  content: none;
}

/* Скидки над периодами. Как и «Хит» — готовые картинки с напечатанным
   процентом, поэтому HTML-текст прячем (в дереве доступности он остаётся). */
.pill--save {
  font-size: 0;
  color: transparent;
}

.pill--save::before {
  content: none;
}

.pill--save-3 {
  z-index: 2;
  left: calc(167.5 * var(--u));
  background: url("/app/assets/icons/save-31.png") no-repeat center / contain;
  top: calc(26 * var(--u));
  width: calc(55 * var(--u));
  height: calc(35 * var(--u));
}

.pill--save-12 {
  z-index: 2;
  left: calc(307.5 * var(--u));
  background: url("/app/assets/icons/save-36.png") no-repeat center / contain;
  top: calc(26 * var(--u));
  width: calc(55 * var(--u));
  height: calc(35 * var(--u));
}

/* ---------- Период подписки ---------- */
.periods {
  position: absolute;
  left: calc(19.5 * var(--u));
  /* Сдвинуты на 20 вместе с заголовком «Период подписки»
     (правка 28.10.2026, отделение пустотой после ссылки пробного). */
  top: calc(599 * var(--u));
  display: flex;
  align-items: center;
  gap: calc(10 * var(--u));
}

.period {
  width: calc(127 * var(--u));
  height: calc(45 * var(--u));
  padding: 0;
  border: 0;
  border-radius: calc(14 * var(--u));
  background: rgba(0, 0, 0, .05);
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(18 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: rgba(0, 0, 0, .3);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.period:active {
  transform: scale(.97);
}

/* Выбранный период — белая «таблетка» со стеклянной подсветкой */
.period.is-active {
  background: #000;
  color: var(--paper);
  box-shadow:
    0 calc(6 * var(--u)) calc(6 * var(--u)) calc(-4 * var(--u)) rgba(0, 0, 0, .3),
    inset calc(5 * var(--u)) calc(5 * var(--u)) calc(15 * var(--u)) calc(-2 * var(--u)) rgba(255, 255, 255, .8),
    inset calc(-2.5 * var(--u)) calc(-2.5 * var(--u)) calc(9 * var(--u)) 0 rgba(255, 255, 255, .7);
}

/* ---------- К оплате ---------- */
.checkout {
  position: absolute;
  /* НИЖЕ панели навигации (z-index 5) — и это важно.

     Правка 18.10.2026 (Мария: «к оплате не должна перекрывать значок
     vpn»). z-index: 6 здесь стоял с тех пор, когда кнопка прижималась
     к низу ОКНА (position: fixed): тогда она была отдельным слоем над
     страницей, и поднять её над панелью было осмысленно. df2ad3f
     вернул кнопку в поток, а поднятый слой остался — панель осталась
     fixed, кнопка поехала по ней и накрыла круглый значок VPN.
     Измерено: на окне 760px палец в центре значка попадал в .checkout,
     то есть значок был не нажимаем вовсе.

     Белое «облако» вокруг значка больше не наползает на кнопку: это
     лечилось прижатием к окну, которого теперь нет, — кнопка стоит в
     потоке выше панели по координате, а не по слою. */
  left: calc(21 * var(--u));
  /* Те же 20, что у заголовка «Период подписки» и периодов выше
     (правка 28.10.2026, отделение пустотой после ссылки пробного). */
  top: calc(666 * var(--u));
  width: calc(398 * var(--u));
  height: calc(86 * var(--u));
  padding: 0;
  border-radius: calc(46.26 * var(--u));
  border: calc(2 * var(--u)) solid transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    linear-gradient(#000, #000),
    linear-gradient(43deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, .7) 26%,
      rgba(255, 255, 255, .3) 97%,
      rgba(255, 255, 255, .2) 100%);
  box-shadow:
    0 calc(32 * var(--u)) calc(22 * var(--u)) calc(-30 * var(--u)) rgba(0, 0, 0, .45),
    inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(16.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .7),
    inset calc(-2.5 * var(--u)) calc(-6.25 * var(--u)) calc(17.5 * var(--u)) calc(-5.5 * var(--u)) rgba(255, 64, 157, .6),
    inset calc(1.25 * var(--u)) calc(1.25 * var(--u)) calc(60 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .2),
    inset calc(-8 * var(--u)) calc(-9.25 * var(--u)) calc(15 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .2);
  transition: transform .18s ease;
}

.checkout:active {
  transform: scale(.99);
}

.checkout__label {
  position: absolute;
  left: calc(30 * var(--u));
  top: calc(30 * var(--u));
  width: calc(152 * var(--u));
  display: flex;
  align-items: center;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(28 * var(--u));
  line-height: 1;
  color: var(--paper);
}

/* Розовая плашка с суммой */
.checkout__sum {
  position: absolute;
  left: calc(262 * var(--u));
  top: calc(16 * var(--u));
  width: calc(122 * var(--u));
  height: calc(54 * var(--u));
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: calc(30 * var(--u));
  /* В макете сумма набрана Asgard Number 28px, но плашка всего 122px:
     «2 999 ₽» туда встаёт впритык, а суммы длиннее вылезали за края.
     Даём внутренние поля и не даём строке переноситься. */
  padding: 0 calc(10 * var(--u));
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(25 * var(--u));
  line-height: 1;
  letter-spacing: -.0357em;
  white-space: nowrap;
  color: var(--ink);
  background-image:
    radial-gradient(circle at 50% 50%, rgba(255, 255, 255, .01) 91%, rgba(255, 255, 255, 1) 100%),
    linear-gradient(#FF2486, #FF2486);
  box-shadow:
    inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(16.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .8),
    inset calc(-2.5 * var(--u)) calc(-3.25 * var(--u)) calc(7.5 * var(--u)) calc(-2.5 * var(--u)) #000,
    inset calc(1.25 * var(--u)) calc(1.25 * var(--u)) calc(30 * var(--u)) calc(-2.5 * var(--u)) #fff,
    inset calc(-8 * var(--u)) calc(-9.25 * var(--u)) calc(15 * var(--u)) calc(-2.5 * var(--u)) rgba(0, 0, 0, .2);
}

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

  .tariffs__back,
  .plan-card,
  .period,
  .checkout {
    transition: none;
  }
}

/* ==================================================================
   Окно оформления заказа (Group 628189 в макете 920:17368)
   Открывается по тапу на тариф. Панель 400×647 поверх затемнения.
   ================================================================== */

/* Затемнение поверх экрана (Rectangle 30188) */
.order-scrim {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, .25);
  opacity: 0;
  visibility: hidden;
  z-index: 10;
  transition: opacity .22s ease, visibility .22s ease;
}

.order-scrim.is-open {
  opacity: 1;
  visibility: visible;
}

/* Сама панель */
.order {
  position: absolute;
  left: calc(20 * var(--u));
  top: calc(138 * var(--u));
  width: calc(400 * var(--u));
  height: calc(647 * var(--u));
  border-radius: calc(60 * var(--u));
  background: var(--paper);
  transform: translateY(calc(24 * var(--u))) scale(.98);
  transition: transform .26s cubic-bezier(.2, .8, .3, 1);
}

.order-scrim.is-open .order {
  transform: none;
}

/* ---------- Шапка: эмблема, сумма, подпись ---------- */

/* Круглая эмблема (Vector, 91×91 в точке 23;32) */
.order__logo {
  position: absolute;
  left: calc(23 * var(--u));
  top: calc(32 * var(--u));
  width: calc(91 * var(--u));
  height: calc(91 * var(--u));
  background: url("/app/assets/icons/modal-logo.svg") no-repeat center / contain;
}

/* Крупная сумма (22;154, шрифт 28) */
.order__total {
  position: absolute;
  left: calc(22 * var(--u));
  top: calc(154 * var(--u));
  display: flex;
  align-items: center;
  font-family: var(--font-number);
  font-weight: 500;
  font-size: calc(60 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--ink);
}

.order__caption {
  position: absolute;
  left: calc(23 * var(--u));
  top: calc(214 * var(--u));
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(18 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--ink);
}

/* ---------- Строки «параметр — значение» ---------- */

/* Подпись слева, значение справа; координаты — из макета */
.order__row {
  position: absolute;
  left: calc(24 * var(--u));
  height: calc(24 * var(--u));
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.order__row--plan {
  top: calc(266 * var(--u));
  width: calc(352 * var(--u));
}

.order__row--user {
  top: calc(298 * var(--u));
  width: calc(352 * var(--u));
}

.order__row--period {
  top: calc(331 * var(--u));
  width: calc(358 * var(--u));
}

.order__row--expires {
  top: calc(363 * var(--u));
  width: calc(358 * var(--u));
}

.order__row--devices {
  top: calc(396 * var(--u));
  width: calc(351 * var(--u));
}

.order__label {
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(18 * var(--u));
  line-height: 1;
  letter-spacing: -.0222em;
  color: rgba(0, 0, 0, .3);
}

.order__value {
  display: flex;
  align-items: center;
  gap: calc(5 * var(--u));
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(16 * var(--u));
  line-height: 1;
  letter-spacing: -.025em;
  color: var(--ink);
}

/* Точки-«кавычки» вокруг значений периода и даты (Ellipse 1655/1656) */
.order__value--dotted::before,
.order__value--dotted::after {
  content: "";
  flex: 0 0 auto;
  width: calc(4 * var(--u));
  height: calc(7.69 * var(--u));
  border-radius: 50%;
  background: var(--ink);
}

/* Аватар получателя — фото 18×20.65 (Group 628121) */
.order__avatar {
  flex: 0 0 auto;
  width: calc(18 * var(--u));
  height: calc(20.65 * var(--u));
  margin-right: calc(3 * var(--u));
  border-radius: 50%;
  background: rgba(0, 0, 0, .12);
}

/* ---------- Количество устройств ----------
   В макете это не счётчик, а две круглые фишки 24×24:
   значок-бейдж (x=301) и чёрный кружок с цифрой (x=327). */
/* Фишки прибиты к координатам макета (301 и 327 от края панели),
   а не прижаты к правому краю строки. */
.order__devices {
  position: absolute;
  left: calc(315 * var(--u));
  /* 301 − 24 (левый край строки) */
  display: flex;
  align-items: center;
  gap: calc(2 * var(--u));
}

.order__devices-badge {
  width: calc(24 * var(--u));
  height: calc(24 * var(--u));
  background: url("/app/assets/icons/tariff-badge.svg") no-repeat center / contain;
}

.order__count {
  width: calc(24 * var(--u));
  height: calc(24 * var(--u));
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--ink);
  font-family: var(--font-text);
  font-weight: 700;
  font-size: calc(14 * var(--u));
  line-height: 1;
  letter-spacing: -.0286em;
  color: var(--paper);
}

/* ---------- Разделители (Line 120/121) ---------- */
.order__line {
  position: absolute;
  left: calc(34 * var(--u));
  width: calc(332 * var(--u));
  height: calc(2 * var(--u));
  /* Line 120/121: горизонтальный градиент, гаснущий к краям. */
  background: linear-gradient(270deg,
      rgba(0, 0, 0, .05) 10%, rgba(0, 0, 0, .25) 50%, rgba(0, 0, 0, .05) 100%);
}

.order__line--top {
  top: calc(442 * var(--u));
}

.order__line--bottom {
  top: calc(518 * var(--u));
}

/* ---------- Списание с баланса ---------- */
.order__charge {
  position: absolute;
  left: calc(24 * var(--u));
  top: calc(461 * var(--u));
  width: calc(190 * var(--u));
  height: calc(35 * var(--u));
}

.order__charge-note {
  position: absolute;
  left: 0;
  top: 0;
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(12 * var(--u));
  line-height: 1;
  letter-spacing: -.0333em;
  color: rgba(0, 0, 0, .4);
}

/* Ширина по макету (190px): длинные суммы ужимаем, а не переносим,
   иначе строка уезжает под кнопку пополнения. */
.order__charge-sum {
  position: absolute;
  left: 0;
  top: calc(25 * var(--u));
  width: calc(190 * var(--u));
  height: calc(20 * var(--u));
  display: flex;
  align-items: center;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(22 * var(--u));
  line-height: 1;
  letter-spacing: -.0357em;
  white-space: nowrap;
  color: var(--ink);
}

/* Текущий баланс — серый: акцент на том, сколько останется после списания. */
.order__charge-was {
  color: rgba(0, 0, 0, .3);
}

/* Кнопка пополнения баланса (Frame 1171276922).
   В макете лежит рядом с панелью: 293;596 на кадре —
   внутри панели (20;138) это 273;458, правее блока списания. */
.order__topup {
  position: absolute;
  left: calc(273 * var(--u));
  top: calc(458 * var(--u));
  width: calc(93 * var(--u));
  height: calc(42 * var(--u));
  padding: 0;
  border: 0;
  background: url("/app/assets/icons/order-topup.svg") no-repeat center / contain;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.order__topup:active {
  transform: scale(.96);
}

/* ---------- Кнопка «Оплатить» ---------- */
.order__pay {
  position: absolute;
  left: calc(19 * var(--u));
  top: calc(542 * var(--u));
  width: calc(362 * var(--u));
  height: calc(85 * var(--u));
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: calc(2 * var(--u)) solid transparent;
  border-radius: calc(46.26 * var(--u));
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    linear-gradient(#000, #000),
    linear-gradient(43deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, .7) 26%,
      rgba(255, 255, 255, .3) 97%,
      rgba(255, 255, 255, .2) 100%);
  box-shadow:
    0 calc(32 * var(--u)) calc(22 * var(--u)) calc(-30 * var(--u)) rgba(0, 0, 0, .45),
    inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(16.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .7),
    inset calc(-2.5 * var(--u)) calc(-6.25 * var(--u)) calc(17.5 * var(--u)) calc(-5.5 * var(--u)) rgba(255, 64, 157, .6),
    inset calc(1.25 * var(--u)) calc(1.25 * var(--u)) calc(60 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .2),
    inset calc(-8 * var(--u)) calc(-9.25 * var(--u)) calc(15 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .2);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(28 * var(--u));
  line-height: 1;
  color: var(--paper);
  transition: transform .18s ease;
}

.order__pay:active {
  transform: scale(.99);
}

/* Полоска-«ручка» вверху панели (Rectangle 30189/30190, 50×6) */
.order__grip {
  position: absolute;
  left: calc(175 * var(--u));
  top: calc(13 * var(--u));
  width: calc(50 * var(--u));
  height: calc(6 * var(--u));
  padding: 0;
  border: calc(.8 * var(--u)) solid transparent;
  border-radius: calc(10 * var(--u));
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    linear-gradient(rgba(0, 0, 0, .1), rgba(0, 0, 0, .1)),
    linear-gradient(180deg, rgba(0, 0, 0, .05) 0%, rgba(0, 0, 0, .2) 100%);
  box-shadow: 0 calc(4 * var(--u)) calc(6 * var(--u)) calc(-3 * var(--u)) rgba(0, 0, 0, .35);
}

/* ------------------------------------------------------------------
   Тот же заказ, но для трафика: периода здесь нет, поэтому строк на
   одну меньше — всё ниже «Получателя» подтягиваем на её место, а панель
   и низ (линии, списание, кнопки) укорачиваем на тот же шаг.
   ------------------------------------------------------------------ */
.order--traffic {
  height: calc(614 * var(--u));
}

.order--traffic .order__row--expires {
  top: calc(331 * var(--u));
}

.order--traffic .order__row--devices {
  top: calc(363 * var(--u));
}

.order--traffic .order__line--top {
  top: calc(409 * var(--u));
}

.order--traffic .order__line--bottom {
  top: calc(485 * var(--u));
}

.order--traffic .order__charge {
  top: calc(428 * var(--u));
}

.order--traffic .order__topup {
  top: calc(425 * var(--u));
}

.order--traffic .order__pay {
  top: calc(509 * var(--u));
}

/* Объём — это три-пять цифр: круглый счётчик устройств их не вмещает,
   поэтому растягиваем кружок в пилюлю. */
.order--traffic .order__count {
  width: auto;
  min-width: calc(24 * var(--u));
  padding: 0 calc(9 * var(--u));
  border-radius: calc(12 * var(--u));
}

/* Пилюля шире кружка — сдвигаем строку левее, чтобы правый край
   остался на месте. */
.order--traffic .order__devices {
  left: auto;
  right: 0;
}

/* В строке объёма значок трафика, а не устройства */
.order--traffic .order__devices-badge {
  background-image: url("/app/assets/icons/traffic-badge-icon.svg");
}

/* ==================================================================
   Счётчик устройств (макет 3063:2744, Frame 1171276914)
   Раскрывается под карточкой «Конструктор»: панель 414x153 заходит
   под карточку, ниже — «−», текущее число и «+».
   ================================================================== */

.counter {
  position: absolute;
  left: calc(13 * var(--u));
  /* Карточка «Конструктор» занимает 390..476 — панель заводим под неё.

     Правка 26.10.2026 (Матвей: «то, что тут заходит на счетчик
     устройств… будто глаз немного режет»). Панель стояла на 453, а
     нижние скругления карточки начинаются с 451 (радиус 25): её
     прямой белый край проходил ровно по ним, и низ карточки выглядел
     срезанным — видно было 2 единицы скругления из 25.

     Правка 26.10.2026, вторая итерация (Матвей: «все еще осталось»).
     Опустить панель было мало. Дело не в том, сколько скругления
     видно, а в том, ЧТО лежит под ним: у карточки углы прозрачные, и
     в полосе перекрытия сквозь них просвечивала белая панель. На
     скриншоте это читается как срезанные углы и ровная линия поперёк
     фиолетового свечения — измерено по пикселям: на y=424 белый
     (249,249,249), на y=425 снова фиолетовый.

     Поэтому заводить карточку под панель нельзя вовсе: любое
     перекрытие подставляет белое под её углы. Ставим панель сразу
     под карточкой (низ 476) с зазором 6 — связь читается расстоянием,
     а не наложением. */
  top: calc(482 * var(--u));
  width: calc(414 * var(--u));
  height: calc(76 * var(--u));
  border-radius: calc(33 * var(--u));
  border: calc(2 * var(--u)) solid transparent;
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    linear-gradient(var(--paper), var(--paper)),
    linear-gradient(43deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, .7) 26%,
      rgba(255, 255, 255, .3) 97%,
      rgba(255, 255, 255, .2) 100%);
  z-index: 0;
}

/* ---------- Кнопки «−» и «+» ---------- */
/* Светлые пилюли со стеклянным бликом — как «+ ₽» в окне заказа */
.counter__step {
  position: absolute;
  /* Правка 29.10.2026 (Мария: «кнопки и цифра не посередине, съехали вниз»). Панель теперь 76 высотой
     (внутри рамки 72), а кнопки остались на отступе от прежней, более высокой: (72 - 39) / 2 = 16.5. */
  top: calc(16.5 * var(--u));
  height: calc(39 * var(--u));
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: calc(1 * var(--u)) solid transparent;
  border-radius: calc(17 * var(--u));
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  /* Правка 12.10.2026 (Мария): «при нажатии на плюс меняет масштаб
     туда-сюда». Два быстрых нажатия подряд вебвью принимал за
     двойной тап и зумил страницу. manipulation отключает именно
     двойной тап, обычные нажатия и прокрутку не трогает. */
  touch-action: manipulation;
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    radial-gradient(120% 140% at 50% -10%,
      rgba(255, 255, 255, .95) 30%, rgba(238, 238, 238, .85) 62%, rgba(206, 206, 206, .8) 100%),
    linear-gradient(180deg, rgba(0, 0, 0, .1) 0%, rgba(0, 0, 0, .3) 100%);
  box-shadow: 0 calc(6 * var(--u)) calc(10 * var(--u)) calc(-6 * var(--u)) rgba(9, 9, 9, .4);
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(22 * var(--u));
  line-height: 1;
  color: var(--ink);
  transition: transform .18s ease;
}

.counter__step--down {
  left: calc(11 * var(--u));
  width: calc(120 * var(--u));
}

.counter__step--up {
  left: calc(278 * var(--u));
  width: calc(121 * var(--u));
}

.counter__step:active {
  transform: scale(.96);
}

/* Недоступную границу диапазона гасим, но кнопку не прячем */
.counter__step[disabled] {
  opacity: .4;
  cursor: default;
}

/* ---------- Текущее число ---------- */
/* Полупрозрачная пилюля со значком устройства и числом */
.counter__value {
  position: absolute;
  left: calc(157 * var(--u));
  top: calc(16.5 * var(--u));
  height: calc(39 * var(--u));
  padding: 0 calc(15 * var(--u));
  display: flex;
  align-items: center;
  gap: calc(5 * var(--u));
  border-radius: calc(56 * var(--u));
  background: rgba(255, 255, 255, .2);
}

.counter__badge {
  width: calc(13 * var(--u));
  height: calc(19 * var(--u));
  background: url("/app/assets/icons/tariff-badge.svg") no-repeat center / contain;
}

/* Число набрано цифровым начертанием, с ведущим нулём */
.counter__num {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(30 * var(--u));
  line-height: .9;
  letter-spacing: -.03em;
  color: var(--ink);
}

/* Экран вырастает, когда счётчик раскрыт */
.screen--tariffs.has-counter {
  height: calc(799 * var(--u));
}

/* Счётчик раскрыт (453..520) — всё, что ниже карточек, опускается под
   него. Правка 24.10.2026: до неё период и кнопка оставались на месте,
   потому что раскрытый счётчик помещался в пустоту между карточками и
   периодом. Пустоту убрали — сдвиг стал нужен. */
.screen--tariffs.has-counter .tariffs__title--period {
  top: calc(601 * var(--u));
}

.screen--tariffs.has-counter .periods {
  top: calc(634 * var(--u));
}

.screen--tariffs.has-counter .checkout {
  top: calc(701 * var(--u));
}

/* Триала нет — ссылки тоже, и всё поднимается на её место. */
.screen--tariffs.has-counter:not(.has-trial) .tariffs__title--period {
  top: calc(573 * var(--u));
}

.screen--tariffs.has-counter:not(.has-trial) .periods {
  top: calc(606 * var(--u));
}

.screen--tariffs.has-counter:not(.has-trial) .checkout {
  top: calc(673 * var(--u));
}

@media (prefers-reduced-motion: reduce) {
  .counter__step {
    transition: none;
  }
}

/* ==================================================================
   Ползунок объёма (макет 3063:2744)
   Раскрывается под карточкой «Свой объем»: белая панель 414x216,
   карточка ложится на её верх, ниже — шкала и быстрый выбор.
   ================================================================== */

/* Панель заходит под карточку: её верх перекрыт самой карточкой,
   поэтому видна только нижняя часть со шкалой. */
.volume {
  position: absolute;
  left: calc(13 * var(--u));
  top: calc(372 * var(--u));
  width: calc(414 * var(--u));
  height: calc(145 * var(--u));
  border-radius: calc(33 * var(--u));
  background: var(--paper);
  border: calc(2 * var(--u)) solid transparent;
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    linear-gradient(var(--paper), var(--paper)),
    linear-gradient(43deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, .7) 26%,
      rgba(255, 255, 255, .3) 97%,
      rgba(255, 255, 255, .2) 100%);
  z-index: 0;
}

/* ---------- Текущий объём ---------- */
/* Крупная цифра с точками по бокам (Frame 1171276947, 11;117) */
.volume__value {
  position: absolute;
  left: calc(11 * var(--u));
  top: calc(46 * var(--u));
  display: flex;
  align-items: center;
  gap: calc(4 * var(--u));
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(18 * var(--u));
  line-height: 1;
  /* Точки по бокам берут currentColor — чернеют вместе с числом */
  color: var(--ink);
}

/* Объём можно не только тянуть ползунком, но и вписать руками.
   Поле должно выглядеть ровно как прежний текст: свой шрифт у input
   не наследуется, поэтому повторяем его явно. Ширина — по содержимому
   (через size в разметке ширина скачет), поэтому фиксируем под «10 000 гб». */
.volume__amount {
  width: calc(96 * var(--u));
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-align: center;
  -webkit-appearance: none;
  appearance: none;
  cursor: text;
}

.volume__amount:focus {
  outline: none;
  /* Подсказываем, что поле редактируется, не сдвигая соседей. */
  box-shadow: 0 calc(2 * var(--u)) 0 calc(-1 * var(--u)) rgba(132, 35, 198, .5);
}

.volume__dot {
  width: calc(7 * var(--u));
  height: calc(7 * var(--u));
  border-radius: 50%;
  background: currentColor;
}

/* ---------- Шкала ---------- */
/* Дорожка 258x26 в точке 144;109, заливка растёт слева */
.volume__track {
  position: absolute;
  left: calc(144 * var(--u));
  top: calc(38 * var(--u));
  width: calc(258 * var(--u));
  height: calc(26 * var(--u));
  border-radius: calc(4 * var(--u));
  /* Пустая часть шкалы — ровная светлая заливка. */
  background: rgba(132, 35, 198, .07);
}

/* Пройденная часть шкалы */
.volume__fill {
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  border-radius: inherit;
  /* Вертикальные штрихи, как в макете: частая «гребёнка» цвета тарифа. */
  background-image:
    repeating-linear-gradient(90deg,
      #8423C6 0 calc(1.5 * var(--u)),
      rgba(132, 35, 198, .25) calc(1.5 * var(--u)) calc(3 * var(--u)));
  pointer-events: none;
}

/* Бегунок: тонкая палочка с треугольной «шапкой» (Group 628206, 7x40) */
.volume__handle {
  position: absolute;
  top: calc(-8 * var(--u));
  width: calc(7 * var(--u));
  height: calc(34 * var(--u));
  margin-left: calc(-3.5 * var(--u));
  pointer-events: none;
}

.volume__handle::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: calc(7 * var(--u));
  height: calc(4 * var(--u));
  background: #8423C6;
  clip-path: polygon(0 0, 100% 0, 50% 100%);
}

.volume__handle::after {
  content: "";
  position: absolute;
  left: calc(2.5 * var(--u));
  top: calc(8 * var(--u));
  width: calc(2 * var(--u));
  height: calc(26 * var(--u));
  background: #8423C6;
}

/* Само поле ввода прозрачное — рисуем заливку и бегунок сами */
.volume__input {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  opacity: 0;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  background: none;
}

.volume__input::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: calc(28 * var(--u));
  height: calc(40 * var(--u));
}

.volume__input::-moz-range-thumb {
  width: calc(28 * var(--u));
  height: calc(40 * var(--u));
  border: 0;
}

/* ---------- Границы шкалы ---------- */
/* Точки по краям (Ellipse 1591/1592) и подписи под ними */
.volume__edge {
  position: absolute;
  top: calc(70 * var(--u));
  width: calc(7 * var(--u));
  height: calc(7 * var(--u));
  border-radius: 50%;
  background: rgba(0, 0, 0, .3);
}

.volume__edge--min {
  left: calc(149 * var(--u));
}

.volume__edge--max {
  left: calc(391 * var(--u));
}

.volume__limit {
  position: absolute;
  top: calc(69 * var(--u));
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(12 * var(--u));
  line-height: .9;
  letter-spacing: -.06em;
  color: rgba(0, 0, 0, .3);
}

.volume__limit--min {
  left: calc(159 * var(--u));
}

.volume__limit--max {
  left: calc(339 * var(--u));
}

/* ---------- Быстрый выбор ---------- */
/* Две кнопки 190x42 в ряд (Frame 1171276946, 13;161) */
.volume__quick {
  position: absolute;
  left: calc(13 * var(--u));
  top: calc(90 * var(--u));
  display: flex;
  align-items: center;
  gap: calc(8 * var(--u));
}

.volume__chip {
  width: calc(190 * var(--u));
  height: calc(42 * var(--u));
  padding: 0 calc(13 * var(--u));
  display: flex;
  align-items: center;
  justify-content: center;
  border: calc(1 * var(--u)) solid transparent;
  border-radius: calc(17 * var(--u));
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  /* Та же защита от зума двойным тапом, что у счётчика устройств. */
  touch-action: manipulation;
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    linear-gradient(180deg, #F2F2F2 0%, #E4E4E4 100%),
    linear-gradient(180deg, rgba(0, 0, 0, .08) 0%, rgba(0, 0, 0, .18) 100%);
  box-shadow: 0 calc(5 * var(--u)) calc(8 * var(--u)) calc(-6 * var(--u)) rgba(9, 9, 9, .17);
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(18 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--ink);
  transition: transform .18s ease;
}

.volume__chip:active {
  transform: scale(.96);
}

/* ---------- Выбранная карточка «Свой объем» ---------- */
/* В макете она фиолетовая, а не чёрная, и лежит поверх панели */
.plan-card[data-pack="custom"].is-active {
  background-image:
    linear-gradient(#8523C6, #8523C6),
    linear-gradient(43deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, .7) 26%,
      rgba(255, 255, 255, .3) 97%,
      rgba(255, 255, 255, .2) 100%);
  box-shadow:
    0 calc(32 * var(--u)) calc(22 * var(--u)) calc(-30 * var(--u)) rgba(79, 11, 126, .45),
    inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(16.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .7),
    inset calc(-2.5 * var(--u)) calc(-6.25 * var(--u)) calc(17.5 * var(--u)) calc(-5.5 * var(--u)) rgba(196, 137, 246, .6),
    inset calc(-8 * var(--u)) calc(-9.25 * var(--u)) calc(15 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .2);
}

.plan-card[data-pack="custom"].is-active .plan-card__price {
  background-image:
    radial-gradient(circle at 50% 50%, rgba(255, 255, 255, .01) 91%, rgba(255, 255, 255, 1) 100%),
    linear-gradient(#9B3FDA, #9B3FDA);
}

/* Экран вырастает, когда шкала раскрыта.

   Правка 12.10.2026 (Мария): «кнопку оплаты при выборе своего объёма
   поднять выше, она уезжает вниз». Кнопка сдвигалась с 696 на 786 —
   на 90px, хотя сама шкала занимает 372..517 и до кнопки не достаёт:
   между ними и так оставалось 179px пустоты. Оставляем небольшой
   сдвиг (40px), чтобы блок не прилипал к кнопке, и на столько же
   укорачиваем экран — иначе внизу остаётся пустая прокрутка. */
.screen--traffic.has-volume {
  height: calc(850 * var(--u));
}

/* Сдвиг действует, только пока кнопка стоит в потоке экрана.

   На невысоком окне (max-height: 760px выше по файлу) она прижимается
   к низу через position: fixed + bottom, и top там должен оставаться
   auto. Это правило лежит ПОЗЖЕ медиазапроса и весит столько же (два
   класса против одного), поэтому без ограничения оно возвращало
   top: 736 — а при fixed это отсчёт от верха ОКНА. На 600px кнопка
   уезжала за нижний край, и достать её было нельзя: у .screen
   overflow: hidden, прокрутки нет (правка 17.10.2026, Александр:
   «нет кнопки К оплате, даже если прокручиваешь вниз»). */
@media (min-height: 761px) {
  .screen--traffic.has-volume .checkout {
    top: calc(736 * var(--u));
  }
}

@media (prefers-reduced-motion: reduce) {
  .volume__chip {
    transition: none;
  }
}

/* ==================================================================
   Успешная оплата (макет 920:16421)
   Открывается после «Оплатить»: карточка 400x289 в точке 20;496,
   звезда со «птичкой» наезжает на неё сверху.
   ================================================================== */

/* Затемнение — тот же Rectangle 30188, что и у окна заказа */
.paid-scrim {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, .25);
  opacity: 0;
  visibility: hidden;
  z-index: 20;
  transition: opacity .22s ease, visibility .22s ease;
}

.paid-scrim.is-open {
  opacity: 1;
  visibility: visible;
}

/* Белая карточка (Rectangle 30175). Начало координат вложенных
   элементов — её левый верхний угол, поэтому звезда уходит в минус. */
.paid {
  position: absolute;
  left: calc(20 * var(--u));
  top: calc(496 * var(--u));
  width: calc(400 * var(--u));
  height: calc(289 * var(--u));
  border-radius: calc(60 * var(--u));
  transform: translateY(calc(24 * var(--u))) scale(.98);
  transition: transform .26s cubic-bezier(.2, .8, .3, 1);
}

.paid-scrim.is-open .paid {
  transform: none;
}

/* Белое поле карточки отдельным слоем: кнопка «На главную» светится
   розовым по краю, и обрезка держит свечение внутри скругления,
   а звезда со стикерами остаётся снаружи. */
.paid::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: var(--paper);
}

/* ---------- Звезда с галочкой (Star 16 + Vector, 170x170 в 130;382) ---------- */
.paid__star {
  position: absolute;
  left: calc(110 * var(--u));
  top: calc(-114 * var(--u));
  width: calc(170 * var(--u));
  height: calc(170 * var(--u));
  background: url("/app/assets/icons/success-star.svg") no-repeat center / contain;
  filter: drop-shadow(0 calc(10 * var(--u)) calc(22 * var(--u)) rgba(213, 6, 72, .35));
}

/* «Птичка» (Vector, 59x53 в 186;438) — по центру звезды */
.paid__star::after {
  content: "";
  position: absolute;
  left: calc(58 * var(--u));
  top: calc(60 * var(--u));
  width: calc(54 * var(--u));
  height: calc(39 * var(--u));
  background: url("/app/assets/icons/success-check.svg") no-repeat center / contain;
}

/* ---------- Подписи-стикеры по бокам звезды ---------- */
/* Чёрный текст в белой обводке; в макете повёрнут к центру */
.paid__sticker {
  position: absolute;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(16 * var(--u));
  line-height: 1.05;
  letter-spacing: -.02em;
  text-align: center;
  color: var(--ink);
  -webkit-text-stroke: calc(5 * var(--u)) var(--paper);
  paint-order: stroke fill;
  text-shadow: 0 calc(4 * var(--u)) calc(14 * var(--u)) rgba(0, 0, 0, .14);
  white-space: nowrap;
}

/* «Спасибо!» слева (37;484 в кадре) */
.paid__sticker--thanks {
  left: calc(-7 * var(--u));
  top: calc(-12 * var(--u));
  width: calc(91 * var(--u));
  transform: rotate(-18deg);
}

/* «Успешная оплата» справа (302;477 в кадре) */
.paid__sticker--done {
  left: calc(282 * var(--u));
  top: calc(-19 * var(--u));
  width: calc(103 * var(--u));
  transform: rotate(16deg);
}

/* ---------- Сумма и подпись ---------- */

/* Крупная сумма (92;553 в кадре, шрифт 28) */
.paid__sum {
  position: absolute;
  left: calc(72 * var(--u));
  top: calc(57 * var(--u));
  width: calc(256 * var(--u));
  height: calc(42 * var(--u));
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(60 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  text-align: center;
  color: #000;
}

/* «Можно запускать, тариф активен!» (94;614 в кадре, шрифт 23) */
.paid__note {
  position: absolute;
  left: calc(74 * var(--u));
  top: calc(118 * var(--u));
  width: calc(253 * var(--u));
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(23 * var(--u));
  line-height: 1.05;
  letter-spacing: -.02em;
  text-align: center;
  color: rgba(0, 0, 0, .4);
}

/* ---------- Кнопка «На главную» (362x85 в 39;680) ---------- */
/* Та же чёрная пилюля со светлой каймой, что и «Оплатить» */
.paid__home {
  position: absolute;
  left: calc(19 * var(--u));
  top: calc(184 * var(--u));
  width: calc(362 * var(--u));
  height: calc(85 * var(--u));
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: calc(2 * var(--u)) solid transparent;
  border-radius: calc(46.26 * var(--u));
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    linear-gradient(#000, #000),
    linear-gradient(43deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, .7) 26%,
      rgba(255, 255, 255, .3) 97%,
      rgba(255, 255, 255, .2) 100%);
  /* Внешней тени нет: кнопка лежит внутри карточки и её край
     иначе пачкает нижние скругления. */
  box-shadow:
    inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(16.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .7),
    inset calc(-2.5 * var(--u)) calc(-6.25 * var(--u)) calc(17.5 * var(--u)) calc(-5.5 * var(--u)) rgba(255, 64, 157, .6),
    inset calc(1.25 * var(--u)) calc(1.25 * var(--u)) calc(60 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .2),
    inset calc(-8 * var(--u)) calc(-9.25 * var(--u)) calc(15 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .2);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(28 * var(--u));
  line-height: 1;
  color: var(--paper);
  transition: transform .18s ease;
}

.paid__home:active {
  transform: scale(.99);
}

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

  .order-scrim,
  .order,
  .order__topup,
  .order__pay,
  .paid-scrim,
  .paid,
  .paid__home {
    transition: none;
  }
}

/* ==================================================================
   Экран «Докупить трафик» (макет 962:9284, сетка 440×956)
   Каркас общий с экраном тарифов: те же .plan-card, .checkout,
   .tariffs__back. Здесь только отличия — розовая выбранная карточка,
   три пакета вместо четырёх и отсутствие блока периода.
   ================================================================== */

.screen--traffic {
  /* 782 = низ кнопки «К оплате» + отступ. */
  height: calc(810 * var(--u));
}

/* Заголовок: в этом макете значок стоит ПОСЛЕ текста (текст с x=64). */
.tariffs__title--traffic {
  left: calc(64 * var(--u));
}

/* Пакеты идут в три ряда: 113, 211, 309 */
.screen--traffic .plan-card:nth-of-type(1) {
  top: calc(113 * var(--u));
}

.screen--traffic .plan-card:nth-of-type(2) {
  top: calc(211 * var(--u));
}

.screen--traffic .plan-card:nth-of-type(3) {
  top: calc(309 * var(--u));
}

/* Прайс не пришёл — вместо карточек объяснение (правка 01.11.2026).
   Позиционируем как первую карточку: .plans — display:contents, и
   обычный поток здесь не работает. */
.screen--traffic .plans__empty {
  position: absolute;
  top: calc(113 * var(--u));
  left: calc(20 * var(--u));
  width: calc(400 * var(--u));
  margin: 0;
  font-size: calc(16 * var(--u));
  line-height: 1.4;
  color: rgba(0, 0, 0, .55);
}

/* Названия пакетов набраны цифровым начертанием (Asgard Number) */
.plan-card__name--num {
  font-family: var(--font-display);
}

/* ---------- Цвет выбранного пакета ----------
   В макете «+150 гб» чёрный (как базовая карточка), «+300 гб» розовый,
   «Свой объем» фиолетовый — цвета заданы ниже по data-pack. */
.plan-card[data-pack="300"].is-active {
  background-image:
    linear-gradient(#F5197B, #F5197B),
    linear-gradient(43deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, .7) 26%,
      rgba(255, 255, 255, .3) 97%,
      rgba(255, 255, 255, .2) 100%);
  box-shadow:
    0 calc(32 * var(--u)) calc(22 * var(--u)) calc(-30 * var(--u)) rgba(143, 12, 70, .5),
    inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(16.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .7),
    inset calc(-2.5 * var(--u)) calc(-6.25 * var(--u)) calc(17.5 * var(--u)) calc(-5.5 * var(--u)) rgba(246, 188, 137, .6),
    inset calc(-8 * var(--u)) calc(-9.25 * var(--u)) calc(15 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .2);
}

/* На розовой карточке подписи белые, без перламутрового градиента */
.screen--traffic .plan-card.is-active .plan-card__name {
  background-image: none;
  -webkit-background-clip: border-box;
  background-clip: border-box;
  color: var(--paper);
}

.screen--traffic .plan-card.is-active .plan-card__devices {
  color: rgba(255, 255, 255, .6);
}

/* Плашка с ценой на розовой карточке — светлая, цифры белые */
/* Плашка почти прозрачная: сквозь неё виден розовый корпус карточки,
   форму держат только внутренние белые блики (значения из макета). */
.screen--traffic .plan-card.is-active .plan-card__price {
  color: var(--paper);
  background-image:
    radial-gradient(51.78% 51.78% at 50% 50.03%,
      rgba(255, 255, 255, 0) 91.47%, rgba(255, 255, 255, .01) 100%);
  box-shadow:
    inset calc(3 * var(--u)) calc(3 * var(--u)) calc(17 * var(--u)) calc(-3 * var(--u)) rgba(255, 255, 255, .8),
    inset calc(1 * var(--u)) calc(1 * var(--u)) calc(20 * var(--u)) calc(-3 * var(--u)) #fff,
    inset calc(1 * var(--u)) calc(1 * var(--u)) calc(20 * var(--u)) calc(-3 * var(--u)) #fff;
}

/* Цена в этом макете без «/ нед» — плашка уже (87–91 вместо 144) */
.screen--traffic .plan-card__price {
  left: calc(293 * var(--u));
  width: calc(91 * var(--u));
}

.screen--traffic .plan-card .plan-card__price {
  left: calc(297 * var(--u));
  width: calc(87 * var(--u));
  height: calc(54 * var(--u));
  border-radius: calc(14 * var(--u));
  /* В макете padding 32x15 — это отступы автолэйаута Figma, они задают
     размер кадра, а не поля внутри готовой плашки 87x54: как CSS-padding
     они съедают всю ширину и «537 ₽» переносится на две строки. */
  padding: 0 calc(8 * var(--u));
  white-space: nowrap;
}

/* ---------- Плашка «Выгоднее» ----------
   Готовая картинка с напечатанной надписью (как «Хит»), но крупнее
   и с другим наклоном: 119.15×74.95 при 1.14;179.17 на кадре. */
.pill--better {
  /* Пропорции берём у самой картинки (351x145 = 2.42), иначе при contain
     скотч ужимается по ширине и болтается в пустой коробке. */
  left: calc(-14 * var(--u));
  top: calc(-24 * var(--u));
  width: calc(119 * var(--u));
  height: calc(49 * var(--u));
  background: url("/app/assets/icons/tape-better.png") no-repeat center / contain;
  font-size: 0;
  color: transparent;
  z-index: 2;
}

.pill--better::before {
  content: none;
}

/* ==================================================================
   Экран «Подарить VPN» (макет 920:19222, сетка 440x956)
   ================================================================== */

.screen--friends {
  background: var(--bg);
  /* Правка 25.10.2026 (Матвей: «дай возможность скролла»).

     Общая высота .screen — 700 единиц, а блок денежной программы
     кончается на 739: он торчал за край экрана, и overflow: hidden его
     обрезал. На Telegram Desktop (450x780) под панель разделов уходило
     94px, на 420x700 — 134px, вместе с кнопкой «Вывести» и обеими
     ссылками: вывести деньги со стороны выглядело невозможным.

     Решение то же, что у экрана тарифов: высота по содержимому, а до
     низа доводит прокрутка СТРАНИЦЫ (у самого экрана своей нет —
     контент размечен абсолютно от верха, и прокручивать внутри нечего).
     760 = низ блока денег (739) плюс воздух, и дальше ещё 135 на
     панель разделов. Складываем вручную, а не полагаемся на
     padding-bottom из .stage:has(.tabbar) .screen: при border-box тот
     отступ съедает высоту ИЗНУТРИ, и блок снова уехал бы под панель —
     ровно та же ловушка, что была у экрана тарифов. */
  height: calc(895 * var(--u));
}

.friends__hero::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: calc(274 * var(--u));
  background: radial-gradient(circle at 50% 137%,
      rgba(255, 255, 255, 0) 59%, rgba(255, 255, 255, 1) 100%);
}

/* Звезда шапки — готовая картинка из макета.
   В ней уже есть и заливка, и стеклянные блики, и обводка, и розовое
   свечение вокруг, поэтому маска, градиенты, кольцо и отдельное
   пятно-блик больше не нужны.
   Холст — во всю ширину сцены (440×477), бокс звезды в макете —
   477×477 в -19;35, то есть картинка ложится в 0;35. */
.friends__star {
  position: absolute;
  z-index: 3;
  pointer-events: none;
}

/* Звезда в макете белая (узел 1007:11848), а start.png выгружен с розового
   варианта того же слоя. Картинку оставляем ради формы — берём её как
   маску, а красим по макету: белый радиальный градиент на #E4E4E4.

   Розовое свечение вокруг силуэта в маске тоже есть, поэтому наружу
   оно уходит тем же градиентом, что и тело, — без розового. */
.friends__star--outer {
  left: 0;
  top: calc(35 * var(--u));
  width: calc(440 * var(--u));
  height: calc(477 * var(--u));
  background:
    radial-gradient(circle at 50% 45%,
      rgba(255, 255, 255, .01) 21%, #fff 76%),
    #E4E4E4;
  -webkit-mask: url("/app/assets/icons/start.png") no-repeat center top / 100% auto;
  mask: url("/app/assets/icons/start.png") no-repeat center top / 100% auto;
  filter: drop-shadow(0 calc(14 * var(--u)) calc(22 * var(--u)) rgba(77, 77, 77, .15));
}

/* Кнопки по краям шапки (59x59 в 20;85 и 361;85). */
.friends__icon {
  position: absolute;
  z-index: 4;
  top: calc(85 * var(--u));
  width: calc(59 * var(--u));
  height: calc(59 * var(--u));
  padding: 0;
  border: calc(1 * var(--u)) solid transparent;
  border-radius: calc(20 * var(--u));
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  background-origin: border-box;
  background-clip: padding-box, border-box;
  /* Серые стопы радиального градиента из макета сильно затемняли кнопку
     на светлом фоне — ослабляем их и поднимаем белую подложку. */
  background-image:
    radial-gradient(circle at 50% 4%,
      rgba(128, 128, 128, .01) 22%, rgba(158, 158, 158, .15) 42%, rgba(158, 158, 158, .3) 56%),
    linear-gradient(180deg, rgba(0, 0, 0, .05) 0%, rgba(0, 0, 0, .18) 100%);
  background-color: rgba(255, 255, 255, .72);
  box-shadow: 0 calc(9 * var(--u)) calc(6 * var(--u)) calc(-6 * var(--u)) rgba(9, 9, 9, .25);
  transition: transform .18s ease;
}

.friends__icon:active {
  transform: scale(.96);
}

.friends__icon--back {
  left: calc(20 * var(--u));
}

.friends__icon--share {
  left: calc(361 * var(--u));
}

.friends__icon::before {
  content: "";
  position: absolute;
  inset: 0;
  background-repeat: no-repeat;
  background-position: center;
  background-size: calc(22 * var(--u));
}

.friends__icon--back::before {
  background-image: url("/app/assets/icons/friends-back.svg");
  background-size: calc(29 * var(--u)) calc(19 * var(--u));
}

.friends__icon--share::before {
  background-image: url("/app/assets/icons/friends-share.svg");
  background-size: calc(21 * var(--u)) calc(21 * var(--u));
}

/* Подпись «Приглашено» с галочкой (Frame 628143 в 158.5;173). */
.friends__invited {
  position: absolute;
  z-index: 5;
  left: 50%;
  top: calc(173 * var(--u));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(7 * var(--u));
  transform: translateX(-50%);
}

.friends__invited-icon {
  width: calc(37 * var(--u));
  height: calc(16 * var(--u));
  background: url("/app/assets/icons/invite-mark.svg") no-repeat center / contain;
}

.friends__invited-label {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(16 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--ink);
}

/* Число приглашённых (208x56 в 116;234, Asgard Number 80). */
.friends__count {
  position: absolute;
  z-index: 5;
  left: calc(116 * var(--u));
  top: calc(234 * var(--u));
  width: calc(208 * var(--u));
  height: calc(56 * var(--u));
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-number);
  font-weight: 800;
  font-size: calc(80 * var(--u));
  line-height: .9;
  letter-spacing: -.03em;
  color: var(--ink);
}

/* Кнопка «Подарить VPN» — готовая картинка из макета.
   В ней уже есть и значок, и надпись по дуге, и розовое свечение, поэтому
   собирать капсулу из градиентов и curved-text больше не нужно.
   Холст картинки — во всю ширину сцены (440×321), сама капсула
   занимает в нём 82..355 по x и 217..309 по y. */
.friends__arc {
  position: absolute;
  z-index: 2;
  left: 0;
  /* Верх капсулы в макете — около 473, а внутри картинки он на 217.
 */
  top: calc(270 * var(--u) - var(--arc-lift, 0px));
  /* 473 − 217 */
  width: calc(440 * var(--u));
  height: calc(321 * var(--u));
  padding: 0;
  border: 0;
  background: url("/app/assets/icons/gift.png") no-repeat center top / 100% auto;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  /* Кликабельна только сама капсула — прозрачный холст пропускает
     нажатия к тому, что лежит ниже. */
  clip-path: inset(calc(217 * var(--u)) calc(84 * var(--u)) calc(11 * var(--u)) calc(82 * var(--u)));
  transition: transform .18s ease;
}

.friends__arc:active {
  transform: scale(.97);
}

/* Формула «39 оформили = 39 мес в подарок» (131;327 и 246;327). */
/* В макете три блока стоят на своих координатах (131;329, 207;325,
   246;329), а не в ряд с зазором: при flex положение правых
   зависело бы от ширины числа слева. */
.friends__formula {
  display: contents;
}

.friends__stat {
  position: absolute;
  z-index: 4;
  top: calc(329 * var(--u));
}

.friends__stat--left {
  left: calc(131 * var(--u));
}

.friends__stat--right {
  left: calc(246 * var(--u));
}

.friends__stat {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: calc(5 * var(--u));
  white-space: nowrap;
}

.friends__stat-value {
  display: flex;
  align-items: flex-end;
  gap: calc(2 * var(--u));
  font-family: var(--font-number);
  font-weight: 400;
  font-size: calc(20 * var(--u));
  line-height: .9;
  letter-spacing: -.03em;
  color: var(--ink);
}

.friends__stat-value b {
  font-weight: 400;
}

/* «мес» набрано мельче числа. */
.friends__stat-value i {
  font-style: normal;
  font-size: calc(14 * var(--u));
}

/* Значок «люди» после числа оформивших (Subtract, 15x9). */
.friends__stat--left .friends__stat-value::after {
  content: "";
  width: calc(15 * var(--u));
  height: calc(9 * var(--u));
  margin-bottom: calc(2 * var(--u));
  background: url("/app/assets/icons/friends-signed.svg") no-repeat center / contain;
}

.friends__stat-note {
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(12 * var(--u));
  line-height: 1;
  letter-spacing: -.0333em;
  color: rgba(0, 0, 0, .4);
}

/* Прогресс до следующей порции бонусных дней (ТЗ п. 6.1).
   Шрифт и цвет — как у подписей формулы выше, чтобы строка читалась
   её продолжением, а не отдельным сообщением. */
.friends__progress {
  position: absolute;
  z-index: 4;
  left: 0;
  top: calc(378 * var(--u));
  width: 100%;
  margin: 0;
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(13 * var(--u));
  line-height: 1.35;
  letter-spacing: -.0333em;
  text-align: center;
  /* .6, а не .55: фон экрана #E4E4E4, и на нём .55 даёт 4.45:1 —
     чуть ниже порога читаемости 4.5:1. */
  color: rgba(0, 0, 0, .6);
}

/* Знак равенства между парами (25x28 в 207;323). */
.friends__equals {
  position: absolute;
  z-index: 4;
  left: calc(207 * var(--u));
  top: calc(325 * var(--u));
  width: calc(25 * var(--u));
  height: calc(28 * var(--u));
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(40 * var(--u));
  line-height: .9;
  letter-spacing: -.03em;
  color: rgba(0, 0, 0, .3);
}

/* Стикер «новый друг» */
.friends__new {
  position: absolute;
  z-index: 4;
  left: calc(24 * var(--u));
  top: calc(545 * var(--u));
  display: flex;
  align-items: center;
  gap: calc(8 * var(--u));
}

.friends__new-avatar {
  width: calc(28 * var(--u));
  height: calc(28 * var(--u));
  border-radius: 50%;
  background: linear-gradient(180deg, #D7D7D7 0%, #9E9E9E 100%);
}

.friends__new-name {
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(14 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--ink);
}

.friends__new-note {
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(12 * var(--u));
  line-height: 1;
  letter-spacing: -.0333em;
  color: rgba(0, 0, 0, .4);
}

/* Значок «VPN за друзей» (Group 628300, 133.1x30.76 в 153;457). */
.friends__vpn {
  position: absolute;
  z-index: 3;
  left: calc(153 * var(--u));
  top: calc(457 * var(--u) - var(--arc-lift, 0px));
  width: calc(133.1 * var(--u));
  height: calc(40 * var(--u));
  background: url("/app/assets/icons/friends-vpn-badges.png") no-repeat center / contain;
  filter: drop-shadow(0 calc(4 * var(--u)) calc(6 * var(--u)) rgba(196, 8, 92, .2));
}

/* Аватарки приглашённых (Group 628286, 341x150.7 в 50;582).

   Правка 24.10.2026 (Матвей: «панель с переключением страниц
   накладывается на изображение кружочков друзей»). Координаты сняты с
   кадра макета 440x956: ряд кончается на 733, панель разделов
   начинается с 821 — в кадре запас есть. Но шаг сетки --u считается
   только от ШИРИНЫ, а окно бывает низким: на Telegram Desktop
   (450x780) панель начиналась с 645, и кружки заходили под неё на
   88px; на 420x700 перекрытие доходило до 135px (измерено).

   Что пробовал и почему не подошло: двигать ряд вверх — он наезжает на
   капсулу «Подарить VPN»; ужимать сетку всего экрана — вместе с ней
   съёживается панель разделов; масштабировать сам ряд — на 420x700 не
   спасает даже вдвое (места остаётся меньше его половины).

   Ряд декоративный: это лица приглашённых, те же люди перечислены в
   «Моих друзьях» по кнопке выше. Поэтому на низком окне мы его просто
   не показываем, а не калечим соседей ради него. Порог: раскладке до
   низа ряда нужно 733 единицы плюс 135 на панель. */
.friends__faces {
  position: absolute;
  z-index: 2;
  left: calc(50 * var(--u));
  top: calc(582 * var(--u));
  width: calc(341 * var(--u));
  height: calc(150.7 * var(--u));
}

/* Класс ставит friends.js: порог зависит и от высоты окна, и от --u
   (он считается от ширины), а media-query умеет сравнивать только с
   пикселями. Container style queries в вебвью Telegram поддержаны не
   везде, поэтому считаем в скрипте. */
.friends__faces.is-cramped {
  display: none;
}

/* Кружок друга. Раньше весь ряд был одной картинкой-заглушкой с восемью
   лицами; теперь это настоящие аватарки, поэтому каждая — свой элемент.
   Позиции и размеры сняты с макета: кружки лежат в шахматном порядке,
   крупные вперемешку с мелкими. */
.friends__face {
  position: absolute;
  border-radius: 50%;
  background: #D9D9D9 no-repeat center / cover;
  box-shadow:
    0 calc(6 * var(--u)) calc(12 * var(--u)) calc(-4 * var(--u)) rgba(0,0,0,.35),
    inset 0 0 0 calc(1.5 * var(--u)) rgba(255,255,255,.5);
}

/* Слоты по макету: left/top/размер для каждой из восьми позиций.
   Порядок — как читается ряд слева направо, чтобы при одном друге
   кружок встал слева, а не в случайном месте. */
.friends__face:nth-child(1) { left: calc(48 * var(--u));  top: calc(12 * var(--u)); width: calc(78 * var(--u));  height: calc(78 * var(--u)); }
.friends__face:nth-child(2) { left: calc(112 * var(--u)); top: calc(62 * var(--u)); width: calc(92 * var(--u));  height: calc(92 * var(--u)); }
.friends__face:nth-child(3) { left: calc(160 * var(--u)); top: calc(0 * var(--u));  width: calc(62 * var(--u));  height: calc(62 * var(--u)); }
.friends__face:nth-child(4) { left: calc(222 * var(--u)); top: calc(22 * var(--u)); width: calc(74 * var(--u));  height: calc(74 * var(--u)); }
.friends__face:nth-child(5) { left: calc(288 * var(--u)); top: calc(0 * var(--u));  width: calc(58 * var(--u));  height: calc(58 * var(--u)); }
.friends__face:nth-child(6) { left: calc(286 * var(--u)); top: calc(52 * var(--u)); width: calc(88 * var(--u));  height: calc(88 * var(--u)); }
.friends__face:nth-child(7) { left: calc(18 * var(--u));  top: calc(74 * var(--u)); width: calc(58 * var(--u));  height: calc(58 * var(--u)); }
.friends__face:nth-child(8) { left: calc(212 * var(--u)); top: calc(96 * var(--u)); width: calc(50 * var(--u));  height: calc(50 * var(--u)); }

/* «+N» справа от ряда (Group 628084, 33x27 в 387;604). */
/* ---------- Активная вкладка нижней навигации (макет 1008:13407) ----------
   Панель целиком нарисована в tabbar.png, и подписи там серые. У активной
   вкладки подпись чёрная, а под значком розовое свечение, поэтому оба слоя
   дорисовываем поверх картинки.

   Подпись: 30x6 в 5;46 внутри кнопки 59x75, набрана 9px. Своя подпись
   встаёт поверх серой из картинки, поэтому под ней подложка. Панель в
   этом месте не одного цвета, а уходит от #E8E8E8 к #EDEDED — подложку
   красим тем же градиентом, иначе виден шов. */
.tabbar__item.is-active .tabbar__label {
  color: var(--ink);
}

/* Значок активной вкладки (макет 1008:13410) — розовый стеклянный шар
   с чёрной иконкой внутри и белым бликом снизу. Собран из десятка слоёв
   с размытиями, поэтому взят картинкой из макета, а не повторён в CSS.

   Шар в макете 39.44x40 в 9;10 от угла кнопки, но свечение выходит за
   его края, и в экспорте холст шире (190x192 при 4x). Кладём картинку
   этим холстом, отцентрировав по месту шара. */
.tabbar__item.is-active::before {
  content: "";
  position: absolute;
  left: calc(5 * var(--u));
  top: calc(6 * var(--u));
  width: calc(47.5 * var(--u));
  height: calc(48 * var(--u));
  background: url("/app/assets/icons/tab-friends-active.png") no-repeat center / contain;
  pointer-events: none;
}

/* Аватарка пользователя поверх значка вкладки. Фон ставит JS: своей
   картинки у нас нет, берём телеграмовскую из initData. Пока её нет,
   виден нарисованный в tabbar.png силуэт. */
.tabbar__avatar {
  position: absolute;
  left: calc(5 * var(--u));
  top: calc(6 * var(--u));
  width: calc(47.5 * var(--u));
  height: calc(48 * var(--u));
  border-radius: 50%;
  background: no-repeat center / cover;
  pointer-events: none;
}

/* У «Профиля» кружок остаётся серым — розовеет только подпись. */
.tabbar__item--profile.is-active::before { content: none; }

/* ---------- Поиск ---------- */
/* Поле 352x85 в 44;160 кадра — внутри панели это 24;21 */
/* Затемнение (Rectangle 30188) */
.whom-scrim {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, .25);
  opacity: 0;
  visibility: hidden;
  z-index: 30;
  transition: opacity .22s ease, visibility .22s ease;
}

.whom-scrim.is-open {
  opacity: 1;
  visibility: visible;
}

/* Панель (Rectangle 30175, 400x751 в 20;139) */
.whom {
  position: absolute;
  left: calc(20 * var(--u));
  top: calc(139 * var(--u));
  width: calc(400 * var(--u));
  height: calc(751 * var(--u));
  border-radius: calc(60 * var(--u));
  background: var(--paper);
  transform: translateY(calc(24 * var(--u))) scale(.98);
  transition: transform .26s cubic-bezier(.2, .8, .3, 1);
}

.whom-scrim.is-open .whom {
  transform: none;
}

/* Полоска-«ручка» (Rectangle 30189/30190, 50x6) */
/* Сама «ручка» уже есть на картинке заголовка, поэтому
   здесь остаётся только прозрачная зона нажатия. */
.whom__grip {
  position: absolute;
  z-index: 3;
  left: calc(175 * var(--u));
  top: calc(-16 * var(--u));
  width: calc(50 * var(--u));
  height: calc(14 * var(--u));
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* Заголовок «Кому дарим» (111;122 кадра — над панелью) */
/* Шапка окна — готовая картинка 231x53: в ней уже есть
   и «ручка», и надпись, и значок подарка. Текст в разметке
   остаётся для скринридеров. */
.whom__title {
  position: absolute;
  z-index: 2;
  left: 50%;
  top: calc(-18 * var(--u));
  width: calc(231 * var(--u));
  height: calc(53 * var(--u));
  margin: 0;
  transform: translateX(-50%);
  background: url("/app/assets/icons/who_gift.png") no-repeat center / contain;
  font-size: 0;
  color: transparent;
}

.whom__search {
  position: absolute;
  left: calc(24 * var(--u));
  top: calc(21 * var(--u));
  width: calc(352 * var(--u));
  height: calc(85 * var(--u));
  padding: 0 calc(20 * var(--u));
  display: flex;
  align-items: center;
  gap: calc(9 * var(--u));
  border: calc(1 * var(--u)) solid transparent;
  border-radius: calc(36 * var(--u));
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    radial-gradient(120% 160% at 50% -20%,
      rgba(255, 255, 255, .98) 32%, rgba(240, 240, 240, .9) 64%, rgba(214, 214, 214, .85) 100%),
    linear-gradient(180deg, rgba(0, 0, 0, .1) 0%, rgba(0, 0, 0, .3) 100%);
  box-shadow: 0 calc(9 * var(--u)) calc(6 * var(--u)) calc(-6 * var(--u)) rgba(9, 9, 9, .22);
}

/* Лупа (Union, 21x21) — рисуем кольцом и ручкой, чтобы не тащить
   SVG с backdrop-filter, который браузеры в фоне не рисуют. */

.whom__search-input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  padding: 0;
  background: none;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(20 * var(--u));
  line-height: .9;
  letter-spacing: -.03em;
  /* Длинная ссылка не разрывает поле — уходит в многоточие */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: rgba(0, 0, 0, .3);
}

.whom__search-input::placeholder {
  color: rgba(0, 0, 0, .3);
}

.whom__search-input:focus {
  outline: none;
}

/* ---------- Список получателей ---------- */
/* Строки 352x66 с шагом 76 — первая в 44;267 кадра */
.whom__list {
  position: absolute;
  left: calc(24 * var(--u));
  top: calc(128 * var(--u));
  width: calc(352 * var(--u));
  /* Ниже панели список не уходит: прокручиваем внутри */
  max-height: calc(600 * var(--u));
  margin: 0;
  padding: 0;
  list-style: none;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  /* Прокрутка остаётся, полосу прячем: в макете её нет. */
  scrollbar-width: none;
  /* Firefox */
  -ms-overflow-style: none;
  /* старый Edge */
}

/* WebKit/Blink — Safari, Chrome, телеграмовский вебвью. */
.whom__list::-webkit-scrollbar {
  width: 0;
  height: 0;
}

/* Подсказка на месте списка: контактов у Telegram не спросить,
   поэтому получателя вводят вручную. Встаёт туда же, где был бы
   список, иначе всплывает потоком поверх поля поиска. */
.whom__empty {
  position: absolute;
  left: calc(24 * var(--u));
  top: calc(128 * var(--u));
  width: calc(352 * var(--u));
  margin: 0;
  text-align: center;
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(16 * var(--u));
  line-height: 1.3;
  letter-spacing: -.03em;
  color: rgba(0, 0, 0, .3);
}

.whom__row {
  position: relative;
  height: calc(70 * var(--u));
  margin-bottom: calc(10 * var(--u));
  display: flex;
  align-items: center;
  gap: calc(12 * var(--u));
}

/* Аватар 65x66 */
.whom__avatar {
  flex: 0 0 auto;
  width: calc(75 * var(--u));
  height: calc(76 * var(--u));
  border-radius: 50%;
  background: rgba(0, 0, 0, .12);
}

.whom__person {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: calc(5 * var(--u));
}

.whom__name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(20 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--ink);
}

.whom__nick {
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(14 * var(--u));
  line-height: 1;
  letter-spacing: -.0286em;
  color: rgba(0, 0, 0, .3);
}

/* Переключатель-пилюля 33x27 справа (Group 628084) */
.whom__pick {
  position: relative;
  flex: 0 0 auto;
  width: calc(33 * var(--u));
  height: calc(27 * var(--u));
  padding: 0;
  border: 0;
  background: url("/app/assets/icons/whom-arrow.svg") no-repeat center / contain;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease, filter .18s ease;
}

.whom__pick:active {
  transform: scale(.94);
}

/* Выбранный получатель: пилюля подсвечивается розовым цветом экрана. */
.whom__pick[aria-checked="true"] {
  filter: brightness(.97) drop-shadow(0 calc(2 * var(--u)) calc(4 * var(--u)) rgba(255, 36, 134, .45));
}

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

  .whom-scrim,
  .whom,
  .whom__pick {
    transition: none;
  }
}

/* ==================================================================
   Окно с QR-кодом (макеты 920:19976 и 920:20390)
   Второй макет — то же окно после нажатия: кнопка становится розовой
   с подписью «Скопировано».
   ================================================================== */

/* Затемнение на весь экран; окно внутри — по центру. Остальные попапы
   выезжают снизу, а этот показывают целиком: у него своя форма с выемкой
   под аватар, и от края она читается хуже. */
.qr-scrim {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, .25);
  opacity: 0;
  visibility: hidden;
  transition: opacity .22s ease, visibility .22s ease;
}

.qr-scrim.is-open {
  opacity: 1;
  visibility: visible;
}

/* Обёртка размером с окно: её центрирует flex, а аватар и имя, лежащие
   снаружи плашки, позиционируются от неё — иначе при центрировании они
   отрывались от окна и уезжали выше экрана. */
.qr-box {
  position: relative;
  flex: 0 0 auto;
  width: calc(398 * var(--u));
  height: calc(517 * var(--u));
}

.qr {
  /* absolute от .qr-box: дети внутри по-прежнему считаются от этого угла. */
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  /* Форма из макета (Subtract 920:20354): скруглённая плашка
     с выемкой под аватар справа сверху — обычным border-radius
     её не повторить, поэтому режем маской по SVG. */
  background: #FF2486;
  -webkit-mask: url("/app/assets/icons/qr-panel.svg") no-repeat center / 100% 100%;
  mask: url("/app/assets/icons/qr-panel.svg") no-repeat center / 100% 100%;
  isolation: isolate;
  transform: translateY(calc(16 * var(--u)));
  transition: transform .22s ease;
}

/* Белый блик по верхней кромке. Отдельным слоем: inset-тени
   самого элемента маска срезала бы. */
.qr::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  box-shadow: inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(16.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .7);
  pointer-events: none;
}

.qr-scrim.is-open .qr {
  transform: none;
}

/* «Ручка» сверху — закрывает окно */
.qr__grip {
  position: absolute;
  left: calc(174 * var(--u));
  top: calc(13 * var(--u));
  width: calc(50 * var(--u));
  height: calc(6 * var(--u));
  padding: 0;
  border: 0;
  border-radius: calc(3 * var(--u));
  background: rgba(0, 0, 0, .1);
  box-shadow: 0 calc(4 * var(--u)) calc(6 * var(--u)) calc(-3 * var(--u)) rgba(0, 0, 0, .35);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* Розовый QR. Картинка выгружена вместе со свечением и потому выше
   своего бокса (314×356 против 314×314). Сам бокс оставляем квадратным,
   а свечение выпускаем наружу через ::before — иначе оно съедает подпись. */
.qr__code {
  position: absolute;
  left: calc(42.12 * var(--u));
  /* 63.12 − 21 */
  top: calc(47 * var(--u));
  /* 315 − 268 */
  width: calc(314 * var(--u));
  height: calc(314 * var(--u));
  /* Свечение выходит за бокс вниз и накрывает подпись —
     уводим весь слой под остальной текст. */
  z-index: 0;
  pointer-events: none;
}

.qr__code::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: calc(356 * var(--u));
  /* Пока настоящий QR не пришёл — пульсирующая плашка, а не код
     из макета: он выглядел как рабочий, но вёл в никуда. */
  border-radius: calc(40 * var(--u));
  background: rgba(0, 0, 0, .12);
  animation: skeleton-pulse 1.2s ease-in-out infinite;
}

/* Пришёл настоящий код (класс ставит JS): картинку макета убираем,
   а сам QR рисуем фоном. В SVG только чёрные модули, поэтому белую
   карточку со скруглением и свечением даём здесь. */
.qr__code.has-code::before { content: none; }

.qr__code.has-code {
  /* Поля внутри белой карточки: вплотную к краю код не сканируется. */
  padding: calc(22 * var(--u));
  background-repeat: no-repeat;
  background-position: center;
  background-size: calc(100% - 44 * var(--u)) calc(100% - 44 * var(--u));
  background-color: #fff;
  border-radius: calc(40 * var(--u));
  box-shadow: 0 0 calc(60 * var(--u)) calc(10 * var(--u)) rgba(255, 255, 255, .9);
}

.qr__hint {
  position: absolute;
  z-index: 1;
  left: calc(112 * var(--u));
  /* 133 − 21 */
  top: calc(384 * var(--u));
  /* 652 − 268 */
  width: calc(175 * var(--u));
  margin: 0;
  text-align: center;
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(17.21 * var(--u));
  line-height: 1;
  letter-spacing: -.0444em;
  color: rgba(0, 0, 0, .4);
}

/* Подпись внутри розовой карточки QR — поверх свечения. */

/* Кнопка «Скопировать» — светлая, 362×86 */
.qr__copy {
  position: absolute;
  left: calc(18 * var(--u));
  /* 39 − 21 */
  top: calc(413 * var(--u));
  /* 681 − 268 */
  width: calc(362 * var(--u));
  height: calc(86 * var(--u));
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(9 * var(--u));
  padding: 0 calc(20 * var(--u));
  border-radius: calc(36 * var(--u));
  border: calc(1 * var(--u)) solid transparent;
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    radial-gradient(circle at 50% 4%,
      rgba(255, 255, 255, .95) 22%, rgba(236, 236, 236, .95) 60%, rgba(214, 214, 214, .95) 100%),
    linear-gradient(180deg, rgba(0, 0, 0, .1) 0%, rgba(0, 0, 0, .3) 100%);
  box-shadow: 0 calc(9 * var(--u)) calc(6 * var(--u)) calc(-6 * var(--u)) rgba(9, 9, 9, .35);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(28 * var(--u));
  line-height: .9;
  letter-spacing: -.03em;
  color: rgba(0, 0, 0, .3);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.qr__copy:active {
  transform: scale(.98);
}

/* Иконку красим маской: в макете она того же цвета, что и надпись. */
.qr__copy-icon {
  flex: 0 0 auto;
  width: calc(33 * var(--u));
  height: calc(23 * var(--u));
  background: currentColor;
  -webkit-mask: url("/app/assets/icons/copy-icon.svg") no-repeat center / contain;
  mask: url("/app/assets/icons/copy-icon.svg") no-repeat center / contain;
}

/* Второй макет (920:20390): нажали — кнопка розовая,
   надпись «Скопировано» тёмная. */
.qr__copy.is-copied {
  background-image:
    radial-gradient(circle at 50% 6%,
      rgba(255, 232, 219, .8) 0%, rgba(255, 135, 188, 1) 24%,
      rgba(255, 49, 140, 1) 55%, rgba(202, 18, 101, .9) 77%),
    linear-gradient(180deg, rgba(0, 0, 0, .1) 0%, rgba(0, 0, 0, .3) 100%);
  color: rgba(0, 0, 0, .9);
}

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

  .qr-scrim,
  .qr,
  .qr__copy {
    transition: none;
  }
}

/* ---------- Окно «Все ваши друзья» (макет 920:19599) ----------
   Затемнение rgba(0,0,0,.25) и белая панель 400x751 в 20;139. */
.all-scrim {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, .25);
  opacity: 0;
  visibility: hidden;
  z-index: 10;
  transition: opacity .22s ease, visibility .22s ease;
}

.all-scrim.is-open {
  opacity: 1;
  visibility: visible;
}

.all {
  position: absolute;
  left: calc(20 * var(--u));
  top: calc(139 * var(--u));
  width: calc(400 * var(--u));
  height: calc(751 * var(--u));
  display: flex;
  flex-direction: column;
  border-radius: calc(60 * var(--u));
  background: var(--paper);
  transform: translateY(calc(24 * var(--u))) scale(.98);
  transition: transform .26s cubic-bezier(.2, .8, .3, 1);
}

.all-scrim.is-open .all {
  transform: none;
}

/* «Ручка» вверху панели (50x6 в 195;111 от кадра). */
.all__grip {
  flex: 0 0 auto;
  width: calc(50 * var(--u));
  height: calc(6 * var(--u));
  /* Заголовок ушёл наверх, поэтому отступ под «ручкой» держим здесь. */
  margin: calc(16 * var(--u)) auto calc(20 * var(--u));
  padding: 0;
  border: 0;
  border-radius: calc(10 * var(--u));
  background: rgba(0, 0, 0, .1);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* Заголовок 26px по центру. */
/* Заголовок — готовая картинка из макета (282×39).
   Сверху у картинки была своя «ручка» — срезали, чтобы не двоилась с кнопкой.
   Текст остаётся в разметке для скринридеров и aria-labelledby,
   но визуально его заменяет изображение. */
/* Заголовок вынесен НАД плашкой: лежит на её верхней кромке,
   поэтому из потока флекса убираем и позиционируем абсолютно. */
.all__title {
  position: absolute;
  z-index: 2;
  left: 50%;
  top: calc(-30 * var(--u));
  width: calc(282 * var(--u));
  height: calc(45 * var(--u));
  margin: 0;
  transform: translateX(-50%);
  background: url("/app/assets/icons/all_friends.png") no-repeat center / contain;
  /* Прячем сам текст, не убирая его из дерева доступности. */
  font-size: 0;
  color: transparent;
}

/* Список прокручивается внутри панели. */
/* Сетка 3 в ряд: аватар, под ним имя и статус (макет 291) */
.all__list {
  flex: 1 1 auto;
  margin: 0;
  /* Сверху — место под вынесенный заголовок. */
  padding: calc(34 * var(--u)) calc(24 * var(--u)) calc(24 * var(--u));
  list-style: none;
  display: grid;
  /* minmax(0, 1fr), а не просто 1fr: иначе колонка не может стать уже
     своего содержимого, длинное имя с nowrap распирает её, и третья
     карточка уезжает за край панели. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-auto-rows: min-content;
  align-content: start;
  /* По вертикали ряды стоят плотно, по горизонтали колонки не слипаются */
  gap: calc(22 * var(--u)) calc(12 * var(--u));
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

/* ---------- Аватар без фото ----------
   Telegram отдаёт photo_url не всегда: фото может не быть вовсе или его
   закрывает приватность. Тогда вместо чужого лица из макета показываем
   первую букву имени. Букву кладём в data-letter, чтобы одно правило
   работало для всех аватарок разом. */
.avatar--letter {
  /* !important и у цвета: у аватарок фон задан шорткатом background,
     который иначе перетёр бы подложку и кружок остался бы прозрачным. */
  background-image: none !important;
  background-color: #C9C9C9 !important;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.avatar--letter::after {
  content: attr(data-letter);
  /* Свой слой: в окне правки поверх кружка лежит затемнение
     (.ask__avatar--dim::before), и без z-index буква уходила
     под него — оставался пустой серый круг. */
  position: relative;
  z-index: 1;
  font-family: var(--font-display);
  font-weight: 500;
  /* Размер буквы задаётся на самом кружке — у каждой аватарки свой. */
  font-size: inherit;
  line-height: 1;
  letter-spacing: 0;
  text-transform: uppercase;
  color: #fff;
}

/* Имени тоже нет — рисуем силуэт вместо пустого серого кружка.

   Мария 18.10.2026: «а у нового пользователя вообще без фотки сначала
   отображается? как будто дыра». Так и было: буква берётся из
   first_name/username, а Telegram отдаёт initDataUnsafe не всегда —
   на сайте его нет вовсе, да и имя пользователь может скрыть. Тогда
   data-letter оказывался пустой строкой: класс стоит, фон серый,
   внутри ничего.

   Лечим в CSS, а не в пяти местах JS (components, account, friends,
   profile, tariffs): там всюду повторён один и тот же charAt(0), и
   запасной вариант разъехался бы при первой же правке одного из них.

   Силуэт нарисован инлайном: отдельный файл пришлось бы тянуть
   запросом ради случая, когда и так нечего показать. */
.avatar--letter[data-letter=""]::after {
  content: "";
  width: 55%;
  height: 55%;
  background: #fff;
  -webkit-mask: var(--avatar-person) no-repeat center / contain;
  mask: var(--avatar-person) no-repeat center / contain;
}

/* Кегль под каждый размер кружка: примерно половина диаметра. */
.whom__avatar.avatar--letter { font-size: calc(28 * var(--u)); }
.all__avatar.avatar--letter { font-size: calc(26 * var(--u)); }
.friends__face.avatar--letter { font-size: calc(26 * var(--u)); }
.profile__avatar.avatar--letter { font-size: calc(60 * var(--u)); }
.ask__avatar.avatar--letter { font-size: calc(26 * var(--u)); }
.tabbar__avatar.avatar--letter { font-size: calc(18 * var(--u)); }

/* Ячейка: аватар, имя, статус — всё по центру колонки */
.all__cell {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(3 * var(--u));
  text-align: center;
}

.all__cell:active .all__avatar { transform: scale(.95); }

.all__avatar {
  /* 84, а не 100: в колонке ~109 единиц крупный кружок не оставлял
     места имени, и оно обрезалось на «Тест-др…». */
  width: calc(84 * var(--u));
  height: calc(84 * var(--u));
  border-radius: 50%;
  background: rgba(0, 0, 0, .12);
}

/* Розовая звезда с галочкой на тех, кто оформил подписку.
   Висит на правом нижнем краю аватара. Координаты считаем от его
   размера (84), а не абсолютом: при прежнем top:72 значок съезжал
   на имя, когда аватар уменьшили. */
.all__check {
  position: absolute;
  left: 50%;
  top: calc(60 * var(--u));
  width: calc(28 * var(--u));
  height: calc(29 * var(--u));
  transform: translateX(calc(14 * var(--u)));
  background: url("/app/assets/icons/friends-check-star.svg") no-repeat center / contain;
}

/* Имя и статус — один блок: так пара держится вместе
   и её можно двигать целиком относительно аватара. */
.all__info {
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: 100%;
  /* Небольшой отступ от аватара: при отрицательном margin имя
     подлезало под розовую галочку «купил подписку». */
  margin-top: calc(4 * var(--u));
}

.all__name {
  /* Длинное имя переносим на вторую строку, а не режем многоточием:
     в колонке ~109 единиц «Александра» превращалась в «Алекс…», и
     друзей было не отличить друг от друга. Дальше двух строк не
     пускаем — иначе ряды разъезжаются по высоте. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  max-width: 100%;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(16 * var(--u));
  line-height: 1.1;
  letter-spacing: -.02em;
  text-align: center;
  overflow-wrap: anywhere;
  overflow: hidden;
  color: var(--ink);
}

/* Статус справа: у оплативших — розовый, у остальных приглушённый. */
.all__state {
  display: block;
  margin-top: calc(3 * var(--u));
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(10 * var(--u));
  line-height: 1;
  letter-spacing: -.05em;
  text-align: center;
  color: rgba(0, 0, 0, .4);
}

.all__state--trial {
  color: rgba(0, 0, 0, .6);
}

/* Значок «VPN за друзей» стал кнопкой — сбрасываем вид кнопки. */
.friends__vpn {
  padding: 0;
  border: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.friends__vpn:active {
  transform: scale(.96);
}

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

  .all,
  .all-scrim,
  .friends__vpn {
    transition: none;
  }
}

/* Скрытый блок не участвует в раскладке и не ловит клики. Без этого
   прозрачное затемнение перехватывает нажатия по всему экрану. */
[hidden] {
  display: none !important;
}

/* ==================================================================
   Попап «Бесплатный VPN за создание профиля» (макет 1007:9139)
   Белый лист с вырезом сверху: в вырез заходит розовая звезда с числом
   дней, по краям — аватар и подарок.
   ================================================================== */

.gift-scrim {
  position: absolute;
  inset: 0;
  z-index: 40;
  background: rgba(0, 0, 0, .25);
  opacity: 0;
  transition: opacity .22s ease;
}

.gift-scrim.is-open {
  opacity: 1;
}

/* Лист — SVG с уже вырезанной «ямкой» под звезду (Subtract 400x240). */
.gift {
  position: absolute;
  left: calc(20 * var(--u));
  top: calc(543 * var(--u));
  width: calc(400 * var(--u));
  height: calc(240 * var(--u));
  background: url("/app/assets/icons/gift-sheet.svg") no-repeat center / contain;
  transform: translateY(calc(20 * var(--u)));
  transition: transform .24s ease;
}

.gift-scrim.is-open .gift {
  transform: none;
}

/* ---------- Звезда с числом дней ----------
   В макете 185x185 в 128;424 на кадре — внутри листа (20;543)
   это 108;-119: звезда заходит в вырез и выступает над листом. */
.gift__star {
  position: absolute;
  left: calc(108 * var(--u));
  top: calc(-119 * var(--u));
  width: calc(185 * var(--u));
  height: calc(185 * var(--u));
  background: url("/app/assets/icons/gift-star.svg") no-repeat center / contain;
}

/* «3» и «дня» — отдельным слоем поверх звезды (189;477 → 169;-66). */
.gift__days {
  position: absolute;
  left: calc(169 * var(--u));
  top: calc(-66 * var(--u));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(5 * var(--u));
  color: var(--paper);
}

.gift__days-num {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(90 * var(--u));
  line-height: 1;
  letter-spacing: -.0111em;
}

.gift__days-word {
  font-style: normal;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(20 * var(--u));
  line-height: 1.1;
}

/* ---------- Аватар и подарок по краям выреза ---------- */
.gift__avatar {
  position: absolute;
  left: calc(49 * var(--u));
  /* 69 − 20 */
  top: calc(-9 * var(--u));
  /* 534 − 543 */
  width: calc(48 * var(--u));
  height: calc(49 * var(--u));
  border-radius: 50%;
  background: rgba(0, 0, 0, .12);
  box-shadow: 0 calc(4 * var(--u)) calc(14 * var(--u)) 0 rgba(0, 0, 0, .14);
}

.gift__box {
  position: absolute;
  left: calc(310 * var(--u));
  /* 330 − 20 */
  top: calc(-21 * var(--u));
  /* 522 − 543 */
  width: calc(54.19 * var(--u));
  height: calc(54.19 * var(--u));
  background: url("/app/assets/icons/gift-box.svg") no-repeat center / contain;
}

/* ---------- Заголовок ----------
   Две строки: первая чёрная, вторая — серая (56;609 → 36;66). */
.gift__title {
  position: absolute;
  left: calc(36 * var(--u));
  top: calc(66 * var(--u));
  width: calc(328 * var(--u));
  height: calc(46 * var(--u));
  margin: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(25 * var(--u));
  line-height: 1.1;
  letter-spacing: -.03em;
  color: var(--ink);
}

.gift__title span {
  color: rgba(0, 0, 0, .3);
}

/* ---------- Кнопка «Забрать :)» ----------
   Чёрная «таблетка» со стеклянной подсветкой (39;680 → 19;137). */
.gift__take {
  position: absolute;
  left: calc(19 * var(--u));
  top: calc(137 * var(--u));
  width: calc(362 * var(--u));
  height: calc(85 * var(--u));
  padding: 0;
  border-radius: calc(46.26 * var(--u));
  border: calc(2 * var(--u)) solid transparent;
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    linear-gradient(#000, #000),
    linear-gradient(43deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, .7) 26%,
      rgba(255, 255, 255, .3) 97%,
      rgba(255, 255, 255, .2) 100%);
  box-shadow:
    0 calc(32 * var(--u)) calc(22 * var(--u)) calc(-30 * var(--u)) rgba(0, 0, 0, .45),
    inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(16.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .7),
    inset calc(-2.5 * var(--u)) calc(-6.25 * var(--u)) calc(17.5 * var(--u)) calc(-5.5 * var(--u)) rgba(255, 64, 157, .6),
    inset calc(1.25 * var(--u)) calc(1.25 * var(--u)) calc(60 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .2),
    inset calc(-8 * var(--u)) calc(-9.25 * var(--u)) calc(15 * var(--u)) calc(-2.5 * var(--u)) rgba(255, 255, 255, .2);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(28 * var(--u));
  line-height: 1;
  color: var(--paper);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.gift__take:active {
  transform: scale(.98);
}

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

  .gift-scrim,
  .gift,
  .gift__take {
    transition: none;
  }
}

/* ==================================================================
   Наведение на экране «Ваши друзья»
   Только для мыши: на тач-устройствах :hover залипает после тапа,
   поэтому всё под @media (hover: hover). Нажатие (:active) уже
   описано у каждой кнопки — здесь добавляем промежуточное состояние.
   ================================================================== */

@media (hover: hover) {

  /* Круглые кнопки шапки (назад и QR) — чуть приподнимаются. */
  .friends__icon:hover {
    transform: scale(1.06);
    filter: brightness(1.04);
  }

  /* «Подарить VPN» и значок «VPN за друзей» — готовые картинки,
     поэтому подсвечиваем их фильтром, а не фоном. */
  .friends__arc:hover,
  .friends__vpn:hover {
    transform: scale(1.03);
    filter: brightness(1.06);
  }

  /* «Ручка» окна: расширяем зону отклика цветом, размер не трогаем —
     она узкая, масштаб был бы заметен как дрожание. */
  .qr__grip:hover,
  .whom__grip:hover,
  .all__grip:hover {
    filter: brightness(.88);
  }

  /* Кнопка «Скопировать» в окне QR. */
  .qr__copy:hover {
    transform: scale(1.01);
    filter: brightness(1.03);
  }

  /* Строка контакта в «Кому дарим» — подсветка всей строки. */
  .whom__row:hover {
    background: rgba(0, 0, 0, .04);
  }

  /* Карточка друга в списке «Все ваши друзья». */
  .all__cell:hover .all__avatar {
    transform: scale(1.05);
    filter: brightness(1.04);
  }
}

/* Плавность для тех элементов, у которых её ещё не было. */
.qr__grip,
.whom__grip,
.all__grip {
  transition: filter .18s ease;
}

.whom__row {
  transition: background .18s ease;
}

.all__cell .all__avatar {
  transition: transform .18s ease, filter .18s ease;
}

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

  .qr__grip,
  .whom__grip,
  .all__grip,
  .whom__row,
  .all__cell .all__avatar {
    transition: none;
  }
}

/* ==================================================================
   Пустое состояние: друзей ещё нет (макет 1007:11845)
   Счётчик и аватарки гаснут, рядом с нулём — грустный смайл.
   ================================================================== */

/* Смайл 70x51 рядом со счётчиком, отступ 7 как в макете */
.friends__sad {
  flex: 0 0 auto;
  width: calc(70 * var(--u));
  height: calc(51 * var(--u));
  margin-left: calc(7 * var(--u));
  background: url("/app/assets/icons/friends-sad.svg") no-repeat center / contain;
}

/* Ноль и смайл — бледные, как в макете */
.friends__count.is-empty {
  color: rgba(0, 0, 0, .1);
}

/* Друзей нет — ряда аватарок нет вовсе: показывать некого, а размытая
   заглушка из чужих лиц только мешала. */
.friends__faces.is-empty {
  display: none;
}

/* ==================================================================
   Экран «Профиль» (макет 960:8796, сетка 440×1305)
   Открывается по кнопке «Профиль» в нижней навигации.
   ================================================================== */

.screen--profile {
  /* Низ макета — 1153 (низ навигации), плюс запас. */
  height: calc(1165 * var(--u));
  background: var(--bg);
  overflow: hidden;
}

/* Навигация на этом экране ниже, чем на экране друзей (0;1018). */
/* Общая сцена — фиксированные 850px, а этот экран выше:
   растягиваем её под содержимое, иначе бургер и навигация уезжают под обрез. */
.stage:has(.screen--profile) {
  height: calc(1165 * var(--u));
}

/* Панель прибита к низу окна — координата по вертикали ей не нужна. */

/* ---------- Кнопки шапки (59×59 в 20;73 и 361;73) ---------- */
.profile__icon {
  position: absolute;
  top: calc(73 * var(--u));
  width: calc(59 * var(--u));
  height: calc(59 * var(--u));
  padding: 0;
  border: 0;
  background: no-repeat center / contain;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.profile__icon:active { transform: scale(.94); }

/* Кнопки шапки — готовые картинки: значок и надпись уже в них.
   Холст 59×68 (выгружен в 4×: 236×272) — выше бокса на величину тени,
   поэтому тянем по ширине и даём тени выйти за край.

   Прежний tg.png лежал в 1× и на телефоне растягивался втрое: подпись
   мылило до нечитаемости. Обе кнопки выгружены заново из макета. */
.profile__icon--write {
  left: calc(20 * var(--u));
  background-image: url("/app/assets/icons/profile-write.png");
  background-size: 100% auto;
  background-position: center top;
}

.profile__icon--edit {
  left: calc(361 * var(--u));
  background-image: url("/app/assets/icons/profile-edit-btn.png");
  background-size: 100% auto;
  background-position: center top;
}

/* ---------- Аватар и дуга ---------- */
/* Заглушка из макета — уже круглая картинка с прозрачными углами, а фото
   из телеграма приходит обычным квадратом. Поэтому круг режем сами:
   border-radius + cover (не contain — тот вписывает кадр целиком и
   оставляет поля, из-за чего фото выглядело квадратным в круге).

   Сторона берётся одна: в макете блок 159.88x162.13, и на таком
   прямоугольнике 50% дали бы эллипс. */
.profile__avatar {
  position: absolute;
  left: calc(140.21 * var(--u));
  top: calc(56 * var(--u));
  width: calc(160 * var(--u));
  height: calc(160 * var(--u));
  border-radius: 50%;
  overflow: hidden;
  /* Размер и положение кадра — отдельными свойствами, а не шорткатом:
     JS подставляет фото через style.backgroundImage, и шорткат в этот
     момент сбрасывал бы cover, из-за чего фото вылезало квадратом. */
  background-color: rgba(0, 0, 0, .12);
  background-repeat: no-repeat;
  background-position: center;
  background-size: cover;
}

/* Имя: белая обводка 6.4px поверх аватара (239×34 в 100;210). */
.profile__name {
  position: absolute;
  left: calc(100 * var(--u));
  /* Правка 20.10.2026 (Мария: «буква Р внизу обрезана»). В макете блок
     239x34 — это габарит НАДПИСИ, а не строки: кегль 48px при
     line-height 1 даёт строку 48px, и 14px с хвостами букв (р, у, д)
     уходили под overflow: hidden, который держим ради длинной почты.

     Даём блоку высоту под кегль, а верх поднимаем на столько же, чтобы
     центр строки остался на прежней линии (210+34/2 = 195+64/2 = 227) —
     имя не съезжает относительно аватара и карточек под ним. */
  /* 23.10.2026: имя наезжало на нижний край аватара (аватар до 216, надпись с контуром
     начиналась с ~203). Центр строки опущен с 227 до 239: низ надписи (~263) всё ещё выше
     карточек (271). */
  top: calc(207 * var(--u));
  width: calc(239 * var(--u));
  height: calc(64 * var(--u));
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(48 * var(--u));
  line-height: 1;
  /* Правка 23.10.2026 (Матвей: «обводка на имени выглядит странно»).
     Было -.01em при контуре 3px: соседние буквы касались контурами и
     «Вадим» читалось как «Вадıım» — у и/м узкие просветы, и обводка их
     затягивала. Контур чуть тоньше, трекинг нулевой. */
  letter-spacing: 0;
  text-align: center;
  /* Длинное «имя» не вылезает за края экрана.

     Мария 18.10.2026: «почта странно выглядит вместо имени огромным
     шрифтом». У входа с почтой имени нет вовсе, и в шапку попадает
     адрес. Измерено: evamlo@gmail.com занимает 375px в блоке на 212px —
     163px наружу, поверх соседних карточек.

     Кегль подбирает profile.js (fitName): CSS не умеет мерить текст, а
     clamp() считает от размера окна, а не от длины строки. Здесь —
     только страховка, если скрипт не отработал. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  /* Белые буквы в чёрном контуре — как в макете. Было
     rgba(255,255,255,.1): сквозь почти прозрачную заливку просвечивал
     аватар, а внутренности узких букв (и, м) затягивало контуром.
     paint-order кладёт контур под заливку, иначе он съедает тонкие
     штрихи Asgard. */
  color: var(--paper);
  -webkit-text-stroke: calc(2.5 * var(--u)) var(--ink);
  paint-order: stroke fill;
}

/* ---------- Карточки «Баланс» и «Подписка» (189×126 в 26;271 и 225;271) ---------- */
.pcard {
  position: absolute;
  top: calc(271 * var(--u));
  width: calc(189 * var(--u));
  height: calc(126 * var(--u));
  border-radius: calc(32 * var(--u));
  border: calc(2.87 * var(--u)) solid transparent;
  background-origin: border-box;
  background-clip: padding-box, border-box;
}

.pcard--balance {
  left: calc(26 * var(--u));
  background-image:
    linear-gradient(#FF2486, #FF2486),
    linear-gradient(43deg,
      rgba(255,255,255,0) 0%, rgba(255,255,255,.7) 26%,
      rgba(255,255,255,.3) 97%, rgba(255,255,255,.2) 100%);
  box-shadow:
    0 calc(29.63 * var(--u)) calc(20.07 * var(--u)) calc(-28.68 * var(--u)) rgba(208,16,102,.4),
    inset calc(2.39 * var(--u)) calc(2.39 * var(--u)) calc(15.77 * var(--u)) calc(-2.39 * var(--u)) rgba(255,255,255,.7),
    inset calc(1.19 * var(--u)) calc(1.19 * var(--u)) calc(28.68 * var(--u)) calc(-2.39 * var(--u)) #fff,
    inset calc(-2.5 * var(--u)) calc(-6.25 * var(--u)) calc(37.5 * var(--u)) calc(-5.5 * var(--u)) rgba(246,188,137,.7);
}

.pcard--sub {
  left: calc(225 * var(--u));
  background-image:
    linear-gradient(180deg, #fff 21%, #E4E4E4 100%),
    linear-gradient(43deg,
      rgba(255,255,255,0) 0%, rgba(255,255,255,.7) 26%,
      rgba(255,255,255,.3) 97%, rgba(255,255,255,.2) 100%);
  box-shadow:
    0 calc(29.63 * var(--u)) calc(20.07 * var(--u)) calc(-28.68 * var(--u)) rgba(0,0,0,.3),
    inset calc(2.39 * var(--u)) calc(2.39 * var(--u)) calc(15.77 * var(--u)) calc(-2.39 * var(--u)) rgba(255,255,255,.7),
    inset calc(1.19 * var(--u)) calc(1.19 * var(--u)) calc(28.68 * var(--u)) calc(-2.39 * var(--u)) #fff,
    inset calc(-2.5 * var(--u)) calc(-6.25 * var(--u)) calc(25 * var(--u)) calc(-5.5 * var(--u)) rgba(246,137,137,.7);
}

/* «Баланс» — подпись сверху (72×10 в 58;19 от карточки). */
.pcard__label {
  position: absolute;
  left: calc(29 * var(--u));
  top: calc(16 * var(--u));
  width: calc(72 * var(--u));
  text-align: center;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(14 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: rgba(255, 255, 255, .6);
}

/* Сумма: крупное число и знак рубля помельче. */
.pcard__sum {
  position: absolute;
  left: 0;
  top: calc(38 * var(--u));
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(2 * var(--u));
  color: var(--paper);
}

.pcard__sum b {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(30 * var(--u));
  line-height: .9;
  letter-spacing: -.03em;
}

.pcard__sum i {
  font-style: normal;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(17 * var(--u));
  line-height: .9;
  letter-spacing: -.03em;
}

/* «Подписка» со значком wi-fi. */
.pcard__head {
  position: absolute;
  left: 0;
  top: calc(16 * var(--u));
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(5 * var(--u));
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(14 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: rgba(0, 0, 0, .5);
}

.pcard__wifi {
  width: calc(17 * var(--u));
  height: calc(10.39 * var(--u));
  background: url("/app/assets/icons/profile-wifi.svg") no-repeat center / contain;
}

/* Дата окончания — красная, в две строки. */
.pcard__expires {
  position: absolute;
  left: calc(24 * var(--u));
  top: calc(38 * var(--u));
  width: calc(135 * var(--u));
  text-align: center;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(14 * var(--u));
  line-height: 1.25;
  letter-spacing: -.02em;
  color: rgba(255, 56, 60, .7);
}

/* Белая кнопка внутри карточки (160×40 в 14;75). */
.pcard__btn {
  position: absolute;
  left: calc(11 * var(--u));
  top: calc(75 * var(--u));
  width: calc(160 * var(--u));
  height: calc(40 * var(--u));
  padding: 0;
  border: calc(1 * var(--u)) solid transparent;
  border-radius: calc(15 * var(--u));
  background-origin: border-box;
  background-clip: padding-box, border-box;
  /* Светлая заливка с сероватым отливом книзу, как в макете;
     вторым слоем — градиентная кайма. */
  background-image:
    radial-gradient(120% 160% at 50% -20%,
      rgba(255,255,255,.95) 22%, rgba(226,226,226,.95) 55%, rgba(184,184,184,.95) 100%),
    linear-gradient(180deg, rgba(0,0,0,.1) 0%, rgba(0,0,0,.3) 100%);
  box-shadow: 0 calc(9 * var(--u)) calc(6 * var(--u)) calc(-6 * var(--u)) rgba(9,9,9,.22);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(18 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--ink);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.pcard__btn:active { transform: scale(.97); }

/* ---------- Подписка с включённым автопродлением (макет 919:7477) ----------
   Оба состояния лежат в разметке, показываем нужное по data-autorenew.
   Выключено — светлая карточка «Закончится / Продлить»,
   включено — чёрная «Автопродление / Отменить». */
.pcard--sub[data-autorenew="off"] .pcard__renew,
.pcard--sub[data-autorenew="off"] .pcard__btn--cancel,
.pcard--sub[data-autorenew="on"] .pcard__expires,
.pcard--sub[data-autorenew="on"] .pcard__btn:not(.pcard__btn--cancel) {
  display: none;
}

/* Чёрный корпус с той же градиентной каймой и лиловым отливом внутри. */
.pcard--sub[data-autorenew="on"] {
  --pcard-accent: linear-gradient(30deg, #F7DED7 0%, #B6C9D7 36%, #B4C2F3 70%, #E2CEEA 100%);
  background-image:
    linear-gradient(#000, #000),
    linear-gradient(43deg,
      rgba(255,255,255,0) 0%, rgba(255,255,255,.7) 26%,
      rgba(255,255,255,.3) 97%, rgba(255,255,255,.2) 100%);
  box-shadow:
    0 calc(32 * var(--u)) calc(22 * var(--u)) calc(-30 * var(--u)) rgba(0,0,0,.45),
    inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(16.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255,255,255,.7),
    inset calc(-2.5 * var(--u)) calc(-6.25 * var(--u)) calc(17.5 * var(--u)) calc(-5.5 * var(--u)) rgba(144,137,246,.6),
    inset calc(-8 * var(--u)) calc(-9.25 * var(--u)) calc(15 * var(--u)) calc(-2.5 * var(--u)) rgba(255,255,255,.2);
}

/* Заголовок и значок набраны светлым градиентом. */
.pcard--sub[data-autorenew="on"] .pcard__head {
  background-image: var(--pcard-accent);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* Тот же значок, но залитый градиентом: сам SVG уводим в маску. */
.pcard--sub[data-autorenew="on"] .pcard__wifi {
  background: var(--pcard-accent);
  -webkit-mask: url("/app/assets/icons/profile-wifi.svg") no-repeat center / contain;
  mask: url("/app/assets/icons/profile-wifi.svg") no-repeat center / contain;
}

/* «Автопродление / дата» (137×24 в 26;41). */
/* От текста до кнопки всего 37 единиц (38 → 75). «Автопродление» плюс
   дата «13 Сентября 2027» в 137 единиц шириной не влезали в строку и
   переносились на три — три строки по 14px с интерлиньяжем 1.25 дают
   52.5 и наезжали на кнопку. Уменьшаем кегль: дата встаёт в две строки
   и укладывается в отведённое место. */
.pcard__renew {
  position: absolute;
  left: calc(23 * var(--u));
  top: calc(38 * var(--u));
  width: calc(137 * var(--u));
  text-align: center;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(12 * var(--u));
  line-height: 1.2;
  letter-spacing: -.02em;
  color: #F4F4F4;
}

/* «Отменить» — полупрозрачное стекло вместо белой заливки. */
.pcard__btn--cancel {
  left: calc(14 * var(--u));
  padding: 0 calc(13 * var(--u));
  background-image:
    radial-gradient(circle at 50% 4%,
      rgba(158,158,158,.5) 5%, rgba(255,255,255,.3) 30%, rgba(255,255,255,.2) 50%),
    linear-gradient(180deg, rgba(0,0,0,.1) 0%, rgba(0,0,0,.3) 100%);
  background-color: rgba(255, 255, 255, .4);
  color: #000;
}

/* ---------- Строки-заголовки разделов ---------- */
.prow {
  position: absolute;
  left: calc(30 * var(--u));
  display: flex;
  align-items: center;
  gap: calc(5 * var(--u));
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(14 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: rgba(0, 0, 0, .3);
}

.prow--devices { top: calc(426 * var(--u)); }
.prow--pay     { top: calc(549 * var(--u)); left: calc(32 * var(--u)); }
.prow--profile { top: calc(671 * var(--u)); left: calc(169 * var(--u)); }

.prow__icon--device {
  width: calc(9 * var(--u));
  height: calc(12 * var(--u));
  background: url("/app/assets/icons/profile-device.svg") no-repeat center / contain;
}

.prow__icon--person {
  width: calc(20 * var(--u));
  height: calc(20 * var(--u));
  border-radius: 50%;
  background: url("/app/assets/icons/profile-person.svg") no-repeat center / cover;
}

.prow__icon--ruble { font-size: calc(14 * var(--u)); }

/* Счётчик «0/0» — цифровым начертанием, чёрный. */
.prow__count {
  font-family: var(--font-display);
  font-size: calc(14 * var(--u));
  color: var(--ink);
}

/* ---------- «Добавить» / «Привязать» справа ---------- */
.prow__add {
  position: absolute;
  display: flex;
  align-items: center;
  gap: calc(3 * var(--u));
  padding: 0;
  border: 0;
  background: none;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(14 * var(--u));
  line-height: 1;
  color: var(--ink);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.prow__add:active { transform: scale(.95); }

.prow__add--devices { left: calc(300 * var(--u)); top: calc(425 * var(--u)); }
.prow__add--pay     { left: calc(296 * var(--u)); top: calc(547 * var(--u)); }

.prow__add-icon {
  width: calc(17 * var(--u));
  height: calc(13 * var(--u));
  background: url("/app/assets/icons/profile-plus.svg") no-repeat center / contain;
}

/* ---------- Загрузка ----------
   Пока данные идут с бэкенда, на их месте пульсируют серые плашки.
   Раньше тут стояли нули и подписи из макета — пользователь читал их
   как факт («баланс 0», «устройств 0/0»), а через секунду цифры
   менялись на настоящие. */
@keyframes skeleton-pulse {
  0%, 100% { opacity: .55; }
  50%      { opacity: .25; }
}

/* Текст прячем, на его месте — серая полоска в размер строки. */
.is-loading .skeleton {
  color: transparent !important;
  position: relative;
}

.is-loading .skeleton::after {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 100%;
  height: 1em;
  border-radius: calc(6 * var(--u));
  background: currentColor;
  color: rgba(0, 0, 0, .18);
  animation: skeleton-pulse 1.2s ease-in-out infinite;
}

/* Полоска на месте списка: та же высота, что у пустой плашки. */
.pskeleton {
  height: calc(60 * var(--u));
  margin: 0 0 calc(10 * var(--u));
  border-radius: calc(18 * var(--u));
  background: rgba(0, 0, 0, .12);
  animation: skeleton-pulse 1.2s ease-in-out infinite;
}

.pskeleton[hidden] { display: none; }
/* Кружок аватара, пока не знаем, чьё фото ставить: пульсирует так же,
   как текстовые скелетоны. Раньше на его месте стояло лицо из макета. */
.avatar-slot:not(.is-ready) {
  animation: skeleton-pulse 1.2s ease-in-out infinite;
}

/* ---------- Пустые плашки (400×60) ---------- */
/* hidden должен работать: у .pempty есть display:flex, а он
   специфичнее браузерного [hidden]{display:none} — без этого
   плашка «не добавлены» висит на экране, пока грузятся данные. */
.pempty[hidden] { display: none; }

.pempty {
  position: absolute;
  left: calc(21 * var(--u));
  width: calc(400 * var(--u));
  height: calc(60 * var(--u));
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: calc(18 * var(--u));
  background: rgba(0, 0, 0, .1);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(18 * var(--u));
  line-height: 1;
  color: rgba(0, 0, 0, .4);
}

.pempty--devices { top: calc(454 * var(--u)); }
.pempty--pay     { top: calc(576 * var(--u)); }

/* ---------- Кнопки «Выйти» и «Удалить» ---------- */
.pbtn {
  position: absolute;
  top: calc(696 * var(--u));          /* 671 + 25 */
  height: calc(50 * var(--u));
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(9 * var(--u));
  padding: 0 calc(13 * var(--u));
  border: calc(1 * var(--u)) solid transparent;
  border-radius: calc(18 * var(--u));
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    radial-gradient(120% 160% at 50% -20%,
      rgba(255,255,255,.95) 22%, rgba(226,226,226,.95) 55%, rgba(184,184,184,.95) 100%),
    linear-gradient(180deg, rgba(0,0,0,.1) 0%, rgba(0,0,0,.3) 100%);
  box-shadow: 0 calc(9 * var(--u)) calc(6 * var(--u)) calc(-6 * var(--u)) rgba(9,9,9,.22);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(21 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.pbtn:active { transform: scale(.98); }

.pbtn--exit {
  left: calc(26 * var(--u));
  width: calc(188 * var(--u));
  color: rgba(0, 0, 0, .6);
}

.pbtn--delete {
  left: calc(225 * var(--u));
  width: calc(190 * var(--u));
  color: rgba(191, 33, 33, .6);
}

.pbtn__icon--exit {
  width: calc(19 * var(--u));
  height: calc(18 * var(--u));
  background: url("/app/assets/icons/profile-exit.svg") no-repeat center / contain;
}

.pbtn__icon--trash {
  width: calc(17 * var(--u));
  height: calc(18 * var(--u));
  background: url("/app/assets/icons/profile-trash.svg") no-repeat center / contain;
}

/* ---------- Копирайт ---------- */
.profile__copy {
  position: absolute;
  left: calc(91.5 * var(--u));        /* 26 + 65.5 */
  top: calc(771 * var(--u));          /* 671 + 100 */
  width: calc(259 * var(--u));
  margin: 0;
  text-align: center;
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(14 * var(--u));
  line-height: 1.15;
  letter-spacing: -.0286em;
  color: rgba(0, 0, 0, .3);
}

/* ---------- Бургер со стикерами внизу ----------
   Это тот же блок, что на главной (.burger + .burger__img + .burger__fade):
   картинку и размытие описывать заново не нужно, здесь только положение. */
.profile__burger {
  left: calc(-9 * var(--u));
  top: calc(806 * var(--u));
  right: auto;
  bottom: auto;
  width: calc(457 * var(--u));
  height: calc(458 * var(--u));
}

@media (hover: hover) {
  .profile__icon:hover,
  .prow__add:hover {
    transform: scale(1.06);
    filter: brightness(1.04);
  }

  .pcard__btn:hover,
  .pbtn:hover {
    transform: scale(1.02);
    filter: brightness(1.03);
  }
}

@media (prefers-reduced-motion: reduce) {
  .profile__icon,
  .pcard__btn,
  .prow__add,
  .pbtn { transition: none; }
}

/* ==================================================================
   Компоненты по макету 3108:2745
   ================================================================== */

/* Демо-страница: компоненты идут в столбик, чтобы смотреть их отдельно. */
.screen--kit {
  height: auto;
  min-height: calc(var(--h) * var(--u));
  padding: calc(24 * var(--u)) 0 calc(48 * var(--u));
  background: var(--bg);
}

.kit__head {
  margin: calc(24 * var(--u)) 0 calc(12 * var(--u));
  padding: 0 calc(20 * var(--u));
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(18 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: rgba(0, 0, 0, .4);
}

/* ---------- Карточка устройства (400x355) ---------- */
.device {
  position: relative;
  width: calc(400 * var(--u));
  height: calc(355 * var(--u));
  margin: 0 auto calc(16 * var(--u));
  border-radius: calc(60 * var(--u));
  background: var(--paper);
}

/* «Ручка» вверху: 50x6 в 13;110 от верха карточки. */
.device__grip {
  position: absolute;
  left: 50%;
  top: calc(13 * var(--u));
  width: calc(50 * var(--u));
  height: calc(6 * var(--u));
  margin-left: calc(-25 * var(--u));
  border-radius: calc(3 * var(--u));
  background: rgba(0, 0, 0, .1);
  box-shadow: 0 calc(4 * var(--u)) calc(6 * var(--u)) calc(-3 * var(--u)) rgba(0, 0, 0, .35);
}

/* Круг с картинкой устройства (125x125 в 38;38). */
.device__icon {
  position: absolute;
  left: 50%;
  top: calc(38 * var(--u));
  width: calc(125 * var(--u));
  height: calc(125 * var(--u));
  margin-left: calc(-62.5 * var(--u));
  border: calc(1 * var(--u)) solid transparent;
  border-radius: 50%;
  background-origin: border-box;
  background-clip: padding-box, border-box;
  /* Стеклянный круг: радиальная подсветка сверху + обводка градиентом. */
  background-image:
    radial-gradient(circle at 50% 4%,
      rgba(128,128,128,.01) 22%, rgba(158,158,158,.4) 42%, rgba(158,158,158,.7) 56%),
    linear-gradient(180deg, rgba(0,0,0,.1) 0%, rgba(0,0,0,.3) 100%);
  background-color: rgba(255, 255, 255, .7);
  box-shadow: 0 calc(6 * var(--u)) calc(10 * var(--u)) calc(-6 * var(--u)) rgba(9, 9, 9, .22);
}

/* Сама картинка поверх круга — размеры у каждой свои, из макета. */
.device__icon::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
}

.device[data-dev="phone"] .device__icon::after {
  width: calc(125 * var(--u));
  height: calc(125 * var(--u));
  background-image: url("/app/assets/icons/dev-phone.png");
}

.device[data-dev="galaxy"] .device__icon::after {
  width: calc(75 * var(--u));
  height: calc(70 * var(--u));
  background-image: url("/app/assets/icons/dev-galaxy.png");
}

.device[data-dev="laptop"] .device__icon::after {
  width: calc(98 * var(--u));
  height: calc(69 * var(--u));
  background-image: url("/app/assets/icons/dev-laptop.png");
}

.device[data-dev="pc"] .device__icon::after {
  width: calc(62 * var(--u));
  height: calc(93 * var(--u));
  background-image: url("/app/assets/icons/dev-pc.png");
}

/* Название устройства (Asgard Number 25, по центру на 181). */
.device__name {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(181 * var(--u));
  margin: 0;
  text-align: center;
  font-family: var(--font-number);
  font-weight: 400;
  font-size: calc(25 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--ink);
}

/* Дата добавления (14, приглушённая, на 211). */
.device__added {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(211 * var(--u));
  margin: 0;
  text-align: center;
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(14 * var(--u));
  line-height: 1;
  letter-spacing: -.0286em;
  color: rgba(0, 0, 0, .3);
}

/* Чёрная кнопка «Скопировать ключ» (362x85 в 19;252). */
.device__copy {
  position: absolute;
  left: 50%;
  top: calc(252 * var(--u));
  width: calc(362 * var(--u));
  height: calc(85 * var(--u));
  margin-left: calc(-181 * var(--u));
  padding: 0 calc(36 * var(--u)) 0 calc(32 * var(--u));
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(12 * var(--u));
  border: 0;
  border-radius: calc(50 * var(--u));
  background: var(--ink);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.device__copy:active { transform: scale(.99); }

.device__copy-text {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(18 * var(--u));
  line-height: 1;
  color: var(--paper);
}

.device__copy-icon {
  flex: 0 0 auto;
  width: calc(30 * var(--u));
  height: calc(30 * var(--u));
  background: url("/app/assets/icons/copy-key.svg") no-repeat center / contain;
}

/* ---------- Плашка подписки (189x126) ---------- */
.sub {
  position: relative;
  width: calc(189 * var(--u));
  height: calc(126 * var(--u));
  margin: 0 auto calc(14 * var(--u));
  border-radius: calc(32 * var(--u));
  border: calc(2 * var(--u)) solid transparent;
  background-origin: border-box;
  background-clip: padding-box, border-box;
  /* Фон темы + светлая обводка градиентом, как у карточек тарифов. */
  background-image:
    linear-gradient(var(--sub-bg), var(--sub-bg)),
    linear-gradient(43deg,
      rgba(255,255,255,0) 0%, rgba(255,255,255,.7) 26%,
      rgba(255,255,255,.3) 97%, rgba(255,255,255,.2) 100%);
  box-shadow:
    0 calc(32 * var(--u)) calc(22 * var(--u)) calc(-30 * var(--u)) var(--sub-shadow),
    inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(16.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255,255,255,.7),
    inset calc(-2.5 * var(--u)) calc(-6.25 * var(--u)) calc(17.5 * var(--u)) calc(-5.5 * var(--u)) var(--sub-glow),
    inset calc(-8 * var(--u)) calc(-9.25 * var(--u)) calc(15 * var(--u)) calc(-2.5 * var(--u)) rgba(255,255,255,.2);
}

/* Темы плашки — цвета из макета. */
.sub[data-theme="green"] {
  --sub-bg: #27E593;
  --sub-shadow: rgba(15, 150, 71, .45);
  --sub-glow: rgba(226, 247, 199, .6);
  --sub-cancel: #22C980;
  --sub-halo: rgba(39, 229, 147, .6);
  --sub-accent: linear-gradient(32deg, #F2F2F2 0%, #D7FFA2 55%, #F2FFD5 100%);
}

.sub[data-theme="pink"] {
  --sub-bg: #FF2486;
  --sub-shadow: rgba(208, 16, 102, .4);
  --sub-glow: rgba(246, 188, 137, .7);
  --sub-cancel: #DD2174;
  --sub-halo: rgba(255, 36, 134, .6);
  --sub-accent: linear-gradient(34deg, #F2F2F2 22%, #FFD2A2 85%, #C4FFE6 100%);
}

.sub[data-theme="violet"] {
  --sub-bg: #8523C6;
  --sub-shadow: rgba(132, 41, 207, .45);
  --sub-glow: rgba(144, 137, 246, .6);
  --sub-cancel: #711DAA;
  --sub-halo: rgba(133, 35, 198, .6);
  --sub-accent: linear-gradient(30deg, #F7EED7 0%, #FFB3E4 36%, #EADECE 100%);
}

.sub[data-theme="black"] {
  --sub-bg: #000;
  --sub-shadow: rgba(0, 0, 0, .45);
  --sub-glow: rgba(144, 137, 246, .6);
  --sub-cancel: #000;
  --sub-halo: rgba(158, 158, 158, .5);
  --sub-accent: linear-gradient(30deg, #F7DED7 0%, #B6C9D7 36%, #B4C2F3 70%, #E2CEEA 100%);
}

/* Заголовок «Подписка» с иконкой (ряд в 42;19). */
.sub__title {
  position: absolute;
  left: calc(42 * var(--u));
  top: calc(19 * var(--u));
  margin: 0;
  display: flex;
  align-items: center;
  gap: calc(5 * var(--u));
  font-family: var(--font-number);
  font-weight: 400;
  font-size: calc(14 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  /* Подпись набрана светлым градиентом темы. */
  background-image: var(--sub-accent);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.sub__icon {
  flex: 0 0 auto;
  width: calc(17 * var(--u));
  height: calc(10.39 * var(--u));
  border-radius: calc(6 * var(--u));
  background-image: var(--sub-accent);
}

/* «Автопродление / дата» (137x24 в 26;41). */
.sub__renew {
  position: absolute;
  left: calc(26 * var(--u));
  top: calc(41 * var(--u));
  width: calc(137 * var(--u));
  margin: 0;
  text-align: center;
  font-family: var(--font-number);
  font-weight: 400;
  font-size: calc(14 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: #F4F4F4;
}

/* Кнопка «Отменить» (160x40 в 14;75). */
.sub__cancel {
  position: absolute;
  left: calc(14 * var(--u));
  top: calc(75 * var(--u));
  width: calc(160 * var(--u));
  height: calc(40 * var(--u));
  padding: 0 calc(13 * var(--u));
  display: flex;
  align-items: center;
  justify-content: center;
  border: calc(1 * var(--u)) solid transparent;
  border-radius: calc(15 * var(--u));
  background-origin: border-box;
  background-clip: padding-box, border-box;
  /* Полупрозрачное «стекло» в цвет темы. */
  background-image:
    radial-gradient(circle at 50% 4%,
      var(--sub-halo) 5%, rgba(255,255,255,.3) 30%, rgba(255,255,255,.2) 50%),
    linear-gradient(180deg, rgba(0,0,0,.1) 0%, rgba(0,0,0,.3) 100%);
  background-color: rgba(255, 255, 255, .4);
  box-shadow: 0 calc(9 * var(--u)) calc(6 * var(--u)) calc(-6 * var(--u)) rgba(9, 9, 9, .22);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(18 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--sub-cancel);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.sub__cancel:active { transform: scale(.97); }

@media (prefers-reduced-motion: reduce) {
  .device__copy,
  .sub__cancel { transition: none; }
}

/* ==================================================================
   Баланс (макет 919:6550)
   Шапка, карточка с суммой, итоги за период и список транзакций.
   ================================================================== */

.screen--balance {
  /* Абсолютные потомки высоту не задают, поэтому считаем её сами:
     низ списка транзакций (1016) плюс запас снизу. */
  height: calc(1060 * var(--u));
}

/* Сцена задана под 850px, а баланс длиннее: тянем её по содержимому
   и прижимаем к верху — иначе центрирование body срезает низ списка. */
.stage:has(.screen--balance) {
  height: calc(1060 * var(--u));
}

body:has(.screen--balance) {
  align-items: flex-start;
}

/* Стрелка «назад» (Vector 26x20 в 20;74) */
.balance__back {
  position: absolute;
  left: calc(20 * var(--u));
  top: calc(74 * var(--u));
  width: calc(26 * var(--u));
  height: calc(20 * var(--u));
  padding: 0;
  border: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  background: url("/app/assets/icons/balance-back.svg") no-repeat center / contain;
}

/* Заголовок «Баланс» (164;75) */
.balance__title {
  position: absolute;
  left: calc(164 * var(--u));
  top: calc(75 * var(--u));
  width: calc(113 * var(--u));
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(26 * var(--u));
  line-height: .9;
  letter-spacing: -.03em;
  text-align: center;
  color: var(--ink);
}

/* ---------- Карточка с суммой (400x218 в 21;113) ---------- */
.balance__card {
  position: absolute;
  left: calc(21 * var(--u));
  top: calc(113 * var(--u));
  width: calc(400 * var(--u));
  height: calc(218 * var(--u));
  border-radius: calc(60 * var(--u));
  background: var(--paper);
}

/* Сумма и знак рубля в одну строку по нижнему краю (47;31) */
.balance__sum {
  position: absolute;
  left: 0;
  top: calc(31 * var(--u));
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: flex-end;
  gap: calc(5 * var(--u));
  color: var(--ink);
}

.balance__amount {
  font-family: var(--font-number);
  font-weight: 800;
  font-size: calc(60 * var(--u));
  line-height: .9;
  letter-spacing: -.03em;
}

.balance__currency {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(30 * var(--u));
  line-height: 1;
  letter-spacing: -.1164em;
}

/* Подпись под суммой (132;86) */
.balance__note {
  position: absolute;
  left: 0;
  top: calc(86 * var(--u));
  width: 100%;
  margin: 0;
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(19 * var(--u));
  line-height: 1;
  letter-spacing: -.0158em;
  text-align: center;
  color: rgba(0, 0, 0, .4);
}

/* Чёрная кнопка «Пополнить» (366x80 в 17;123 внутри карточки) */
.balance__topup {
  position: absolute;
  left: calc(17 * var(--u));
  top: calc(123 * var(--u));
  width: calc(366 * var(--u));
  height: calc(80 * var(--u));
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(9 * var(--u));
  border: calc(3 * var(--u)) solid transparent;
  border-radius: calc(50 * var(--u));
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    linear-gradient(#000, #000),
    linear-gradient(43deg,
      rgba(255,255,255,0) 0%,
      rgba(255,255,255,.7) 26%,
      rgba(255,255,255,.3) 97%,
      rgba(255,255,255,.2) 100%);
  box-shadow:
    0 calc(32 * var(--u)) calc(22 * var(--u)) calc(-30 * var(--u)) rgba(0,0,0,.45),
    inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(16.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255,255,255,.7),
    inset calc(-2.5 * var(--u)) calc(-6.25 * var(--u)) calc(17.5 * var(--u)) calc(-5.5 * var(--u)) rgba(223,223,223,.6),
    inset calc(-8 * var(--u)) calc(-9.25 * var(--u)) calc(15 * var(--u)) calc(-2.5 * var(--u)) rgba(255,255,255,.2);
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(21 * var(--u));
  line-height: 1;
  color: var(--paper);
  transition: transform .18s ease;
}

.balance__topup:active { transform: scale(.99); }

/* Стрелка «вниз на полку» — в файле уже белая, перекрашивать не нужно. */
.balance__topup-icon {
  width: calc(20 * var(--u));
  height: calc(20 * var(--u));
  background: url("/app/assets/icons/topup-arrow.svg") no-repeat center / contain;
}

/* ---------- Итоги за период (54;354 и 264;354) ---------- */
.balance__stats {
  position: absolute;
  left: calc(54 * var(--u));
  top: calc(354 * var(--u));
  width: calc(340 * var(--u));
  display: flex;
  justify-content: space-between;
}

.balance__stat {
  display: flex;
  align-items: center;
  gap: calc(8 * var(--u));
}

/* Квадратный значок 27x27 с бледной заливкой */
.balance__stat-icon {
  flex: 0 0 auto;
  width: calc(27 * var(--u));
  height: calc(27 * var(--u));
  border-radius: calc(8 * var(--u));
  background: rgba(0, 0, 0, .05) no-repeat center / calc(13 * var(--u));
}

.balance__stat-icon--spent { background-image: url("/app/assets/icons/balance-spent.svg"); }
.balance__stat-icon--added { background-image: url("/app/assets/icons/balance-added.svg"); }

.balance__stat-body {
  display: flex;
  flex-direction: column;
  gap: calc(5 * var(--u));
}

/* Сумма: крупное число и знак рубля помельче */
.balance__stat-value {
  display: flex;
  align-items: flex-end;
  gap: calc(2 * var(--u));
  font-family: var(--font-number);
  font-weight: 400;
  line-height: .9;
  letter-spacing: -.03em;
  color: var(--ink);
}

.balance__stat-value b {
  font-weight: 400;
  font-size: calc(28 * var(--u));
}

.balance__stat-value i {
  font-style: normal;
  font-size: calc(17 * var(--u));
}

.balance__stat-note {
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(14 * var(--u));
  line-height: 1;
  letter-spacing: -.0286em;
  color: rgba(0, 0, 0, .4);
}

/* Заголовок «Транзакции» (124;443) */
.balance__heading {
  position: absolute;
  z-index: 1;
  left: calc(20 * var(--u));
  top: calc(428 * var(--u));
  width: calc(400 * var(--u));
  height: calc(48 * var(--u));
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Надпись — графика из макета: серые буквы в белой обводке. Она лежит
     на кромке карточки, поэтому своей подложки у блока нет. */
  background: url("/app/assets/icons/balance-heading.svg")
    no-repeat center / calc(214 * var(--u)) auto;
  text-indent: -9999px;
  overflow: hidden;
}

/* ---------- Список транзакций (400 в 20;452) ----------
   Белое поле идёт от заголовка до низа экрана: под ним не должно
   оставаться полосы фона, даже когда операций мало. */
.ops {
  position: absolute;
  left: calc(20 * var(--u));
  top: calc(452 * var(--u));
  bottom: 0;
  width: calc(400 * var(--u));
  padding: 0 0 calc(24 * var(--u));
  /* Скругление только сверху: низ уходит за край экрана. */
  border-radius: calc(60 * var(--u)) calc(60 * var(--u)) 0 0;
  background: var(--paper);
  overflow-y: auto;
  scrollbar-width: none;
}

.ops::-webkit-scrollbar {
  width: 0;
  height: 0;
}

/* Операций ещё нет: подпись стоит по центру белого поля. */
.ops.is-empty {
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.ops__empty {
  margin: 0;
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(16 * var(--u));
  line-height: 1.2;
  letter-spacing: -.02em;
  text-align: center;
  color: rgba(0, 0, 0, .3);
}

/* Название месяца над группой */
/* Месяц-разделитель (макет 919:7143): подпись и две полукруглые
   «скобки» 6x11 по бокам, зазор 8. */
.ops__month {
  height: calc(33 * var(--u));
  /* Первый заголовок стоит на 40 от верха карточки (макет), остальные
     отбиваются от предыдущего списка. */
  margin: calc(19 * var(--u)) 0 0;
  padding: 0 calc(24 * var(--u));
  display: flex;
  align-items: center;
  /* По левому краю, вровень со строками списка */
  justify-content: flex-start;
  gap: calc(8 * var(--u));
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(20 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: rgba(0, 0, 0, .3);
}

/* Скобки по бокам названия месяца (Ellipse 1593/1594, 6x11) */
.ops__month-mark {
  flex: 0 0 auto;
  width: calc(6 * var(--u));
  height: calc(11 * var(--u));
  background: no-repeat center / contain;
}

.ops__month-mark--left  { background-image: url("/app/assets/icons/month-cap-left.svg"); }
.ops__month-mark--right { background-image: url("/app/assets/icons/month-cap-right.svg"); }

.ops__list:last-child { margin-bottom: calc(16 * var(--u)); }

/* Первый заголовок стоит на 40 от верха карточки. */
/* Первый заголовок стоит на 40 от верха карточки (макет 919:7143). */
.ops > .ops__month:first-child { margin-top: calc(40 * var(--u)); }

.ops__list {
  margin: 0;
  padding: 0 calc(24 * var(--u));
  list-style: none;
  /* В макете строки идут вплотную: шаг 62 задаёт сама высота строки. */
  display: flex;
  flex-direction: column;
}

/* Строка операции 352x62 с разделителем снизу */
.op {
  position: relative;
  /* Макет 919:6571: строка 352×62 — значок слева, название и время
     в центре, сумма справа. */
  height: calc(62 * var(--u));
  display: flex;
  align-items: center;
  gap: calc(8 * var(--u));
}

/* Разделитель гаснет к краям, как в макете */
/* Значок операции в макете отсутствует. */
.op__icon {
  flex: 0 0 auto;
  width: calc(38 * var(--u));
  height: calc(38 * var(--u));
  border-radius: 50%;
  background: no-repeat center / contain;
}

.op[data-kind="sbp"] .op__icon {
  background-image: url("/app/assets/icons/op-sbp.svg");
}

.op[data-kind="card"] .op__icon {
  background-image: url("/app/assets/icons/op-card.svg");
}

.op[data-kind="crypto"] .op__icon {
  background-image: url("/app/assets/icons/op-crypto.svg");
}

.op[data-kind="stars"] .op__icon {
  background-image: url("/app/assets/icons/op-stars.svg");
}

/* Кешбэк приходит от друга — показываем его аватар */
.op[data-kind="cash"] .op__icon {
  background-color: rgba(0, 0, 0, .12);
  background-size: cover;
}

.op__body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: calc(7 * var(--u));
}

.op__name {
  font-family: var(--font-number);
  font-weight: 400;
  font-size: calc(15 * var(--u));
  line-height: .9;
  letter-spacing: -.0333em;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Время и дата через точку */
.op__meta {
  display: flex;
  align-items: center;
  gap: calc(5 * var(--u));
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(10 * var(--u));
  line-height: 1;
  letter-spacing: -.04em;
  color: rgba(0, 0, 0, .4);
}

.op__dot {
  width: calc(2.5 * var(--u));
  height: calc(2.5 * var(--u));
  border-radius: 50%;
  background: currentColor;
}

/* Тонкая линия под строкой, гаснущая к краям (stroke fill_B8XNWJ) */
.op:not(:last-child)::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: calc(1 * var(--u));
  background: linear-gradient(270deg,
    rgba(0,0,0,.05) 10%, rgba(0,0,0,.25) 50%, rgba(0,0,0,.05) 100%);
}

/* Списание бледнее поступления: гаснет вся строка — значок,
   название и сумма. */
.op[data-flow="out"] .op__name,
.op[data-flow="out"] .op__sum {
  color: rgba(0, 0, 0, .25);
}

.op[data-flow="out"] .op__icon {
  opacity: .45;
}

/* Сумма операции справа */
.op__sum {
  flex: 0 0 auto;
  margin-left: auto;
  padding-left: calc(8 * var(--u));
  display: flex;
  align-items: baseline;
  gap: calc(2 * var(--u));
  font-family: var(--font-number);
  font-weight: 400;
  font-size: calc(20 * var(--u));
  line-height: .9;
  letter-spacing: -.0333em;
  /* В макете сумма чёрная (fill_07IPWT), приглушены только время и дата */
  color: var(--ink);
  white-space: nowrap;
}

/* Знак операции: крупнее и легче самой суммы */
.op__sign {
  font-style: normal;
  font-family: var(--font-display);
  font-weight: 300;
  font-size: calc(25 * var(--u));
  line-height: 1;
  letter-spacing: -.14em;
}

@media (prefers-reduced-motion: reduce) {
  .balance__topup { transition: none; }
}

/* ==================================================================
   <pay-card> — карточка привязанной карты (макет 3108:2744, 352x149)
   ================================================================== */

pay-card {
  display: block;
  width: calc(352 * var(--u));
  height: calc(149 * var(--u));
}

.paycard {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: calc(32 * var(--u));
  background: #000;
  box-shadow:
    0 calc(10 * var(--u)) calc(18 * var(--u)) calc(-30 * var(--u)) rgba(0,0,0,.3),
    inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(16.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255,255,255,.7),
    inset calc(-2.5 * var(--u)) calc(-4.25 * var(--u)) calc(7.5 * var(--u)) calc(-5.5 * var(--u)) rgba(246,137,139,.5),
    inset calc(-8 * var(--u)) calc(-9.25 * var(--u)) calc(15 * var(--u)) calc(-2.5 * var(--u)) rgba(255,255,255,.2);
}

/* Красный вариант карты (например, Альфа-банк). */
.paycard--red { background: #F5352A; }

/* Рамка вокруг номера: два вложенных прямоугольника из макета
   (333x68 в 10;13 и 325x60 в 14;17). */
.paycard__top {
  position: absolute;
  left: calc(10 * var(--u));
  top: calc(13 * var(--u));
  width: calc(333 * var(--u));
  height: calc(68 * var(--u));
}

/* Внешняя рамка отдельным слоем: маску нельзя вешать на сам блок —
   она срезала бы номер и подпись внутри него. */
.paycard__top::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: calc(18 * var(--u));
  border: calc(1 * var(--u)) solid transparent;
  background: linear-gradient(180deg, rgba(255,255,255,.1) 0%, rgba(255,255,255,.3) 68%) border-box;
  -webkit-mask: linear-gradient(#000 0 0) padding-box, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) padding-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  pointer-events: none;
}

/* Внутренняя рамка. */
.paycard__top::after {
  content: "";
  position: absolute;
  left: calc(4 * var(--u));
  top: calc(4 * var(--u));
  width: calc(325 * var(--u));
  height: calc(60 * var(--u));
  border-radius: calc(15 * var(--u));
  border: calc(1 * var(--u)) solid rgba(255, 255, 255, .12);
}

/* Номер карты (Asgard Number 15, трекинг 10%). */
.paycard__number {
  position: absolute;
  left: calc(20 * var(--u));
  top: calc(19 * var(--u));
  font-family: var(--font-display);
  font-weight: 400;
  /* Asgard Number 15 с трекингом 10% — как в макете. */
  font-size: calc(15 * var(--u));
  line-height: 1;
  letter-spacing: .1em;
  color: #838383;
  white-space: nowrap;
}

/* Подписи под значениями — 14px, полупрозрачные белые. */
.paycard__caption {
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(14 * var(--u));
  line-height: 1;
  letter-spacing: -.0286em;
  color: rgba(255, 255, 255, .3);
}

.paycard__top .paycard__caption {
  position: absolute;
  left: calc(20 * var(--u));
  top: calc(38 * var(--u));
}

/* Чип (44x30 в 282;32). */
.paycard__chip {
  position: absolute;
  left: calc(272 * var(--u));
  top: calc(19 * var(--u));
  width: calc(44 * var(--u));
  height: calc(30 * var(--u));
  border-radius: calc(5 * var(--u));
  background: url("/app/assets/icons/card-chip.png") no-repeat center / contain;
}

/* CVV (30;100) и срок действия (97;100). */
.paycard__field {
  position: absolute;
  display: flex;
  flex-direction: column;
  gap: calc(6 * var(--u));
}

.paycard__field--cvv    { left: calc(30 * var(--u)); top: calc(100 * var(--u)); }
.paycard__field--expiry { left: calc(97 * var(--u)); top: calc(100 * var(--u)); }

.paycard__value {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(15 * var(--u));
  line-height: 1;
  letter-spacing: .1em;
  color: #838383;
}

/* Значок платёжной системы (93x42 в 245;92). */
.paycard__bank {
  position: absolute;
  left: calc(245 * var(--u));
  top: calc(92 * var(--u));
  width: calc(93 * var(--u));
  height: calc(42 * var(--u));
  border-radius: calc(14 * var(--u));
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
}

/* ==================================================================
   Заполненное состояние профиля (макет 955:7596)
   Списки устройств и способов оплаты. Пустые плашки прячутся,
   когда в данных что-то есть, — и наоборот.
   ================================================================== */

.plist {
  position: absolute;
  left: calc(26 * var(--u));
  width: calc(389 * var(--u));
  margin: 0;
  padding: 0;
  list-style: none;
  /* Поток, а не абсолютные координаты: при удалении строки
     остальные поднимаются сами и пустоты не остаётся. */
  display: flex;
  flex-direction: column;
}

/* ---------- Устройства (ряды с шагом 79: 454, 533, 612) ---------- */
.plist--devices { top: calc(454 * var(--u)); }

.plist--devices { gap: calc(13 * var(--u)); }

.pdev {
  flex: 0 0 auto;
  height: calc(66 * var(--u));
  display: flex;
  align-items: center;
  gap: calc(12 * var(--u));
}

/* Плитка с картинкой устройства (92×66). */
.pdev__icon {
  flex: 0 0 auto;
  width: calc(92 * var(--u));
  height: calc(66 * var(--u));
  border-radius: calc(14 * var(--u));
  background: no-repeat center / contain;
}

.pdev__body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: calc(8 * var(--u));
  min-width: 0;
}

.pdev__name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(22 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Неактивное устройство — имя блёклое. */
.pdev.is-off .pdev__name { color: rgba(0, 0, 0, .3); }

.pdev__added {
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(14 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: rgba(0, 0, 0, .3);
}

/* Кнопка-стрелка справа (30×30). */
.pdev__go {
  flex: 0 0 auto;
  width: calc(30 * var(--u));
  height: calc(30 * var(--u));
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: url("/app/assets/icons/whom-arrow.svg") no-repeat center / contain;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.pdev__go:active { transform: scale(.9); }

/* ---------- Способы оплаты (ряды с шагом 57: 741, 798, 855, 912) ---------- */
.plist--pay { top: calc(741 * var(--u)); }

.plist--pay { gap: calc(15 * var(--u)); }

.ppay {
  flex: 0 0 auto;
  height: calc(42 * var(--u));
  display: flex;
  align-items: center;
}

/* Цветной значок платёжной системы (93×42). */
.ppay__badge {
  flex: 0 0 auto;
  width: calc(93 * var(--u));
  height: calc(42 * var(--u));
  border-radius: calc(12 * var(--u));
  background: no-repeat center / contain;
}

/* Название/номер — от x=130, т.е. 104 от левого края ряда. */
.ppay__name {
  flex: 1 1 auto;
  margin-left: calc(11 * var(--u));
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(22 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Непривязанный способ — блёклый. */
.ppay.is-off .ppay__name { color: rgba(0, 0, 0, .3); }

/* Кружок выбора (30×30 в x=353). */
.ppay__pick {
  flex: 0 0 auto;
  width: calc(30 * var(--u));
  height: calc(30 * var(--u));
  margin-right: calc(7 * var(--u));
  padding: 0;
  border: 0;
  background: url("/app/assets/icons/ppay-uncheck.png") no-repeat center / contain;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.ppay__pick {
  position: relative;
}

.ppay__pick[aria-checked="true"] {
  background-image: url("/app/assets/icons/ppay-check.png");
}

/* Белая «птичка» 12x11 по центру выбранного переключателя */
.ppay__pick[aria-checked="true"]::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(12 * var(--u));
  height: calc(11 * var(--u));
  transform: translate(-50%, -50%);
  background: url("/app/assets/icons/ppay-check.svg") no-repeat center / contain;
}

.ppay__pick:active { transform: scale(.9); }

/* Кнопка удаления (25×25 в x=390). */
.ppay__del {
  flex: 0 0 auto;
  width: calc(25 * var(--u));
  height: calc(25 * var(--u));
  padding: 0;
  border: 0;
  background: url("/app/assets/icons/ppay-del.png") no-repeat center / contain;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.ppay__del:active { transform: scale(.9); }

/* ---------- Сдвиг нижних блоков, когда списки заполнены ----------
   В пустом состоянии «Способы оплаты» на 549, а в заполненном — на 715.
   Разницу задаём модификатором на экране, чтобы не дублировать правила. */
/* Бургер и навигация встают под потоком: высоту его содержимого
   знает только браузер, поэтому её прокидывает JS в --pflow-bottom. */
.screen--profile .profile__burger { top: var(--pflow-bottom, calc(806 * var(--u))); }

@media (hover: hover) {
  .pdev__go:hover,
  .ppay__pick:hover,
  .ppay__del:hover {
    transform: scale(1.1);
    filter: brightness(1.05);
  }
}

@media (prefers-reduced-motion: reduce) {
  .pdev__go,
  .ppay__pick,
  .ppay__del { transition: none; }
}

/* ==================================================================
   Нижняя часть профиля — поток вместо абсолютных координат.
   Раньше каждый блок стоял на своей отметке (426, 549, 671…), и после
   удаления строки на её месте оставалась дыра. Теперь блоки идут друг
   за другом и подтягиваются сами.
   ================================================================== */

.pflow {
  position: absolute;
  left: 0;
  /* Верх — там же, где раньше стоял заголовок «Устройства». */
  top: calc(426 * var(--u));
  width: calc(440 * var(--u));
  display: flex;
  flex-direction: column;
}

/* Заголовки разделов и кнопка справа от них — на одной строке. */
.pflow .prow {
  position: static;
  left: auto;
  top: auto;
  height: calc(14 * var(--u));
  margin: 0 0 calc(14 * var(--u)) calc(30 * var(--u));
}

/* «Профиль» в макете стоит по центру. */
.pflow .prow--profile {
  margin-left: 0;
  justify-content: center;
}

/* Строка заголовка растягивается на всю ширину, чтобы кнопка
   «Добавить» / «Привязать» встала у правого края той же строки. */
.pflow .prow--devices,
.pflow .prow--pay {
  margin-right: calc(25 * var(--u));
}

.pflow .prow--devices .prow__count { margin-right: auto; }
.pflow .prow--pay .prow__label     { margin-right: auto; }

/* Кнопка — обычный элемент строки, а не абсолют. */
.pflow .prow__add {
  position: static;
  left: auto;
  top: auto;
}

/* Списки и пустые плашки — обычные блоки в потоке. */
.pflow .plist {
  position: static;
  left: auto;
  top: auto;
  width: calc(389 * var(--u));
  margin: 0 auto 0 calc(26 * var(--u));
}

.pflow .pempty {
  position: static;
  left: auto;
  top: auto;
  width: calc(400 * var(--u));
  margin-left: calc(21 * var(--u));
}

/* Отступ между разделами: список → следующий заголовок. */
.pflow .plist--devices,
.pflow .pempty--devices { margin-bottom: calc(37 * var(--u)); }

.pflow .plist--pay,
.pflow .pempty--pay { margin-bottom: calc(39 * var(--u)); }

/* Пустой список не должен занимать место и давать лишний отступ. */
.pflow .plist:empty { display: none; }

/* Пара кнопок «Выйти» / «Удалить». */
.pbtns {
  display: flex;
  gap: calc(11 * var(--u));
  margin: calc(11 * var(--u)) 0 0 calc(26 * var(--u));
}

.pflow .pbtn {
  position: static;
  left: auto;
  top: auto;
}

.pflow .profile__copy {
  position: static;
  left: auto;
  top: auto;
  width: calc(259 * var(--u));
  margin: calc(25 * var(--u)) auto 0;
}

/* ==================================================================
   Об устройстве (макет 919:7184)
   Открывается по тапу на устройство: карточка 400x355 в точке 20;416
   поверх затемнения — картинка, название, дата и кнопка с ключом.
   ================================================================== */

/* Затемнение (Rectangle 30188) */
.dev-scrim {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, .25);
  opacity: 0;
  visibility: hidden;
  z-index: 30;
  transition: opacity .22s ease, visibility .22s ease;
}

.dev-scrim.is-open {
  opacity: 1;
  visibility: visible;
}

/* Карточка (Rectangle 30175, 400x355) */
/* Окно у нижнего края экрана: страница профиля длиннее кадра
   Figma, и привязка по top оставляла панель посередине. */
.dev {
  position: absolute;
  left: 50%;
  bottom: calc(20 * var(--u));
  margin-left: calc(-200 * var(--u));
  width: calc(400 * var(--u));
  height: calc(355 * var(--u));
  border-radius: calc(60 * var(--u));
  background: var(--paper);
  transform: translateY(calc(24 * var(--u))) scale(.98);
  transition: transform .26s cubic-bezier(.2, .8, .3, 1);
}

.dev-scrim.is-open .dev {
  transform: none;
}

/* «Ручка» сверху (Rectangle 30189/30190, 50x6 в 195;429 кадра) */
/* Наклейка «Об устройстве» — над левым верхним углом окна
   (в макете 36;391 при панели 20;416, то есть 16;-25 относительно неё).
   Белая обводка даёт эффект наклеенной бумажки. */
.dev__sticker {
  position: absolute;
  left: calc(16 * var(--u));
  /* Наклейка сильнее заходит на окно, чем в макете. */
  top: calc(-22 * var(--u));
  width: calc(140 * var(--u));
  text-align: center;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(20 * var(--u));
  line-height: .9;
  letter-spacing: -.02em;
  color: var(--ink);
  -webkit-text-stroke: calc(6 * var(--u)) var(--paper);
  paint-order: stroke fill;
  text-shadow: 0 calc(4 * var(--u)) calc(14 * var(--u)) rgba(0, 0, 0, .14);
  transform: rotate(-8deg);
  pointer-events: none;
}

.dev__grip {
  position: absolute;
  left: calc(175 * var(--u));
  top: calc(13 * var(--u));
  width: calc(50 * var(--u));
  height: calc(6 * var(--u));
  padding: 0;
  border: calc(.8 * var(--u)) solid transparent;
  border-radius: calc(10 * var(--u));
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    linear-gradient(rgba(0,0,0,.1), rgba(0,0,0,.1)),
    linear-gradient(180deg, rgba(0,0,0,.05) 0%, rgba(0,0,0,.2) 100%);
  box-shadow: 0 calc(4 * var(--u)) calc(6 * var(--u)) calc(-3 * var(--u)) rgba(0,0,0,.35);
}

/* Картинка устройства в рамке (125x125 в 157;454 кадра) */
.dev__photo {
  position: absolute;
  left: calc(137 * var(--u));
  top: calc(38 * var(--u));
  width: calc(125 * var(--u));
  height: calc(125 * var(--u));
  border: calc(1 * var(--u)) solid transparent;
  border-radius: calc(30 * var(--u));
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    url("/app/assets/icons/devadd-photo.png"),
    linear-gradient(180deg, rgba(0,0,0,.1) 0%, rgba(0,0,0,.3) 100%);
  background-repeat: no-repeat;
  background-position: center, center;
  background-size: cover, cover;
  box-shadow: 0 calc(6 * var(--u)) calc(10 * var(--u)) calc(-6 * var(--u)) rgba(9,9,9,.22);
}

/* Новое устройство: заглушка сама несёт рамку, тень и скругление,
   поэтому у бокса своё оформление отключаем. */
.dev.is-adding .dev__photo {
  left: calc(133 * var(--u));
  top: calc(32 * var(--u));
  width: calc(133 * var(--u));
  height: calc(135 * var(--u));
  border: 0;
  border-radius: 0;
  box-shadow: none;
  background-image: url("/app/assets/icons/devadd-blank.svg");
  background-size: contain;
  background-position: center;
}

/* Плитка-заглушка уже стоит у .dev__photo выше — здесь только
   блёклое название: «Новое устройство» — подсказка, а не данные. */
.dev.is-adding .dev__name,
.dev.is-new .dev__name { color: rgba(0, 0, 0, .3); }

/* Стрелки перебора устройств (58x47 в 64;497 и 317;497 кадра) */
/* Круглые кнопки по краям — готовые картинки 60×49 из макета:
   в них уже и фон, и градиентная рамка, и сам значок. */
.dev__nav {
  position: absolute;
  top: calc(81 * var(--u));
  width: calc(60 * var(--u));
  height: calc(49 * var(--u));
  padding: 0;
  border: 0;
  background: no-repeat center / contain;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.dev__nav--prev { left: calc(44 * var(--u)); }
.dev__nav--next { left: calc(297 * var(--u)); }

.dev__nav:active { transform: scale(.94); }

/* Стрелка внутри кнопки */

/* Слева — платформа устройства, справа — удаление (макет 919:7184) */
/* Слева — платформа устройства, справа — корзина удаления. */
/* Значок платформы подставляет JS: он зависит от устройства.
   Apple остаётся запасным — на нём вёрстка и рисовалась. */
.dev__nav--prev { background-image: url("/app/assets/icons/dev-apple.svg"); }
.dev__nav--next { background-image: url("/app/assets/icons/dev-basket.svg"); }

/* Название устройства (189x18 в 125;597 кадра) */
.dev__name {
  position: absolute;
  left: calc(61 * var(--u));
  top: calc(181 * var(--u));
  width: calc(277 * var(--u));
  margin: 0;
  /* Asgard Number 25, как в макете (style_RLLELE). */
  font-family: var(--font-number);
  font-weight: 400;
  font-size: calc(25 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  text-align: center;
  color: var(--ink);
  /* Правка 23.10.2026 (Матвей: «текст чуть выезжает»). Блок 277px, а
     имя у Windows приходит вида WIN-MO4T3HNHRSO_x86_64: измерено 548px
     при overflow: visible — 271px вылезали за края карточки, поверх
     кнопок «платформа» и «удалить».

     Кегль подбирает fitDevName в profile.js (CSS не умеет мерить
     текст); здесь — страховка на случай, если скрипт не отработал.
     Строка одна: ниже на 30px дата, переносом наехали бы на неё. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Дата добавления (141x10 в 150;627 кадра) */
.dev__added {
  position: absolute;
  left: calc(130 * var(--u));
  top: calc(211 * var(--u));
  width: calc(141 * var(--u));
  margin: 0;
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(14 * var(--u));
  line-height: 1;
  letter-spacing: -.0286em;
  text-align: center;
  color: rgba(0, 0, 0, .3);
}

/* Кнопка «Скопировать ключ» (362x85 в 38.85;668 кадра) */
/* Кнопка «Скопировать ключ» — готовая картинка 362×85 из макета:
   в ней уже и фон, и надпись, и значок. Текст остаётся в разметке
   для скринридеров, но не рисуется. */
.dev__copy {
  position: absolute;
  left: calc(19 * var(--u));
  top: calc(252 * var(--u));
  width: calc(362 * var(--u));
  height: calc(85 * var(--u));
  padding: 0;
  border: 0;
  background: url("/app/assets/icons/copy.png") no-repeat center / contain;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  font-size: 0;
  color: transparent;
  transition: transform .18s ease;
}

/* Надпись и значок уже на картинке. */
.dev__copy-icon { display: none; }

.dev__copy:active { transform: scale(.99); }

/* Значок ключа справа от подписи */

/* После нажатия кнопка подтверждает копирование */
/* Нажали — кнопка розовеет и пишет «Скопировано».
   Картинку прячем и возвращаем текст: иначе отклика не видно. */
.dev__copy.is-copied {
  background-image: none;
  background-color: #FF2486;
  border-radius: calc(50 * var(--u));
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(18 * var(--u));
  line-height: 1;
  color: var(--paper);
  /* Подсказка бывает длиннее «Скопировано» — ужимаем, а не обрезаем. */
  padding: 0 calc(16 * var(--u));
  text-align: center;
}

/* Сообщение без успеха (подсказка/диагностика): текст тоже должен быть
   виден, а у кнопки по умолчанию font-size:0 — надпись зашита в PNG. */
.dev__copy.is-note {
  background-image: none;
  background-color: rgba(0, 0, 0, .08);
  border-radius: calc(50 * var(--u));
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 calc(16 * var(--u));
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(15 * var(--u));
  line-height: 1.15;
  text-align: center;
  color: rgba(0, 0, 0, .55);
}

@media (prefers-reduced-motion: reduce) {
  .dev-scrim,
  .dev,
  .dev__nav,
  .dev__copy { transition: none; }
}

/* ==================================================================
   Привязка карты (макет 952:10413). Панель 400 в 20;386.
   Карта сама служит формой: поля лежат поверх подписей.
   ================================================================== */

.bind-scrim {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, .25);
  opacity: 0;
  visibility: hidden;
  z-index: 10;
  transition: opacity .22s ease, visibility .22s ease;
}

.bind-scrim.is-open {
  opacity: 1;
  visibility: visible;
}

.bind {
  position: absolute;
  left: 50%;
  margin-left: calc(-200 * var(--u));
  bottom: calc(20 * var(--u));
  width: calc(400 * var(--u));
  padding: 0 0 calc(24 * var(--u));
  border-radius: calc(60 * var(--u));
  background: var(--paper);
  transform: translateY(calc(24 * var(--u))) scale(.98);
  transition: transform .26s cubic-bezier(.2, .8, .3, 1);
  /* Стикер выходит за верхний край — обрезать его нельзя. */
  overflow: visible;
}

.bind-scrim.is-open .bind { transform: none; }

/* «Ручка» 50x6 вверху панели. */
.bind__grip {
  display: block;
  width: calc(50 * var(--u));
  height: calc(6 * var(--u));
  margin: calc(13 * var(--u)) auto 0;
  padding: 0;
  border: 0;
  border-radius: calc(10 * var(--u));
  background: rgba(0, 0, 0, .1);
  box-shadow: 0 calc(4 * var(--u)) calc(6 * var(--u)) calc(-3 * var(--u)) rgba(0, 0, 0, .35);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* Заголовка в макете нет — оставляем для скринридеров. */
.bind__title {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ---------- Стикер «Сделать основным способом» ----------
   Лежит поверх верхнего края окна: звезда в 305.84;321 кадра и подпись
   в 272;357 — считаем от панели (20;386), поэтому уходим в минус по Y. */
.bind__primary {
  position: absolute;
  left: calc(252 * var(--u));
  top: calc(-65 * var(--u));
  z-index: 2;
  width: calc(126 * var(--u));
  height: calc(110 * var(--u));
  padding: 0;
  border: 0;
  background: none;
  /* Наклон тот же, что у стикера в окне готовой карты (.paym__primary). */
  transform: rotate(6deg);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.bind__primary:active { transform: rotate(-9deg) scale(.96); }

/* Белая звезда-галочка 41x41 (Star 23 + Star 24 из макета). */
.bind__primary-star {
  position: absolute;
  left: calc(45 * var(--u));
  top: 0;
  width: calc(41 * var(--u));
  height: calc(41 * var(--u));
  background: url("/app/assets/icons/bind-star-empty.svg") no-repeat center / contain;
  filter: drop-shadow(0 calc(1 * var(--u)) calc(4 * var(--u)) rgba(0, 0, 0, .15));
  transition: filter .15s ease;
}

/* Выбранный способ — розовая звезда с галочкой. Белый кант рисуем
   тенями без размытия: по фигурному краю иначе выходит свечение. */
.bind__primary[aria-checked="true"] .bind__primary-star {
  background-image: url("/app/assets/icons/friends-check-star.svg");
  filter:
    drop-shadow(calc(2 * var(--u)) 0 0 #fff)
    drop-shadow(calc(-2 * var(--u)) 0 0 #fff)
    drop-shadow(0 calc(2 * var(--u)) 0 #fff)
    drop-shadow(0 calc(-2 * var(--u)) 0 #fff)
    drop-shadow(0 calc(1 * var(--u)) calc(4 * var(--u)) rgba(0, 0, 0, .15));
}

/* Подпись в три строки, белая обводка отделяет её от фона. */
.bind__primary-text {
  position: absolute;
  left: 0;
  top: calc(36 * var(--u));
  width: 100%;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(16 * var(--u));
  line-height: .9;
  letter-spacing: -.02em;
  color: var(--ink);
  -webkit-text-stroke: calc(10 * var(--u)) #fff;
  paint-order: stroke fill;
}

/* ---------- Карта 352x149 ---------- */
.bind__card {
  position: relative;
  width: calc(352 * var(--u));
  height: calc(149 * var(--u));
  margin: calc(14 * var(--u)) auto 0;
  border: calc(1 * var(--u)) solid transparent;
  border-radius: calc(32 * var(--u));
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    linear-gradient(#fff, #fff),
    linear-gradient(180deg, rgba(0, 0, 0, .1) 0%, rgba(0, 0, 0, .3) 100%);
  box-shadow: 0 calc(9.63 * var(--u)) calc(14 * var(--u)) calc(-28.68 * var(--u)) rgba(66, 66, 66, .15);
}

/* Рамка-прорезь под номер: точки, поле ввода и подпись лежат в ней. */
.bind__slot {
  position: absolute;
  left: calc(10 * var(--u));
  top: calc(13 * var(--u));
  width: calc(333 * var(--u));
  height: calc(68 * var(--u));
  border: calc(1 * var(--u)) solid rgba(0, 0, 0, .08);
  border-radius: calc(22 * var(--u));
}

/* Четыре группы точек — то, что видно, пока номер не введён. */
.bind__digits {
  position: absolute;
  left: calc(20 * var(--u));
  top: calc(17 * var(--u));
  display: flex;
  align-items: center;
  gap: calc(8 * var(--u));
  font-family: var(--font-number);
  font-weight: 400;
  font-size: calc(15 * var(--u));
  line-height: 1;
  letter-spacing: .1em;
  color: #484848;
  pointer-events: none;
}

/* Золотой чип справа вверху карты. */
.bind__chip {
  position: absolute;
  right: calc(16 * var(--u));
  top: calc(16 * var(--u));
  width: calc(44 * var(--u));
  height: calc(34 * var(--u));
  background: url("/app/assets/icons/card-chip.png") no-repeat center / contain;
}

/* Подпись поля — под значением, приглушённая. */
.bind__caption {
  position: absolute;
  left: 0;
  bottom: 0;
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(14 * var(--u));
  line-height: 1;
  letter-spacing: -.0286em;
  color: rgba(0, 0, 0, .3);
  pointer-events: none;
}

.bind__caption--number {
  left: calc(20 * var(--u));
  bottom: calc(16 * var(--u));
}

/* CVV и срок: заглушка сверху, подпись снизу, поле поверх. */
.bind__pair {
  position: absolute;
  bottom: calc(18 * var(--u));
  height: calc(34 * var(--u));
}

.bind__pair--cvv    { left: calc(24 * var(--u)); width: calc(70 * var(--u)); }
.bind__pair--expiry { left: calc(110 * var(--u)); width: calc(120 * var(--u)); }

.bind__dots {
  position: absolute;
  left: 0;
  top: 0;
  font-family: var(--font-number);
  font-weight: 400;
  font-size: calc(15 * var(--u));
  line-height: 1;
  letter-spacing: .1em;
  color: #484848;
  pointer-events: none;
}

/* Поля ввода прозрачны: значение видно на месте заглушки. */
.bind__input {
  -webkit-appearance: none;
  appearance: none;
  position: absolute;
  left: 0;
  top: 0;
  padding: 0;
  border: 0;
  background: none;
  font-family: var(--font-number);
  font-weight: 400;
  font-size: calc(15 * var(--u));
  line-height: 1;
  letter-spacing: .1em;
  color: #484848;
  caret-color: #484848;
}

.bind__input:focus { outline: none; }

/* Номер занимает всю ширину прорези над точками. */
.bind__input--number {
  left: calc(20 * var(--u));
  top: calc(14 * var(--u));
  width: calc(230 * var(--u));
  height: calc(20 * var(--u));
}

.bind__input--cvv,
.bind__input--expiry {
  width: 100%;
  height: calc(18 * var(--u));
}

/* Код скрываем точками того же кегля, что и цифры: браузерный password
   рисует их крупнее и ломает строку. */
.bind__input--cvv {
  -webkit-text-security: disc;
  letter-spacing: .12em;
}

/* Пока поле пустое, под ним видно заглушку из точек. */
.bind__input:placeholder-shown { color: transparent; }

/* Кнопка «Скан» в правом нижнем углу карты. */
.bind__scan {
  position: absolute;
  right: calc(14 * var(--u));
  bottom: calc(16 * var(--u));
  height: calc(40 * var(--u));
  padding: 0 calc(13 * var(--u));
  display: flex;
  justify-content: center;
  align-items: center;
  gap: calc(5 * var(--u));
  border: calc(1 * var(--u)) solid transparent;
  border-radius: calc(15 * var(--u));
  background-origin: border-box;
  background-clip: padding-box, border-box;
  /* Белая кнопка с серым отливом от верхнего края и градиентной каймой. */
  background-image:
    radial-gradient(circle at 50% 4%,
      rgba(255, 255, 255, .99) 22%, rgba(226, 226, 226, .95) 42%, rgba(200, 200, 200, .95) 56%),
    linear-gradient(180deg, rgba(0, 0, 0, .1) 0%, rgba(0, 0, 0, .3) 100%);
  box-shadow: 0 calc(9 * var(--u)) calc(6 * var(--u)) calc(-6 * var(--u)) rgba(9, 9, 9, .22);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(18 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--ink);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.bind__scan:active { transform: scale(.96); }

.bind__scan-icon {
  flex: 0 0 auto;
  width: calc(18 * var(--u));
  height: calc(14 * var(--u));
  background: url("/app/assets/icons/bind-scan.svg") no-repeat center / contain;
}

/* ---------- Другие способы оплаты ---------- */
.bind__ways {
  display: flex;
  justify-content: center;
  gap: calc(10 * var(--u));
  margin: calc(18 * var(--u)) 0 0;
}

/* Кнопка — цельная картинка во всю площадь, как .paym__alt в окне карты. */
.bind__way {
  width: calc(100 * var(--u));
  height: calc(40 * var(--u));
  padding: 0;
  border: 0;
  background-repeat: no-repeat;
  background-position: center;
  background-size: 100% 100%;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.bind__way:active { transform: scale(.96); }

.bind__way--sbp    { background-image: url("/app/assets/icons/pay-sbp.png"); }
.bind__way--crypto { background-image: url("/app/assets/icons/pay-crypto.png"); }
.bind__way--stars  { background-image: url("/app/assets/icons/pay-stars.png"); }

/* Подпись «Данные шифруются и защищены». */
.bind__note {
  margin: calc(16 * var(--u)) 0 0;
  text-align: center;
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(14 * var(--u));
  line-height: 1;
  letter-spacing: -.0286em;
  color: rgba(0, 0, 0, .3);
}

/* Чёрная кнопка «Привязать» 362x85. */
.bind__submit {
  display: block;
  width: calc(362 * var(--u));
  height: calc(85 * var(--u));
  margin: calc(14 * var(--u)) auto 0;
  padding: 0;
  border: 0;
  border-radius: calc(50 * var(--u));
  background: var(--ink);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(26 * var(--u));
  line-height: 1;
  color: var(--paper);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease, opacity .18s ease;
}

.bind__submit:active { transform: scale(.99); }

/* Пока карта не заполнена — кнопка неактивна. */
.bind__submit:disabled {
  opacity: .35;
  cursor: default;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .bind,
  .bind-scrim,
  .bind__scan,
  .bind__way,
  .bind__submit { transition: none; }
}

/* ==================================================================
   Окно способа оплаты (макет 919:8445): открывается по тапу на карту
   ================================================================== */

.paym-scrim {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, .25);
  opacity: 0;
  visibility: hidden;
  z-index: 30;
  transition: opacity .22s ease, visibility .22s ease;
}

.paym-scrim.is-open {
  opacity: 1;
  visibility: visible;
}

/* Панель 400x405 в 20;366. */
.paym {
  position: absolute;
  left: 50%;
  margin-left: calc(-200 * var(--u));
  bottom: calc(20 * var(--u));
  width: calc(400 * var(--u));
  height: calc(405 * var(--u));
  border-radius: calc(60 * var(--u));
  background: var(--paper);
  transform: translateY(calc(24 * var(--u))) scale(.98);
  transition: transform .26s cubic-bezier(.2, .8, .3, 1);
  /* Стикер выходит за верхний край — обрезать его нельзя. */
  overflow: visible;
}

.paym-scrim.is-open .paym { transform: none; }

/* «Ручка» 50x6 в 194.85;379 кадра -> внутри панели 175;13. */
.paym__grip {
  position: absolute;
  left: calc(175 * var(--u));
  top: calc(13 * var(--u));
  width: calc(50 * var(--u));
  height: calc(6 * var(--u));
  padding: 0;
  border: 0;
  border-radius: calc(10 * var(--u));
  background: rgba(0, 0, 0, .1);
  box-shadow: 0 calc(4 * var(--u)) calc(6 * var(--u)) calc(-3 * var(--u)) rgba(0, 0, 0, .35);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* ---------- Стикер «Сделать основным способом» ----------
   Тот же компонент, что и в окне привязки карты: звезда сверху, подпись
   в три строки под ней. Панели у обоих окон одинаковые (400 шириной,
   прижаты к низу), поэтому координаты совпадают один в один. */
.paym__primary {
  position: absolute;
  left: calc(252 * var(--u));
  top: calc(-65 * var(--u));
  z-index: 2;
  width: calc(126 * var(--u));
  height: calc(110 * var(--u));
  padding: 0;
  border: 0;
  background: none;
  /* Наклон: в выгрузке Figma поворота нет, но габарит группы 104.12x81.01
     с дробными сторонами выдаёт повёрнутый блок — прямой он был бы
     примерно 96x73, лишнее и набегает от наклона. */
  transform: rotate(6deg);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.paym__primary:active { transform: rotate(-9deg) scale(.96); }

/* Белая звезда-галочка 41x41 (Star 23 + Star 24 из макета). */
.paym__primary-star {
  position: absolute;
  left: calc(45 * var(--u));
  top: 0;
  width: calc(41 * var(--u));
  height: calc(41 * var(--u));
  background: url("/app/assets/icons/bind-star-empty.svg") no-repeat center / contain;
  filter: drop-shadow(0 calc(1 * var(--u)) calc(4 * var(--u)) rgba(0, 0, 0, .15));
  transition: filter .15s ease;
}

/* Выбранный способ — розовая звезда с галочкой. Белый кант рисуем
   тенями без размытия: по фигурному краю иначе выходит свечение. */
.paym__primary[aria-checked="true"] .paym__primary-star {
  background-image: url("/app/assets/icons/friends-check-star.svg");
  filter:
    drop-shadow(calc(2 * var(--u)) 0 0 #fff)
    drop-shadow(calc(-2 * var(--u)) 0 0 #fff)
    drop-shadow(0 calc(2 * var(--u)) 0 #fff)
    drop-shadow(0 calc(-2 * var(--u)) 0 #fff)
    drop-shadow(0 calc(1 * var(--u)) calc(4 * var(--u)) rgba(0, 0, 0, .15));
}

/* Подпись в три строки, белая обводка отделяет её от фона. */
.paym__primary-text {
  position: absolute;
  left: 0;
  top: calc(36 * var(--u));
  width: 100%;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(16 * var(--u));
  line-height: .9;
  letter-spacing: -.02em;
  color: var(--ink);
  -webkit-text-stroke: calc(10 * var(--u)) #fff;
  paint-order: stroke fill;
}

/* Карта 352x149 в 44;399 кадра -> внутри панели 24;33. */
.paym__card {
  position: absolute;
  left: calc(24 * var(--u));
  top: calc(33 * var(--u));
}

/* «Или оплатите через»: 124x10 в 158;564 -> 138;198. */
.paym__or {
  position: absolute;
  left: 0;
  top: calc(194 * var(--u));
  width: 100%;
  margin: 0;
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(14 * var(--u));
  line-height: 1;
  letter-spacing: -.0286em;
  text-align: center;
  color: rgba(0, 0, 0, .3);
}

/* Ряд кнопок: 40 высотой в 584 -> 218 внутри панели. */
.paym__alts {
  position: absolute;
  left: calc(30 * var(--u));
  top: calc(218 * var(--u));
  width: calc(340 * var(--u));
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.paym__alt {
  flex: 0 0 auto;
  width: calc(105 * var(--u));
  height: calc(40 * var(--u));
  padding: 0;
  border: 0;
  background-repeat: no-repeat;
  background-position: center;
  /* Картинка тянется на всю ширину кнопки, а не вписывается с полями. */
  background-size: 100% 100%;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.paym__alt:active { transform: scale(.96); }

.paym__alt--sbp {
  background-image: url("/app/assets/icons/pay-sbp.png");
}

.paym__alt--crypto {
  background-image: url("/app/assets/icons/pay-crypto.png");
}

.paym__alt--stars {
  background-image: url("/app/assets/icons/pay-stars.png");
}

/* «Данные шифруются и защищены»: 211x10 в 115;647 -> 95;281. */
.paym__note {
  position: absolute;
  left: 0;
  top: calc(277 * var(--u));
  width: 100%;
  margin: 0;
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(14 * var(--u));
  line-height: 1;
  letter-spacing: -.0286em;
  text-align: center;
  color: rgba(0, 0, 0, .3);
}

/* Кнопка «Привязать»: 362x85 в 38.85;668 -> 18.85;302. */
.paym__submit {
  position: absolute;
  left: calc(19 * var(--u));
  top: calc(302 * var(--u));
  width: calc(362 * var(--u));
  height: calc(85 * var(--u));
  padding: 0;
  border: 0;
  border-radius: calc(50 * var(--u));
  background: #000;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(28 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--paper);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .18s ease;
}

.paym__submit:active { transform: scale(.99); }

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

  .paym-scrim,
  .paym,
  .paym__primary,
  .paym__primary-star,
  .paym__alt,
  .paym__submit {
    transition: none;
  }
}

/* ==================================================================
   Окна-подтверждения профиля: выход, удаление, изменение данных,
   удаление карты и отмена подписки. Действие подтверждается
   слайдером «смахните», а не обычной кнопкой.
   ================================================================== */

/* Затемнение */
.ask-scrim {
  position: fixed;
  left: 50%;
  top: 0;
  width: var(--stage);
  margin-left: calc(var(--stage) / -2);
  height: 100%;
  background: rgba(0, 0, 0, .25);
  opacity: 0;
  visibility: hidden;
  z-index: 40;
  transition: opacity .22s ease, visibility .22s ease;
}

/* Удаление карты и профиля — красное свечение снизу (макет 919:9239).
   В макете это отдельный слой 440x876 с градиентом и blur(50px): красный
   копится у нижнего края, за панелью окна, а верх экрана остаётся чистым.
   Поэтому не плоская заливка, а градиент — плоская мыла весь экран. */
.ask-scrim[data-ask="card"],
.ask-scrim[data-ask="device"],
.ask-scrim[data-ask="wipe"],
.ask-scrim[data-ask="logout"],
.ask-scrim[data-ask="cancel"] {
  background:
    linear-gradient(180deg, rgba(255, 30, 30, 0) 0%, rgba(248, 60, 60, .6) 100%),
    rgba(0, 0, 0, .25);
}

.ask-scrim.is-open {
  opacity: 1;
  visibility: visible;
}

/* Панель окна */
.ask {
  position: absolute;
  /* По центру по горизонтали, как .dev: жёсткий left уводил окно влево,
     когда экран шире 440. */
  left: 50%;
  margin-left: calc(-200 * var(--u));
  /* Прижато к низу экрана, как остальные окна (.dev, .bind). */
  bottom: calc(20 * var(--u));
  width: calc(400 * var(--u));
  border-radius: calc(60 * var(--u));
  background: var(--paper);
  transform: translateY(calc(24 * var(--u))) scale(.98);
  transition: transform .26s cubic-bezier(.2, .8, .3, 1);
}

.ask-scrim.is-open .ask {
  transform: none;
}

/* Окно с аватаром: выход, удаление профиля, изменение данных */
.ask--user {
  height: calc(492 * var(--u));
}

/* ---------- Окно-подтверждение с аватаром (.ask--confirm) ----------
   Общий вид для выхода из профиля (макет 919:10035) и удаления профиля:
   различаются только подписи, поэтому это один компонент, а тексты
   приходят из разметки и data-done.

   Панель 400x233 в 20;538 на холсте 440x956 — низ в 185 от нижнего края.
   Аватар и наклейка выходят за верхнюю границу, поэтому overflow видимый. */
.ask--confirm {
  height: calc(233 * var(--u));
  overflow: visible;
}

/* Окно с картой и окно отмены подписки */
.ask--card {
  height: calc(300 * var(--u));
}

.ask--device {
  /* Высота под карточку устройства, подсказку в две строки и слайдер:
     на 290 подсказка ложилась прямо на дорожку. */
  height: calc(330 * var(--u));
}

/* Карточка устройства в окне подтверждения: значок, имя и дата —
   тем же порядком, что в списке, чтобы узнавалось с одного взгляда. */
.ask__device {
  position: absolute;
  left: 0;
  /* Заголовок висит над кромкой окна, поэтому карточка начинается сразу
     под верхним краем, как карта в окне удаления способа оплаты. */
  top: calc(30 * var(--u));
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(8 * var(--u));
}

.ask__device-icon {
  width: calc(88 * var(--u));
  height: calc(88 * var(--u));
  border-radius: calc(24 * var(--u));
  background: no-repeat center / contain,
    linear-gradient(180deg, rgba(0, 0, 0, .06) 0%, rgba(0, 0, 0, .12) 100%);
}

.ask__device-name {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(20 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--ink);
}

.ask__device-added {
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(13 * var(--u));
  line-height: 1;
  color: rgba(0, 0, 0, .4);
}

/* Подсказка стоит под карточкой, а не на месте из окна отмены. */
.ask--device .ask__hint {
  top: calc(176 * var(--u));
  /* Уже полной ширины: иначе строка «устройство отключится от VPN»
     не переносится там, где задумано. */
  left: calc(40 * var(--u));
  width: calc(320 * var(--u));
}

.ask--cancel {
  height: calc(250 * var(--u));
}

/* «Ручка» сверху — закрывает окно */
.ask__grip {
  position: absolute;
  left: calc(175 * var(--u));
  top: calc(13 * var(--u));
  width: calc(50 * var(--u));
  height: calc(6 * var(--u));
  padding: 0;
  border: calc(.8 * var(--u)) solid transparent;
  border-radius: calc(10 * var(--u));
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    linear-gradient(rgba(0,0,0,.1), rgba(0,0,0,.1)),
    linear-gradient(180deg, rgba(0,0,0,.05) 0%, rgba(0,0,0,.2) 100%);
  box-shadow: 0 calc(4 * var(--u)) calc(6 * var(--u)) calc(-3 * var(--u)) rgba(0,0,0,.35);
}

/* Заголовок окна («Точно удаляем?», «Точно отменяем?») */
.ask__title {
  position: absolute;
  left: 0;
  top: calc(34 * var(--u));
  width: 100%;
  margin: 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(26 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  text-align: center;
  color: var(--ink);
}

/* «Точно удаляем?» и «Точно отменяем?»: в макете это готовые надписи
   серыми буквами, поэтому подставляем их картинками, а текст оставляем
   для скринридеров. Обе сидят над верхней кромкой окна, а не внутри. */
.ask-scrim[data-ask="card"] .ask__title,
.ask-scrim[data-ask="device"] .ask__title,
.ask-scrim[data-ask="cancel"] .ask__title {
  text-indent: -9999px;
  overflow: hidden;
}

/* Надпись удаления — 285x54. */
.ask-scrim[data-ask="card"] .ask__title,
.ask-scrim[data-ask="device"] .ask__title {
  top: calc(-27 * var(--u));
  height: calc(54 * var(--u));
  background: url("/app/assets/icons/sure_delete.png")
    no-repeat center / calc(285 * var(--u)) auto;
}

/* Надпись отмены — 306x49, чуть шире и ниже предыдущей. */
.ask-scrim[data-ask="cancel"] .ask__title {
  top: calc(-24.5 * var(--u));
  height: calc(49 * var(--u));
  background: url("/app/assets/icons/sure_otmena.png")
    no-repeat center / calc(306 * var(--u)) auto;
}

/* Наклейка над окном («Выход из профиля», «Удаление профиля») */
.ask__sticker {
  position: absolute;
  left: 50%;
  top: calc(-14 * var(--u));
  transform: translateX(-50%) rotate(-4deg);
  padding: calc(6 * var(--u)) calc(14 * var(--u));
  border-radius: calc(12 * var(--u));
  background: var(--ink);
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(16 * var(--u));
  line-height: 1.05;
  letter-spacing: -.02em;
  text-align: center;
  color: var(--paper);
  white-space: nowrap;
}

/* Красная плашка — только у старого вида наклейки: в .ask--confirm
   наклейка вообще без подложки. */
.ask:not(.ask--confirm) .ask__sticker--wipe { background: #BF2121; }

/* Наклейка окна-подтверждения (макет 919:10426): не плашка, а чёрный
   текст с белой обводкой 5px — она и отделяет его от фона. Стоит справа
   сверху, наполовину выходя за верхний край панели (297;515 при панели в
   20;538 → 277;-23 от её угла).

   Наклон: в выгрузке Figma поворота нет, но габарит блока 121.02x37.88
   с дробными сторонами выдаёт повёрнутый текст — две строки 16px при
   line-height .9 занимают ~29px, лишняя высота и набегает от наклона. */
.ask--confirm .ask__sticker {
  left: calc(277 * var(--u));
  top: calc(-15 * var(--u));
  width: calc(121 * var(--u));
  padding: 0;
  border-radius: 0;
  background: none;
  transform: rotate(7deg);
  font-size: calc(16 * var(--u));
  line-height: .9;
  color: var(--ink);
  /* Обводка рисуется под заливкой, иначе она съедает тонкие штрихи. */
  -webkit-text-stroke: calc(5 * var(--u)) var(--paper);
  paint-order: stroke fill;
  filter: drop-shadow(0 calc(4 * var(--u)) calc(14 * var(--u)) rgba(0, 0, 0, .14));
}

/* Значок в углу аватара */
.ask__badge {
  position: absolute;
  left: calc(232 * var(--u));
  top: calc(150 * var(--u));
  z-index: 1;
  width: calc(52 * var(--u));
  height: calc(52 * var(--u));
  border-radius: 50%;
  background: var(--paper) no-repeat center / calc(24 * var(--u));
  box-shadow: 0 calc(4 * var(--u)) calc(10 * var(--u)) calc(-4 * var(--u)) rgba(0,0,0,.3);
}

/* В окне выхода значок — пустой кружок с тонкой обводкой в левом верхнем
   углу панели (макет 919:10423, 47x47 в 43;560 → 23;22 от угла панели). */
.ask--confirm .ask__badge {
  left: calc(23 * var(--u));
  top: calc(22 * var(--u));
  width: calc(47 * var(--u));
  height: calc(47 * var(--u));
  background: none no-repeat center;
  border: calc(1 * var(--u)) solid rgba(0, 0, 0, .2);
  box-shadow: none;
}

/* Значки внутри кружка: иконка 22x21, поэтому размер задаём свой.
   Селектор с .ask--confirm — иначе правило выше перебивает фон. */
.ask__badge--exit,
.ask--confirm .ask__badge--exit {
  background-image: url("/app/assets/icons/ask-exit.svg");
  background-size: calc(22 * var(--u)) calc(21 * var(--u));
}

.ask__badge--pen,
.ask--confirm .ask__badge--pen {
  background-image: url("/app/assets/icons/ask-pen.svg");
  background-size: calc(19 * var(--u)) calc(19 * var(--u));
}

/* Удаление профиля — в кружке корзина вместо стрелки выхода (26x28). */
.ask__badge--trash,
.ask--confirm .ask__badge--trash {
  background-image: url("/app/assets/icons/ask-trash.svg");
  background-size: calc(26 * var(--u)) calc(28 * var(--u));
}

/* Аватар пользователя */
.ask__avatar {
  position: absolute;
  left: calc(125 * var(--u));
  top: calc(64 * var(--u));
  width: calc(150 * var(--u));
  height: calc(150 * var(--u));
  /* Сбросы нужны, потому что в окне правки это <button>, а не span:
     иначе браузер добавит свою рамку, фон и padding. */
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(0, 0, 0, .12);
  background-size: cover;
  background-position: center;
  font: inherit;
  -webkit-tap-highlight-color: transparent;
}

/* Кликабельный только в окне правки — там он меняет фото. */
.ask--edit .ask__avatar {
  cursor: pointer;
}

/* Аватар в окне выхода (макет 919:10401): 126x126 в 157;465 — то есть
   137;-73 от угла панели, поэтому он наполовину висит над ней. Белая
   обводка и мягкая тень снизу отделяют его от фона. */
.ask--confirm .ask__avatar {
  left: calc(137 * var(--u));
  top: calc(-73 * var(--u));
  width: calc(126 * var(--u));
  height: calc(126 * var(--u));
  border: calc(.9 * var(--u)) solid rgba(255, 255, 255, .5);
  box-shadow: 0 calc(12 * var(--u)) calc(10 * var(--u)) calc(-8 * var(--u)) rgba(128, 128, 128, .3);
}

/* Белое свечение по краю: в макете это отдельный слой с радиальным
   градиентом поверх фотографии. */
.ask--confirm .ask__avatar::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%,
    rgba(255, 255, 255, 0) 56%, rgba(255, 255, 255, 1) 100%);
  pointer-events: none;
}

/* У окна изменения данных аватар приглушён и размыт под карандаш.
   Размытие даёт backdrop-filter на затемняющем слое, а не filter на
   самом элементе: иначе вместе с фотографией размылись бы и карандаш,
   и белая обводка. */
/* Затемнение на ::before, а не ::after: ::after занят буквой имени
   (.avatar--letter), и у пользователя без фото слой перекрывал её —
   в кружке оставался пустой серый круг с карандашом. */
.ask__avatar--dim::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: 50%;
  background: rgba(0, 0, 0, .35);
  -webkit-backdrop-filter: blur(calc(6 * var(--u)));
  backdrop-filter: blur(calc(2 * var(--u)));
}

.ask__avatar-pen {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 1;
  width: calc(44 * var(--u));
  height: calc(44 * var(--u));
  transform: translate(-50%, -50%);
  background: url("/app/assets/icons/pen.svg") no-repeat center / contain;
  filter: brightness(0) invert(1);
}

/* Имя и ник под аватаром */
.ask__name {
  position: absolute;
  left: 0;
  top: calc(232 * var(--u));
  width: 100%;
  margin: 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(28 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  text-align: center;
  color: var(--ink);
}

.ask__nick {
  position: absolute;
  left: 0;
  top: calc(268 * var(--u));
  width: 100%;
  margin: 0;
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(16 * var(--u));
  line-height: 1;
  letter-spacing: -.0286em;
  text-align: center;
  color: rgba(0, 0, 0, .3);
}

/* Имя и ник в окне выхода (макет 919:10399 и 919:10400). Имя набрано
   цифровым начертанием Asgard Number 25px, ник — 14px в 40% чёрного.
   Координаты y считаются от верха панели: 611-538 и 641-538. */
.ask--confirm .ask__name {
  top: calc(73 * var(--u));
  font-family: var(--font-number);
  font-weight: 400;
  font-size: calc(25 * var(--u));
}

.ask--confirm .ask__nick {
  top: calc(103 * var(--u));
  font-size: calc(14 * var(--u));
  color: rgba(0, 0, 0, .4);
}

/* ---------- Окно изменения данных (макет 919:10430) ----------
   Панель ниже остальных окон с аватаром: 400x233 вместо 492.
   Имя и почта — не плашки, а обычный текст по центру, как в макете:
   поля остаются полями (их правят), но выглядят как подписи. */
.ask--edit {
  height: calc(233 * var(--u));
}

.ask__input {
  position: absolute;
  left: 0;
  width: 100%;
  padding: 0;
  border: none;
  background: none;
  line-height: 1;
  text-align: center;
  color: rgba(0, 0, 0, .3);
}

.ask__input:focus { outline: none; }
.ask__input::placeholder { color: rgba(0, 0, 0, .3); }

/* Имя: Asgard Number 25px — то же начертание, что и в окне выхода. */
.ask__input--name {
  top: calc(73 * var(--u));
  height: calc(25 * var(--u));
  font-family: var(--font-number);
  font-weight: 400;
  font-size: calc(25 * var(--u));
  letter-spacing: -.02em;
}

/* Почта: 14px обычным текстовым начертанием. */
.ask__input--mail {
  top: calc(100 * var(--u));
  height: calc(18 * var(--u));
  font-family: var(--font-text);
  font-weight: 400;
  font-size: calc(14 * var(--u));
  letter-spacing: -.0286em;
}

/* Аватар под карандашом приглушён сильнее, чем в окне выхода: в макете
   фотография уходит в тёмно-серый, иначе белый карандаш на ней теряется.
   Белое свечение по краю от .ask--confirm тут лишнее — оно высветляет
   как раз тот край, который должен быть притемнён. */
/* ::before тут несёт затемнение (см. .ask__avatar--dim::before),
   гасить его больше нельзя. Белое свечение от .ask--confirm
   перебиваем фоном выше. */

/* В окне правки буква имени не нужна: кружок — это кнопка «выбрать
   фото», и смысл несёт карандаш по центру. Буква вставала бы ровно
   под него и читалась бы как грязь на иконке. */
.ask--edit .ask__avatar.avatar--letter::after { content: none; }

.ask--edit .ask__avatar--dim::before {
  background: rgba(0, 0, 0, .45);
}

/* Наклейка «Измените данные» стоит чуть правее и выше, чем в окне
   выхода (306.54;525.84 при панели в 20;538 → 286.54;-12.16). */
.ask--edit .ask__sticker {
  left: calc(280 * var(--u));
  top: calc(-12 * var(--u));
  width: calc(100 * var(--u));
}

/* Кнопка «Готово»: 362x85 в 19;132 от угла панели, чёрная, r50. */
.ask--edit .ask__done {
  position: absolute;
  left: calc(19 * var(--u));
  top: calc(132 * var(--u));
  width: calc(362 * var(--u));
  height: calc(85 * var(--u));
  padding: 0;
  border: none;
  border-radius: calc(50 * var(--u));
  background: #000;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(28 * var(--u));
  line-height: 1;
  color: #fff;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* Тексты окна отмены подписки */
.ask__note,
.ask__hint {
  position: absolute;
  left: 0;
  width: 100%;
  margin: 0;
  font-family: var(--font-text);
  font-weight: 400;
  line-height: 1.2;
  text-align: center;
  color: rgba(0, 0, 0, .4);
}

/* Окно отмены на 230px: над слайдером (он начинается со 121) остаётся
   мало места, поэтому строки стоят плотно — «Доступ сохранится до»,
   дата и подсказка укладываются в 12..118. */
.ask__note {
  top: calc(17 * var(--u));
  font-size: calc(16 * var(--u));
}

.ask__date {
  position: absolute;
  left: 0;
  top: calc(41 * var(--u));
  width: 100%;
  margin: 0;
  font-family: var(--font-number);
  font-weight: 400;
  font-size: calc(34 * var(--u));
  line-height: 1;
  letter-spacing: -.03em;
  text-align: center;
  color: var(--ink);
}

.ask__hint {
  top: calc(87 * var(--u));
  font-size: calc(14 * var(--u));
}

/* Карта, которую удаляем */
.ask__card {
  position: absolute;
  left: calc(25 * var(--u));
  top: calc(25 * var(--u));
  width: calc(312 * var(--u));
  height: calc(141 * var(--u));
}

/* ---------- Слайдер «смахните» ---------- */
.swipe {
  position: absolute;
  /* Тянем шарик — выделять текст при этом не нужно. */
  -webkit-user-select: none;
  user-select: none;
  left: calc(19 * var(--u));
  bottom: calc(24 * var(--u));
  width: calc(362 * var(--u));
  height: calc(85 * var(--u));
  border-radius: calc(50 * var(--u));
  background: rgba(0, 0, 0, .1);
  overflow: hidden;
  -webkit-tap-highlight-color: transparent;
  touch-action: none;
}

/* Подпись по центру дорожки */
.swipe__label {
  position: absolute;
  left: calc(88 * var(--u));
  top: 50%;
  
  transform: translateY(-50%);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(20 * var(--u));
  line-height: 1;
  text-align: left;
  color: rgba(0, 0, 0, .2);
  pointer-events: none;
}

/* Значок у правого края — куда тянуть */
.swipe__icon {
  position: absolute;
  right: calc(26 * var(--u));
  top: 50%;
  width: calc(30 * var(--u));
  height: calc(30 * var(--u));
  transform: translateY(-50%);
  background: no-repeat center / contain;
  opacity: .5;
  pointer-events: none;
}

/* Стрелка после слова «Смахните»: отдельная картинка 20x12 */
.swipe__arrow {
  display: inline-block;
  width: calc(20 * var(--u));
  height: calc(12 * var(--u));
  margin-left: calc(7 * var(--u));
  vertical-align: middle;
  background: url("/app/assets/icons/swipe-arrow.svg") no-repeat center / contain;
}

/* В макете значка справа нет — форму задаёт сама подпись. */
.swipe__icon { display: none; }

.swipe__icon--exit  { background-image: url("/app/assets/icons/profile-exit.svg"); }
.swipe__icon--trash { background-image: url("/app/assets/icons/profile-trash.svg"); }

/* ---------- Промежуточный этап свайпа (макет 919:9637) ----------
   Пока тянут, за шариком тянется красный след, шарик наливается красным,
   а подпись «Смахните» сменяется на «Удаляем...». Прогресс приходит из
   JS переменной --swipe-p (0..1). */

/* След за шариком: в макете это прямоугольник #FF3B30 с blur(40px),
   скруглённый слева. Ширину гоним от прогресса. */
.swipe__trail {
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  /* 102px следа в макете при шарике, ушедшем на ~119px: держим след
     чуть короче центра шарика, чтобы край размытия жил под ним. */
  width: calc((8 + 61 + (285 - 8) * var(--swipe-p, 0)) * var(--u));
  border-radius: calc(42 * var(--u)) 0 0 calc(42 * var(--u));
  background: #FF3B30;
  /* Размытие в макете (40px) — на слое поверх фона; у нас след лежит
     внутри дорожки, и такой радиус размазывал его в бледное пятно.
     Берём вдвое меньше: мягкий край остаётся, цвет держится. */
  filter: blur(calc(20 * var(--u)));
  /* Цвет набирается быстрее хода — к середине след уже плотный, как в макете. */
  opacity: calc(var(--swipe-p, 0) * 1.8);
  pointer-events: none;
}

/* Подпись хода: лежит там же, где обычная, и проявляется вместе со следом */
.swipe__progress {
  position: absolute;
  left: calc(88 * var(--u));
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(20 * var(--u));
  line-height: 1;
  text-align: left;
  color: rgba(0, 0, 0, .3);
  opacity: 0;
  pointer-events: none;
}

.swipe__progress::after { content: attr(data-text); }

/* Как только тронули — обычная подпись гаснет, подпись хода проявляется. */
.swipe.is-moving .swipe__label,
.swipe.is-moving .swipe__arrow { opacity: 0; }
.swipe.is-moving .swipe__progress { opacity: 1; }

/* Шарик наливается красным по мере хода (радиальная заливка из макета) */
.swipe.is-moving .swipe__knob::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  opacity: calc(var(--swipe-p, 0) * 1.6);
  background: radial-gradient(circle at 50% 50%,
    rgba(255, 59, 48, 0) 0%,
    rgba(255, 59, 48, .3) 63%,
    rgba(255, 59, 48, .6) 100%);
}

/* Свайп доведён до конца: дорожка краснеет и показывает результат.
   Подпись подставляется из data-done, шарик уезжает к правому краю. */
.swipe.is-done {
  background: #FF3B30;
  transition: background .2s ease;
}

.swipe.is-done .swipe__label,
.swipe.is-done .swipe__arrow,
.swipe.is-done .swipe__icon,
.swipe.is-done .swipe__progress,
.swipe.is-done .swipe__trail {
  opacity: 0;
}

/* При промежуточном этапе (is-moving) иконка корзины исчезает */
.swipe.is-moving .swipe__knob {
  background-image: none;
}

/* На финальном этапе красноту даёт сама дорожка — подсветка шарика лишняя. */
.swipe.is-done .swipe__knob::after { opacity: 0; }

.swipe__done {
  position: absolute;
  left: 0;
  top: 50%;
  width: 100%;
  transform: translateY(-50%);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(21 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  text-align: center;
  color: rgba(0, 0, 0, .3);
  opacity: 0;
  transition: opacity .2s ease;
  pointer-events: none;
}

.swipe.is-done .swipe__done { opacity: 1; }

/* Значок в шарике меняется на корзину — действие произошло. */
.swipe.is-done .swipe__knob {
  /* Макет 919:12756: 77x77 в 281;4 от края дорожки. */
  left: calc(281 * var(--u));
  top: calc(4 * var(--u));
  width: calc(77 * var(--u));
  height: calc(77 * var(--u));
  background: #fff url("/app/assets/icons/swipe-done-knob.svg") no-repeat center / calc(71 * var(--u));
  box-shadow:
    inset calc(2.5 * var(--u)) calc(2.5 * var(--u)) calc(6.5 * var(--u)) calc(-2.5 * var(--u)) rgba(255,255,255,.7),
    inset calc(-2.5 * var(--u)) calc(-3.25 * var(--u)) calc(7.5 * var(--u)) calc(-2.5 * var(--u)) #000,
    inset calc(1.25 * var(--u)) calc(1.25 * var(--u)) calc(20 * var(--u)) calc(-2.5 * var(--u)) #fff,
    inset calc(-8 * var(--u)) calc(-9.25 * var(--u)) calc(10 * var(--u)) calc(-2.5 * var(--u)) rgba(0,0,0,.2);
}

/* Шарик, который тянут */
.swipe__knob {
  position: absolute;
  left: calc(8 * var(--u));
  top: calc(8 * var(--u));
  width: calc(69 * var(--u));
  height: calc(69 * var(--u));
  border-radius: 50%;
  background: var(--paper);
  box-shadow:
    0 calc(4 * var(--u)) calc(10 * var(--u)) calc(-4 * var(--u)) rgba(0,0,0,.25),
    0 0 0 calc(1 * var(--u)) rgba(0,0,0,.06);
  cursor: grab;
  transition: left .22s cubic-bezier(.2, .8, .3, 1);
}

/* Пока тянут — за пальцем без задержки */
.swipe.is-dragging .swipe__knob {
  cursor: grabbing;
  transition: none;
}

/* ---------- Слайдер в окне выхода (макет 919:10414) ----------
   Дорожка стоит в 39;670 при панели в 20;538 — 19 от левого края и 16 от
   низа. Шарик крупнее общего: 77x77 в 5;4, со стеклянным набором теней. */
.ask--confirm .swipe {
  bottom: calc(16 * var(--u));
}

/* Цель у правого края (макет 919:11594): гнездо 77x77 в 285;4, внутри
   кольцо 71x71 с градиентной обводкой, а в кольце — значок выхода 38x38.
   Само гнездо без заливки, видно только кольцо. */
.ask--confirm .swipe::after {
  content: "";
  position: absolute;
  left: calc(285 * var(--u));
  top: calc(7 * var(--u));
  width: calc(71 * var(--u));
  height: calc(71 * var(--u));
  border-radius: 50%;
  /* Обводка-градиент снизу вверх: 25% чёрного у низа, 5% у верха.
     Внутри кольца пусто, поэтому градиент даёт не border, а вторая
     заливка в border-box, из которой padding-box вырезает середину. */
  border: calc(1.42 * var(--u)) solid transparent;
  background:
    linear-gradient(0deg, rgba(0, 0, 0, .25) 0%, rgba(0, 0, 0, .05) 100%) border-box;
  -webkit-mask:
    linear-gradient(#000 0 0) padding-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask:
    linear-gradient(#000 0 0) padding-box,
    linear-gradient(#000 0 0);
  mask-composite: exclude;
  pointer-events: none;
}

/* Значок выхода внутри кольца (38x38 по центру гнезда 77x77 в 285;4). */
.ask--confirm .swipe__exit {
  position: absolute;
  left: calc(304.5 * var(--u));
  top: calc(23.5 * var(--u));
  width: calc(38 * var(--u));
  height: calc(38 * var(--u));
  background: url("/app/assets/icons/swipe-exit.svg") no-repeat center / contain;
  pointer-events: none;
}

/* В окне удаления профиля на конце дорожки стоит корзина, а не выход.
   Картинка уже содержит кольцо целиком (77x77), поэтому отдельное
   кольцо гасим, а значок растягиваем на всё гнездо. */
.ask-scrim[data-ask="wipe"] .swipe::after { content: none; }

/* Гнездо на конце дорожки в окне удаления карты: кольцо с корзиной
   уже целиком в картинке (77x77 в 285;4). */
.ask-scrim[data-ask="card"] .swipe::after {
  content: "";
  position: absolute;
  left: calc(285 * var(--u));
  top: calc(4 * var(--u));
  width: calc(77 * var(--u));
  height: calc(77 * var(--u));
  background: url("/app/assets/icons/swipe-target-trash.svg") no-repeat center / contain;
  pointer-events: none;
}

.ask-scrim[data-ask="card"] .swipe.is-done::after { content: none; }

/* Гнездо на конце дорожки в окне отмены подписки: кольцо со значком
   выхода целиком в картинке (77x77 в 285;4), как и в окне удаления. */
.ask-scrim[data-ask="cancel"] .swipe::after {
  content: "";
  position: absolute;
  left: calc(285 * var(--u));
  top: calc(4 * var(--u));
  width: calc(77 * var(--u));
  height: calc(77 * var(--u));
  background: url("/app/assets/icons/swipe-target-exit.svg") no-repeat center / contain;
  pointer-events: none;
}

.ask-scrim[data-ask="cancel"] .swipe.is-done::after { content: none; }

.ask-scrim[data-ask="wipe"] .swipe__exit {
  left: calc(285 * var(--u));
  top: calc(4 * var(--u));
  width: calc(77 * var(--u));
  height: calc(77 * var(--u));
  background-image: url("/app/assets/icons/swipe-trash-ring.svg");
}

.ask--confirm .swipe__knob {
  left: calc(5 * var(--u));
  top: calc(4 * var(--u));
  width: calc(77 * var(--u));
  height: calc(77 * var(--u));
  box-shadow:
    0 calc(8.57 * var(--u)) calc(12.24 * var(--u)) calc(-7.34 * var(--u)) rgba(0, 0, 0, .5),
    inset calc(3.06 * var(--u)) calc(3.06 * var(--u)) calc(20.19 * var(--u)) calc(-3.06 * var(--u)) #fff,
    inset calc(-5.51 * var(--u)) calc(-3.98 * var(--u)) calc(14.07 * var(--u)) calc(-3.06 * var(--u)) rgba(0, 0, 0, .2),
    inset calc(1.53 * var(--u)) calc(1.53 * var(--u)) calc(12.24 * var(--u)) calc(-3.06 * var(--u)) #fff,
    inset calc(-4.9 * var(--u)) calc(-3.98 * var(--u)) calc(12.24 * var(--u)) calc(-3.06 * var(--u)) rgba(0, 0, 0, .2);
}

.ask--confirm .swipe__label {
  left: calc(101 * var(--u));
  font-weight: 400;
  letter-spacing: 0;
}

/* В окне удаления профиля подпись длиннее — сдвигаем левее. */
.ask-scrim[data-ask="wipe"] .swipe__label {
  left: calc(93 * var(--u));
}

/* ---------- Конечный кадр (макет 919:10820) ----------
   Свайп доведён: дорожка сплошь красная, шарик доехал до правого края и
   стал прозрачным (в макете у него пустая заливка), по центру — итог в
   две строки. Текст берётся из разметки, поэтому кадр общий для выхода
   и удаления. */
.ask--confirm .swipe.is-done .swipe__knob {
  left: calc(285 * var(--u));
  top: calc(4 * var(--u));
  width: calc(77 * var(--u));
  height: calc(77 * var(--u));
  background: none;
  box-shadow: none;
}

/* Кружок-цель растворяется: его место занял сам шарик. */
.ask--confirm .swipe.is-done::after,
.ask--confirm .swipe.is-done .swipe__exit { opacity: 0; }

/* В конечном кадре значок слева опускается на 15px и заполняется
   (макет 919:11208: 47x47 уже в 43;575, внутри квадрат 31x31). Состояние
   живёт на дорожке, поэтому дотягиваемся до значка через :has() — класса
   на самой панели JS не ставит. */
.ask--confirm:has(.swipe.is-done) .ask__badge {
  top: calc(37 * var(--u));
  transition: top .2s ease;
}

.ask--confirm:has(.swipe.is-done) .ask__badge::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(31 * var(--u));
  height: calc(31 * var(--u));
  border-radius: calc(6 * var(--u));
  transform: translate(-50%, -50%);
  background: rgba(0, 0, 0, .2);
}

.ask--confirm .swipe__done {
  /* Подпись 149x34 в 107;25 — по центру дорожки, в две строки. */
  font-weight: 400;
  font-size: calc(20 * var(--u));
  line-height: 1.15;
  letter-spacing: 0;
}

/* Только для скринридеров */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

@media (prefers-reduced-motion: reduce) {
  .ask-scrim,
  .ask,
  .swipe__knob { transition: none; }
}

/* Лист выбора суммы пополнения (правка 12.10.2026).
   Пополнение переехало в мини-апп из бота, отдельного экрана под него
   в макете нет — показываем лист поверх баланса. Цвета и формы берём
   из существующих контролов: --ink/--paper, скруглённые пилюли. */
.topup-sheet {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(0, 0, 0, .45);
}

.topup-sheet__box {
  width: var(--stage);
  max-width: 100%;
  box-sizing: border-box;
  padding: calc(24 * var(--u)) calc(17 * var(--u))
    calc(24 * var(--u) + env(safe-area-inset-bottom, 0px));
  border-radius: calc(32 * var(--u)) calc(32 * var(--u)) 0 0;
  background: var(--paper, #fff);
}

.topup-sheet__title {
  margin: 0 0 calc(18 * var(--u));
  font-family: var(--font-display);
  font-size: calc(22 * var(--u));
  color: var(--ink, #000);
  text-align: center;
}

.topup-sheet__row {
  display: flex;
  flex-wrap: wrap;
  gap: calc(10 * var(--u));
  margin-bottom: calc(14 * var(--u));
}

.topup-sheet__amount {
  flex: 1 1 calc(45%);
  height: calc(64 * var(--u));
  border: 0;
  border-radius: calc(50 * var(--u));
  background: var(--ink, #000);
  color: var(--paper, #fff);
  font-family: var(--font-display);
  font-size: calc(20 * var(--u));
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.topup-sheet__cancel {
  width: 100%;
  height: calc(56 * var(--u));
  border: calc(2 * var(--u)) solid var(--ink, #000);
  border-radius: calc(50 * var(--u));
  background: transparent;
  color: var(--ink, #000);
  font-family: var(--font-text);
  font-size: calc(17 * var(--u));
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* ==================================================================
   Денежная реферальная программа (ТЗ 13.10.2026, п.6.2)
   Отдельного макета нет — собрано в стиле блоков экрана «Друзья»:
   те же шрифты, скругления и подписи под числами.
   ================================================================== */
.money {
  position: absolute;
  z-index: 3;
  left: calc(20 * var(--u));
  top: calc(590 * var(--u));
  width: calc(400 * var(--u));
  padding: calc(18 * var(--u)) calc(20 * var(--u));
  border-radius: calc(32 * var(--u));
  background: var(--paper);
  box-sizing: border-box;
}

.money[hidden],
.friends__faces[hidden] {
  display: none;
}

.money__row {
  display: flex;
  align-items: center;
  gap: calc(12 * var(--u));
}

.money__cell {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: calc(6 * var(--u));
  min-width: 0;
}

/* Числа — тем же шрифтом, что счётчики выше. */
.money__value {
  font-family: var(--font-number);
  font-weight: 400;
  font-size: calc(28 * var(--u));
  line-height: .9;
  letter-spacing: -.03em;
}

.money__note {
  font-size: calc(12 * var(--u));
  opacity: .55;
}

.money__history-open {
  display: block;
  width: 100%;
  margin-top: calc(14 * var(--u));
  padding: calc(6 * var(--u)) 0 0;
  background: none;
  border: 0;
  font-size: calc(13 * var(--u));
  text-decoration: underline;
  text-underline-offset: 3px;
  opacity: .7;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

/* Возврат с выплат на бонусы днями (правка 18.10.2026, Мария: «как
   сделать, чтобы дни начислились?»). Соседствует с «Историей», поэтому
   оформлена так же — ссылкой, а не второй крупной кнопкой: главное
   действие в этом блоке одно, «Вывести». */
.money__to-days {
  display: block;
  width: 100%;
  margin-top: calc(8 * var(--u));
  padding: calc(6 * var(--u)) 0 0;
  background: none;
  border: 0;
  font-size: calc(13 * var(--u));
  text-decoration: underline;
  text-underline-offset: 3px;
  opacity: .7;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

/* «Получать деньги вместо дней подписки»: ссылка на днях, под кружками друзей */
.friends__to-money {
  position: absolute;
  z-index: 3;
  left: calc(20 * var(--u));
  /* Правка 24.10.2026. Координата 746 снята с кадра макета 440x956 —
     там ссылка стоит над панелью разделов (821). В реальном окне кадра
     нет, и на трёх размерах из пяти она оказывалась ПОД панелью, а на
     420x700 — вовсе за нижним краем (измерено).

     В отличие от ряда аватарок, у ссылки нет внутренних координат:
     это одна строка, и её достаточно прижать к низу. 49 — тот же
     зазор до панели, что в макете (821 − 772).

     Правка 24.10.2026, вторая итерация (Матвей: «какой-то другой текст
     уже наезжает»). Капсула «Подарить VPN» со значком стоит от ВЕРХА,
     ссылка — от низа: на низком окне они съезжаются навстречу. На
     428x625 ссылка упиралась в значок «VPN за другой» (его верх —
     457 единиц макета).

     max() не даёт ей подняться выше значка: отсчитываем от верха
     экрана, оставляя 10 единиц зазора. Что ниже — то и берём: на
     высоком окне работает прижатие к низу (184), на низком — упор под
     значок. */
  /* Правка 25.10.2026 (Матвей: «подчёркнутую строку чуть пониже бы»).
     Строка стояла впритык под подсказкой о рубежах, а под капсулой
     «Подарить VPN» до панели разделов оставалось больше 200px пустоты.
     Переносим строку туда: она отделяется от карточки и заполняет
     пустое место. 150 — середина просвета на высоком окне; max() на
     низком по-прежнему не даёт ей уехать под панель. */
  /* Положение ставит friends.js (fitToMoney): ссылка идёт за капсулой,
     а та на низком окне поднимается к панели разделов. Одной формулой
     это не выразить — нужен и --u (от ширины), и высота окна. */
  top: calc(594 * var(--u));
  width: calc(400 * var(--u));
  padding: calc(6 * var(--u)) 0;
  background: none;
  border: 0;
  font-size: calc(13 * var(--u));
  text-align: center;
  text-decoration: underline;
  text-underline-offset: 3px;
  opacity: .7;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

/* Низкое окно: под капсулой места нет, строка остаётся над значком
   «VPN за друзей» — там же, где стояла до правки 25.10.2026. */
.friends__to-money.is-above {
  top: auto;
  bottom: max(
    calc(184 * var(--u)),
    calc(100% - 447 * var(--u))
  );
}

.friends__to-money[hidden] {
  display: none;
}

/* Отклик на нажатие. Без него строка молчит, пока Telegram открывает
   нативное окно подтверждения, и кажется, что нажатие не прошло
   (Матвей, 01.11.2026: «срабатывает не сразу»). У капсулы «Подарить
   VPN» такой отклик был с самого начала — здесь его просто забыли. */
.friends__to-money:active,
.money__to-days:active {
  opacity: .45;
}

.friends__to-money:disabled {
  opacity: .35;
  cursor: default;
}

.money__to-days:disabled {
  opacity: .35;
  cursor: default;
}

/* Правка 17.10.2026 (Александр): «История плохо открывается».

   Шторка наследовала .whom-scrim — absolute с height 100% от .stage.
   На экране друзей сцена выше окна (список друзей, баланс, история),
   поэтому «низ сцены» оказывался за нижним краем экрана: открытая
   шторка уезжала вниз, и был виден только её заголовок.

   Крепим к окну: fixed + dvh, чтобы учитывалась адресная строка
   мобильного браузера. Ширину ограничиваем холстом — иначе на десктопе
   шторка растянулась бы во весь экран мимо макета. */
.money-scrim {
  position: fixed;
  left: 50%;
  top: 0;
  width: 100%;
  max-width: var(--stage);
  height: 100vh;
  height: 100dvh;
  transform: translateX(-50%);
}

.money-sheet {
  position: absolute;
  left: calc(20 * var(--u));
  right: calc(20 * var(--u));
  bottom: calc(20 * var(--u));
  /* --u считается от ШИРИНЫ холста, поэтому одной величины в --u мало:
     на широком и невысоком окне 620 единиц перерастают экран, и низ
     списка снова обрезается. Берём меньшее из макетной высоты и того,
     что реально осталось в окне за вычетом отступов. */
  max-height: min(calc(620 * var(--u)), calc(100dvh - 40 * var(--u)));
  display: flex;
  flex-direction: column;
  padding: calc(28 * var(--u)) calc(24 * var(--u)) calc(24 * var(--u));
  border-radius: calc(40 * var(--u));
  background: var(--paper);
  box-sizing: border-box;
  transform: translateY(calc(24 * var(--u)));
  transition: transform .26s cubic-bezier(.2, .8, .3, 1);
}

.money-scrim.is-open .money-sheet {
  transform: none;
}

.money-sheet__close {
  position: absolute;
  top: calc(10 * var(--u));
  left: 50%;
  width: calc(50 * var(--u));
  height: calc(6 * var(--u));
  transform: translateX(-50%);
  border: 0;
  border-radius: 3px;
  background: rgba(0, 0, 0, .2);
  cursor: pointer;
  touch-action: manipulation;
}

.money-sheet__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: calc(22 * var(--u));
}

.money-sheet__total {
  margin: calc(6 * var(--u)) 0 0;
  font-size: calc(13 * var(--u));
  opacity: .6;
}

.money-sheet__body {
  margin-top: calc(6 * var(--u));
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

.money-sheet__empty {
  margin: calc(18 * var(--u)) 0 0;
  font-size: calc(13 * var(--u));
  opacity: .55;
}

.money-sheet__empty[hidden] {
  display: none;
}

.friends__progress[hidden] {
  display: none;
}

.money__rate {
  margin: calc(14 * var(--u)) 0 0;
  font-size: calc(13 * var(--u));
  opacity: .7;
}

.money__withdraw {
  margin-top: calc(14 * var(--u));
  width: 100%;
  height: calc(48 * var(--u));
  border: 0;
  border-radius: calc(24 * var(--u));
  background: #000;
  color: #fff;
  font-size: calc(15 * var(--u));
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

/* Выводить нечего — кнопка не ведёт в тупик. */
.money__withdraw:disabled {
  opacity: .35;
  cursor: default;
}

.money__history {
  margin-top: calc(18 * var(--u));
}

.money__history-title {
  margin: 0 0 calc(10 * var(--u));
  font-size: calc(13 * var(--u));
  font-weight: 600;
  opacity: .6;
}

.money__history-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: calc(8 * var(--u));
}

.money__history-item {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: calc(10 * var(--u));
  font-size: calc(13 * var(--u));
}

.money__history-item b {
  font-family: var(--font-number);
  font-weight: 400;
}

.money__history-item span {
  opacity: .5;
}

/* Выплаченное выделяем, отклонённое приглушаем. */
.money__history-item--completed b { color: #1a7f37; }
.money__history-item--rejected { opacity: .45; }

/* ================= Подписка (SubManage / Renew / Extend / Auto) =========
   Макеты этого раздела (артефакт «Burger VPN — mini app», 13.10.2026)
   свёрстаны потоком, а не по координатам: число вариантов продления
   приходит из прайса и заранее не известно. Поэтому экран здесь —
   единственный в мини-аппе, который тянется по содержимому, а шаг сетки
   --u сохраняем, чтобы размеры совпадали с остальными экранами.
   ====================================================================== */
.screen--sub {
  height: auto;
  min-height: calc(var(--h) * var(--u));
  /* Нижний отступ — под полосу «К оплате»: она прибита к низу окна и
     иначе накрыла бы последнюю карточку. */
  padding: calc(22 * var(--u)) calc(22 * var(--u)) calc(140 * var(--u));
}

/* Сцена этого раздела тянется на всю высоту окна, а не на высоту макета.
   Иначе снизу (а из-за центрирования body — и сверху) просвечивал серый
   фон страницы: окно Telegram выше 700px макета. Тот же приём уже
   применён к экранам с нижней панелью, но этот раздел под то правило не
   подходит — панели у него нет. */
.stage:has(.screen--sub) {
  height: auto;
  min-height: 100vh;
  min-height: 100dvh;
}

/* min-height: 100% здесь не работает: у сцены задана не height, а
   min-height, а процент от min-height родителя не считается — экран
   остался бы по содержимому, и снизу просвечивал бы серый фон.
   Поэтому меряем от окна, как сама сцена. */
.stage:has(.screen--sub) .screen--sub {
  min-height: 100vh;
  min-height: 100dvh;
  /* Колонка — чтобы полоса «К оплате» прижималась к низу через
     margin-top: auto. */
  display: flex;
  flex-direction: column;
}

/* ---------- Шапка: кружок «назад» и заголовок ---------- */
.pick-head {
  display: flex;
  align-items: center;
  gap: calc(14 * var(--u));
  margin: calc(16 * var(--u)) 0 calc(18 * var(--u));
}

.pick-head__back {
  width: calc(38 * var(--u));
  height: calc(38 * var(--u));
  border-radius: 50%;
  border: calc(2 * var(--u)) solid rgba(0, 0, 0, .18);
  flex-shrink: 0;
  -webkit-tap-highlight-color: transparent;
  /* Без этого Safari принимает быстрые повторные тапы за
     двойной и зумит страницу — особенно заметно на «+»/«−». */
  touch-action: manipulation;
  /* Стрелка влево с хвостом — как в макете */
  background:
    no-repeat center / calc(17 * var(--u)) auto
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23595959' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 6l-6 6 6 6'/%3E%3Cpath d='M8 12h12'/%3E%3C/svg%3E");
}

.pick-head__back:active {
  transform: scale(.94);
}

.pick-head__title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  /* 22px: «Расширить подписку» — самый длинный заголовок раздела, и на
     440px он должен уместиться в одну строку, как в макете. */
  font-size: calc(22 * var(--u));
  letter-spacing: -.03em;
  line-height: 1.1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---------- Карточка подписки ---------- */
.sub-card {
  padding: calc(18 * var(--u)) calc(20 * var(--u));
  border-radius: calc(24 * var(--u));
  background: #111;
  color: var(--paper);
  display: flex;
  flex-direction: column;
  gap: calc(7 * var(--u));
  box-shadow: 0 calc(10 * var(--u)) calc(24 * var(--u)) calc(-14 * var(--u)) rgba(0, 0, 0, .5);
}

.sub-card__big {
  margin: 0;
  display: flex;
  align-items: center;
  gap: calc(9 * var(--u));
  flex-wrap: wrap;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(22 * var(--u));
  letter-spacing: -.02em;
}

/* Розовая пилюля с числом устройств */
.sub-card__dev {
  font-family: var(--font-text);
  font-weight: 700;
  font-size: calc(13 * var(--u));
  background: #FF2486;
  color: #000;
  padding: calc(4 * var(--u)) calc(10 * var(--u));
  border-radius: 999px;
  white-space: nowrap;
}

.sub-card__dev:empty {
  display: none;
}

.sub-card__row {
  margin: 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: calc(10 * var(--u));
  font-size: calc(14 * var(--u));
  color: rgba(255, 255, 255, .6);
}

.sub-card__row b {
  color: var(--paper);
  font-weight: 700;
}

/* Светлый вариант карточки — блок привязки карты на экране автопродления */
.sub-card--light {
  background: var(--paper);
  color: var(--ink);
  gap: calc(10 * var(--u));
  margin-top: calc(14 * var(--u));
  box-shadow: 0 calc(8 * var(--u)) calc(20 * var(--u)) calc(-14 * var(--u)) rgba(0, 0, 0, .25);
}

.sub-card__t {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(17 * var(--u));
  letter-spacing: -.02em;
}

.sub-card__d {
  margin: 0;
  font-size: calc(14 * var(--u));
  line-height: 1.45;
  opacity: .6;
}

/* ---------- Подпись над группой ---------- */
.sublbl {
  margin: calc(22 * var(--u)) 0 calc(2 * var(--u));
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(13 * var(--u));
  letter-spacing: .02em;
  opacity: .45;
}

/* ---------- Строка-действие (SubManage) ---------- */
.act-row {
  display: flex;
  align-items: center;
  gap: calc(14 * var(--u));
  width: 100%;
  padding: calc(15 * var(--u)) calc(16 * var(--u));
  margin-top: calc(10 * var(--u));
  border-radius: calc(24 * var(--u));
  background: var(--paper);
  color: var(--ink);
  text-align: left;
  -webkit-tap-highlight-color: transparent;
  /* Без этого Safari принимает быстрые повторные тапы за
     двойной и зумит страницу — особенно заметно на «+»/«−». */
  touch-action: manipulation;
  box-shadow: 0 calc(6 * var(--u)) calc(16 * var(--u)) calc(-12 * var(--u)) rgba(0, 0, 0, .3);
}

.act-row:active {
  transform: scale(.99);
}

/* Строка автопродления на своём экране не кнопка — не жмётся */
.act-row--static:active {
  transform: none;
}

.act-row__ic {
  width: calc(40 * var(--u));
  height: calc(40 * var(--u));
  border-radius: calc(14 * var(--u));
  flex-shrink: 0;
  background-repeat: no-repeat;
  background-position: center;
  background-size: calc(20 * var(--u)) auto;
}

/* Круговая стрелка — продление */
.act-row__ic--pink {
  background-color: #FF2486;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 12a8 8 0 1 1-2.3-5.7'/%3E%3Cpath d='M20 4v5h-5'/%3E%3C/svg%3E");
}

/* Телефон с плюсом — расширение */
.act-row__ic--purple {
  background-color: #C9B8FF;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='7' y='2.5' width='10' height='19' rx='3'/%3E%3Cpath d='M12 9v6M9 12h6'/%3E%3C/svg%3E");
}

/* Карта — автопродление */
.act-row__ic--mint {
  background-color: #49F9AD;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='5.5' width='18' height='13' rx='3'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
}

.act-row__text {
  display: flex;
  flex-direction: column;
  gap: calc(3 * var(--u));
  flex: 1;
  min-width: 0;
}

.act-row__t {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(16 * var(--u));
  letter-spacing: -.02em;
}

.act-row__d {
  font-size: calc(13 * var(--u));
  opacity: .5;
  line-height: 1.3;
}

.act-row__chev {
  width: calc(18 * var(--u));
  height: calc(18 * var(--u));
  flex-shrink: 0;
  opacity: .3;
  background: no-repeat center / contain
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 5l7 7-7 7'/%3E%3C/svg%3E");
}

.act-row__state {
  font-size: calc(13 * var(--u));
  font-weight: 600;
  opacity: .45;
  flex-shrink: 0;
  white-space: nowrap;
}

/* Данные подписки не загрузились: управлять нечем, пока мы не знаем,
   что у человека за подписка. Гасим действия, чтобы нажатие не уводило
   на экран, который посчитает цену от нулей. */
.sub-pane.is-unavailable .act-row {
  opacity: .4;
  pointer-events: none;
}

/* ---------- Вариант выбора (срок продления, способ расширения) ---------- */
.opt-list {
  display: contents;
}

.opt {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: calc(2 * var(--u)) calc(12 * var(--u));
  width: 100%;
  padding: calc(15 * var(--u)) calc(18 * var(--u));
  margin-top: calc(10 * var(--u));
  border-radius: calc(24 * var(--u));
  background: var(--paper);
  color: var(--ink);
  text-align: left;
  border: calc(2 * var(--u)) solid transparent;
  -webkit-tap-highlight-color: transparent;
  /* Без этого Safari принимает быстрые повторные тапы за
     двойной и зумит страницу — особенно заметно на «+»/«−». */
  touch-action: manipulation;
  box-shadow: 0 calc(6 * var(--u)) calc(16 * var(--u)) calc(-12 * var(--u)) rgba(0, 0, 0, .3);
}

.opt:active {
  transform: scale(.99);
}

/* Выбранный вариант обведён чёрным — как в макете SubRenew. */
.opt.is-active {
  border-color: var(--ink);
}

.opt__t {
  grid-column: 1;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(16 * var(--u));
  letter-spacing: -.02em;
}

.opt__d {
  grid-column: 1;
  font-size: calc(13 * var(--u));
  opacity: .5;
  line-height: 1.3;
}

.opt__p {
  grid-column: 2;
  grid-row: 1 / span 2;
  /* Колонкой: цена сверху, плашка со скидкой под ней — как в макете. */
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: calc(6 * var(--u));
  font-family: var(--font-number);
  font-weight: 600;
  font-size: calc(19 * var(--u));
  white-space: nowrap;
  /* Место под плашку скидки держим всегда. У «1 месяца» скидки нет,
     и без этого его карточка выходила ниже остальных на 8-10px —
     разнобой видно глазом (Матвей, 29.10.2026). Высота плашки:
     11px кегля x 1.2 межстрочного + по 3 отступа сверху и снизу,
     плюс gap 6 до цены. Измерено на четырёх размерах: карточки
     сравнялись, у остальных высота не изменилась. */
  min-height: calc(19 * 1.2 * var(--u) + 25.2 * var(--u));
}

/* Процент скидки — зелёная плашка под ценой (макет SubRenew). */
.opt__p small {
  font-family: var(--font-text);
  font-size: calc(11 * var(--u));
  font-weight: 700;
  color: #000;
  background: #49F9AD;
  padding: calc(3 * var(--u)) calc(9 * var(--u));
  border-radius: 999px;
  line-height: 1.2;
}

/* ---------- Мини-переключатель периода (внутри «С продлением») ---------- */
.mini-period {
  display: flex;
  gap: calc(6 * var(--u));
  margin-top: calc(10 * var(--u));
}

.mini-period button {
  flex: 1;
  min-height: calc(40 * var(--u));
  border-radius: calc(14 * var(--u));
  background: var(--paper);
  font-size: calc(13 * var(--u));
  font-weight: 600;
  border: calc(2 * var(--u)) solid transparent;
  -webkit-tap-highlight-color: transparent;
  /* Без этого Safari принимает быстрые повторные тапы за
     двойной и зумит страницу — особенно заметно на «+»/«−». */
  touch-action: manipulation;
}

/* Выбор здесь тот же, что у .opt — обводим чёрным, а не розовым. */
.mini-period button.is-active {
  border-color: var(--ink);
}

/* ---------- Счётчик устройств ---------- */
.stepper {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: calc(10 * var(--u));
  margin-top: calc(10 * var(--u));
  padding: calc(14 * var(--u));
  border-radius: calc(24 * var(--u));
  background: rgba(255, 255, 255, .92);
}

.stepper button {
  flex: 1;
  min-height: calc(48 * var(--u));
  border-radius: calc(16 * var(--u));
  background: linear-gradient(#fafafa, #ececec);
  box-shadow: 0 calc(2 * var(--u)) calc(4 * var(--u)) rgba(0, 0, 0, .12), inset 0 calc(1 * var(--u)) 0 #fff;
  font-size: calc(22 * var(--u));
  font-weight: 500;
  -webkit-tap-highlight-color: transparent;
  /* Без этого Safari принимает быстрые повторные тапы за
     двойной и зумит страницу — особенно заметно на «+»/«−». */
  touch-action: manipulation;
}

.stepper button:disabled {
  opacity: .35;
}

.stepper button:not(:disabled):active {
  transform: scale(.96);
}

.stepper__cnt {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(30 * var(--u));
  letter-spacing: -.03em;
  min-width: calc(86 * var(--u));
  text-align: center;
}

/* ---------- Тумблер автопродления ---------- */
.switch {
  width: calc(52 * var(--u));
  height: calc(32 * var(--u));
  border-radius: 999px;
  background: rgba(0, 0, 0, .14);
  flex-shrink: 0;
  padding: calc(3 * var(--u));
  display: flex;
  /* Правка 17.10.2026 (Мария: «кривоватый переключатель»): кружок сидел
     на 4px ниже середины. Размеры в --u дают дробные пиксели (52x32 при
     padding 3 и кружке 26 — это 3+26+3=32 в теории, но после округления
     выходило 28 на 23+5), и остаток уходил вниз. Выравниваем по центру
     явно: тогда перекос не зависит от округления. */
  align-items: center;
  transition: background .18s ease;
  -webkit-tap-highlight-color: transparent;
  /* Без этого Safari принимает быстрые повторные тапы за
     двойной и зумит страницу — особенно заметно на «+»/«−». */
  touch-action: manipulation;
}

.switch i {
  width: calc(26 * var(--u));
  height: calc(26 * var(--u));
  border-radius: 50%;
  background: var(--paper);
  box-shadow: 0 calc(2 * var(--u)) calc(4 * var(--u)) rgba(0, 0, 0, .2);
  /* margin-left, а не transform: кружок прижимается флексом
     (см. .switch.is-on i), и анимировать надо именно отступ. */
  transition: margin-left .18s ease;
}

.switch.is-on {
  background: #49F9AD;
}

.switch.is-on i {
  /* Кружок прижимаем к правому краю самим флексом, а не сдвигом на
     вычисленное число. Любая формула промахивается: --u даёт дробные
     пиксели, дорожка округляется до 46px вместо 52, и жёсткий сдвиг в
     20px оставлял 1px справа против 5px слева. С margin-left: auto
     отступы равны при любом округлении (измерено). */
  margin-left: auto;
}

/* Пока ждём ответ сервера — тумблер неактивен */
.switch:disabled {
  opacity: .5;
}

/* ---------- Строка способа оплаты ---------- */
.card-row {
  display: flex;
  align-items: center;
  gap: calc(12 * var(--u));
  padding: calc(15 * var(--u)) calc(18 * var(--u));
  margin-top: calc(10 * var(--u));
  border-radius: calc(22 * var(--u));
  background: var(--paper);
  font-size: calc(14 * var(--u));
  box-shadow: 0 calc(6 * var(--u)) calc(16 * var(--u)) calc(-12 * var(--u)) rgba(0, 0, 0, .3);
}

.card-row__cc {
  width: calc(32 * var(--u));
  height: calc(22 * var(--u));
  border-radius: calc(5 * var(--u));
  background: linear-gradient(135deg, #2b2b2b, #555);
  flex-shrink: 0;
}

.card-row__x {
  margin-left: auto;
  font-size: calc(13 * var(--u));
  font-weight: 600;
  color: #FF2486;
  -webkit-tap-highlight-color: transparent;
  /* Без этого Safari принимает быстрые повторные тапы за
     двойной и зумит страницу — особенно заметно на «+»/«−». */
  touch-action: manipulation;
}

.card-row--next {
  font-weight: 500;
}

.card-row--next b {
  margin-left: auto;
  font-family: var(--font-number);
  font-weight: 600;
}

/* ---------- Сноска ---------- */
.note {
  margin: calc(16 * var(--u)) 0 0;
  font-size: calc(13 * var(--u));
  line-height: 1.45;
  opacity: .45;
}

.note:empty {
  display: none;
}

/* ---------- Кнопки в карточке привязки ----------
   Своё имя, а не .btn: общий .btn в мини-аппе позиционируется абсолютно
   (left/width от сетки макета), и внутри потоковой карточки он вылезал
   за её края. */
.bind-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: calc(54 * var(--u));
  margin-top: calc(4 * var(--u));
  border-radius: calc(28 * var(--u));
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(16 * var(--u));
  -webkit-tap-highlight-color: transparent;
  /* Без этого Safari принимает быстрые повторные тапы за
     двойной и зумит страницу — особенно заметно на «+»/«−». */
  touch-action: manipulation;
}

.bind-btn:active {
  transform: scale(.99);
}

.bind-btn--pink {
  background: #FF2486;
  color: #000;
}

.bind-btn--white {
  background: var(--paper);
  font-family: var(--font-text);
  font-weight: 600;
  font-size: calc(15 * var(--u));
}

/* ---------- Полоса «К оплате» ---------- */
/* Правка 16.10.2026 (Евгений, скриншот «сделай отступ»): полоса «К
   оплате» прижата к низу через margin-top:auto, а auto — это ОСТАТОК
   места. Пока список короткий, зазор большой; когда контент дорастает
   до низа, остатка не остаётся и карточка упирается в кнопку.

   Отступ даём панели: он не съедается, как auto, и держится при любой
   длине списка. На самой полосе это не сделать — margin-top занят
   (auto нельзя положить в max(), правило отбрасывается целиком), а
   padding-top перебивается короткой записью padding ниже и раздул бы
   высоту кнопки. */
.sub-pane {
  margin-bottom: calc(18 * var(--u));
}

.paybar {
  /* Прижата к низу экрана: margin-top:auto в flex-колонке. Так полоса
     стоит внизу и при коротком списке, и при длинном (sticky без
     скролла не прилипал и повисал посреди экрана), и при этом остаётся
     внутри сцены шириной 440 — fixed уводил её за край на десктопе. */
  margin-top: auto;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: calc(12 * var(--u));
  width: 100%;
  height: calc(78 * var(--u));
  padding: 0 calc(12 * var(--u)) 0 calc(28 * var(--u));
  border-radius: 999px;
  background: #111;
  color: var(--paper);
  -webkit-tap-highlight-color: transparent;
  /* Без этого Safari принимает быстрые повторные тапы за
     двойной и зумит страницу — особенно заметно на «+»/«−». */
  touch-action: manipulation;
  box-shadow: 0 calc(16 * var(--u)) calc(30 * var(--u)) calc(-18 * var(--u)) rgba(0, 0, 0, .55);
}

.paybar:active {
  transform: scale(.99);
}

.paybar__k {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: calc(22 * var(--u));
  letter-spacing: -.03em;
}

.paybar__sum {
  min-width: calc(130 * var(--u));
  height: calc(54 * var(--u));
  padding: 0 calc(18 * var(--u));
  border-radius: 999px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #FF2486;
  color: #000;
  font-family: var(--font-number);
  font-weight: 600;
  font-size: calc(21 * var(--u));
}

/* ================= Мои устройства (макет Active) =======================
   Главный экран после покупки и единственный вход в управление:
   «Управлять подпиской», «Докупить трафик», «Получить конфиг» живут в
   меню устройства, а не на плитках главной.

   Экран потоковый, как раздел подписки: число устройств заранее не
   известно, по координатам макета его не разложить.
   ====================================================================== */
.screen--devices {
  height: auto;
  min-height: 100vh;
  min-height: 100dvh;
  /* Боковые поля и верх — свои; низ отдельной строкой, чтобы его не
     перебивало общее правило .stage:has(.tabbar) .screen и чтобы под
     нижней панелью оставался запас: иначе она накрывает «Добавить
     устройство». */
  padding: calc(18 * var(--u)) calc(22 * var(--u)) 0;
  padding-bottom: calc(170 * var(--u));
}

.stage:has(.screen--devices) {
  height: auto;
  min-height: 100vh;
  min-height: 100dvh;
}

/* ---------- Шапка с логотипом ---------- */
.dev-top {
  display: flex;
  justify-content: center;
  align-items: center;
  height: calc(40 * var(--u));
}

.dev-top__mark {
  display: flex;
  align-items: center;
  gap: calc(6 * var(--u));
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(15 * var(--u));
  letter-spacing: -.02em;
}

.dev-top__tag {
  background: var(--ink);
  color: var(--paper);
  font-size: calc(9 * var(--u));
  letter-spacing: .04em;
  padding: calc(3 * var(--u)) calc(6 * var(--u));
  border-radius: calc(6 * var(--u));
}

/* ---------- Подпись раздела: слева название, справа значение ---------- */
.dev-sec {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: calc(10 * var(--u));
  margin: calc(22 * var(--u)) 0 calc(10 * var(--u));
}

.dev-sec__k {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(17 * var(--u));
  letter-spacing: -.02em;
}

.dev-sec__v {
  font-size: calc(13 * var(--u));
  opacity: .5;
}

.dev-sec__v--mint {
  background: #49F9AD;
  color: #000;
  opacity: 1;
  font-weight: 700;
  padding: calc(3 * var(--u)) calc(9 * var(--u));
  border-radius: 999px;
}

/* ---------- Карточка устройства ---------- */
.dev-card {
  background: #111;
  color: var(--paper);
  border-radius: calc(26 * var(--u));
  padding: calc(18 * var(--u));
  margin-bottom: calc(12 * var(--u));
  box-shadow: 0 calc(10 * var(--u)) calc(24 * var(--u)) calc(-14 * var(--u)) rgba(0, 0, 0, .5);
}

.dev-card__head {
  display: flex;
  align-items: center;
  gap: calc(12 * var(--u));
}

/* Иконка платформы: своей картинки под каждую ОС нет, рисуем силуэт
   телефона — он подходит и телефону, и планшету, и десктопу. */
.dev-card__ic {
  width: calc(36 * var(--u));
  height: calc(36 * var(--u));
  border-radius: calc(12 * var(--u));
  background: rgba(255, 255, 255, .12) no-repeat center / calc(18 * var(--u)) auto;
  flex-shrink: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round'%3E%3Crect x='7' y='2.5' width='10' height='19' rx='3'/%3E%3Cpath d='M11 18.5h2'/%3E%3C/svg%3E");
}

.dev-card__name {
  flex: 1;
  min-width: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(16 * var(--u));
  letter-spacing: -.02em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dev-card__name i {
  font-style: normal;
  opacity: .45;
}

/* Плашка тарифа */
.dev-card__chip {
  background: #FF2486;
  color: #000;
  font-size: calc(11 * var(--u));
  font-weight: 700;
  padding: calc(4 * var(--u)) calc(9 * var(--u));
  border-radius: 999px;
  white-space: nowrap;
  flex-shrink: 0;
}

/* ---------- Факты: срок и автопродление ---------- */
.dev-card__facts {
  display: flex;
  flex-direction: column;
  gap: calc(5 * var(--u));
  margin-top: calc(14 * var(--u));
  font-size: calc(13 * var(--u));
  color: rgba(255, 255, 255, .6);
}

.dev-card__facts span {
  display: flex;
  align-items: center;
  gap: calc(8 * var(--u));
}

/* Точка-маркер перед строкой */
.dev-card__facts span::before {
  content: "";
  width: calc(5 * var(--u));
  height: calc(5 * var(--u));
  border-radius: 50%;
  background: #49F9AD;
  flex-shrink: 0;
}

/* ---------- Трафик ---------- */
.dev-card__meter {
  margin-top: calc(16 * var(--u));
}

.dev-card__row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: calc(10 * var(--u));
  font-size: calc(12 * var(--u));
  color: rgba(255, 255, 255, .55);
  margin-bottom: calc(6 * var(--u));
}

.dev-card__row b {
  color: var(--paper);
  font-family: var(--font-number);
  font-weight: 600;
}

.dev-card__row--second {
  margin-top: calc(14 * var(--u));
}

.dev-card__unl {
  color: #49F9AD !important;
}

.dev-card__bar {
  height: calc(8 * var(--u));
  border-radius: 999px;
  background: rgba(255, 255, 255, .14);
  overflow: hidden;
}

.dev-card__bar i {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, #FFD9E8, #B9C6FF);
}

/* Безлимитная полоса залита целиком — ограничения нет. */
.dev-card__bar--unl i {
  width: 100%;
  background: linear-gradient(90deg, #49F9AD, #8BFFD0);
  opacity: .55;
}

/* ---------- Кнопка раскрытия меню ---------- */
.dev-card__toggle {
  width: 100%;
  margin-top: calc(16 * var(--u));
  padding: calc(10 * var(--u));
  border-radius: calc(16 * var(--u));
  background: rgba(255, 255, 255, .1);
  color: var(--paper);
  font-size: calc(13 * var(--u));
  font-weight: 600;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.dev-card__toggle:active {
  transform: scale(.99);
}

/* ---------- Меню устройства ---------- */
.dev-menu {
  margin-top: calc(14 * var(--u));
  padding-top: calc(14 * var(--u));
  border-top: 1px solid rgba(255, 255, 255, .12);
}

.dev-menu__id {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: calc(10 * var(--u));
  font-size: calc(12 * var(--u));
  color: rgba(255, 255, 255, .5);
  margin-bottom: calc(12 * var(--u));
}

.dev-menu__id b {
  color: rgba(255, 255, 255, .8);
  font-family: var(--font-number);
  font-weight: 600;
}

/* Главное действие — розовая кнопка на всю ширину */
.dev-menu__main {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: calc(52 * var(--u));
  border-radius: calc(26 * var(--u));
  background: #FF2486;
  color: #000;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(15 * var(--u));
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.dev-menu__main:active {
  transform: scale(.99);
}

.dev-menu__howto {
  display: block;
  width: 100%;
  margin-top: calc(8 * var(--u));
  padding: calc(6 * var(--u)) 0;
  background: none;
  border: 0;
  color: rgba(255, 255, 255, .7);
  font-family: var(--font-display);
  font-size: calc(13 * var(--u));
  text-decoration: underline;
  text-underline-offset: 3px;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.dev-menu__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: calc(8 * var(--u));
  margin-top: calc(8 * var(--u));
}

.dev-menu__btn {
  min-height: calc(46 * var(--u));
  border-radius: calc(16 * var(--u));
  background: rgba(255, 255, 255, .1);
  color: var(--paper);
  font-size: calc(13 * var(--u));
  font-weight: 600;
  padding: 0 calc(8 * var(--u));
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.dev-menu__btn:active {
  transform: scale(.98);
}

/* «Удалить устройство» — по макету Active отличается от соседей.
   Красим текст, а не фон: кнопка остаётся в одном ряду с остальными,
   но действие читается как необратимое. */
.dev-menu__btn--danger {
  color: #FF6B8A;
}

/* ---------- Пусто ---------- */
.dev-empty {
  margin: calc(10 * var(--u)) 0 0;
  padding: calc(18 * var(--u));
  border-radius: calc(22 * var(--u));
  background: var(--paper);
  font-size: calc(14 * var(--u));
  line-height: 1.45;
  opacity: .7;
}

/* ---------- Нет подписки: блок покупки ----------
   Правка 22.10.2026 (Матвей): без подписки на экране устройств не было
   способа купить — оставалась только «Расширить подписку», которая
   считает доплату от тарифа, которого нет. */
.dev-buy {
  margin: calc(10 * var(--u)) 0 0;
  padding: calc(18 * var(--u));
  border-radius: calc(22 * var(--u));
  background: var(--paper);
}

.dev-buy__text {
  margin: 0 0 calc(14 * var(--u));
  font-size: calc(14 * var(--u));
  line-height: 1.45;
  opacity: .7;
}

.dev-buy__go {
  width: 100%;
  min-height: calc(52 * var(--u));
  padding: 0 calc(18 * var(--u));
  border: 0;
  border-radius: calc(26 * var(--u));
  background: #FF2486;
  color: var(--ink);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(15 * var(--u));
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: transform .18s ease;
}

.dev-buy__go:active {
  transform: scale(.99);
}

/* ---------- Добавить устройство ---------- */
.dev-add {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(10 * var(--u));
  width: 100%;
  min-height: calc(58 * var(--u));
  border-radius: calc(26 * var(--u));
  background: var(--paper);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(15 * var(--u));
  box-shadow: 0 calc(8 * var(--u)) calc(20 * var(--u)) calc(-14 * var(--u)) rgba(0, 0, 0, .3);
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.dev-add:active {
  transform: scale(.99);
}

.dev-add__plus {
  width: calc(22 * var(--u));
  height: calc(22 * var(--u));
  background: no-repeat center / contain
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 8v8M8 12h8'/%3E%3C/svg%3E");
}

/* ================= Подтверждение пробного периода =====================
   Макет TrialConfirm. Оплаты нет, поэтому окно заказа не подходит:
   вместо суммы и способов — два условия и одна кнопка.
   ====================================================================== */
.ask--trial {
  padding: calc(30 * var(--u)) calc(24 * var(--u)) calc(26 * var(--u));
}

/* Общий .ask__title позиционирован абсолютно — он рассчитан на окно, где
   содержимое тоже разложено по координатам. Здесь содержимое потоковое,
   и абсолютный заголовок наезжал на текст условий. */
.ask--trial .ask__title {
  position: static;
  text-align: left;
  font-size: calc(24 * var(--u));
  line-height: 1.15;
}

/* Зелёная надпись над заголовком — акцент «бесплатно». */
.trial__eyebrow {
  margin: 0 0 calc(8 * var(--u));
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(12 * var(--u));
  letter-spacing: .08em;
  text-transform: uppercase;
  color: #12a36a;
}

.trial__facts {
  list-style: none;
  margin: calc(18 * var(--u)) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: calc(12 * var(--u));
}

.trial__fact {
  position: relative;
  padding-left: calc(34 * var(--u));
  font-size: calc(14 * var(--u));
  line-height: 1.45;
  opacity: .75;
}

/* Кружок со значком перед строкой */
.trial__fact::before {
  content: "";
  position: absolute;
  left: 0;
  top: calc(1 * var(--u));
  width: calc(24 * var(--u));
  height: calc(24 * var(--u));
  border-radius: 50%;
  background: #49F9AD no-repeat center / calc(13 * var(--u)) auto;
}

/* Восклицательный знак — ограничения пробного периода */
.trial__fact--info::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round'%3E%3Cpath d='M12 7v6'/%3E%3Cpath d='M12 17h.01'/%3E%3C/svg%3E");
}

/* Галочка — условие «один раз» */
.trial__fact--ok::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round'%3E%3Cpath d='M5 12l5 5 9-10'/%3E%3C/svg%3E");
}

.trial__actions {
  display: flex;
  gap: calc(10 * var(--u));
  margin-top: calc(22 * var(--u));
}

.trial__back {
  flex: 0 0 calc(110 * var(--u));
  min-height: calc(54 * var(--u));
  border-radius: calc(28 * var(--u));
  background: #f1f1f1;
  font-size: calc(15 * var(--u));
  font-weight: 600;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

/* Зелёная кнопка: в макете активация подчёркнуто «бесплатная», поэтому
   мятная, а не розовая как платные действия. */
.trial__go {
  flex: 1;
  min-height: calc(54 * var(--u));
  border-radius: calc(28 * var(--u));
  background: #49F9AD;
  color: #000;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(16 * var(--u));
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.trial__back:active,
.trial__go:active {
  transform: scale(.99);
}

.trial__go:disabled {
  opacity: .6;
}

/* ================= Экран входа =========================================
   Правка 15.10.2026 (Мария): «что я должна сюда ввести, я не понимаю».

   Здесь была форма «Имя / Почта / Пароль» с кнопкой «Создать профиль» —
   копия регистрации. Для входа она не годилась: имя не нужно, пароль
   нигде не хранится (ни в API, ни в модели), а кнопка отправляла на
   /api/register, то есть «Войти» регистрировало заново.

   Вместо полей — объяснение и кнопка Telegram. Экран позиционируется по
   координатам макета, поэтому блоку задаём место явно.
   ====================================================================== */
.login-note {
  position: absolute;
  left: calc(26 * var(--u));
  /* Под переключателем: он на 85 и высотой 46. */
  top: calc(160 * var(--u));
  width: calc(388 * var(--u));
  text-align: center;
}

.login-note__title {
  margin: 0 0 calc(14 * var(--u));
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(26 * var(--u));
  letter-spacing: -.02em;
  line-height: 1.1;
}

.login-note__text {
  margin: 0 0 calc(12 * var(--u));
  font-size: calc(15 * var(--u));
  line-height: 1.45;
  opacity: .75;
}

.login-note__text--dim {
  opacity: .5;
}

/* Кнопка Telegram здесь — главное действие, а не запасной путь, как на
   регистрации: поднимаем её ближе к тексту. Позиционируем внутренний
   .tg; обёртке tg-button position: absolute задавать нельзя — она
   тогда перестаёт показывать кнопку. */
/* Правка 17.10.2026: выше стояла форма входа по почте, поэтому кнопка
   опустилась под неё. Это теперь второй путь, а не главный. */
.screen--login .tg {
  top: calc(470 * var(--u));
}

/* Ошибка входа встаёт ПОД виджетом телеграма, а не на фиксированной
   координате.

   Мария 21.10.2026: «тоже накладывается текст» — «Введите почту»
   налезало на кнопку «Войти через Telegram».

   Координату 560 подбирали под запасную кнопку-заглушку. Настоящий
   виджет — iframe от telegram.org: он выше и грузится асинхронно.
   Измерено на макете виджета 48px: он занимает 462..510, а текст
   ошибки стоял на 494..512 — перекрытие 16px. Зашить число нельзя,
   высота виджета нам не принадлежит.

   Остальные элементы экрана размечены абсолютно, поэтому в поток
   ошибку не вернуть — сместился бы весь экран. Вместо этого считаем
   верх от НИЗА виджета: --tg-bottom выставляет email-auth.js после
   того, как виджет смонтирован. Запасное значение — прежние 560, на
   случай если скрипт не отработал. */
.login-note__error {
  position: absolute;
  left: calc(26 * var(--u));
  top: var(--tg-bottom, calc(560 * var(--u)));
  width: calc(388 * var(--u));
  text-align: center;
}

/* ---------- Вход по почте (правка 17.10.2026) ---------- */
/* Шаги занимают одно место: поле почты скрывается, поле кода встаёт на
   его координату — экран не прыгает при переходе к коду. */
.screen--login .field--email,
.screen--login .field--phone,
.screen--login .field--code {
  top: calc(160 * var(--u));
}

/* Код набирают цифрами и сверяют с письмом по одной: разрядка и центр
   делают это читаемым, моноширинный шрифт не даёт строке дёргаться. */
.field--code .field__input {
  text-align: center;
  font-family: var(--font-display), ui-monospace, monospace;
  font-size: calc(22 * var(--u));
  letter-spacing: calc(6 * var(--u));
}

/* Куда ушло письмо. Под полем, чтобы опечатка в адресе бросалась в глаза
   до того, как человек начнёт искать несуществующее письмо. */
.code-sent {
  position: absolute;
  left: calc(26 * var(--u));
  top: calc(236 * var(--u));
  width: calc(388 * var(--u));
  margin: 0;
  font-family: var(--font-text);
  font-size: calc(14 * var(--u));
  line-height: 1.35;
  text-align: center;
  opacity: .6;
  /* Длинный адрес не должен ломать раскладку */
  overflow-wrap: anywhere;
}

/* Кнопка отправки стоит ниже подписи «код отправлен на …» */
.screen--login .submit {
  top: calc(292 * var(--u));
}

.screen--login .consent {
  top: calc(400 * var(--u));
}

/* Запасные действия: выслать ещё раз и сменить почту. Ссылками, а не
   кнопками: главное действие на экране одно, и это отправка кода. */
.code-actions {
  position: absolute;
  left: calc(26 * var(--u));
  top: calc(400 * var(--u));
  width: calc(388 * var(--u));
  display: flex;
  justify-content: center;
  gap: calc(24 * var(--u));
}

.code-actions__btn {
  padding: calc(6 * var(--u)) 0;
  border: 0;
  background: none;
  font-family: var(--font-text);
  font-weight: 500;
  font-size: calc(15 * var(--u));
  color: inherit;
  text-decoration: underline;
  text-underline-offset: calc(3 * var(--u));
  opacity: .6;
  cursor: pointer;
  transition: opacity .2s ease;
}

.code-actions__btn:hover {
  opacity: .9;
}

/* ---------- Сайт вне Telegram: вход и «3 дня бесплатно» ---------- */
/* Макет — холст 440×1000 в единицах --u. На сайте аватарки нет, а вместо пароля и
   имени — блок «3 дня бесплатно», поэтому всё стоит на своих местах, как у .screen--login. */
.screen--web .avatar {
  display: none;
}

.screen--web .field--email,
.screen--web .field--phone {
  top: calc(160 * var(--u));
}

/* Переключатель «по почте / по номеру» — ссылка под кнопкой, как запасные действия кода */
.method-switch {
  position: absolute;
  left: calc(26 * var(--u));
  top: calc(400 * var(--u));
  width: calc(388 * var(--u));
  display: flex;
  justify-content: center;
}

/* На регистрации под кнопкой стоит согласие — переключатель уходит под него */
.method-switch--below-consent {
  top: calc(438 * var(--u));
}

.web-extra,
.web-tg {
  position: absolute;
  z-index: 1;
  left: calc(44 * var(--u));
  width: calc(352 * var(--u));
  margin: 0;
  text-align: center;
}

.web-extra {
  top: calc(246 * var(--u));
}

.screen--trial .submit {
  top: calc(520 * var(--u));
}

.screen--trial .consent {
  top: calc(630 * var(--u));
}

.web-extra__title {
  margin: 0;
  font-size: calc(20 * var(--u));
  font-weight: 700;
}

.web-extra__text,
.web-tg__hint {
  margin: calc(4 * var(--u)) 0 0;
  font-size: calc(14 * var(--u));
  line-height: 1.35;
  opacity: 0.6;
}

.web-extra__methods[hidden] {
  display: none;
}

.web-extra__methods {
  display: flex;
  gap: calc(8 * var(--u));
  margin-top: calc(12 * var(--u));
}

.web-extra__methods button {
  flex: 1;
  height: calc(44 * var(--u));
  border-radius: calc(14 * var(--u));
  background: rgba(0, 0, 0, 0.08);
  font-size: calc(16 * var(--u));
  font-weight: 600;
}

.web-extra__methods button[aria-checked="true"] {
  background: #000;
  color: #fff;
}

/* Кнопка рисуется стилем: подпись у неё своя («Выслать код», «Войти», «Получить 3 дня»),
   а у картинки она зашита («Создать профиль») и на входе вводила в заблуждение. */
.screen--mail .submit__btn::before,
.screen--mail .submit__btn::after,
.screen--trial .submit__btn::before,
.screen--trial .submit__btn::after {
  display: none;
}

.screen--mail .submit__btn,
.screen--trial .submit__btn {
  border-radius: calc(36 * var(--u));
  background: linear-gradient(180deg, #e8e8e8, #c9c9c9);
  color: rgba(0, 0, 0, 0.35);
  font-family: var(--font-display);
  font-size: calc(21 * var(--u));
  letter-spacing: -0.02em;
  box-shadow:
    inset 0 calc(3 * var(--u)) calc(6 * var(--u)) rgba(255, 255, 255, 0.8),
    0 calc(10 * var(--u)) calc(18 * var(--u)) rgba(0, 0, 0, 0.12);
  transition:
    background 0.35s ease,
    color 0.35s ease,
    box-shadow 0.35s ease;
}

.screen--mail.is-ready .submit__btn,
.screen--trial.is-ready .submit__btn {
  background: radial-gradient(120% 150% at 50% 35%, #ff4fa0 0%, #ff0f7b 60%, #ff3d96 100%);
  color: #000;
  box-shadow:
    0 0 0 calc(3 * var(--u)) rgba(190, 190, 190, 0.9),
    0 calc(14 * var(--u)) calc(26 * var(--u)) rgba(255, 20, 130, 0.45);
}

/* «3 дня бесплатно» для вошедшего: ни переключателя, ни поля почты — всё выше */
.screen--trial-in .seg,
.screen--trial-in .field {
  display: none;
}

.screen--trial-in .web-extra {
  top: calc(130 * var(--u));
}

.screen--trial-in .submit {
  top: calc(440 * var(--u));
}

.screen--trial-in .consent {
  top: calc(552 * var(--u));
}

/* Вход на сайте: сначала почта, ниже — Telegram. Виджет не «улетает» наверх: его место задано. */
.web-tg {
  top: calc(520 * var(--u));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(12 * var(--u));
}

/* Кнопка почты всегда выглядит рабочей: серая читалась как «недоступно», и вход без Telegram
   не замечали. Пустую почту она не отправит, а скажет «Введите почту». */
.screen.screen--mail:not(.is-busy) .submit__btn {
  pointer-events: auto;
  cursor: pointer;
  background: radial-gradient(120% 150% at 50% 35%, #ff4fa0 0%, #ff0f7b 60%, #ff3d96 100%);
  color: #000;
  box-shadow:
    0 0 0 calc(3 * var(--u)) rgba(190, 190, 190, 0.9),
    0 calc(14 * var(--u)) calc(26 * var(--u)) rgba(255, 20, 130, 0.45);
}

/* Страница «3 дня» вошедшего: кнопка «Назад» и ошибка над согласием, а не поверх него */
.web-back {
  position: absolute;
  z-index: 3;
  left: calc(24 * var(--u));
  top: calc(36 * var(--u));
  padding: calc(8 * var(--u)) calc(12 * var(--u));
  background: none;
  /* Рамку снимаем явно: background: none её не убирает, и браузер
     рисовал кнопке свою серую обводку (Евгений 22.10.2026: «кнопку
     назад надо без обводки сделать»). */
  border: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  font-family: var(--font-display);
  font-size: calc(18 * var(--u));
  letter-spacing: -0.02em;
  color: rgba(0, 0, 0, 0.7);
}

.screen--trial-in .form-error {
  top: calc(516 * var(--u));
  bottom: auto;
}

/* Введённая почта мельче «Почты» из макета: адрес целиком иначе не помещается */
.field--email .field__input:not(:placeholder-shown),
.field--phone .field__input:not(:placeholder-shown) {
  font-size: calc(22 * var(--u));
  letter-spacing: -0.01em;
}

/* Мелкое имя-почта: обычный тёмный текст без контура (класс ставит fitName в profile.js) */
.profile__name.is-small {
  color: var(--ink);
  -webkit-text-stroke: 0;
  paint-order: normal;
}

/* Нет ни фото, ни имени — вместо пустой «дыры» силуэт человека */
.avatar--letter[data-letter=""]::after {
  content: "";
  width: 62%;
  height: 62%;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Ccircle cx='12' cy='8' r='4.2'/%3E%3Cpath d='M3.5 21c0-4.7 3.8-7.5 8.5-7.5s8.5 2.8 8.5 7.5z'/%3E%3C/svg%3E") no-repeat center / contain;
}

.money__row .money__withdraw {
  flex: none;
  width: auto;
  margin-top: 0;
  padding: 0 calc(26 * var(--u));
}


/* Правка 16.10.2026 (Евгений): «закомментируй полностью вход/регистрацию,
   они не нужны, все данные из тг берутся». Внутри Telegram личность
   подтверждает подпись initData, имя и username приходят оттуда же —
   форма с почтой и паролем не нужна. Кнопки остаются для сайта
   (.is-browser), где Telegram нет и войти больше нечем. */
.is-telegram .actions {
  display: none;
}

/* На сайте web.js подставляет Telegram.WebApp и тоже ставит .is-telegram, а Telegram там нет:
   стартовые кнопки нужны, иначе остаётся одна «Войти через Telegram» и не видно, что можно
   войти почтой (Александр, 21.10.2026). Правило ниже перебивает прежнее. */
.is-web .actions {
  display: contents;
}

.is-web .actions .btn[hidden] {
  display: none;
}

.is-web .screen:not(.screen--reg) .tg {
  top: calc(340 * var(--u));
}

/* ---------- Экран «Инструкция»: выбор устройства ----------

   Правка 19.10.2026 (Евгений): «предлагаю отойти от инструкции в
   телеграфе и открывать все на сайте. Вначале выбор устройства и после
   инструкция с ссылками и фото».

   Каркас общий с тарифами: та же стрелка «назад», тот же заголовок,
   та же панель разделов — экран встраивается в раздел VPN. */
.screen--howto {
  height: calc(700 * var(--u));
}

.howto__lead {
  position: absolute;
  left: calc(20 * var(--u));
  top: calc(118 * var(--u));
  width: calc(400 * var(--u));
  margin: 0;
  font-family: var(--font-text);
  font-size: calc(15 * var(--u));
  line-height: 1.3;
  color: rgba(0, 0, 0, .5);
  text-align: center;
}

/* Карточки в потоке, а не absolute: их всего две, и так экран не
   придётся переразмечать, если добавится третья (телевизор, ПК). */
.howto__list {
  position: absolute;
  left: calc(20 * var(--u));
  top: calc(170 * var(--u));
  width: calc(400 * var(--u));
  display: flex;
  flex-direction: column;
  gap: calc(14 * var(--u));
}

.howto__card {
  display: flex;
  align-items: center;
  gap: calc(16 * var(--u));
  height: calc(86 * var(--u));
  padding: 0 calc(20 * var(--u));
  border-radius: calc(25 * var(--u));
  border: calc(2 * var(--u)) solid transparent;
  text-decoration: none;
  color: var(--ink);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  /* Без этого двойной тап по карточке зумит страницу вместо перехода. */
  touch-action: manipulation;
  /* Та же заливка и обводка-градиент, что у неактивной карточки
     тарифа — экраны должны выглядеть одинаково. */
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    linear-gradient(rgba(0, 0, 0, .18), rgba(0, 0, 0, .18)),
    linear-gradient(43deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, .7) 26%,
      rgba(255, 255, 255, .3) 97%,
      rgba(255, 255, 255, .2) 100%);
  transition: transform .18s ease;
}

.howto__card:active {
  transform: scale(.99);
}

.howto__icon {
  flex: none;
  width: calc(40 * var(--u));
  height: calc(40 * var(--u));
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
}

.howto__icon--apple {
  background-image: url("/app/assets/icons/dev-apple.svg");
}

.howto__icon--android {
  background-image: url("/app/assets/icons/dev-android.svg");
}

.howto__text {
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--u));
  min-width: 0;
}

.howto__name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(20 * var(--u));
  line-height: 1.1;
}

.howto__note {
  font-family: var(--font-text);
  font-size: calc(13 * var(--u));
  color: rgba(0, 0, 0, .45);
}

/* Шеврон вправо — рисуем рамкой, чтобы не заводить файл ради галочки. */
.howto__arrow {
  flex: none;
  margin-left: auto;
  width: calc(10 * var(--u));
  height: calc(10 * var(--u));
  border-right: calc(2 * var(--u)) solid rgba(0, 0, 0, .35);
  border-bottom: calc(2 * var(--u)) solid rgba(0, 0, 0, .35);
  transform: rotate(-45deg);
}

/* «Привязать Telegram» в профиле сайта: отдельная широкая кнопка над «Выйти / Удалить» */
.pbtns--link[hidden] {
  display: none;
}

.pbtn--link {
  width: calc(388 * var(--u));
  color: rgba(0, 0, 0, 0.75);
}

/* ---------- Экран «Как оплатить?» (макет «2 · Оплата») ----------

   Правка 21.10.2026. Между окном заказа и оплатой встал выбор способа:
   до этого платили всегда СБП, а ?method= в адресе приходил только из
   профиля — на экране тарифов выбрать было нечем.

   Это полноэкранная страница поверх тарифов, а не шторка: в макете у
   неё своя шапка (логотип, шаги, заголовок) и кнопка во всю ширину
   внизу. Шторка заказа остаётся открытой под ней — «назад» возвращает
   в неё, а не на список тарифов. */
.pays-scrim {
  position: fixed;
  left: 50%;
  top: 0;
  width: min(100vw, calc(440 * var(--u)));
  height: 100%;
  transform: translateX(-50%);
  background: var(--bg);
  opacity: 0;
  visibility: hidden;
  /* Выше шторки заказа (10) и панели разделов. */
  z-index: 30;
  transition: opacity .22s ease, visibility .22s ease;
}

.pays-scrim.is-open {
  opacity: 1;
  visibility: visible;
}

.pays {
  position: absolute;
  inset: 0;
  background: var(--bg);
}

/* Стрелка «назад» — на том же месте, что и на экране тарифов, чтобы
   при переходе она не прыгала. */
.pays__back {
  position: absolute;
  left: calc(20 * var(--u));
  top: calc(74 * var(--u));
  width: calc(26 * var(--u));
  height: calc(20 * var(--u));
  padding: 0;
  border: 0;
  background: url("/app/assets/icons/back-arrow.svg") no-repeat center / contain;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: transform .18s ease;
}

/* Та же невидимая подложка под палец, что у .tariffs__back. */
.pays__back::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(48 * var(--u));
  height: calc(48 * var(--u));
  transform: translate(-50%, -50%);
}

.pays__back:active {
  transform: scale(.9);
}

/* Знак «Burger VPN» по центру шапки. Набран шрифтом, как на экране
   устройств (.dev-top__mark): отдельного файла с логотипом в проекте
   нет, а рисовать второй — плодить расхождения. */
.pays__logo {
  position: absolute;
  left: 50%;
  top: calc(68 * var(--u));
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: calc(8 * var(--u));
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(22 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--ink);
  white-space: nowrap;
}

.pays__tag {
  background: var(--ink);
  color: var(--paper);
  font-size: calc(13 * var(--u));
  letter-spacing: .04em;
  padding: calc(4 * var(--u)) calc(8 * var(--u));
  border-radius: calc(8 * var(--u));
}

/* Шаги оформления: две точки и «таблетка» текущего шага */
.pays__steps {
  position: absolute;
  left: calc(24 * var(--u));
  top: calc(140 * var(--u));
  display: flex;
  align-items: center;
  gap: calc(6 * var(--u));
}

.pays__step {
  width: calc(8 * var(--u));
  height: calc(8 * var(--u));
  border-radius: calc(4 * var(--u));
  background: var(--ink);
  transition: width .2s ease, background-color .2s ease;
}

.pays__step.is-active {
  width: calc(26 * var(--u));
  background: #FF2486;
}

/* Надстрочник «Продвинутый · Год» */
.pays__eyebrow {
  position: absolute;
  left: calc(24 * var(--u));
  top: calc(164 * var(--u));
  margin: 0;
  font-family: var(--font-text);
  font-weight: 700;
  font-size: calc(14 * var(--u));
  line-height: 1;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: #FF2486;
}

.pays__title {
  position: absolute;
  left: calc(24 * var(--u));
  top: calc(186 * var(--u));
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(44 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--ink);
}

/* Список способов */
.pays__list {
  position: absolute;
  left: calc(24 * var(--u));
  top: calc(252 * var(--u));
  width: calc(392 * var(--u));
  display: flex;
  flex-direction: column;
  gap: calc(12 * var(--u));
}

/* Строка «Stars + Крипта» — две половинки в ряд */
.pays__row {
  display: flex;
  gap: calc(12 * var(--u));
}

/* Карточка способа */
.pay-opt {
  position: relative;
  width: 100%;
  height: calc(72 * var(--u));
  padding: 0 calc(22 * var(--u));
  display: flex;
  align-items: center;
  gap: calc(14 * var(--u));
  border: calc(2 * var(--u)) solid transparent;
  border-radius: calc(36 * var(--u));
  background: var(--paper);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  text-align: left;
  transition: border-color .18s ease, transform .18s ease;
}

.pay-opt--half {
  flex: 1 1 0;
  min-width: 0;
  /* Места вдвое меньше, чем у строк во всю ширину: «Крипта» обрезалась
     в «Кри…». Ужимаем отступы, зазор, значок и кружок — слово влезает
     целиком, как в макете. */
  padding: 0 calc(14 * var(--u));
  gap: calc(8 * var(--u));
}

.pay-opt--half .pay-opt__icon {
  width: calc(22 * var(--u));
  height: calc(22 * var(--u));
}

.pay-opt--half .pay-opt__mark {
  width: calc(22 * var(--u));
  height: calc(22 * var(--u));
}

.pay-opt--half.is-active .pay-opt__mark::after {
  width: calc(11 * var(--u));
  height: calc(11 * var(--u));
}

.pay-opt.is-active {
  border-color: var(--ink);
}

.pay-opt:active {
  transform: scale(.99);
}

.pay-opt__icon {
  flex: 0 0 auto;
  width: calc(26 * var(--u));
  height: calc(26 * var(--u));
  background: no-repeat center / contain;
}

/* Значки нарисованы инлайном: в макете это плоские чёрные глифы, а
   готовые op-*.svg — тёмные кружки из истории операций, другой вид. */
.pay-opt__icon--sbp {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 2 4 13.5h6L9 22l9-11.5h-6L13 2Z" fill="black"/></svg>');
}

.pay-opt__icon--balance {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><rect x="2.5" y="5.5" width="19" height="13" rx="2.6" fill="none" stroke="black" stroke-width="1.8"/><path d="M2.5 10h19" stroke="black" stroke-width="1.8"/><path d="M5.6 14.6h3.6" stroke="black" stroke-width="1.8" stroke-linecap="round"/></svg>');
}

/* Карта и «С баланса» стоят рядом, и один значок на двоих путал бы.
   У карты — чип слева, у баланса остаётся полоска-подпись снизу. */
.pay-opt__icon--card {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><rect x="2.5" y="5.5" width="19" height="13" rx="2.6" fill="none" stroke="black" stroke-width="1.8"/><path d="M2.5 9.2h19" stroke="black" stroke-width="1.8"/><rect x="5.4" y="12.4" width="4.4" height="3.4" rx="0.9" fill="none" stroke="black" stroke-width="1.5"/></svg>');
}

.pay-opt__icon--stars {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m12 2.6 2.9 5.9 6.5.95-4.7 4.6 1.1 6.45L12 17.45 6.2 20.5l1.1-6.45-4.7-4.6 6.5-.95L12 2.6Z" fill="black"/></svg>');
}

.pay-opt__icon--crypto {
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 1.8 21 7v10l-9 5.2L3 17V7l9-5.2Z" fill="none" stroke="black" stroke-width="1.8" stroke-linejoin="round"/><path d="M12 7.2v9.6M9.6 9.8h3.1a1.8 1.8 0 0 1 0 3.6H9.6h3.4a1.8 1.8 0 0 1 0 3.6H9.6" fill="none" stroke="black" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/></svg>');
}

.pay-opt__name {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(22 * var(--u));
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Сумма на балансе — подсказкой справа от названия */
.pay-opt__sum {
  flex: 0 0 auto;
  margin-right: calc(4 * var(--u));
  font-family: var(--font-number);
  font-weight: 400;
  font-size: calc(15 * var(--u));
  line-height: 1;
  color: rgba(0, 0, 0, .4);
}

/* Кружок-отметка справа */
.pay-opt__mark {
  position: relative;
  flex: 0 0 auto;
  width: calc(26 * var(--u));
  height: calc(26 * var(--u));
  border-radius: 50%;
  border: calc(2 * var(--u)) solid rgba(0, 0, 0, .18);
  transition: border-color .18s ease;
}

.pay-opt.is-active .pay-opt__mark {
  border-color: var(--ink);
}

.pay-opt.is-active .pay-opt__mark::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(13 * var(--u));
  height: calc(13 * var(--u));
  border-radius: 50%;
  background: var(--ink);
  transform: translate(-50%, -50%);
}

/* Кнопка оплаты — розовая, во всю ширину, у нижнего края */
.pays__go {
  position: absolute;
  left: calc(24 * var(--u));
  bottom: calc(118 * var(--u));
  width: calc(392 * var(--u));
  height: calc(76 * var(--u));
  padding: 0;
  border: 0;
  border-radius: calc(38 * var(--u));
  background: #FF2486;
  box-shadow: 0 calc(16 * var(--u)) calc(30 * var(--u)) calc(-12 * var(--u)) rgba(255, 36, 134, .55);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: calc(26 * var(--u));
  line-height: 1;
  color: var(--ink);
  transition: transform .18s ease, opacity .18s ease;
}

.pays__go:active {
  transform: scale(.99);
}

.pays__go:disabled {
  opacity: .6;
  cursor: default;
}

.pays__error {
  position: absolute;
  left: calc(24 * var(--u));
  bottom: calc(204 * var(--u));
  width: calc(392 * var(--u));
  margin: 0;
  text-align: center;
  font-size: calc(14 * var(--u));
  line-height: 1.25;
  color: #BF2121;
}

.pays__error[hidden] {
  display: none;
}

.pay-opt[hidden] {
  display: none;
}

/* На невысоком окне кнопка поднимается к краю, иначе уезжает за обрез */
@media (max-height: 760px) {
  .pays__go {
    bottom: calc(40 * var(--u));
  }
}

/* ---------- Гость на сайте ----------
   Правка 22.10.2026 (Матвей): «когда именно на лендинге заходим на сайт,
   сразу без почты и всего доступен только главный экран с выбором тарифа.
   Кнопки профиль и друзья не видны».

   Класс is-guest ставит web.js, пока нет сессии, и снимает сразу после
   входа. В Telegram его не бывает вовсе: там личность известна с первого
   кадра. Прячем панель целиком, а не две кнопки: её фон — картинка с уже
   вшитыми боковыми площадками, и без значков панель выглядит поломанной.
   Заодно она перестаёт накрывать кнопку «К оплате». */
.is-guest .tabbar {
  display: none;
}

/* Стрелка «назад» гостю тоже ни к чему: на сайте тарифы — первый экран,
   возвращаться ему некуда (в Telegram она ведёт на «Мои устройства»). */
.is-guest .tariffs__back {
  display: none;
}

.money__row .money__withdraw {
  flex: none;
  width: auto;
  margin-top: 0;
  padding: 0 calc(26 * var(--u));
}


/* Правка 16.10.2026 (Евгений): «закомментируй полностью вход/регистрацию,
   они не нужны, все данные из тг берутся». Внутри Telegram личность
   подтверждает подпись initData, имя и username приходят оттуда же —
   форма с почтой и паролем не нужна. Кнопки остаются для сайта
   (.is-browser), где Telegram нет и войти больше нечем. */
.is-telegram .actions {
  display: none;
}

/* ---------- Экран «Инструкция»: выбор устройства ----------

   Правка 19.10.2026 (Евгений): «предлагаю отойти от инструкции в
   телеграфе и открывать все на сайте. Вначале выбор устройства и после
   инструкция с ссылками и фото».

   Каркас общий с тарифами: та же стрелка «назад», тот же заголовок,
   та же панель разделов — экран встраивается в раздел VPN. */
.screen--howto {
  height: calc(700 * var(--u));
}

.howto__lead {
  position: absolute;
  left: calc(20 * var(--u));
  top: calc(118 * var(--u));
  width: calc(400 * var(--u));
  margin: 0;
  font-family: var(--font-text);
  font-size: calc(15 * var(--u));
  line-height: 1.3;
  color: rgba(0, 0, 0, .5);
  text-align: center;
}

/* Карточки в потоке, а не absolute: их всего две, и так экран не
   придётся переразмечать, если добавится третья (телевизор, ПК). */
.howto__list {
  position: absolute;
  left: calc(20 * var(--u));
  top: calc(170 * var(--u));
  width: calc(400 * var(--u));
  display: flex;
  flex-direction: column;
  gap: calc(14 * var(--u));
}

.howto__card {
  display: flex;
  align-items: center;
  gap: calc(16 * var(--u));
  height: calc(86 * var(--u));
  padding: 0 calc(20 * var(--u));
  border-radius: calc(25 * var(--u));
  border: calc(2 * var(--u)) solid transparent;
  text-decoration: none;
  color: var(--ink);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  /* Без этого двойной тап по карточке зумит страницу вместо перехода. */
  touch-action: manipulation;
  /* Та же заливка и обводка-градиент, что у неактивной карточки
     тарифа — экраны должны выглядеть одинаково. */
  background-origin: border-box;
  background-clip: padding-box, border-box;
  background-image:
    linear-gradient(rgba(0, 0, 0, .18), rgba(0, 0, 0, .18)),
    linear-gradient(43deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, .7) 26%,
      rgba(255, 255, 255, .3) 97%,
      rgba(255, 255, 255, .2) 100%);
  transition: transform .18s ease;
}

.howto__card:active {
  transform: scale(.99);
}

.howto__icon {
  flex: none;
  width: calc(40 * var(--u));
  height: calc(40 * var(--u));
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
}

.howto__icon--apple {
  background-image: url("/app/assets/icons/dev-apple.svg");
}

.howto__icon--android {
  background-image: url("/app/assets/icons/dev-android.svg");
}

.howto__text {
  display: flex;
  flex-direction: column;
  gap: calc(2 * var(--u));
  min-width: 0;
}

.howto__name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: calc(20 * var(--u));
  line-height: 1.1;
}

.howto__note {
  font-family: var(--font-text);
  font-size: calc(13 * var(--u));
  color: rgba(0, 0, 0, .45);
}

/* Шеврон вправо — рисуем рамкой, чтобы не заводить файл ради галочки. */
.howto__arrow {
  flex: none;
  margin-left: auto;
  width: calc(10 * var(--u));
  height: calc(10 * var(--u));
  border-right: calc(2 * var(--u)) solid rgba(0, 0, 0, .35);
  border-bottom: calc(2 * var(--u)) solid rgba(0, 0, 0, .35);
  transform: rotate(-45deg);
}

@media (max-height: 760px) {
/* Правка 24.10.2026. На невысоком окне (360x640 — обычный бюджетный
     Android) сетка макета просто не помещается над панелью разделов:
     измерено, кнопка 529..599px при верхе панели на 530 — перекрытие
     69px, и нажать её нельзя вовсе.

     Ужимаем карточки и зазоры: высота карточки 86 -> 72, шаг 94 -> 78.
     Это единственное место, где мы отходим от макетных размеров, — на
     обычном телефоне (390x844 и выше) всё остаётся как в макете. */
  .plan-card {
    height: calc(72 * var(--u));
  }

  .plan-card[data-plan="personal"] { top: calc(100 * var(--u)); }
  .plan-card[data-plan="advanced"] { top: calc(178 * var(--u)); }
  .plan-card[data-plan="family"]   { top: calc(256 * var(--u)); }
  .plan-card[data-plan="custom"]   { top: calc(334 * var(--u)); }

  /* Тот же запас под скругления карточки, что в основной раскладке:
     её низ 406, углы начинаются с 381 (правка 26.10.2026). */
  /* Панель ставим ПОД карточку, а не заводим под неё: у карточки углы
     прозрачные, и в полосе перекрытия сквозь них просвечивает белое —
     углы выглядят срезанными (та же причина, что в основной раскладке,
     правка 26.10.2026). Низ карточки 406, зазор 6. */
  .counter { top: calc(412 * var(--u)); }

  /* Карточка здесь 72 вместо 86, а плашка с ценой осталась макетной
     (14 + 54 = 68) — снизу оставалось 4 единицы, и панель счётчика
     задевала её. Ужимаем плашку вслед за карточкой. */
  .plan-card__price {
    top: calc(10 * var(--u));
    height: calc(48 * var(--u));
  }

  /* Ссылка пробного периода стояла вплотную к панели. */
  .screen--tariffs.has-counter .trial-link { top: calc(494 * var(--u)); }

  .trial-link { top: calc(420 * var(--u)); }

  /* Правка 28.10.2026 (Матвей): после ссылки пробного нужно отделение
     пустотой. Те же 20, что в основной раскладке выше; вариант
     :not(.has-trial) ниже не трогаем — там ссылки нет. */
  .screen--tariffs .tariffs__title--period { top: calc(478 * var(--u)); }
  .screen--tariffs .periods { top: calc(508 * var(--u)); }
  .screen--tariffs .checkout { top: calc(568 * var(--u)); }

  .screen--tariffs:not(.has-trial) .tariffs__title--period { top: calc(436 * var(--u)); }
  .screen--tariffs:not(.has-trial) .periods { top: calc(466 * var(--u)); }
  .screen--tariffs:not(.has-trial) .checkout { top: calc(526 * var(--u)); }

  /* Счётчик «Конструктора» раскрыт — ссылка и всё ниже уходят под него. */
  .screen--tariffs.has-counter .tariffs__title--period { top: calc(516 * var(--u)); }
  .screen--tariffs.has-counter .periods { top: calc(544 * var(--u)); }
  .screen--tariffs.has-counter .checkout { top: calc(598 * var(--u)); }

  .screen--tariffs.has-counter:not(.has-trial) .tariffs__title--period { top: calc(490 * var(--u)); }
  .screen--tariffs.has-counter:not(.has-trial) .periods { top: calc(522 * var(--u)); }
  .screen--tariffs.has-counter:not(.has-trial) .checkout { top: calc(576 * var(--u)); }

  .screen--tariffs.has-counter { height: calc(712 * var(--u)); }

  /* С панелью разделов эта высота мала: кнопка кончается на 684, и на
     панель остаётся 28 единиц вместо 135. Задаём высоту от содержимого:
     низ кнопки плюс панель, иначе до кнопки не долистать (на 440x640
     не хватало ровно 22px). */
  .stage:has(.tabbar) .screen--tariffs.has-counter {
    height: calc(684 * var(--u) + 135 * var(--u));
  }
}

/* ---------- «Как оплатить?»: строки помещаются над кнопкой, «С баланса» — не способ ----------
   Правка 31.10.2026 (скриншот из Telegram): с четвёртой строкой («С баланса» к СБП, Карте и Stars/Крипте)
   список не помещался, и розовая «Оплатить» ложилась на нижний ряд.

   Высота строки теперь считается от окна: сколько места между списком и кнопкой, поделённое на четыре
   строки (худший случай), но не больше макетных 72 и не меньше 54. Высокое окно остаётся как в макете.
   Верх списка 252, кнопка стоит на 118 от низа (на невысоком окне — на 40), зазор над ней 12, между
   строками по 12. */
.pays__list {
  --pay-row: clamp(
    calc(54 * var(--u)),
    calc((100vh - 494 * var(--u)) / 4),
    calc(72 * var(--u))
  );
  --pay-row: clamp(
    calc(54 * var(--u)),
    calc((100dvh - 494 * var(--u)) / 4),
    calc(72 * var(--u))
  );
}

.pays__list .pay-opt {
  height: var(--pay-row);
}

/* Условие записано с max-width: тесты раскладки тарифов ищут последний блок для невысоких окон по точной
   строке условия и не должны принимать этот блок за свой */
@media (max-width: 9999px) and (max-height: 760px) {
  .pays__list {
    --pay-row: clamp(
      calc(54 * var(--u)),
      calc((100vh - 416 * var(--u)) / 4),
      calc(72 * var(--u))
    );
    --pay-row: clamp(
      calc(54 * var(--u)),
      calc((100dvh - 416 * var(--u)) / 4),
      calc(72 * var(--u))
    );
  }
}

/* «С баланса» — флажок (зачёт к выбранному способу), а не вариант выбора: квадратная отметка с галочкой
   и розовая обводка вместо чёрной. Раньше она выглядела такой же радиокнопкой, и казалось, что выбрано
   два способа оплаты сразу (скриншот Марии). */
.pay-opt[role="checkbox"] .pay-opt__mark {
  border-radius: calc(8 * var(--u));
}

.pay-opt[role="checkbox"].is-active {
  border-color: #FF2486;
}

.pay-opt[role="checkbox"].is-active .pay-opt__mark {
  border-color: #FF2486;
  background: #FF2486;
}

.pay-opt[role="checkbox"].is-active .pay-opt__mark::after {
  width: calc(7 * var(--u));
  height: calc(12 * var(--u));
  border-radius: 0;
  background: none;
  border: solid var(--ink);
  border-width: 0 calc(2.5 * var(--u)) calc(2.5 * var(--u)) 0;
  transform: translate(-50%, -58%) rotate(45deg);
}
