/* _campaigns.css - Domain styles for campaigns - lists, editors, positions, status system. Class prefix: campaign-.
   See docs/css-refaktoreringsplan.md.
   No CSS isolation here: every class MUST carry the domain prefix. */


/* ---------------------------------------------------------------------------
   Campaign list loading states

   Two states, because loading means different things depending on whether the
   list already has something to show:

   - campaign-skeleton-*  first load. There is nothing to preserve, so
                          placeholder rows stand in for the rows about to arrive
                          and hold the layout still.
   - campaign-list-busy   reload after a sort, filter or page change. The rows
                          the user is reading stay on screen, dimmed and inert,
                          and are replaced when the new ones arrive.
   --------------------------------------------------------------------------- */

.campaign-skeleton-row > td {
    vertical-align: middle;
}

.campaign-skeleton-bar {
    display: block;
    width: 100%;
    height: var(--space-3);
    border-radius: var(--radius-sm);

    background-color: var(--color-surface-subtle);
    background-image: linear-gradient(
        90deg,
        var(--color-surface-subtle) 25%,
        var(--color-background-light) 37%,
        var(--color-surface-subtle) 63%
    );
    background-size: 400% 100%;

    animation: campaign-skeleton-shimmer 1.4s ease-in-out infinite;
}

/* Staggering the rows keeps the shimmer from marching across the table in one
   solid band, which reads as a progress bar rather than as placeholder content. */
.campaign-skeleton-row:nth-child(even) .campaign-skeleton-bar {
    animation-delay: 0.18s;
}

.campaign-skeleton-row:nth-child(3n) .campaign-skeleton-bar {
    animation-delay: 0.32s;
}

@keyframes campaign-skeleton-shimmer {
    0%   { background-position: 100% 50%; }
    100% { background-position: 0 50%; }
}


/* Reload with rows already on screen. Opacity rather than a covering layer, so
   the table keeps its size and nothing below it shifts. */
.campaign-list-busy {
    position: relative;
}

.campaign-list-busy tbody {
    opacity: 0.45;
    transition: opacity 120ms ease-in-out;

    /* The rows are stale for a moment - do not let them be clicked or tabbed to. */
    pointer-events: none;
    user-select: none;
}

/* A thin indeterminate bar along the top edge of the table. */
.campaign-list-busy::before {
    content: "";

    position: absolute;
    inset-inline: 0;
    top: 0;
    height: 3px;
    z-index: var(--z-base);

    border-radius: var(--radius-pill);
    background: linear-gradient(
        90deg,
        transparent 0%,
        var(--color-primary-main) 50%,
        transparent 100%
    );
    background-size: 40% 100%;
    background-repeat: no-repeat;

    animation: campaign-list-busy-sweep 1.1s ease-in-out infinite;
}

@keyframes campaign-list-busy-sweep {
    0%   { background-position: -40% 0; }
    100% { background-position: 140% 0; }
}


/* Motion here is decoration: it signals "working", and the dimmed rows and
   aria-busy already carry that meaning without it. */
@media (prefers-reduced-motion: reduce) {

    .campaign-skeleton-bar,
    .campaign-list-busy::before {
        animation: none;
    }

    .campaign-list-busy::before {
        background: var(--color-primary-main);
        background-size: 100% 100%;
        opacity: 0.5;
    }
}
