/* = Composants partagés — utilisés par au moins deux modules : card,
   badge, bouton, formulaires, tables, alertes, toasts, modales…
   Issu du découpage de main.css (15/09/2026), chargé sur toutes les pages
   dans l'ordre fixé par templates/partials/feuilles_de_style.html.  */

/* Bouton ghost compact, texte rouge seul (pas de fond/bordure comme .btn--danger) —
   boutons de suppression icone-only dans une rangee d'actions dense. */

/* Focus clavier sur les lignes cliquables (cf. conventions §13).
   Les lignes sont rendues focalisables par static/js/table-rows.js ; sans
   indicateur visible, la navigation au clavier serait inutilisable. */

/* Les .card contenant directement une table sont scrollables */

/* Also style generic .table for templates using it */

.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: var(--space-8);
  gap: var(--space-4);
  padding-bottom: 0;
}

.page-header__left {
  min-width: 0;
}

/* 24 px, le titre de page de l'échelle de title.css (`title--page`) : un seul
   titre de page dans toute l'application (#342, arbitrage du 23/09/2026 ; le
   30 px d'avant était hors de l'échelle 16 / 24 / 14 / 11) */
.page-header__title {
  font-size: var(--text-24);
  font-weight: var(--weight-bold);
  letter-spacing: -0.02em;
  color: var(--color-text);
  line-height: var(--leading-tight);
}

.page-header__subtitle {
  font-size: var(--text-13);
  color: var(--color-text-secondary);
  margin-top: var(--space-1);
}

/* les actions passent à la ligne : cinq boutons font 430 px, plus qu'un
   téléphone (test_responsive) — le repli était posé page par page en
   `flex-wrap` ou `cluster`, il est celui du block depuis #342 */
.page-header__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
  flex-shrink: 0;
}

.vue {
  display: inline-flex;
  gap: 0.2em;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: var(--space-0-5);
  background: var(--color-bg-subtle);
}

.vue a,
.vue button {
  padding: var(--space-1-5) var(--space-3-5);
  font-size: var(--text-12);
  border-radius: var(--radius-xs);
  border: none;
  background: transparent;
  color: var(--color-text-secondary);
  cursor: pointer;
  text-decoration: none;
  transition: all var(--transition-fast);
  font-weight: var(--weight-medium);
}

.vue a:hover,
.vue button:hover {
  color: var(--color-text);
  text-decoration: none;
}

.vue a.active,
.vue button.active {
  background: var(--color-surface);
  color: var(--color-primary);
  box-shadow: var(--shadow-xs);
}

/* La barre d'actions de masse d'une liste à cases à cocher (documents, projets) :
   `hidden` tant que rien n'est coché, le script de la page bascule l'attribut
   (`[data-barre]`). Le compteur et les boutons composent (`flex-1`, `btn`). */
.selection-bar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  padding: var(--space-2) var(--space-3);
  margin-bottom: var(--space-3);
  border-radius: var(--radius-md);
  background: var(--color-bg-hover);
  border: 1px solid var(--color-border);
}

/* Une classe qui pose `display` l'emporte sur le `[hidden]` du navigateur. */
.selection-bar[hidden] {
  display: none;
}

/* Collée en haut de la page pendant qu'on fait défiler une longue sélection
   (la validation des pointages). */
.selection-bar--sticky {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--color-surface);
}

@media (width <= 768px) {
  .page-header {
    flex-direction: column;
    align-items: flex-start;
  }
}

.htmx-request [id$="-content"] {
  opacity: 0.5;
  transition: opacity 200ms ease;
  pointer-events: none;
}

/* ═══════════════════════════════════════════════════════════
   HTMX — Indicateur de chargement global
   ═══════════════════════════════════════════════════════════ */
.htmx-indicator {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  z-index: var(--z-indicator);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s;
}

.htmx-indicator--active {
  opacity: 1;
}

.htmx-indicator__bar {
  height: 100%;
  width: 30%;
  background: var(--color-primary);
  border-radius: 0 var(--radius-xs) var(--radius-xs) 0;
  animation: htmx-loading 1.2s ease-in-out infinite;
}

@keyframes htmx-loading {
  0% {
    width: 10%;
    margin-left: 0;
  }

  50% {
    width: 40%;
    margin-left: 30%;
  }

  100% {
    width: 10%;
    margin-left: 90%;
  }
}

/* Zone loading spinner with hx-indicator support */
.zone-loading {
  position: relative;
  min-height: 60px;
  display: none;
  align-items: center;
  justify-content: center;
  padding: var(--space-6);
  color: var(--color-text-secondary);
  font-size: var(--text-13);
  gap: var(--space-2);
}

.zone-loading::after {
  content: "";
  display: none;
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--color-surface) 70%, transparent);
  z-index: 1;
}

.zone-loading--active::after {
  display: flex;
  align-items: center;
  justify-content: center;
  content: "";
  background: color-mix(in srgb, var(--color-surface) 70%, transparent)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Ccircle cx='12' cy='12' r='10' stroke='%231B4965' stroke-width='3' fill='none' stroke-dasharray='31.4 31.4' stroke-linecap='round'%3E%3CanimateTransform attributeName='transform' type='rotate' dur='0.8s' values='0 12 12;360 12 12' repeatCount='indefinite'/%3E%3C/circle%3E%3C/svg%3E")
    center no-repeat;
}

/* Désactiver les éléments pendant le chargement htmx */
.htmx-request {
  pointer-events: none;
  opacity: 0.7;
  transition: opacity 0.15s;
}

/* --- Zone loading spinner (htmx) --- */
.htmx-request > .zone-loading,
.htmx-request.zone-loading {
  display: flex;
}

/* --- Mobile --- */

.d-inline {
  display: inline;
}

@media (width <= 768px) {
  /* Page header en colonne */
  .page-header {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-3);
  }
}

@media (width <= 480px) {
  /* Tables : conversion en cartes empilées */

  /* État vide avec message + bouton : le flex « libellé / valeur » ci-dessus
     les mettrait côte à côte. On garde le flex, en colonne et centré. */

  /* Pseudo label depuis data-label si défini sur <td> */

  /* Boutons : touch-friendly (44px min) */

  /* Page header titre plus petit */
  .page-header__title {
    font-size: var(--text-20);
  }
}

/* --- Picto d'aide : un « ? » cerclé de 14 px à côté d'un libellé, qui porte
   un `title` (le widget du tableau de bord, le chemin critique du Gantt). --- */
.help-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  margin-left: var(--space-1);
  border-radius: var(--radius-circle);
  border: 1px solid var(--color-text-secondary);
  color: var(--color-text-secondary);
  font-size: var(--text-9);
  font-weight: var(--weight-bold);
  cursor: help;
  vertical-align: middle;
}

.month-label {
  font-weight: var(--weight-semibold);
  font-size: var(--text-16);
  min-width: 180px;
  text-align: center;
}
