/* Микроанимации интерфейса.
 *
 * Правило одно: движение объясняет действие, а не украшает его. Корзина —
 * подпрыгивает, колокольчик — звонит, удаление — уезжает, обновление — крутится,
 * стрелка «в магазин» — уходит вперёд. Длительности 0.2–0.45с: заметно, но не
 * задерживает. В самом низу — общий выключатель для prefers-reduced-motion.
 */

/* Базовое: любая кнопка проминается под пальцем. */
button {
  transition: transform .12s ease, background-color .2s ease, color .2s ease,
              border-color .2s ease, opacity .2s ease;
}
button:active { transform: scale(.96); }

/* ── «+ В корзину»: кнопка отдаёт товар, вкладка корзины его принимает ── */
@keyframes addPop {
  0%   { transform: scale(1); }
  35%  { transform: scale(.9); }
  70%  { transform: scale(1.08); }
  100% { transform: scale(1); }
}
.add.pop { animation: addPop .34s ease; }

@keyframes cartBump {
  0%   { transform: translateY(-1px) scale(1); }
  40%  { transform: translateY(-7px) scale(1.16); }
  100% { transform: translateY(-1px) scale(1); }
}
nav.tabbar button .ic.bump { animation: cartBump .45s cubic-bezier(.3, 1.4, .5, 1); }

@keyframes badgePop { from { transform: scale(0); } 60% { transform: scale(1.25); } to { transform: scale(1); } }
.nav-badge { animation: badgePop .28s ease; }

/* ── Колокольчик «Следить»: звонит при подписке ── */
@keyframes bellRing {
  0%, 100% { transform: rotate(0); }
  15% { transform: rotate(-14deg); }
  30% { transform: rotate(11deg); }
  45% { transform: rotate(-8deg); }
  60% { transform: rotate(5deg); }
  75% { transform: rotate(-3deg); }
}
.bell.ring { animation: bellRing .6s ease; }

/* ── Удаление: строка уезжает вправо и схлопывается ── */
@keyframes rowOut {
  to { opacity: 0; transform: translateX(40px); max-height: 0;
       padding-top: 0; padding-bottom: 0; margin-top: 0; margin-bottom: 0; }
}
.watch-item { animation: cardIn .32s ease both; animation-delay: calc(var(--i, 0) * 40ms); }
.wi-off { animation: badgePop .4s ease both; animation-delay: calc(var(--i, 0) * 40ms + .2s); }
.cart-item.removing,
.watch-item.removing { animation: rowOut .24s ease forwards; overflow: hidden; max-height: 140px; }

/* «Очистить» — действие разрушительное, кнопка вздрагивает */
@keyframes shakeX {
  10%, 90% { transform: translateX(-1px); }
  20%, 80% { transform: translateX(2px); }
  30%, 50%, 70% { transform: translateX(-3px); }
  40%, 60% { transform: translateX(3px); }
}
.link-btn:active { animation: shakeX .35s ease; }

/* ── «Обновить»: пока идёт обновление, значок крутится ── */
.refresh-btn .ic { display: inline-block; vertical-align: -.2em; }
.refresh-btn .ic .i { display: block; }
.refresh-btn.spinning .ic { animation: spin .9s linear infinite; }

/* ── «В магазин →»: стрелка уходит вперёд ── */
.store-link .arr,
.open-store .arr { display: inline-block; transition: transform .18s ease; }
.store-link:active .arr,
.open-store:active .arr { transform: translateX(5px); }

/* ── Выдача: карточки выкладываются лесенкой сверху вниз ── */
@keyframes cardIn { from { opacity: 0; transform: translateY(9px); } to { opacity: 1; transform: none; } }
.card.enter { animation: cardIn .3s ease both; animation-delay: calc(var(--i, 0) * 26ms); }

/* ── Скидки: история цены разворачивается, галочка переворачивается ── */
.wi-chevron { display: inline-block; transition: transform .22s ease; }
.watch-item.open .wi-chevron { transform: rotate(180deg); }
@keyframes panelIn { from { opacity: 0; transform: translateY(-7px); } to { opacity: 1; transform: none; } }
.wh-panel { animation: panelIn .22s ease; }

/* ── Меню: иконка активной вкладки подпрыгивает, экран въезжает по ходу движения ── */
@keyframes tabPop {
  0%   { transform: translateY(-1px) scale(1); }
  45%  { transform: translateY(-5px) scale(1.12); }
  100% { transform: translateY(-1px) scale(1); }
}
nav.tabbar button.active .ic { animation: tabPop .32s cubic-bezier(.3, 1.4, .5, 1); }

@keyframes viewFromRight { from { opacity: 0; transform: translateX(20px); } to { opacity: 1; transform: none; } }
@keyframes viewFromLeft  { from { opacity: 0; transform: translateX(-20px); } to { opacity: 1; transform: none; } }
@keyframes viewFromBelow { from { opacity: 0; transform: translateY(18px) scale(.985); } to { opacity: 1; transform: none; } }
.view.active.from-right { animation: viewFromRight .26s cubic-bezier(.2, .8, .2, 1); }
.view.active.from-left  { animation: viewFromLeft .26s cubic-bezier(.2, .8, .2, 1); }
.view.active.from-below { animation: viewFromBelow .3s cubic-bezier(.2, .8, .2, 1); }
/* подложка активной вкладки в меню перетекает, а не перескакивает */
nav.tabbar button .ic { transition: background-color .25s ease, color .25s ease; }

/* ── Въезд экрана: его карточки выкладываются лесенкой (класс entering держится
      ~0.7с после переключения, перерисовки позже — без анимации) ── */
.view.entering :is(.watch-item, .cart-group, .saved-row, .set-group, .shop-card, .rec-card,
                   .nt-day, .nt-sec, .nt-modes, .tile, .cart-total) {
  animation: cardIn .34s cubic-bezier(.2, .8, .2, 1) both;
}
.view.entering :is(.watch-item, .cart-group, .saved-row, .set-group, .shop-card, .rec-card, .nt-sec):nth-child(2) { animation-delay: 40ms; }
.view.entering :is(.watch-item, .cart-group, .saved-row, .set-group, .shop-card, .rec-card, .nt-sec):nth-child(3) { animation-delay: 80ms; }
.view.entering :is(.watch-item, .cart-group, .saved-row, .set-group, .shop-card, .rec-card, .nt-sec):nth-child(4) { animation-delay: 120ms; }
.view.entering :is(.watch-item, .cart-group, .saved-row, .set-group, .shop-card, .rec-card, .nt-sec):nth-child(n+5) { animation-delay: 160ms; }

/* ── Переливы: градиентные кнопки и цифры «БЖУ»/«Протеина» медленно текут.
      Переключатель режимов БЖУ в теме — белая плашка: переливать там нечего,
      а анимация фона перерисовывала бы её в каждом кадре ── */
@keyframes gradFlow { from { background-position: 0% 50%; } to { background-position: 100% 50%; } }
#v-nutrition .rec-primary:not(:disabled),
#v-search .protein-chip.active,
.nt-kcal b {
  background-size: 220% 100%;
  animation: gradFlow 5s ease-in-out infinite alternate;
}
/* кольцо калорий заполняется, а не появляется готовым (см. NutritionTab._renderData) */
@property --p { syntax: "<number>"; inherits: false; initial-value: 0; }
.nt-ring { transition: --p .9s cubic-bezier(.2, .8, .2, 1); }

/* ── Пока ищем: скелеты карточек с бегущим бликом вместо пустоты ── */
@keyframes shimmer { from { background-position: 150% 0; } to { background-position: -50% 0; } }
.skel { display: flex; gap: 12px; margin-bottom: 10px; padding: 12px; border-radius: var(--radius, 16px); background: var(--card); box-shadow: var(--shadow); animation: fade .3s ease both; animation-delay: calc(var(--i, 0) * 60ms); }
.skel i { display: block; border-radius: 10px;
  background: linear-gradient(100deg, var(--sep) 30%, color-mix(in srgb, var(--card) 70%, var(--sep)) 50%, var(--sep) 70%) var(--sep);
  background-size: 200% 100%; animation: shimmer 1.3s linear infinite; }
.skel .s-img { width: 72px; height: 72px; flex-shrink: 0; }
.skel .s-lines { flex: 1; display: flex; flex-direction: column; gap: 8px; padding-top: 4px; }
.skel .s-lines i:nth-child(1) { height: 12px; width: 40%; }
.skel .s-lines i:nth-child(2) { height: 14px; width: 85%; }
.skel .s-lines i:nth-child(3) { height: 18px; width: 30%; }
.state.searching { padding: 10px 20px 16px; }
.state.searching .spinner { margin: 0 auto 8px; }
[data-theme="vv"] #results > .skel.skel { grid-column: auto; flex-direction: column; margin: 0; }
[data-theme="vv"] #results .skel .s-img { width: 100%; height: auto; aspect-ratio: 1; border-radius: 16px; }

/* ── Шестерёнка настроек поворачивается, как настоящая ── */
header .gear { transition: transform .3s ease; }
header .gear:active { transform: rotate(90deg) scale(.94); }

/* ── Поиск: поле «зажигается» в фокусе, подсказки проявляются ── */
.search input { transition: border-color .15s ease, box-shadow .2s ease; }
.search input:focus { box-shadow: 0 0 0 3px var(--accent-soft); }
.ac { animation: fade .15s ease; }

/* ── Чипы и плитки под поиском выкладываются лесенкой, как карточки ── */
#suggest > * { animation: cardIn .3s ease both; animation-delay: calc(var(--i, 0) * 30ms); }
/* плитка: иконка продукта проминается отдельно от подписи */
.tile-ic { transition: transform .15s ease; }
.tile:active { transform: none; }
.tile:active .tile-ic { transform: scale(.9); }
/* плитки-действия («БЖУ», «Протеин») — не товары: при прокрутке до них иконка
   покачивается, а по подложке пробегает блик (класс nudge ставит SearchTab) */
@keyframes tileWiggle {
  0%, 100% { transform: none; }
  20% { transform: rotate(-10deg) scale(1.08); }
  40% { transform: rotate(8deg) scale(1.08); }
  60% { transform: rotate(-4deg) scale(1.04); }
  80% { transform: rotate(2deg); }
}
@keyframes tileShine { from { transform: translateX(-120%) skewX(-20deg); } to { transform: translateX(220%) skewX(-20deg); } }
.tile-action.nudge .tile-ic .i { animation: tileWiggle .8s ease .15s both; }
.tile-action.nudge:not(.loading) .tile-ic::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 45%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .75), transparent);
  animation: tileShine .9s ease .1s both;
}

/* ── Переключатели (Категория, ИИ, ₽/кг, Дороже, группы выдачи, диета в профиле):
      включённый «щёлкает» — видно, что нажатие принято ── */
@keyframes iconPop {
  0%   { transform: scale(1) rotate(0); }
  45%  { transform: scale(1.3) rotate(-12deg); }
  100% { transform: scale(1) rotate(0); }
}
.chip.cat-mode.active .i { animation: iconPop .35s cubic-bezier(.3, 1.4, .5, 1); }
@keyframes chipOn { 0% { transform: scale(.9); } 60% { transform: scale(1.06); } 100% { transform: scale(1); } }
.refine-chip.active,
.pf-chip.on { animation: chipOn .26s ease; }
/* точка «запрос можно расширить» появляется с отскоком */
.chip.cat-mode .hint:not([hidden]) { animation: badgePop .28s ease; }

/* ── Пустые экраны, ошибки, подсказки ИИ: проявляются, а не возникают ── */
.state { animation: fade .25s ease both; }
.state > .i { animation: badgePop .35s ease both; }
.ai-note:not([hidden]),
.corrected { animation: fade .2s ease both; }

/* ── Настройки: «Мой район» раскрывается, найденные места выкладываются ── */
.store-picker:not([hidden]) { animation: panelIn .22s ease; }
.store-opt { animation: cardIn .25s ease both; }

/* ── Полоски: БЖУ, нормы и статистика растут от нуля ── */
@keyframes barX { from { transform: scaleX(0); } }
.nt-bar i { transform-origin: left; animation: barX .5s ease both; }
/* в карточке дня полоски растут переходом от прошлого значения (NutritionTab._fillDay),
   а не с нуля на каждую перерисовку */
.nt-day .nt-mrow .nt-bar i { animation: none; transition: width .7s cubic-bezier(.2, .8, .2, 1); }
@keyframes barY { from { transform: scaleY(0); } }
.st-bars i { transform-origin: bottom; animation: barY .45s ease both; }
.st-bars i:nth-child(n+8) { animation-delay: .08s; }

/* ── «БЖУ» на карточке: по кнопке пробегает блик — её замечают. Раз в ~4с,
      у соседних карточек со сдвигом по --i, чтобы не мигали хором ── */
@keyframes nutriShine {
  0%, 72% { transform: translateX(-130%) skewX(-20deg); }
  100%    { transform: translateX(230%) skewX(-20deg); }
}
.nutri::after {
  content: ""; position: absolute; inset: 0; width: 60%; pointer-events: none;
  /* подложка светлая — белый блик на ней не виден, бежит полоса цвета акцента */
  background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--accent) 35%, transparent), transparent);
  transform: translateX(-130%) skewX(-20deg);
  animation: nutriShine 4.2s ease-in-out infinite;
  animation-delay: calc(var(--i, 0) * 180ms + 1s);
}

/* ── Ингредиенты рецепта: новая строка появляется, удалённая исчезает ── */
@keyframes ingIn { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
.ing-row.enter { animation: ingIn .22s ease; }

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