/*
 * Barre de progression des traitements de fond — bundle wf-miniapp.
 *
 * Chargée APRÈS theme.css : plusieurs règles ci-dessous ont la même
 * spécificité que leur homologue du thème et comptent sur l'ordre source.
 */

/* ════════ Tokens ════════ */
:root {
    /* Hauteur réservée sous le contenu quand la barre est visible.
       ⚠️ PILOTÉE PAR `js/background-jobs.js`, qui écrit ici la hauteur RÉELLE
       mesurée sur le nœud. La valeur ci-dessous n'est qu'un REPLI si le script
       ne tourne pas : la hauteur dépend du nombre de tâches empilées et du
       repli de leurs trois lignes de texte, et aucune propriété CSS ne sait
       exprimer « la hauteur de cet autre élément ». Mesuré dans Chrome avec
       trois tâches : 79px pour cette constante de 56px, soit 23px de pied de
       page recouverts. Le BASCULEMENT visible/invisible, lui, reste bien en
       CSS seule (`body:has(.miniapp-jobs-bar--visible)` plus bas) — c'est ce
       point-là que visait la spec « sans une ligne de JavaScript ». */
    --miniapp-jobs-h: 56px;

    /* Distance au bas de la fenêtre. Vaut 0 en production ; la barre de debug
       Symfony la repousse (voir « Réserves cumulées » plus bas). */
    --miniapp-jobs-bottom: 0px;

    --miniapp-jobs-bg:     #fff;
    --miniapp-jobs-border: rgba(27, 42, 74, .12);
}

/* ════════ Conteneur ════════
   `fixed`, JAMAIS `sticky` : le shell défile sur le body et
   `_footer.html.twig` est inclus À L'INTÉRIEUR de <main>. Un élément sticky se
   décollerait dès le haut du pied de page — précisément là où l'utilisateur
   descend pour savoir si son traitement avance.

   z-index 1030 : entre la barre latérale (100, theme.css) et la pile de
   tiroirs (1040, _drawer.css). Les popovers de pastilles (1080) passent donc
   AU-DESSUS de la barre : c'est VOULU, un popover ouvert près du bas doit
   rester lisible. Ne pas y voir une régression d'empilement. */
.miniapp-jobs-bar {
    display: none;
    position: fixed;
    bottom: var(--miniapp-jobs-bottom);
    left: var(--sidebar-w);
    right: 0;
    z-index: 1030;
    gap: 16px;
    align-items: center;
    flex-wrap: wrap;
    padding: 8px 20px;
    background: var(--miniapp-jobs-bg);
    border-top: 1px solid var(--miniapp-jobs-border);
    box-shadow: 0 -6px 24px rgba(27, 42, 74, .10);
    font-size: .85rem;
}

/* Le nœud est rendu même vide (il porte l'interrogation htmx) : c'est ce
   modificateur, et non sa présence, qui décide de l'affichage. */
.miniapp-jobs-bar--visible {
    display: flex;
}

/* ════════ Régime « barre latérale repliée » ════════
   theme.css:1444-1451 surcharge `width` et `margin-left` EN DUR à 64px sans
   toucher `--sidebar-w` : sans la redéfinition ci-dessous, la barre resterait
   décalée de 260px, soit un trou de 196px à gauche — en permanence, puisque
   sidebar.js persiste la préférence dans localStorage.

   ⚠️ Porté par `body:has(…)` et NON par `.miniapp-layout--sidebar-collapsed` :
   les variables CSS ne descendent que dans le sous-arbre où elles sont
   définies, or la barre est un FRÈRE de `.miniapp-layout`, pas un descendant.
   Le `:has()` remonte la condition jusqu'à un ancêtre commun. Même idiome que
   `body:has(.sf-toolbar)` de theme.css.

   Point de rupture 769/768px : aligné sur la règle de la barre latérale.
   theme.css en compte cinq (600, 768, 800, 900, 991.98) ; toute autre valeur
   créerait une bande de largeurs où la barre est mal placée. */
@media (min-width: 769px) {
    body:has(.miniapp-layout--sidebar-collapsed) {
        --sidebar-w: 64px;
    }
}

/* ════════ Régime mobile ════════
   La barre latérale sort de l'écran par `translateX(-100%)` mais CONSERVE sa
   largeur, pour être utilisable une fois ouverte en tiroir. `--sidebar-w` vaut
   donc toujours 260px ici : on décale la barre, on ne neutralise PAS la
   variable — la mettre à zéro rendrait la barre latérale invisible ouverte. */
@media (max-width: 768px) {
    .miniapp-jobs-bar {
        left: 0;
        gap: 10px;
        padding: 8px 14px;
    }

    .miniapp-jobs-bar .miniapp-job {
        flex: 1 1 100%;
    }
}

/* ════════ Réserves de place — elles s'ADDITIONNENT ════════
   theme.css:459 réserve déjà 48px sous le contenu quand la barre de debug
   Symfony est présente. En dev — seul endroit où l'on pourra répéter le
   scénario avant preprod — la barre serait recouverte si les deux réserves se
   concurrençaient : on les cumule explicitement.

   `body.miniapp-shell:has(…)` (0,3,1) l'emporte sur `body:has(.sf-toolbar)
   .miniapp-layout__main` (0,2,1) de theme.css : la spécificité tranche, sans
   dépendre de l'ordre de chargement. */
body:has(.sf-toolbar) {
    --miniapp-jobs-bottom: 48px;
}

body.miniapp-shell:has(.miniapp-jobs-bar--visible) .miniapp-layout__main {
    padding-bottom: calc(var(--miniapp-jobs-bottom) + var(--miniapp-jobs-h));
}

/* ════════ Une tâche ════════ */
.miniapp-job {
    display: flex;
    align-items: center;
    gap: 12px;
    flex: 1 1 320px;
    min-width: 0;
}

.miniapp-job__text {
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 0 1 auto;
}

.miniapp-job__label {
    font-weight: 600;
    color: var(--clr-navy, #1b2a4a);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.miniapp-job__state,
.miniapp-job__count {
    font-size: .78rem;
    color: var(--clr-text-muted, #6b7a90);
}

/* Invitation à prévenir l'administrateur (`failed`/`stalled`) — le détail
   technique de l'erreur ne vit qu'en `title` (cf. gabarit), jamais ici. Même
   couleur d'alerte que `--failed`/`--stalled` plus bas : cette ligne annonce
   la même chose que l'état, elle doit se lire de la même couleur, pas hériter
   du gris atténué de `.miniapp-job__count` par simple emprunt de classe.
   Règle après `.miniapp-job__count` (même spécificité) : l'ordre source
   tranche, comme partout ailleurs dans ce fichier. */
.miniapp-job__error {
    color: var(--clr-orange, #f5a623);
}

/* ════════ Jauge ════════ */
.miniapp-job__gauge {
    flex: 1 1 120px;
    min-width: 80px;
    height: 8px;
    border-radius: 999px;
    background: rgba(27, 42, 74, .10);
    overflow: hidden;
}

.miniapp-job__gauge-fill {
    display: block;
    height: 100%;
    border-radius: inherit;
    background: var(--clr-blue-mid, #2e6daa);
    transition: width var(--transition, .22s ease);
}

.miniapp-job__percent {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    color: var(--clr-navy, #1b2a4a);
}

/* ════════ Couleurs par état ════════ */
.miniapp-job--done .miniapp-job__gauge-fill {
    background: var(--clr-teal, #3ab5b0);
}

.miniapp-job--failed .miniapp-job__gauge-fill,
.miniapp-job--stalled .miniapp-job__gauge-fill {
    background: var(--clr-orange, #f5a623);
}

.miniapp-job--failed .miniapp-job__state,
.miniapp-job--stalled .miniapp-job__state {
    color: var(--clr-orange, #f5a623);
    font-weight: 600;
}

/* Seul `running` bouge : une tâche en attente montre une jauge IMMOBILE,
   sinon le mouvement laisserait croire à du travail en cours. */
.miniapp-job--running .miniapp-job__gauge-fill {
    background-image: linear-gradient(
        90deg,
        rgba(255, 255, 255, .00) 0%,
        rgba(255, 255, 255, .35) 50%,
        rgba(255, 255, 255, .00) 100%
    );
    background-size: 60px 100%;
    background-repeat: repeat-x;
    animation: miniapp-job-shimmer 1.2s linear infinite;
}

@keyframes miniapp-job-shimmer {
    from { background-position: -60px 0; }
    to   { background-position: 60px 0; }
}

/* Respect de la préférence système : l'animation n'est qu'un renfort, le
   pourcentage et le décompte portent déjà l'information. */
@media (prefers-reduced-motion: reduce) {
    .miniapp-job--running .miniapp-job__gauge-fill {
        animation: none;
    }

    .miniapp-job__gauge-fill {
        transition: none;
    }
}

/* ════════ Actions ════════ */
.miniapp-job__actions {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-left: auto;
}

.miniapp-job__refresh {
    display: inline-flex;
    align-items: center;
    padding: 4px 12px;
    border-radius: var(--radius, 6px);
    background: var(--clr-navy, #1b2a4a);
    color: #fff;
    text-decoration: none;
    font-weight: 600;
    font-size: .8rem;
    white-space: nowrap;
}

.miniapp-job__refresh:hover,
.miniapp-job__refresh:focus-visible {
    background: var(--clr-blue-mid, #2e6daa);
    color: #fff;
}

.miniapp-job__dismiss {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--clr-text-muted, #6b7a90);
    cursor: pointer;
    transition: background var(--transition, .22s ease);
}

.miniapp-job__dismiss:hover {
    background: rgba(27, 42, 74, .08);
}

.miniapp-job__refresh:focus-visible,
.miniapp-job__dismiss:focus-visible {
    outline: 2px solid var(--clr-blue-mid, #2e6daa);
    outline-offset: 2px;
}

/* ════════ Repli « et N autre(s) » ════════ */
.miniapp-jobs-bar__more {
    margin: 0;
    flex: 0 0 auto;
    font-size: .78rem;
    color: var(--clr-text-muted, #6b7a90);
    white-space: nowrap;
}
