/* ==========================================================================
   Движение интерфейса
   Один файл на все анимации: каждое действие получает короткий отклик.
   Держим их быстрыми (120–380 мс) и на transform/opacity — они не заставляют
   браузер пересчитывать вёрстку, поэтому не дёргаются на слабых машинах.
   В самом низу — полное отключение для тех, кто просил уменьшить движение.
   ========================================================================== */

/* ---------- базовые кривые ---------- */
:root {
  --ease-out: cubic-bezier(.22, .8, .3, 1);
  --ease-soft: cubic-bezier(.4, 0, .2, 1);
}

/* ---------- появление страницы ---------- */
@keyframes fadeUp {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes popIn {
  0%   { opacity: 0; transform: scale(.94); }
  60%  { opacity: 1; transform: scale(1.01); }
  100% { opacity: 1; transform: scale(1); }
}
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-6px); }
  40% { transform: translateX(5px); }
  60% { transform: translateX(-3px); }
  80% { transform: translateX(2px); }
}
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes pulseSoft {
  0%, 100% { opacity: 1; }
  50% { opacity: .45; }
}

/* ---------- нажатия и наведения ---------- */
.btn, .ep-btn, .send-btn, .cap-btn, .model-btn, .refund-btn, .chat-item, .mm-item {
  transition: transform .16s var(--ease-out), background .18s var(--ease-soft),
              border-color .18s var(--ease-soft), box-shadow .22s var(--ease-out),
              color .18s var(--ease-soft), opacity .18s var(--ease-soft);
}
.btn:active, .send-btn:active, .model-btn:active, .cap-btn:active, .refund-btn:active {
  transform: scale(.97);
}
.btn-primary:hover { transform: translateY(-1px); }
.tariff, .card, .rank-card { transition: transform .3s var(--ease-out), box-shadow .3s var(--ease-out); }
.tariff:hover, .rank-card:hover { transform: translateY(-4px); }

/* иконки соцсетей и знак статуса чуть оживают под курсором */
.social a { transition: transform .2s var(--ease-out), background .2s, color .2s, border-color .2s; }
.social a:hover { transform: translateY(-2px) scale(1.06); }
.rank-box:hover .rank-shape { transform: rotate(-8deg) scale(1.06); }
.rank-shape { transition: transform .35s var(--ease-out); }

/* ---------- чат: сообщения ---------- */
.m { animation: fadeUp .32s var(--ease-out) both; }
.m.user .body { transform-origin: right center; }
/* ответ проявляется чуть медленнее — видно, что он «пришёл», а не был всегда */
.m.assistant .text { animation: fadeIn .35s var(--ease-soft) both; }
.cost-row { animation: fadeUp .3s var(--ease-out) both; }

/* курсор печати */
.typing {
  display: inline-block;
  width: 7px; height: 1em;
  margin-left: 2px;
  background: currentColor;
  vertical-align: -2px;
  border-radius: 1px;
  animation: blink 1s steps(2, start) infinite;
}

/* ---------- чат: боковая панель ---------- */
.chat-item { animation: fadeUp .26s var(--ease-out) both; }
.chat-item:hover { transform: translateX(2px); }
.chat-item .del { transition: opacity .18s var(--ease-soft), transform .18s var(--ease-out), color .15s; }
.chat-item:hover .del { transform: scale(1.1); }
.chat-item.leaving { animation: chatLeave .22s var(--ease-soft) forwards; }
@keyframes chatLeave {
  to { opacity: 0; transform: translateX(-14px); max-height: 0; padding-top: 0; padding-bottom: 0; margin: 0; }
}

/* полоски остатка и прогресса статуса ползут, а не прыгают */
.free-bar i { transition: width .5s var(--ease-out); }

/* ---------- чат: выбор модели ---------- */
.model-menu { transform-origin: top right; animation: popIn .2s var(--ease-out) both; }
.mm-item:hover { transform: translateX(3px); }

/* ---------- чат: панели ---------- */
.cap-panel { animation: fadeUp .22s var(--ease-out) both; }
.paywall { animation: popIn .3s var(--ease-out) both; }
.msg.show { animation: fadeUp .25s var(--ease-out) both; }
.msg.error.show { animation: shake .4s var(--ease-soft) both; }

/* кнопка отправки: во время ответа крутится, а не просто гаснет */
.send-btn.sending {
  pointer-events: none;
  position: relative;
  color: transparent;
}
.send-btn.sending::after {
  content: '';
  position: absolute; inset: 8px;
  border: 2px solid rgba(255, 255, 255, .35);
  border-top-color: #fff;
  border-radius: 50%;
  animation: spin .7s linear infinite;
}

/* оценка стоимости мигает, пока считается */
.estimate.calc .est-dot { animation: pulseSoft .9s var(--ease-soft) infinite; }

/* ---------- формы и кассы ---------- */
.input, textarea, select {
  transition: border-color .18s var(--ease-soft), box-shadow .22s var(--ease-out), background .18s;
}
.input:focus, textarea:focus { box-shadow: 0 0 0 4px rgba(13, 14, 18, .07); }
.pack-card, .tariff .btn { transition: transform .18s var(--ease-out); }

/* ---------- появление блоков лендинга ---------- */
.one-price, .free-block, .status-card { animation: fadeUp .4s var(--ease-out) both; }

/* ==========================================================================
   Секция «Возможности» — постоянное движение
   Всё построено на transform и opacity: браузер не пересчитывает вёрстку,
   поэтому карточки не подтормаживают даже на слабых машинах.
   Ниже по файлу стоит общий выключатель для «уменьшить движение».
   ========================================================================== */

/* мягкие пятна за карточками — задают жизнь пустому фону */
#features { position: relative; overflow: hidden; }
#features::before,
#features::after {
  content: '';
  position: absolute;
  width: 46vw; height: 46vw;
  max-width: 620px; max-height: 620px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 0;
  background: radial-gradient(circle, rgba(13, 14, 18, .07), transparent 68%);
}
#features::before { top: -14%; left: -12%; animation: blobA 22s ease-in-out infinite; }
#features::after  { bottom: -18%; right: -10%; animation: blobB 27s ease-in-out infinite; }
@keyframes blobA {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50%      { transform: translate(7vw, 4vw) scale(1.12); }
}
@keyframes blobB {
  0%, 100% { transform: translate(0, 0) scale(1.06); }
  50%      { transform: translate(-6vw, -5vw) scale(.94); }
}
#features .wrap { position: relative; z-index: 1; }

/* Карточки чуть дышат, каждая в своём такте.
   Парение и подъём под курсором складываются в одном transform через
   отдельные величины: раньше при наведении анимация снималась, и карточка
   скачком уходила из середины цикла — отсюда резкость. */
@property --fy { syntax: '<length>'; inherits: false; initial-value: 0px; }
@property --hy { syntax: '<length>'; inherits: false; initial-value: 0px; }

#features .card {
  position: relative;
  overflow: hidden;
  transform: translate3d(0, calc(var(--fy) + var(--hy)), 0);
  animation: cardFloat 8s ease-in-out infinite;
  transition: --hy .4s var(--ease-out),
              border-color .3s var(--ease-soft),
              box-shadow .4s var(--ease-out);
}
/* такт задаётся построчно: соседи в ряду поднимаются вместе,
   иначе карточки в одной строке разъезжаются по высоте */
#features .card:nth-child(3), #features .card:nth-child(4) { animation-delay: -2.7s; }
#features .card:nth-child(5), #features .card:nth-child(6) { animation-delay: -5.4s; }
@keyframes cardFloat {
  0%, 100% { --fy: 0px; }
  50%      { --fy: -5px; }
}
#features .card:hover {
  --hy: -10px;                       /* плавно, поверх текущего парения */
  border-color: var(--text);
  box-shadow: 0 22px 50px rgba(13, 14, 18, .13);
}

/* по тёмным карточкам раз в несколько секунд проходит хромовый блик */
#features .card.dark::after {
  content: '';
  position: absolute;
  top: -60%; bottom: -60%; left: 0; width: 55%;
  pointer-events: none;
  background: linear-gradient(100deg, transparent 0%, rgba(255, 255, 255, .16) 45%, transparent 100%);
  transform: translateX(-180%) rotate(8deg);
  animation: sheen 7s ease-in-out infinite;
}
#features .card.dark:nth-child(5)::after { animation-delay: -3.5s; }
@keyframes sheen {
  0%, 55%  { transform: translateX(-180%) rotate(8deg); }
  100%     { transform: translateX(320%) rotate(8deg); }
}

/* номер: тонкое кольцо расходится от значка */
#features .card-num { position: relative; }
#features .card-num::after {
  content: '';
  position: absolute; inset: -3px;
  border-radius: inherit;
  border: 1px solid currentColor;
  opacity: 0;
  animation: numRing 5s ease-out infinite;
}
#features .card:nth-child(2) .card-num::after { animation-delay: -.8s; }
#features .card:nth-child(3) .card-num::after { animation-delay: -1.6s; }
#features .card:nth-child(4) .card-num::after { animation-delay: -2.4s; }
#features .card:nth-child(5) .card-num::after { animation-delay: -3.2s; }
#features .card:nth-child(6) .card-num::after { animation-delay: -4s; }
@keyframes numRing {
  0%   { opacity: .45; transform: scale(.92); }
  60%  { opacity: 0;   transform: scale(1.3); }
  100% { opacity: 0;   transform: scale(1.3); }
}

/* ==========================================================================
   Статусы — мячик скачет по ступеням
   Карточки стоят лесенкой (раскладка в style.css), а мячик перепрыгивает
   с одной на другую снизу вверх: видно, что каждый следующий статус выше.
   Горизонталь и вертикаль разведены по двум элементам — обёртка едет вбок
   ровными шагами, шарик внутри рисует дугу. Обёртка шириной ровно в один
   шаг сетки (колонка + отступ), поэтому translateX(100%) = соседняя карточка.
   ========================================================================== */
@media (min-width: 1081px) {
  .rank-hop {
    display: block;
    position: absolute;
    top: 0;
    left: calc(var(--rgap) / -2);
    width: calc((100% + var(--rgap)) / 5);
    height: 0;
    z-index: 3;
    pointer-events: none;
    animation: hopX 7s linear infinite;
  }
  .rank-hop i {
    display: block;
    width: 15px; height: 15px;
    margin: 0 auto;
    border-radius: 50%;
    background: radial-gradient(circle at 32% 26%, #767c8e, var(--text) 64%);
    box-shadow: 0 7px 14px rgba(13, 14, 18, .3);
    animation: hopY 7s linear infinite;
  }

  /* карточка отзывается на приземление тонким кольцом;
     задержки = момент касания в семисекундном цикле */
  .rank-card::after {
    content: '';
    position: absolute;
    inset: -1px;
    border-radius: inherit;
    border: 1px solid var(--text);
    opacity: 0;
    pointer-events: none;
    animation: rankLit 7s ease-out infinite;
  }
  .rank-card:nth-child(2)::after { animation-delay: 1.54s; }
  .rank-card:nth-child(3)::after { animation-delay: 3.08s; }
  .rank-card:nth-child(4)::after { animation-delay: 4.62s; }
  .rank-card:nth-child(5)::after { animation-delay: 6.16s; }
}

@keyframes hopX {
  0%        { transform: translateX(0);    opacity: 0; }
  4%, 10%   { transform: translateX(0);    opacity: 1; }
  22%, 32%  { transform: translateX(100%); }
  44%, 54%  { transform: translateX(200%); }
  66%, 76%  { transform: translateX(300%); }
  88%, 94%  { transform: translateX(400%); opacity: 1; }
  97%       { transform: translateX(400%); opacity: 0; }
  99%, 100% { transform: translateX(0);    opacity: 0; }
}

/* Вверх — с замедлением, вниз — с разгоном: так дуга читается как настоящий
   прыжок. После касания короткий доскок, чтобы мячик не прилипал к крышке.
   Все карточки на одном уровне, поэтому опора у всех прыжков одна. */
@keyframes hopY {
  0%, 10%   { transform: translateY(var(--rest)); animation-timing-function: cubic-bezier(.2, .75, .45, 1); }
  16%       { transform: translateY(calc(var(--rest) - var(--arc))); animation-timing-function: cubic-bezier(.55, .05, .85, .5); }
  22%       { transform: translateY(var(--rest)); animation-timing-function: cubic-bezier(.25, .8, .5, 1); }
  25%       { transform: translateY(calc(var(--rest) - 8px)); animation-timing-function: cubic-bezier(.55, .05, .85, .5); }
  28%, 32%  { transform: translateY(var(--rest)); animation-timing-function: cubic-bezier(.2, .75, .45, 1); }
  38%       { transform: translateY(calc(var(--rest) - var(--arc))); animation-timing-function: cubic-bezier(.55, .05, .85, .5); }
  44%       { transform: translateY(var(--rest)); animation-timing-function: cubic-bezier(.25, .8, .5, 1); }
  47%       { transform: translateY(calc(var(--rest) - 8px)); animation-timing-function: cubic-bezier(.55, .05, .85, .5); }
  50%, 54%  { transform: translateY(var(--rest)); animation-timing-function: cubic-bezier(.2, .75, .45, 1); }
  60%       { transform: translateY(calc(var(--rest) - var(--arc))); animation-timing-function: cubic-bezier(.55, .05, .85, .5); }
  66%       { transform: translateY(var(--rest)); animation-timing-function: cubic-bezier(.25, .8, .5, 1); }
  69%       { transform: translateY(calc(var(--rest) - 8px)); animation-timing-function: cubic-bezier(.55, .05, .85, .5); }
  72%, 76%  { transform: translateY(var(--rest)); animation-timing-function: cubic-bezier(.2, .75, .45, 1); }
  82%       { transform: translateY(calc(var(--rest) - var(--arc))); animation-timing-function: cubic-bezier(.55, .05, .85, .5); }
  88%       { transform: translateY(var(--rest)); animation-timing-function: cubic-bezier(.25, .8, .5, 1); }
  91%       { transform: translateY(calc(var(--rest) - 8px)); animation-timing-function: cubic-bezier(.55, .05, .85, .5); }
  94%, 100% { transform: translateY(var(--rest)); }
}

/* Телефон: мячик появляется в правом верхнем углу первой карточки и падает вниз,
   отскакивая от того же угла следующей. Кадры собирает mobile.js по фактическим
   координатам карточек (высота у них разная), пуск — когда блок виден на экране. */
@keyframes nodeLit {
  0%        { transform: scale(1.9); box-shadow: 0 0 0 4px rgba(13, 14, 18, .10); }
  9%, 100%  { transform: scale(1); box-shadow: 0 0 0 0 rgba(13, 14, 18, 0); }
}

@keyframes rankLit {
  0%        { opacity: .8; transform: scale(1); }
  9%        { opacity: 0;  transform: scale(1.035); }
  100%      { opacity: 0;  transform: scale(1.035); }
}

/* ==========================================================================
   Мобильное меню — раскрывается, а не возникает
   Полотно разворачивается сверху вниз (от шапки), строки подтягиваются
   лесенкой снизу. Закрытие короче открытия: уходить всегда быстрее.
   ========================================================================== */
@media (max-width: 760px) {
  .nav-links.open { animation: menuIn .34s var(--ease-out) both; }
  .nav-links.open > * { animation: menuItem .36s var(--ease-out) both; }
  .nav-links.open > *:nth-child(1) { animation-delay: .07s; }
  .nav-links.open > *:nth-child(2) { animation-delay: .11s; }
  .nav-links.open > *:nth-child(3) { animation-delay: .15s; }
  .nav-links.open > *:nth-child(4) { animation-delay: .19s; }
  .nav-links.open > *:nth-child(5) { animation-delay: .23s; }
  .nav-links.open > *:nth-child(6) { animation-delay: .27s; }
  .nav-links.open > *:nth-child(7) { animation-delay: .31s; }
  .nav-links.open > *:nth-child(8) { animation-delay: .35s; }
  /* закрытие — то же движение задом наперёд: полотно сворачивается вверх,
     строки уходят разом, чтобы не растягивать прощание */
  .nav-links.open.closing { animation: menuOut .3s var(--ease-out) both; }
  .nav-links.open.closing > * { animation: menuItemOut .16s var(--ease-soft) both; }
}
@keyframes menuIn {
  from { opacity: 1; clip-path: inset(0 0 100% 0); }
  to   { opacity: 1; clip-path: inset(0 0 0 0); }
}
@keyframes menuOut {
  from { opacity: 1; clip-path: inset(0 0 0 0); }
  to   { opacity: 1; clip-path: inset(0 0 100% 0); }
}
@keyframes menuItemOut {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(10px); }
}
@keyframes menuItem {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}

/* ---------- уважение к системной настройке ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
