/* ═══════════════════════════════════════════════════════════════════
   Движение.

   Правило одно: анимация подсказывает, а не задерживает. Всё короче
   четверти секунды, ничего не прыгает, ничего не ждёт. Задача — чтобы
   интерфейс не «моргал» между состояниями и было видно, что нажатие
   дошло и что-то происходит.
   ═══════════════════════════════════════════════════════════════════ */

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

@keyframes gg-fade {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@keyframes gg-modal-in {
    from { opacity: 0; transform: translateY(-10px) scale(.985); }
    to   { opacity: 1; transform: none; }
}

@keyframes gg-spin { to { transform: rotate(360deg); } }

@keyframes gg-bar {
    0%   { transform: translateX(-100%); }
    50%  { transform: translateX(-15%); }
    100% { transform: translateX(-100%); }
}

/* ── Появление содержимого страницы ──────────────────────────────────
   Панели фильтров и сортировки исключены вместе с обёртками, внутри
   которых они лежат: они position: fixed, а движение у родителя делает
   их absolute — панель перестаёт уезжать за край и висит поверх таблиц.
   Именно так она и «залипла» на дашборде, где лежит внутри обёртки. */
.main-content > *:not(.filter-menu):not(:has(.filter-menu)) {
    animation: gg-in .22s var(--ease) both;
}

/* Второй и третий блок появляются чуть позже — взгляд успевает пройти
   сверху вниз. Дальше задержку не наращиваем: ждать никто не должен. */
.main-content > *:nth-child(2) { animation-delay: .03s; }
.main-content > *:nth-child(3) { animation-delay: .06s; }

/* ── Нажатие ─────────────────────────────────────────────────────── */

.action-btn:not(.disabled):active,
.gg-preset:active,
.gg-pick-btn:active,
.fl-act:active,
.table-icon:active {
    transform: scale(.94);
}

.action-btn,
.gg-preset,
.gg-pick-btn,
.fl-act,
.table-icon {
    transition: background-color var(--t), border-color var(--t),
                color var(--t), transform var(--t-fast);
}

/* ── Выпадающие меню ─────────────────────────────────────────────────
   Меню под кнопкой пользователя досталось от Bootstrap и появлялось
   мгновенно: только что ничего не было — и вот оно уже здесь. Остальные
   всплывающие блоки в трекере проявляются со смещением на несколько
   точек, и это единственное, что им нужно.

   Закрытие не анимируем: Bootstrap просто снимает класс, и элемент
   исчезает. Ловить это переходом — значит держать на экране то, что
   человек уже закрыл. */
.dropdown-menu.show {
    animation: gg-drop .15s var(--ease) both;
}

/* Смещение задаём через translate, а не transform.
   Bootstrap ставит меню на место своим transform в inline-стиле, а
   анимация в каскаде сильнее inline — из-за transform в кадрах меню
   теряло позицию и всплывало поверх кнопки. Отдельное свойство translate
   складывается с чужим transform и ничего не ломает. */
@keyframes gg-drop {
    from { opacity: 0; translate: 0 -5px; }
    to   { opacity: 1; translate: none; }
}

/* Список с поиском — тем же шагом, что и остальные всплывающие блоки. */
.searchable-select-panel.open {
    animation: gg-drop .15s var(--ease) both;
}

/* ── Модалка ─────────────────────────────────────────────────────── */

.itc-modal-show .itc-modal-content {
    animation: gg-modal-in .18s var(--ease) both;
}

.itc-modal-show .itc-modal-backdrop {
    animation: gg-fade .15s ease both;
}

/* ── Кнопка в работе ─────────────────────────────────────────────────
   Подпись не убираем из потока, а делаем прозрачной: иначе кнопка
   меняет ширину и соседние кнопки прыгают. */
.action-btn.is-busy,
.itc-modal-button.is-busy,
.btn-primary.is-busy,
.gg-preset.is-busy,
.add-item-btn.is-busy {
    position: relative;
    pointer-events: none;
    color: transparent !important;
}

.action-btn.is-busy > *,
.itc-modal-button.is-busy > *,
.btn-primary.is-busy > *,
.gg-preset.is-busy > *,
.add-item-btn.is-busy > * { opacity: 0; }

.action-btn.is-busy::after,
.itc-modal-button.is-busy::after,
.btn-primary.is-busy::after,
.gg-preset.is-busy::after,
.add-item-btn.is-busy::after {
    content: '';
    position: absolute;
    inset: 0;
    margin: auto;
    width: 15px;
    height: 15px;
    border: 2px solid rgba(255, 255, 255, .22);
    border-top-color: #fff;
    border-radius: 50%;
    animation: gg-spin .55s linear infinite;
}

/* У кнопок без заливки крутилка должна быть видна на тёмном. */
.action-btn:not(.action-btn-ok):not(.action-btn-primary).is-busy::after {
    border-color: rgba(255, 255, 255, .16);
    border-top-color: var(--text);
}

/* ── Полоса загрузки при переходе ────────────────────────────────────
   Переход между страницами занимает доли секунды на быстрых разделах
   и заметно больше на кампаниях и кликах. Без полосы непонятно,
   дошло ли нажатие. */
.gg-topbar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 2px;
    z-index: 12000;
    background-color: transparent;
    pointer-events: none;
    overflow: hidden;
}

.gg-topbar::before {
    content: '';
    display: block;
    height: 100%;
    width: 100%;
    background: linear-gradient(90deg, transparent, var(--accent), transparent);
    animation: gg-bar 1.1s ease-in-out infinite;
}

/* ── Скелет таблицы ──────────────────────────────────────────────── */

.gg-skeleton-rows {
    display: flex;
    flex-direction: column;
    gap: 3px;
}

/* ── Уважение к настройке системы ────────────────────────────────────
   Кому движение мешает — тому его не будет. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
    }

    .gg-topbar::before { animation: none; opacity: .6; }
}
