﻿/* motion.css — анимации форума (без layout-shift, 2026-10-16) */

:root {
  --motion-micro: 120ms;
  --motion-fast: 180ms;
  --motion-base: 220ms;
  --motion-route: 220ms;
  --motion-ease-emphasized: cubic-bezier(0.2, 0, 0, 1);
  --motion-ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
  --motion-ease-decel: cubic-bezier(0, 0, 0.2, 1);
  --motion-ease-accel: cubic-bezier(0.4, 0, 1, 1);
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --motion-micro: 0ms;
    --motion-fast: 0ms;
    --motion-base: 0ms;
    --motion-route: 0ms;
  }
}

#view {
  view-transition-name: forum-view;
  transition: opacity var(--motion-base) var(--motion-ease-emphasized);
}

#view.is-leaving {
  opacity: 0;
}

#view.is-entering {
  animation: fr-view-enter var(--motion-base) var(--motion-ease-emphasized) backwards;
}

@keyframes fr-view-enter {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Поверхности, вход (видимый финальный state; ≤ 5 элементов по спискам). */
.fr-fade-in,
.forum-card, .conversation-item, .chat-message,
.pf-card, .pf-side-card, .pf-person, .pf-act-row,
.board-card, .sv-card, .topic-row,
.hero, .pf-hero, .section-header, .chat-header,
.profile-empty, .msg-menu-item, .peer-menu-item,
.notif-panel, .ui-select, .ui-date,
.auth-modal, .gs-modal, .msg-modal,
.bd-modal, .sv-modal, .th-modal, .mod-modal,
.crop-modal, .card {
  animation: fr-surface-in var(--motion-micro) var(--motion-ease-decel) both;
}

@keyframes fr-surface-in {
  from { opacity: 0; transform: translateY(5px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Stagger utility, applied by JS только там, где нужен. */
.motion-stagger-1 { animation-delay: 40ms; }
.motion-stagger-2 { animation-delay: 80ms; }
.motion-stagger-3 { animation-delay: 120ms; }
.motion-stagger-4 { animation-delay: 160ms; }
.motion-stagger-5 { animation-delay: 200ms; }

/* Модалки и оверлеи. */
.auth-modal-backdrop,
.msg-modal-backdrop,
.gs-modal-backdrop,
.sv-modal-backdrop,
.bd-modal-backdrop,
.th-modal-backdrop,
.mod-backdrop,
.crop-backdrop,
.th-modal-backdrop {
  animation: fr-backdrop-in var(--motion-fast) var(--motion-ease-standard) both;
}

@keyframes fr-backdrop-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

.auth-modal-backdrop.is-leaving,
.mod-backdrop.is-leaving,
.crop-backdrop.is-leaving,
.gs-modal-backdrop.is-leaving,
.msg-modal-backdrop.is-leaving,
.sv-modal-backdrop.is-leaving,
.bd-modal-backdrop.is-leaving,
.th-modal-backdrop.is-leaving {
  animation: fr-backdrop-out var(--motion-micro) var(--motion-ease-accel) both;
}

@keyframes fr-backdrop-out {
  from { opacity: 1; }
  to { opacity: 0; }
}

.auth-modal,
.gs-modal,
.msg-modal,
.bd-modal,
.sv-modal,
.th-modal,
.mod-modal,
.crop-modal {
  animation: fr-modal-in var(--motion-fast) var(--motion-ease-decel) both;
  transform-origin: center;
}

@keyframes fr-modal-in {
  from { opacity: 0; transform: scale(0.97); }
  to { opacity: 1; transform: scale(1); }
}

.auth-modal.is-leaving,
.gs-modal.is-leaving,
.msg-modal.is-leaving,
.bd-modal.is-leaving,
.sv-modal.is-leaving,
.th-modal.is-leaving,
.mod-modal.is-leaving,
.crop-modal.is-leaving {
  animation: fr-modal-out var(--motion-micro) var(--motion-ease-accel) both;
}

@keyframes fr-modal-out {
  from { opacity: 1; transform: scale(1); }
  to { opacity: 0; transform: scale(0.97); }
}

/* Всплывания (auth profile, context menu, chat menus, notif). */
.auth-menu,
.peer-menu,
.msg-menu,
.dropdown,
.popover,
.tooltip,
.notif-panel {
  animation: fr-popup-in var(--motion-micro) var(--motion-ease-decel) both;
  transform-origin: top center;
}

@keyframes fr-popup-in {
  from { opacity: 0; transform: scaleY(0.96) translateY(-2px); }
  to { opacity: 1; transform: scaleY(1) translateY(0); }
}

/* Toast. */
.toast-wrap {
  pointer-events: none;
}

.toast {
  animation: fr-toast-in var(--motion-fast) var(--motion-ease-decel) both;
}

.toast.is-leaving {
  animation: fr-toast-out var(--motion-fast) var(--motion-ease-accel) both;
}

@keyframes fr-toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes fr-toast-out {
  from { opacity: 1; transform: translateY(0); }
  to { opacity: 0; transform: translateY(8px); }
}

@keyframes fr-badge-bump {
  from { transform: scale(1); }
  50% { transform: scale(1.18); }
  to { transform: scale(1); }
}

.badge {
  animation: fr-badge-bump var(--motion-fast) var(--motion-ease-emphasized) both;
}

.skeleton {
  animation: fr-skeleton-pulse 1.2s var(--motion-ease-standard) infinite alternate;
}

.server-card-skeleton {
  display: grid;
  gap: 10px;
}

.server-skeleton-label,
.server-skeleton-name,
.server-skeleton-row i {
  display: block;
  height: 8px;
  border-radius: 4px;
  background: var(--border-light, #3a3f4a);
}

.server-skeleton-label { width: 72px; }
.server-skeleton-name { width: 78%; height: 12px; margin: 3px 0; }

.server-skeleton-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
}

.server-skeleton-row i:first-child { width: 42px; }
.server-skeleton-row i:last-child { width: 58px; }

@keyframes fr-skeleton-pulse {
  from { opacity: 0.35; }
  to { opacity: 0.75; }
}

/* Формы / ошибки. */
.auth-error.is-shake,
.form-shake {
  animation: fr-shake 220ms var(--motion-ease-standard) both;
}

@keyframes fr-shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-3px); }
  50% { transform: translateX(3px); }
  75% { transform: translateX(-1px); }
}

/* Капча: смена картинки по opacity. */
.auth-captcha img {
  transition: opacity var(--motion-micro) var(--motion-ease-standard);
  will-change: opacity;
}

.auth-captcha img.is-crossfading {
  opacity: 0;
}

/* Сообщения ЛС. */
.chat-message {
  animation: fr-message-in var(--motion-fast) var(--motion-ease-decel) both;
}

@keyframes fr-message-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

.chat-message.is-new {
  animation: fr-new-message var(--motion-fast) var(--motion-ease-decel) both;
}

@keyframes fr-new-message {
  from { opacity: 0; transform: translateY(8px); }
  40% { opacity: 0.95; }
  to { opacity: 1; transform: translateY(0); }
}

/* Кнопки и поля. */
button, .button {
  transition: background var(--motion-micro) var(--motion-ease-standard),
              border-color var(--motion-micro) var(--motion-ease-standard),
              color var(--motion-micro) var(--motion-ease-standard),
              transform var(--motion-micro) var(--motion-ease-standard);
}

button:active, .button:active {
  transform: scale(0.98);
}

input, textarea, select {
  transition: border-color var(--motion-micro) var(--motion-ease-standard),
              box-shadow var(--motion-micro) var(--motion-ease-standard),
              background var(--motion-micro) var(--motion-ease-standard);
}

input:focus, textarea:focus, select:focus {
  border-color: var(--accent, #D6332E);
}

/* Переход затрагивает только содержимое страницы; оболочка остаётся статичной. */
::view-transition-old(forum-view) {
  animation: fr-root-out var(--motion-route) var(--motion-ease-accel) both;
}

::view-transition-new(forum-view) {
  animation: fr-root-in var(--motion-route) var(--motion-ease-decel) both;
}

@keyframes fr-root-out {
  from { opacity: 1; transform: translateY(0); }
  to { opacity: 0; transform: translateY(-2px); }
}

@keyframes fr-root-in {
  from { opacity: 0; transform: translateY(2px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Небольшой stagger только для первых пяти элементов видимых списков. */
#view .forum-grid > .forum-card:nth-child(1),
#view .topic-row:nth-child(1),
#view .sv-card:nth-child(1),
#view .conversation-item:nth-child(1) { animation-delay: 40ms; }

#view .forum-grid > .forum-card:nth-child(2),
#view .topic-row:nth-child(2),
#view .sv-card:nth-child(2),
#view .conversation-item:nth-child(2) { animation-delay: 80ms; }

#view .forum-grid > .forum-card:nth-child(3),
#view .topic-row:nth-child(3),
#view .sv-card:nth-child(3),
#view .conversation-item:nth-child(3) { animation-delay: 120ms; }

#view .forum-grid > .forum-card:nth-child(4),
#view .topic-row:nth-child(4),
#view .sv-card:nth-child(4),
#view .conversation-item:nth-child(4) { animation-delay: 160ms; }

#view .forum-grid > .forum-card:nth-child(5),
#view .topic-row:nth-child(5),
#view .sv-card:nth-child(5),
#view .conversation-item:nth-child(5) { animation-delay: 200ms; }

@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  #view .forum-card,
  #view .topic-row,
  #view .sv-card {
    transition: background var(--motion-micro) var(--motion-ease-standard),
                translate var(--motion-micro) var(--motion-ease-standard);
  }

  #view .forum-card:hover,
  #view .forum-card:focus-visible,
  #view .topic-row:hover,
  #view .topic-row:focus-visible,
  #view .sv-card:hover {
    translate: 0 -1px;
  }

  .forum-icon,
  .topic-icon {
    transition: transform var(--motion-fast) var(--motion-ease-standard);
  }

  .forum-card:hover .forum-icon,
  .forum-card:focus-visible .forum-icon,
  .topic-row:hover .topic-icon,
  .topic-row:focus-visible .topic-icon {
    transform: scale(1.05);
  }
}

@media (prefers-reduced-motion: reduce) {
  .fr-fade-in, .auth-error.is-shake, .form-shake, .auth-captcha img,
  #view, #view.is-entering, #view.is-leaving,
  .auth-modal-backdrop, .msg-modal-backdrop, .gs-modal-backdrop,
  .sv-modal-backdrop, .bd-modal-backdrop, .th-modal-backdrop,
  .mod-backdrop, .crop-backdrop,
  .forum-card, .forum-icon, .topic-icon, .topic-row, .sv-card, .conversation-item, .chat-message,
  .pf-card, .pf-side-card, .pf-person, .pf-act-row,
  .board-card, .sv-card, .topic-row,
  .hero, .pf-hero, .section-header, .chat-header,
  .profile-empty, .msg-menu-item, .peer-menu-item,
  .notif-panel, .ui-select, .ui-date,
  .auth-modal, .gs-modal, .msg-modal, .bd-modal, .sv-modal,
  .th-modal, .mod-modal, .crop-modal, .card,
  .auth-menu, .peer-menu, .msg-menu, .dropdown, .popover, .tooltip,
  .toast, .badge, .skeleton, button, .button, input, textarea, select {
    transition: none !important;
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
    translate: none !important;
  }

  .server-skeleton-label,
  .server-skeleton-name,
  .server-skeleton-row i {
    opacity: 0.55 !important;
  }

  ::view-transition-old(forum-view),
  ::view-transition-new(forum-view) {
    animation: none !important;
  }
}

/* ---------------------------------------------------------------------------
   Мобильные анимации (≤780px). На телефоне нет hover, а базовые появления
   (120 мс, сдвиг 5px) почти не видны, поэтому здесь они длиннее и заметнее,
   а нажатие даёт отклик через :active. Блок целиком выключается, если в системе
   включено «Уменьшение движения».
   Все «входные» анимации идут с fill-mode backwards и без конечного кадра:
   после окончания transform не остаётся на элементе (иначе он становится
   контейнером для position:fixed внутри).
   --------------------------------------------------------------------------- */
@media (max-width: 780px) and (prefers-reduced-motion: no-preference) {
  :root { --motion-m-ease: cubic-bezier(0.2, 0.8, 0.2, 1); }

  /* Страница: резервный вход (router.js, браузеры без View Transitions). */
  #view.is-entering { animation: fr-m-view-in 340ms var(--motion-m-ease) backwards; }
  @keyframes fr-m-view-in { from { opacity: 0; transform: translateY(14px); } }

  /* Там, где View Transitions есть, переход тоже делаем заметнее. */
  ::view-transition-old(forum-view) { animation: fr-m-root-out 160ms var(--motion-ease-accel) both; }
  ::view-transition-new(forum-view) { animation: fr-m-root-in 340ms var(--motion-m-ease) both; }
  @keyframes fr-m-root-out { to { opacity: 0; transform: translateY(-6px); } }
  @keyframes fr-m-root-in { from { opacity: 0; transform: translateY(16px); } }

  /* Карточки и блоки: подъём с задержкой по порядку. */
  .fr-fade-in, .forum-card, .conversation-item, .pf-card, .pf-side-card, .pf-person,
  .pf-act-row, .board-card, .sv-card, .topic-row, .hero, .pf-hero, .section-header,
  .profile-empty, .card, .chat-header {
    animation: fr-m-rise 440ms var(--motion-m-ease) backwards;
  }
  @keyframes fr-m-rise { from { opacity: 0; transform: translateY(22px); } }

  #view .pf-card:nth-child(2), #view .pf-side-card:nth-child(2), #view .board-card:nth-child(2) { animation-delay: 70ms; }
  #view .pf-card:nth-child(3), #view .pf-side-card:nth-child(3), #view .board-card:nth-child(3) { animation-delay: 140ms; }
  #view .pf-card:nth-child(4), #view .pf-side-card:nth-child(4), #view .board-card:nth-child(4) { animation-delay: 210ms; }
  #view .pf-card:nth-child(5), #view .pf-side-card:nth-child(5), #view .board-card:nth-child(5) { animation-delay: 280ms; }

  /* Сообщения: свои — вылетают справа, чужие — слева. */
  .chat-message.sent, .chat-message.sent.is-new {
    transform-origin: right bottom;
    animation: fr-m-msg-right 380ms var(--motion-m-ease) backwards;
  }
  .chat-message.received, .chat-message.received.is-new {
    transform-origin: left bottom;
    animation: fr-m-msg-left 380ms var(--motion-m-ease) backwards;
  }
  @keyframes fr-m-msg-right { from { opacity: 0; transform: translateX(28px) scale(0.96); } }
  @keyframes fr-m-msg-left { from { opacity: 0; transform: translateX(-28px) scale(0.96); } }

  /* Появление при прокрутке (js/mobileMotion.js): класс rv ставится только тем
     блокам, что ниже экрана; без JS всё просто видно. */
  .rv { opacity: 0; transform: translateY(28px); animation: none; }
  #view .rv.rv-in {
    opacity: 1;
    transform: none;
    transition: opacity 500ms var(--motion-m-ease), transform 500ms var(--motion-m-ease);
  }

  /* Отклик на касание вместо hover. */
  #view .forum-card, #view .topic-row, #view .sv-card, #view .board-card,
  #view .pf-person, #view .conversation-item, #view .pf-act-row {
    transition: scale 140ms var(--motion-ease-standard), background 140ms var(--motion-ease-standard);
  }
  #view .forum-card:active, #view .topic-row:active, #view .sv-card:active,
  #view .board-card:active, #view .pf-person:active, #view .conversation-item:active,
  #view .pf-act-row:active {
    scale: 0.985;
  }

  /* Нижняя панель. */
  .tabbar-item { transition: color 200ms var(--motion-ease-standard), scale 140ms var(--motion-ease-standard); }
  .tabbar-item:active { scale: 0.92; }
  .tabbar-item.active svg { animation: fr-m-tab-pop 440ms cubic-bezier(0.3, 1.5, 0.5, 1) backwards; }
  @keyframes fr-m-tab-pop { from { transform: translateY(5px) scale(0.78); } }

  /* Боковое меню: шторка выезжает, затемнение плавно появляется и исчезает,
     пункты выезжают по очереди. Класс closing ставит sidebar.js. */
  .sidebar { transition: transform 340ms var(--motion-m-ease); }
  .sidebar-backdrop.open { animation: fr-backdrop-in 280ms ease both; }
  .sidebar-backdrop.closing {
    display: block; position: fixed; inset: 0; z-index: 105;
    background: rgba(0, 0, 0, 0.5); pointer-events: none;
    animation: fr-backdrop-out 260ms ease both;
  }
  .sidebar.open .sidebar-link { animation: fr-m-drawer-item 440ms var(--motion-m-ease) backwards; }
  .sidebar.open .sidebar-link:nth-of-type(1) { animation-delay: 60ms; }
  .sidebar.open .sidebar-link:nth-of-type(2) { animation-delay: 100ms; }
  .sidebar.open .sidebar-link:nth-of-type(3) { animation-delay: 140ms; }
  .sidebar.open .sidebar-link:nth-of-type(4) { animation-delay: 180ms; }
  .sidebar.open .sidebar-link:nth-of-type(5) { animation-delay: 220ms; }
  .sidebar.open .sidebar-link:nth-of-type(6) { animation-delay: 260ms; }
  .sidebar.open .sidebar-link:nth-of-type(n+7) { animation-delay: 300ms; }
  @keyframes fr-m-drawer-item { from { opacity: 0; transform: translateX(-20px); } }

  /* Окна выезжают снизу. Закрытие (.is-leaving) остаётся прежним. */
  .auth-modal, .gs-modal, .msg-modal, .bd-modal, .sv-modal, .th-modal, .mod-modal, .crop-modal {
    transform-origin: bottom center;
    animation: fr-m-sheet-in 400ms var(--motion-m-ease) backwards;
  }
  @keyframes fr-m-sheet-in { from { opacity: 0; transform: translateY(40px) scale(0.97); } }
}
