/* ── Analytics page motion ─────────────────────────────────────────────────────────────────────
   The whole of /analytics (and the booth page's Аналітика tab, same AnalyticsPanel) animates in:
   KPI tiles pop up one after another and count their figures up, section headings slide in with
   their icon spinning into place, cards rise, table rows cascade down, bar charts rise from the
   baseline, lines draw left to right, pies spin open and share bars fill.

   A "block" is a direct child of AnalyticsPanel's `.an-motion` wrapper or, for a `.row`, each of
   its columns. Blocks on screen when the panel renders play on insertion, cascading in page order;
   js/analyticsMotion.js holds the ones below the fold back (data-an="wait") and lets each in as it
   scrolls into view (data-an="in"). Everything inside a block times itself off the block's own
   delay, --an-d.

   Every entrance uses fill-mode BACKWARDS, never forwards/both: once it has played nothing is left
   on the element — above all no transform, which would turn the block into the containing block of
   any position:fixed tooltip or dialog inside it.

   Reduced motion keeps the same cascade as plain fades (the Browser pane on the dev PC reports
   `reduce`, and the owner's own browser may too). */

.an-motion {
    display: contents;   /* the wrapper exists for JS and these selectors, never for layout */
}

@keyframes an-rise {
    from { opacity: 0; transform: translateY(28px) scale(0.98); }
    to   { opacity: 1; transform: none; }
}
@keyframes an-pop {
    0%   { opacity: 0; transform: translateY(20px) scale(0.9); }
    55%  { opacity: 1; transform: translateY(-4px) scale(1.02); }
    100% { opacity: 1; transform: none; }
}
@keyframes an-slide {
    from { opacity: 0; transform: translateX(-24px); }
    to   { opacity: 1; transform: none; }
}
@keyframes an-icon {
    0%   { opacity: 0; transform: scale(0.2) rotate(-45deg); }
    65%  { opacity: 1; transform: scale(1.15) rotate(6deg); }
    100% { opacity: 1; transform: none; }
}
@keyframes an-row {
    from { opacity: 0; transform: translateX(-14px); }
    to   { opacity: 1; transform: none; }
}
@keyframes an-wipe-x {
    from { clip-path: inset(0 100% 0 0); }
    to   { clip-path: inset(0 0 0 0); }
}
@keyframes an-wipe-y {
    from { clip-path: inset(0 0 100% 0); }
    to   { clip-path: inset(0 0 0 0); }
}
@keyframes an-wipe-up {
    from { clip-path: inset(100% 0 0 0); }
    to   { clip-path: inset(0 0 0 0); }
}
@keyframes an-fill {
    from { transform: scaleX(0); }
    to   { transform: none; }
}
@keyframes an-spin {
    from { opacity: 0; transform: rotate(-110deg) scale(0.55); }
    to   { opacity: 1; transform: none; }
}
@keyframes an-drop {
    from { opacity: 0; transform: translateY(-16px); }
    to   { opacity: 1; transform: none; }
}
@keyframes an-fade {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* ── Cascade order ──
   --an-base: a block's beat in page order; --an-j: a column's place in its row. */
.an-motion > * { --an-base: 0ms; }
.an-motion > :nth-child(2) { --an-base: 70ms; }
.an-motion > :nth-child(3) { --an-base: 140ms; }
.an-motion > :nth-child(4) { --an-base: 210ms; }
.an-motion > :nth-child(5) { --an-base: 280ms; }
.an-motion > :nth-child(6) { --an-base: 350ms; }
.an-motion > :nth-child(7) { --an-base: 420ms; }
.an-motion > :nth-child(8) { --an-base: 490ms; }
.an-motion > :nth-child(n+9) { --an-base: 560ms; }

.an-motion .row > * { --an-j: 0; }
.an-motion .row > :nth-child(2) { --an-j: 1; }
.an-motion .row > :nth-child(3) { --an-j: 2; }
.an-motion .row > :nth-child(4) { --an-j: 3; }
.an-motion .row > :nth-child(5) { --an-j: 4; }
.an-motion .row > :nth-child(6) { --an-j: 5; }
.an-motion .row > :nth-child(7) { --an-j: 6; }
.an-motion .row > :nth-child(8) { --an-j: 7; }
.an-motion .row > :nth-child(9) { --an-j: 8; }
.an-motion .row > :nth-child(10) { --an-j: 9; }
.an-motion .row > :nth-child(11) { --an-j: 10; }
.an-motion .row > :nth-child(n+12) { --an-j: 11; }

.an-motion > :not(.row) { --an-d: var(--an-base); }
.an-motion > .row > * { --an-d: calc(var(--an-base) + var(--an-j) * 60ms); }

/* ── Blocks ── */
.an-motion > :not(.row),
.an-motion > .row > * {
    animation: an-rise 0.7s cubic-bezier(0.22, 1, 0.36, 1) backwards;
    animation-delay: var(--an-d, 0ms);
}
/* KPI tiles pop, with a little overshoot */
.an-motion > .row > :has(> .stats-card) {
    animation-name: an-pop;
    animation-duration: 0.65s;
}
/* Section headings slide in from the left */
.an-motion > :has(> .d-flex > h5) {
    animation-name: an-slide;
    animation-duration: 0.6s;
}
/* Columns of a row nested inside a block (pie trios, tiles inside a component) follow their block */
.an-motion > * .row > * {
    animation: an-rise 0.6s cubic-bezier(0.22, 1, 0.36, 1) backwards;
    animation-delay: calc(var(--an-d, 0ms) + 120ms + var(--an-j) * 60ms);
}

/* ── Inside a block ── */
.an-motion > :has(> .d-flex > h5) > .d-flex > span:first-child,
.an-motion .stat-icon-container {
    animation: an-icon 0.7s cubic-bezier(0.34, 1.4, 0.64, 1) backwards;
    animation-delay: calc(var(--an-d, 0ms) + 180ms);
}

.an-motion tbody > tr {
    animation: an-row 0.5s cubic-bezier(0.22, 1, 0.36, 1) backwards;
    animation-delay: calc(var(--an-d, 0ms) + 200ms + var(--an-r, 0) * 30ms);
}
.an-motion tbody > tr:nth-child(2) { --an-r: 1; }
.an-motion tbody > tr:nth-child(3) { --an-r: 2; }
.an-motion tbody > tr:nth-child(4) { --an-r: 3; }
.an-motion tbody > tr:nth-child(5) { --an-r: 4; }
.an-motion tbody > tr:nth-child(6) { --an-r: 5; }
.an-motion tbody > tr:nth-child(7) { --an-r: 6; }
.an-motion tbody > tr:nth-child(8) { --an-r: 7; }
.an-motion tbody > tr:nth-child(9) { --an-r: 8; }
.an-motion tbody > tr:nth-child(10) { --an-r: 9; }
.an-motion tbody > tr:nth-child(11) { --an-r: 10; }
.an-motion tbody > tr:nth-child(12) { --an-r: 11; }
.an-motion tbody > tr:nth-child(13) { --an-r: 12; }
.an-motion tbody > tr:nth-child(14) { --an-r: 13; }
.an-motion tbody > tr:nth-child(15) { --an-r: 14; }
.an-motion tbody > tr:nth-child(n+16) { --an-r: 15; }

/* Share bars (refunds, failed attempts, promo codes, the couples funnel, people/age bars) fill from
   the left once their row is in. */
.an-motion .progress-bar,
.an-motion .cpl-bar-fill,
.an-motion .ba-bar-fill,
.an-motion .age-bar-fill {
    transform-origin: left center;
    animation: an-fill 0.9s cubic-bezier(0.22, 1, 0.36, 1) backwards;
    animation-delay: calc(var(--an-d, 0ms) + 320ms + var(--an-r, 0) * 30ms);
}

/* Charts (ApexCharts renders with its own animations off). The series layer is wiped in left to
   right — a line draws itself — and each bar series is uncovered from the baseline up, so the bars
   rise as the wipe passes. A horizontal chart (ApexCharts marks it with an "inversed" axis) does the
   same turned on its side. Pies and donuts spin open; the legend fades in last.
   ⚠️ Only clip-path on the series GROUPS, never a transform on the bar paths: every bar path already
   carries ApexCharts' own transform (.apexcharts-flip-x / -flip-y), which an animated transform or
   transform-origin would replace and throw the bar off its slot. */
.an-motion .apexcharts-plot-series {
    animation: an-wipe-x 1.1s cubic-bezier(0.45, 0, 0.2, 1) backwards;
    animation-delay: calc(var(--an-d, 0ms) + 220ms);
}
.an-motion .apexcharts-bar-series > .apexcharts-series {
    animation: an-wipe-up 0.9s cubic-bezier(0.22, 1, 0.36, 1) backwards;
    animation-delay: calc(var(--an-d, 0ms) + 220ms);
}
.an-motion .apexcharts-inner:has(> .apexcharts-xaxis-inversed) > .apexcharts-plot-series {
    animation-name: an-wipe-y;
}
.an-motion .apexcharts-inner:has(> .apexcharts-xaxis-inversed) > .apexcharts-bar-series > .apexcharts-series {
    animation-name: an-wipe-x;
}
.an-motion .apexcharts-slices {
    transform-box: fill-box;
    transform-origin: center;
    animation: an-spin 0.9s cubic-bezier(0.22, 1, 0.36, 1) backwards;
    animation-delay: calc(var(--an-d, 0ms) + 200ms);
}
.an-motion .apexcharts-legend {
    animation: an-fade 0.6s ease backwards;
    animation-delay: calc(var(--an-d, 0ms) + 550ms);
}

/* ── Held below the fold until it scrolls into view (js/analyticsMotion.js) ──
   Everything inside is stopped too, so it all plays from the start on reveal. */
.an-motion > [data-an="wait"],
.an-motion > .row > [data-an="wait"] {
    opacity: 0;
    pointer-events: none;
    animation: none !important;
}
.an-motion [data-an="wait"] * {
    animation: none !important;
}

/* ── Hover ── */
.an-motion .stats-card {
    transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.25s ease;
}
.an-motion .stats-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 10px 24px rgba(17, 24, 39, 0.09);
}
.an-motion .card {
    transition: box-shadow 0.25s ease;
}
.an-motion .card:hover {
    box-shadow: 0 8px 22px rgba(17, 24, 39, 0.07);
}

/* ── The page's filter bar (Pages/Analytics.razor) drops in once, when the page opens ── */
.an-filterbar {
    animation: an-drop 0.5s cubic-bezier(0.22, 1, 0.36, 1) backwards;
}
.an-filterbar .preset-btn:active {
    transform: scale(0.95);
}

/* ── Reduced motion: the same cascade, as plain fades ──
   Same selectors as above (and after them) so each one's animation-name is the one that wins. */
@media (prefers-reduced-motion: reduce) {
    .an-motion > :not(.row),
    .an-motion > .row > *,
    .an-motion > .row > :has(> .stats-card),
    .an-motion > :has(> .d-flex > h5),
    .an-motion > * .row > *,
    .an-motion > :has(> .d-flex > h5) > .d-flex > span:first-child,
    .an-motion .stat-icon-container,
    .an-motion tbody > tr,
    .an-motion .progress-bar,
    .an-motion .cpl-bar-fill,
    .an-motion .ba-bar-fill,
    .an-motion .age-bar-fill,
    .an-motion .apexcharts-plot-series,
    .an-motion .apexcharts-bar-series > .apexcharts-series,
    .an-motion .apexcharts-inner:has(> .apexcharts-xaxis-inversed) > .apexcharts-plot-series,
    .an-motion .apexcharts-inner:has(> .apexcharts-xaxis-inversed) > .apexcharts-bar-series > .apexcharts-series,
    .an-motion .apexcharts-slices,
    .an-filterbar {
        animation-name: an-fade;
    }
    .an-motion .stats-card:hover,
    .an-filterbar .preset-btn:active {
        transform: none;
    }
}
