/* VPN-32 Telegram Mini App — dark theme, 1:1 with design/vpn32-miniapp.html
   Reusable tokens / phone shell / tab bar / keyframes live here.
   Per-screen markup keeps the design's inline styles (in app.js) for pixel fidelity. */

:root{
  /* уровень предмета и центра колец — доля высоты экрана, ЕДИНАЯ для всех экранов
     (щит главной, шаги мастера, «Оплачено»): при переключении ничего не перескакивает.
     На низких экранах чуть выше, чтобы текст главной не налезал на кнопки. */
  --ringK:.30;
  --bg:#0C0E11;
  --ink:#F2F3F5;
  --muted:#C2C8D0;
  --muted2:#B6BCC4;
  --dim:#7E848E;
  --row:#121419;
  --green:#7ED69F;
  --green-ink:#A6E5C0;
  --amber:#E3C77A;
  --coral:#D87C66;
  --safe-top:env(safe-area-inset-top,0px);
  --safe-bottom:env(safe-area-inset-bottom,0px);
}

*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
/* тот же цвет, что у экрана: если кадр отрисовался раньше содержимого, подложка не темнее */
html{background:var(--bg);-webkit-text-size-adjust:100%;}
body{
  margin:0;
  background:var(--bg);
  color:var(--ink);
  font-family:'Manrope',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
  min-height:100vh;
  min-height:100dvh;
  overflow-x:hidden;
}
img{max-width:100%;}
a{color:inherit;text-decoration:none;}
button{font:inherit;color:inherit;background:none;border:0;margin:0;padding:0;cursor:pointer;-webkit-tap-highlight-color:transparent;}

/* ---- phone shell: dark content area, edge to edge, full viewport ---- */
/* Постоянный фон под всеми экранами: та же колонка-«телефон», что #app. Круги в нём
   рисуются один раз в index.html и НЕ перерисовываются при навигации — поэтому на любом
   экране они стоят на одном и том же месте и анимация не стартует заново. */
#bg{
  position:fixed;
  top:0;bottom:0;left:0;right:0;
  margin:0 auto;
  width:100%;
  max-width:520px;
  overflow:hidden;
  pointer-events:none;
  background:var(--bg);
}
#app{
  position:relative;   /* поверх #bg */
  z-index:1;
  display:block;
  width:100%;
  max-width:520px;      /* keep it phone-shaped on wide screens */
  margin:0 auto;
  min-height:var(--vh, 100dvh);
}
/* Все экраны одного размера — ровно вьюпорт Telegram. Что не влезло, прокручивается
   ВНУТРИ экрана, поэтому страница целиком не «едет» и высота везде одинаковая. */
.screen{
  position:relative;
  /* колонка контента уже вьюпорта (как у Ultima): на телефоне не влияет, а в широком
     окне (Telegram Desktop) кнопки перестают растягиваться во всю ширину */
  max-width:450px;
  margin:0 auto;
  /* --vh приходит из Telegram (viewportStableHeight): dvh в вебвью врёт,
     и низ экрана уезжал под край окна */
  height:var(--vh, 100dvh);
  min-height:var(--vh, 100dvh);
  overflow-y:auto;
  overflow-x:hidden;
  -webkit-overflow-scrolling:touch;
  overscroll-behavior:contain;
  scrollbar-width:none;
  isolation:isolate;
  /* фон прозрачный: тёмную подложку и круги даёт постоянный слой #bg — экран его не перекрывает */
  background:transparent;
  color:var(--ink);
  display:flex;
  flex-direction:column;
  padding:calc(20px + var(--safe-top)) 20px calc(18px + var(--safe-bottom));
}
.screen::-webkit-scrollbar{display:none;}
.screen.pad-tight{padding-top:calc(14px + var(--safe-top));}
/* экран ровно в высоту вьюпорта: длинный список прокручивается внутри (.scroll),
   а шапка, плашка со ссылкой и таб-бар остаются на месте (профиль) */
/* профиль и «частые вопросы» прокручивают только середину: шапка и нижняя кнопка
   должны оставаться на месте, поэтому сам экран не скроллится */
.screen.fixed{overflow:hidden;}

/* ---- планшет/узкое окно: тот же «телефон» по центру, но с рамкой и глубиной фона ---- */
@media (min-width: 700px){
  html{background:radial-gradient(120% 90% at 50% 0%, #101318 0%, #08090B 60%) fixed #08090B;}
  body{background:transparent;}
  #app{box-shadow:0 0 0 1px rgba(255,255,255,.08), 0 40px 120px rgba(0,0,0,.6);}
}

/* ---- боковое меню сайта: живёт в index.html вне #app, на телефоне скрыто ---- */
#rail{display:none;}

/* ---- ноутбук/большой экран: полноценный сайт — меню слева, тёмная карта контента справа.
       Карту рисует постоянный слой #bg (он же держит фоновые круги), контент #app лежит
       поверх него колонкой привычной ширины по центру. Нижний таб-бар не нужен — его
       заменяет боковое меню (тот же data-action="tab", обработчик общий). ---- */
@media (min-width: 1024px){
  :root{--railw:264px;--cardgap:18px;}
  #rail{
    display:flex;flex-direction:column;
    position:fixed;left:0;top:0;bottom:0;width:var(--railw);
    z-index:2;padding:26px 20px 22px;
  }
  #rail .brand{
    display:flex;align-items:center;gap:11px;padding:0 10px;
    font-family:'Unbounded',sans-serif;font-size:17px;font-weight:700;
  }
  #rail nav{margin:auto 0;display:flex;flex-direction:column;gap:6px;padding-bottom:8vh;}
  #rail nav button{
    display:flex;align-items:center;gap:12px;
    padding:12px 14px;border-radius:14px;
    font-size:15px;font-weight:700;color:var(--muted);
    transition:background .12s ease,color .12s ease;
  }
  #rail nav button:hover{background:rgba(255,255,255,.06);color:var(--ink);}
  #rail nav button.active{background:linear-gradient(135deg,#FFFFFF,#D3D7DC);color:#0F1113;}
  #rail nav svg{width:20px;height:20px;stroke:currentColor;fill:none;flex:none;}
  #rail .foot{padding:0 10px;font-size:12.5px;color:var(--dim);}

  /* фоновый слой превращается в карту контента со скруглением и рамкой */
  #bg{
    left:var(--railw);right:var(--cardgap);top:var(--cardgap);bottom:var(--cardgap);
    width:auto;max-width:none;margin:0;
    border-radius:26px;border:1px solid rgba(255,255,255,.09);
    box-shadow:0 30px 80px rgba(0,0,0,.5);
  }
  #app{
    margin:var(--cardgap) var(--cardgap) var(--cardgap) var(--railw);
    width:auto;max-width:none;min-height:0;
    box-shadow:none;
  }
  .screen{
    height:calc(var(--vh, 100dvh) - var(--cardgap)*2);
    min-height:calc(var(--vh, 100dvh) - var(--cardgap)*2);
    max-width:600px;margin:0 auto;
    padding:30px 24px 26px;
  }
  /* нижний таб-бар заменён боковым меню; #app в селекторе — чтобы перебить
     базовое правило .tabbar, объявленное ниже по файлу */
  #app .tabbar{display:none;}
  /* экраны входа/загрузки: навигация не нужна — меню прячем, карта на всю ширину */
  body.bare #rail{display:none;}
  body.bare #bg{left:var(--cardgap);}
  body.bare #app{margin-left:var(--cardgap);}
}

/* animated background blobs — живут в постоянном слое #bg (index.html), не в экранах */
.blob{position:absolute;border-radius:50%;pointer-events:none;}

/* Кольца (постоянный слой #bg): ТОЛЬКО медленные волны, расходящиеся от центра героя.
   Статичной сетки окружностей больше нет — рядом с ней движение читалось как «стоит».
   Слой не перерисовывается — при переходах волны не прерываются и не прыгают. */
/* --ringK — доля высоты экрана, где стоит центр колец и героя: .34 на главной,
   .45 на шагах мастера (там заголовок сверху, предмет по середине свободной зоны).
   Смена якоря плавная — кольца переезжают, а не прыгают. */
.rings{position:absolute;left:50%;top:calc(var(--vh, 100dvh) * var(--ringK, .34));width:0;height:0;pointer-events:none;transition:opacity .45s ease, top .5s cubic-bezier(.3,.8,.3,1);}
/* Экраны без колец (всё, кроме главной и «оплачено»): волны мягко гаснут за .45с.
   Класс ставит render() в app.js — список экранов с кольцами там же, в RINGS_ON. */
body.norings .rings{opacity:0;}
/* Волна: кольцо выезжает из-за щита (240px) и уходит далеко за край экрана (1280px) —
   ход шире прежнего, поэтому видно, что круги едут, а не стоят. Яркость держим почти
   до конца пути, иначе на чёрном фоне волна пропадает на полдороге. Отрицательные
   задержки — четыре волны сразу в противофазе, интервал 1.9с. */
.wring{position:absolute;left:0;top:0;transform:translate(-50%,-50%);border:1.5px solid rgba(255,255,255,.34);border-radius:50%;animation:vRipple 7.6s linear infinite;}
@keyframes vRipple{
  0%{width:240px;height:240px;opacity:0}
  7%{opacity:.38}
  78%{opacity:.16}
  100%{width:1280px;height:1280px;opacity:0}
}
/* Герой шагов мастера (flowHero в app.js): полоса между заголовком и кнопками целиком,
   предмет по её середине. Ужимается вместе с полосой, поэтому на низком окне не наезжает
   ни на «ШАГ N ИЗ 3» сверху, ни на кнопки снизу. */
.hero-flow{position:relative;flex:1 1 auto;min-height:0;display:flex;flex-direction:column;align-items:center;justify-content:center;pointer-events:none;}
.hero-obj{position:relative;width:264px;height:264px;max-height:100%;flex:0 1 auto;display:flex;align-items:center;justify-content:center;}

/* мягкое проявление экрана при СМЕНЕ экрана (только opacity — без сдвига и вспышки) */
@keyframes vScreenIn{from{opacity:0}to{opacity:1}}

/* ---- dark back header (light Telegram chrome from mockups is intentionally omitted) ---- */
/* Отрицательные поля гасят выросший внутренний отступ кнопки: стрелка осталась ровно на
   прежнем месте, а попасть по ней теперь можно с 48px вместо 36px. */
.backbar{
  position:relative;
  display:flex;
  align-items:center;
  gap:6px;
  margin:-6px 0 0 -8px;
  flex:none;
}
.backbar button{
  display:flex;align-items:center;gap:4px;
  padding:14px 12px 14px 8px;border-radius:12px;
  color:var(--muted);font-size:16px;font-weight:700;
}
.backbar button:active{background:rgba(255,255,255,.06);}
.backbar svg{width:20px;height:20px;}

/* Невидимая «подушка» вокруг маленькой кнопки (крестик устройства, переключатель
   автопродления, строка про промокод): рисунок прежний, а палец попадает с запасом. */
.hit{position:relative;}
.hit::after{content:'';position:absolute;inset:-9px;border-radius:inherit;}

/* ---- generic pressable feedback on interactive design blocks ---- */
[data-action]{-webkit-tap-highlight-color:transparent;}
[data-action]:not(.tab):active{filter:brightness(.94);}
.tap{cursor:pointer;transition:transform .05s ease, filter .1s ease;}
.tap:active{transform:scale(.985);}

/* ---- tab bar (bottom): row of 4 pills, active = white gradient ---- */
.tabbar{
  position:relative;
  display:flex;
  gap:8px;
  margin-top:16px;
  flex:none;
}
.tab{
  flex:1;height:54px;border-radius:999px;
  display:flex;align-items:center;justify-content:center;
  background:rgba(255,255,255,.07);
  border:1px solid rgba(255,255,255,.12);
}
.tab svg{width:21px;height:21px;stroke:var(--muted);}
.tab.active{
  background:linear-gradient(135deg,#FFFFFF,#D3D7DC);
  border:0;
}
.tab.active svg{stroke:#0F1113;}

/* ---- сегментный переключатель (тарифы: Год / 3 месяца / Месяц) ---- */
.seg{
  position:relative;display:flex;gap:6px;padding:5px;
  background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.12);border-radius:999px;
}
.seg button{
  flex:1;font-size:16px;font-weight:700;color:var(--muted);
  text-align:center;padding:11px 4px;border-radius:999px;
}
.seg button.on{background:linear-gradient(135deg,#FFFFFF,#D3D7DC);color:#0F1113;font-weight:800;}

/* ---- ползунок «сколько устройств» ---- */
.slider{position:relative;height:26px;display:flex;align-items:center;touch-action:pan-y;}
.slider input{
  position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:pointer;
}
.slider .trk{position:absolute;left:0;right:0;height:6px;border-radius:999px;background:rgba(255,255,255,.12);}
.slider .fil{position:absolute;left:0;height:6px;border-radius:999px;background:linear-gradient(90deg,#FFFFFF,#B6BCC4);}
/* .snap стоит в покое: ручка мягко доезжает до ступени. Во время перетаскивания класс
   снимается — иначе ручка тянулась бы за пальцем с задержкой. */
.slider.snap .fil,
.slider.snap .knb{transition:left .22s cubic-bezier(.2,.9,.3,1), width .22s cubic-bezier(.2,.9,.3,1);}
.slider .knb{transition:transform .12s ease;}
.slider:active .knb{transform:scale(1.12);}
.slider .knb{
  position:absolute;margin-left:-13px;width:26px;height:26px;border-radius:50%;
  background:linear-gradient(135deg,#FFFFFF,#C7CBD2);box-shadow:0 4px 12px rgba(0,0,0,.45);
  pointer-events:none;
}
/* засечки ступеней — чисто ориентир, тянуть можно в любом месте дорожки */
.slider .dot{
  position:absolute;top:50%;margin-top:-4px;margin-left:-4px;
  width:8px;height:8px;border-radius:50%;
  background:rgba(255,255,255,.34);pointer-events:none;transition:opacity .15s ease;
}
.slider .dot.on{opacity:0;}

/* ---- аккордеон «частые вопросы» ---- */
.faq{background:rgba(255,255,255,.055);border:1px solid rgba(255,255,255,.11);border-radius:18px;padding:13px 16px;}
.faq.on{background:rgba(255,255,255,.08);border-color:rgba(255,255,255,.18);}
.faq .a{font-size:15px;color:var(--muted);line-height:1.5;margin-top:6px;display:none;}
.faq.on .a{display:block;}

/* ---- аватар профиля: фото из Telegram, при отсутствии/ошибке — инициалы ---- */
.ava{
  width:52px;height:52px;border-radius:50%;flex:none;
  background:linear-gradient(135deg,#FAFBFC,#C7CBD2);color:#0F1113;
  display:flex;align-items:center;justify-content:center;font-weight:800;font-size:19px;
}

/* ---- конфетти на экране «Готово!» ---- */
.conf{position:absolute;inset:0;z-index:9;pointer-events:none;overflow:hidden;}

/* ---- бумажный чек: белая лента с зубчатыми краями ---- */
.receipt{
  position:relative;background:#F4F5F7;color:#14181A;
  font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.5;
  padding:24px 20px 26px;box-shadow:0 18px 40px rgba(0,0,0,.45);
}
/* зубцы — полукруги цвета фона экрана, «отрывающие» ленту сверху и снизу */
.receipt::before,
.receipt::after{
  content:'';position:absolute;left:0;right:0;height:10px;
  background:radial-gradient(circle at 5px 5px, var(--bg) 5px, transparent 5.5px) repeat-x;
  background-size:10px 10px;
}
.receipt::before{top:-5px;}
.receipt::after{bottom:-5px;}
.rc-head{text-align:center;font-size:19px;font-weight:700;letter-spacing:.22em;}
.rc-sub{text-align:center;font-size:11px;letter-spacing:.16em;color:#5C626B;margin-top:4px;text-transform:uppercase;}
.rc-sep{border-top:1px dashed rgba(20,24,26,.28);margin:12px 0;}
.rc-line{display:flex;align-items:baseline;gap:6px;margin:5px 0;}
.rc-k{white-space:nowrap;color:#3A3E45;}
/* точечный лидер между названием и суммой — как на кассовой печати */
.rc-dots{flex:1;border-bottom:1px dotted rgba(20,24,26,.35);transform:translateY(-3px);}
.rc-v{white-space:nowrap;font-weight:700;}
.rc-total{display:flex;justify-content:space-between;align-items:baseline;font-size:17px;font-weight:700;letter-spacing:.06em;}
/* штамп ставим под углом, как оттиск печати */
.rc-stamp{
  margin:16px auto 0;width:max-content;border:2px solid;border-radius:6px;
  padding:6px 14px;font-size:13px;font-weight:700;letter-spacing:.18em;
  transform:rotate(-7deg);opacity:.85;
}

/* ---- toast ---- */
.toast{
  position:fixed;left:50%;bottom:calc(24px + var(--safe-bottom));
  transform:translateX(-50%) translateY(12px);
  background:#1A1D22;color:#F2F3F5;
  border:1px solid rgba(255,255,255,.14);
  border-radius:14px;padding:12px 18px;font-size:15px;font-weight:700;
  box-shadow:0 12px 30px rgba(0,0,0,.5);
  opacity:0;pointer-events:none;transition:opacity .22s ease, transform .22s ease;
  z-index:50;max-width:88vw;text-align:center;
}
.toast.show{opacity:1;transform:translateX(-50%) translateY(0);}

/* ---- small helper: selected radio / check states toggled by JS ---- */
.rd{width:24px;height:24px;border-radius:50%;border:2px solid rgba(255,255,255,.22);flex:none;display:flex;align-items:center;justify-content:center;}
.rd.on{background:#F2F3F5;border:0;color:#0F1113;font-size:15px;font-weight:800;}

/* спиннер ожидания входа */
@keyframes vSpinBtn{to{transform:rotate(360deg);}}
.spin{animation:vSpinBtn .9s linear infinite;}

/* прокручиваемый список внутри экрана (профиль) — шапка и таб-бар остаются на месте */
.scroll{-webkit-overflow-scrolling:touch;overscroll-behavior:contain;scrollbar-width:none;}
.scroll::-webkit-scrollbar{display:none;}

/* поле ввода почты на экране «Сохранение доступа» */
#emailInput{width:100%;background:none;border:none;outline:none;color:#F2F3F5;
  font-family:inherit;font-size:16px;font-weight:600;padding:13px 0;}
#emailInput::placeholder{color:#6B727C;font-weight:500;}
#emailInput:disabled{opacity:.6;}

/* ---- ячейки промокода: символы видно по одному, поле ввода лежит поверх ---- */
.pc-wrap{position:relative;}
.pc-row{display:flex;gap:8px;justify-content:center;}
.pc{
  flex:1;max-width:54px;aspect-ratio:.86;border-radius:14px;
  background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.12);
  display:flex;align-items:center;justify-content:center;
  font-family:'JetBrains Mono',monospace;font-size:20px;font-weight:700;color:#F2F3F5;
  transition:border-color .15s ease, background .15s ease;
}
.pc-on{background:rgba(255,255,255,.09);border-color:rgba(255,255,255,.26);}
/* код друга длиннее промокода — ячейки ужимаем, чтобы строка не вылезла за экран */
.pc-row.pc-long{gap:5px;}
.pc-long .pc{max-width:34px;border-radius:10px;font-size:15px;}
/* каретка: подсвечиваем ячейку, в которую попадёт следующий символ */
.pc-cur{border-color:rgba(255,255,255,.5);}
.pc-ok{border-color:rgba(126,214,159,.5);background:rgba(126,214,159,.1);color:#C9EBD6;}
.pc-bad{border-color:rgba(216,124,102,.5);background:rgba(216,124,102,.1);color:#EDB4A3;}
/* само поле невидимо и растянуто по ячейкам — тап открывает клавиатуру */
.pc-wrap #promoInput{
  position:absolute;inset:0;width:100%;height:100%;
  opacity:0;background:none;border:0;padding:0;color:transparent;
  font-size:16px;             /* меньше 16px — Safari зумит страницу при фокусе */
}


/* Экраны появляются мгновенно, без fade-анимации: раньше .screen на КАЖДЫЙ render проигрывал
   vFade (старт с opacity:0 = чёрная вспышка + сдвиг = дёрганье) при любом тапе по кнопке/вкладке. */
@view-transition{navigation:auto;}
@keyframes vFade{from{opacity:0;transform:translateY(6px);}to{opacity:1;transform:none;}}

/* ---- keyframes copied 1:1 from the design ---- */
@keyframes vDrift{0%{transform:translate(0,0) scale(1)}50%{transform:translate(40px,-30px) scale(1.18)}100%{transform:translate(0,0) scale(1)}}
@keyframes vDrift2{0%{transform:translate(0,0) scale(1.1)}50%{transform:translate(-46px,34px) scale(.92)}100%{transform:translate(0,0) scale(1.1)}}
@keyframes vSpin{from{transform:translate(-50%,-50%) rotate(0)}to{transform:translate(-50%,-50%) rotate(360deg)}}
/* пульс колец: шире размах и ярче вспышка, чем в исходном макете — кольцо должно
   «выстреливать» из-под щита, а не еле проступать */
/* Волна доходит до бортов приложения и только там исчезает. Ключевое — не размер,
   а непрозрачность: раньше кольцо гасло на полпути и до краёв долетало невидимым. */
@keyframes vPulse{
  0%{transform:translate(-50%,-50%) scale(.34);opacity:0}
  6%{opacity:1}
  55%{opacity:.72}
  85%{opacity:.34}
  100%{transform:translate(-50%,-50%) scale(2.15);opacity:0}
}
/* дыхание свечения: больше разница масштаба и прозрачности, чтобы биение читалось */
@keyframes vBreath{
  0%{transform:translate(-50%,-50%) scale(.86);opacity:.35}
  50%{transform:translate(-50%,-50%) scale(1.16);opacity:1}
  100%{transform:translate(-50%,-50%) scale(.86);opacity:.35}
}
@keyframes vWave{0%{transform:scale(.36);opacity:0}14%{opacity:.5}100%{transform:scale(1.55);opacity:0}}
@keyframes vRot{from{transform:rotate(0)}to{transform:rotate(360deg)}}
@keyframes vConf{0%{transform:translate(0,0) rotate(0);opacity:0}8%{opacity:1}100%{transform:translate(var(--dx),var(--dy)) rotate(var(--rot));opacity:0}}

@media (max-height:640px){
  :root{--ringK:.24;}
}

@media (prefers-reduced-motion:reduce){
  *{animation-duration:.001ms !important;animation-iteration-count:1 !important;}
  .screen{animation:none;}
}
