/* ============================================================
   DESIGN SYSTEM v6 — UTILITIES
   ============================================================
   Classes utilitaires de layout (flex/grid/gap/alignement).

   Volontairement PAS themables : un `.gap-4` doit représenter
   la même distance physique quel que soit le thème actif. Elles
   référencent donc l'échelle brute --base-space-* (primitives), jamais
   les tokens sémantiques --space-* ou --layout-* de tokens.css.
   ============================================================ */

/* Display */
.flex        { display: flex; }
.inline-flex { display: inline-flex; }
.grid        { display: grid; }

/* Direction & wrap */
.col  { flex-direction: column; }
.wrap { flex-wrap: wrap; }

/* Alignement (spécificité nulle via :where) */
:where(.items-center)   { align-items: center; }
:where(.items-start)    { align-items: flex-start; }
:where(.items-end)      { align-items: flex-end; }
:where(.items-baseline) { align-items: baseline; }
:where(.justify-center)  { justify-content: center; }
:where(.justify-between) { justify-content: space-between; }
:where(.justify-end)     { justify-content: flex-end; }

/* Gap */
:where(.gap-1) { gap: var(--base-space-1); }
:where(.gap-2) { gap: var(--base-space-2); }
:where(.gap-3) { gap: var(--base-space-3); }
:where(.gap-4) { gap: var(--base-space-4); }
:where(.gap-6) { gap: var(--base-space-6); }
:where(.gap-8) { gap: var(--base-space-8); }

/* Colonnes de grille.
   minmax(min(100%, N), 1fr) et non minmax(N, 1fr) : sans le
   min(100%, …), une piste de largeur fixe N déborde de son
   conteneur dès que celui-ci est plus étroit que N (mobile
   étroit, colonne imbriquée…) et déclenche un défilement
   horizontal. min(100%, N) plafonne la piste à la largeur
   disponible. */
.cols-2    { grid-template-columns: repeat(2, 1fr); }
.cols-3    { grid-template-columns: repeat(3, 1fr); }
.cols-4    { grid-template-columns: repeat(4, 1fr); }
.cols-auto    { grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); }
.cols-auto-sm { grid-template-columns: repeat(auto-fit, minmax(min(100%, 180px), 1fr)); }
.cols-auto-xs { grid-template-columns: repeat(auto-fit, minmax(min(100%, 130px), 1fr)); }

/* Déclare un bloc comme conteneur de requête : ses enfants peuvent alors
   s'adapter à SA largeur. À poser sur un bloc dont la largeur vient du
   parent — jamais sur un élément dimensionné par son contenu, que le
   confinement figerait.

   container-type: inline-size ne crée pas de bloc conteneur pour les
   descendants en position: fixed (contrairement à contain: layout ou à
   transform) : .skip-link et .toast-region restent ancrés au viewport.
   Vérifié dans le navigateur avant adoption. */
.container { container-type: inline-size; }

/* Une grille répond d'abord à SON conteneur, pas au viewport : trois
   colonnes dans une carte de 280px donnaient trois colonnes de 86px,
   quelle que soit la taille de l'écran.

   Le repli @media couvre le contenu placé hors de tout conteneur — sans
   lui, une grille sans conteneur ancêtre ne basculerait jamais. Même
   seuil dans les deux cas : le comportement mobile est inchangé. */
@container (max-width: 768px) {
  :is(.cols-2, .cols-3, .cols-4) { grid-template-columns: 1fr; }
}
@media (max-width: 768px) {
  :is(.cols-2, .cols-3, .cols-4) { grid-template-columns: 1fr; }
}

/* Alignement de texte */
.text-center { text-align: center; }
.text-right  { text-align: right; }

/* Masquage visuel accessible : retiré de l'écran, lu par les
   lecteurs d'écran (ex. <legend> d'un fieldset dont le titre
   visible est porté ailleurs). Mécanique, non themable. */
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* Remarque : .text-gradient (couleur de marque) vit dans
   components.css, pas ici — une classe qui rend une couleur
   thémable n'est pas un utilitaire de layout mécanique. */
