/* =========================================================================
   Altius Group — couche « Console » du site public, par-dessus Anw Theme.

   Édition 3 (août 2026) : refonte des layouts, fond sombre par défaut.
   L'édition 2 posait un système clair à filets ; celle-ci le retourne sur
   l'encre et pousse la mono partout où il y a une étiquette ou un chiffre.
   Registre visé : document technique d'un éditeur de logiciel, pas plaquette
   d'agence.

   Ce qui vient de la charte, sans écart :
     · deux fonds seulement — l'encre et le papier. Le site public tourne sur
       l'encre ; le mode clair reste servi par les mêmes règles, via les
       jetons de rôle (jamais d'hexadécimal en dur ici) ;
     · la terre cuite CLAIRE (clay-400) est l'accent sur fond encre — c'est
       la charte p. 06 qui l'impose, et c'est aussi le seul « vif » du site ;
     · Archivo pour les titres, IBM Plex Mono pour tout le reste de la
       signalétique : numéros de section, unités, libellés de navigation,
       boutons, en-têtes de colonne, légendes de graphique ;
     · aucune ombre sur les pages publiques. Un filet d'un pixel, ou rien.

   Préfixe `ag-` = pièce de CE système. Les classes sans préfixe
   (`.public-nav`, `.site-footer`, `.faq__item`…) sont celles que theme.js
   pilote : conservées et resurchargées, jamais renommées.
   ========================================================================= */

/* ═════════════════════════════════════════════════════════════════════════
   1. RÉGLAGES
   ═════════════════════════════════════════════════════════════════════════ */
[data-bs-theme="dark"] {
  /* theme.css fige `brand-300` pour le texte d'emphase en sombre ; la charte
     veut clay-400 (contraste mesuré 5,5 : 1). */
  --bs-primary-text-emphasis: var(--clay-400);
}

body.site-public {
  /* Pleine largeur d'écran. La page n'est plus une colonne posée au milieu
     d'un fond : les filets de section, la grille technique et les rangées de
     cartes vont d'un bord à l'autre, et seule la gouttière tient le texte à
     distance du bord. C'est ce qui donne au site son air de tableau de bord
     plutôt que de brochure. Le confort de lecture est repris ailleurs, par
     `--ag-measure` : ce sont les BLOCS de texte qui sont bornés, pas la page. */
  --ag-shell:   100%;
  --ag-gutter:  40px;
  --ag-measure: 62ch;
  --ag-sec-y:   84px;      /* dense : la page doit se lire, pas respirer */
  --ag-rule:    1px solid var(--color-border);
  --ag-filet-w: 26px;
  --ag-line:    rgba(16, 18, 17, .07);   /* trait de la grille de fond */
  --ag-cell:    72px;                    /* maille de la grille de fond */

  /* Échelle typographique du site public, relevée d'un cran par rapport aux
     jetons de la charte (16 px). Redéclarée ICI et non dans theme-tokens.css :
     le chrome applicatif — tableau de bord, admin — doit rester à son échelle
     dense, et la charte règle la page, pas la barre d'outils. */
  --text-body:  17px;
  --text-small: 15px;
  --text-label: 12.5px;
  --text-mono:  15px;
}
[data-bs-theme="dark"] body.site-public {
  --ag-line: rgba(244, 243, 240, .055);
}
@media (max-width: 1199.98px) { body.site-public { --ag-gutter: 28px; } }
@media (max-width: 767.98px) {
  body.site-public { --ag-gutter: 20px; --ag-sec-y: 52px; --ag-cell: 48px; }
}
body.site-public { background: var(--color-bg); color: var(--color-text); }

/* ═════════════════════════════════════════════════════════════════════════
   2. TYPOGRAPHIE
   Tout est enveloppé dans `:where()`, qui ne compte pour rien dans le calcul
   de spécificité : ces règles sont des DÉFAUTS, et le moindre composant qui
   pose sa propre taille ou sa propre couleur doit l'emporter.
   ═════════════════════════════════════════════════════════════════════════ */
:where(body.site-public) {
  font-family: var(--font-sans);
  font-weight: 400;
}
/* Le corps de texte est posé à spécificité RÉELLE, hors `:where()`. Dans le
   wrapper il pesait 0 et perdait contre l'échelle dense (13 px) que theme.css
   pose sur le body : les paragraphes non classés retombaient à 13 px juste
   sous un chapô à 17. Les défauts de titres et d'étiquettes restent, eux, dans
   `:where()` — un composant doit pouvoir les surcharger. */
body.site-public {
  font-size: var(--text-body);
  line-height: var(--text-body-lh);
}
/* Archivo n'a pas les variantes stylistiques d'Inter : les demander laissait
   le moteur chercher des tables absentes. Hors `:where()` — correction, pas
   défaut à laisser surcharger. */
body.site-public { font-feature-settings: normal; }

:where(body.site-public) :where(h1, .h1, h2, .h2, h3, .h3, h4, .h4, h5, .h5, h6, .h6) {
  font-family: var(--font-sans);
  font-weight: 600;
  text-wrap: pretty;
}
:where(body.site-public) :where(h1, .h1) {
  font-size: var(--text-h1); line-height: var(--text-h1-lh); letter-spacing: var(--text-h1-track);
}
:where(body.site-public) :where(h2, .h2) {
  font-size: clamp(26px, 2.6vw, 34px); line-height: 1.15; letter-spacing: -.022em;
}
:where(body.site-public) :where(h3, .h3) { font-size: 21px; line-height: 1.3; letter-spacing: -.012em; }
:where(body.site-public) :where(h4, .h4, h5, .h5, h6, .h6) { font-size: var(--text-body); line-height: 1.35; }
:where(body.site-public) :where(.display-title, .hero__title) {
  font-size: clamp(32px, 5.2vw, var(--text-display));
  line-height: var(--text-display-lh);
  letter-spacing: var(--text-display-track);
  font-weight: 600;
}
:where(body.site-public) :where(small, .small) { font-size: var(--text-small); line-height: var(--text-small-lh); }
:where(body.site-public) :where(code, kbd, samp, pre) {
  font-family: var(--font-mono); font-size: var(--text-mono); line-height: var(--text-mono-lh);
}

/* L'étiquette du système : mono, capitales, +0,08 em. Elle remplace partout
   l'étiquette Archivo espacée de l'édition précédente — c'est ce qui donne au
   site son air d'appareil de mesure plutôt que de page d'accueil. */
.ag-mono,
:where(body.site-public) :where(.eyebrow, .section-label, .hero__eyebrow, .logo-row__caption) {
  font-family: var(--font-mono);
  font-size: var(--text-label);
  line-height: var(--text-label-lh);
  letter-spacing: .09em;
  text-transform: uppercase;
  font-weight: 400;
}
.ag-mono--sm { font-size: 10.5px; letter-spacing: .12em; }
.ag-muted { color: var(--color-text-muted); }
.ag-accent { color: var(--accent-fg); }

/* Le filet : 26 × 2 px de terre cuite. Seul ornement du système — reprise du
   filet qui sépare ALTIUS de GROUP dans le logotype. */
.ag-filet {
  display: block; width: var(--ag-filet-w); height: 2px;
  background: var(--accent-fg); border: 0; flex: none;
}

/* ═════════════════════════════════════════════════════════════════════════
   3. GRILLE TECHNIQUE DE FOND
   Une maille de 72 px, tracée en pseudo-élément et non en image : elle suit
   la couleur du thème et ne coûte aucune requête. `mask-image` l'estompe vers
   le bas pour qu'elle n'entre jamais en concurrence avec le texte.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-mesh { position: relative; isolation: isolate; }
.ag-mesh > * { position: relative; z-index: 1; }
.ag-mesh::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    linear-gradient(to right,  var(--ag-line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--ag-line) 1px, transparent 1px);
  background-size: var(--ag-cell) var(--ag-cell);
  mask-image: linear-gradient(to bottom, #000 0%, #000 55%, transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 55%, transparent 100%);
}

/* ═════════════════════════════════════════════════════════════════════════
   4. PRIMITIVES DE MISE EN PAGE
   ═════════════════════════════════════════════════════════════════════════ */
.ag-shell {
  width: 100%; max-width: var(--ag-shell);
  margin-inline: auto; padding-inline: var(--ag-gutter);
}

/* Section : un filet pleine largeur en tête. C'est lui qui donne le rythme —
   pas un fond alterné à chaque bloc. */
.ag-section { padding-block: var(--ag-sec-y); border-top: var(--ag-rule); }
.ag-section--flush { border-top: 0; }
.ag-section--tight { padding-block: calc(var(--ag-sec-y) * .55); }

/* Bloc tranché : la surface remonte d'un cran et le bloc se referme sur deux
   filets. Deux fonds seulement dans tout le site — celui de la page et
   celui-ci ; aucune troisième teinte n'est introduite. */
.ag-section--panel {
  background: var(--color-surface);
  border-top: var(--ag-rule);
  border-bottom: var(--ag-rule);
}

/* En-tête de section : 5/7 asymétrique, numéro et filet à gauche, chapô à
   droite. Le texte centré est banni — il fait ressembler chaque page à
   toutes les autres. */
.ag-sec-head {
  display: grid; grid-template-columns: 1fr;
  gap: 18px 48px; margin-bottom: 44px;
}
@media (min-width: 992px) { .ag-sec-head { grid-template-columns: 5fr 7fr; align-items: start; } }
.ag-sec-head__left { display: flex; flex-direction: column; gap: 14px; }
.ag-sec-head__title { margin: 0; }
.ag-num {
  font-family: var(--font-mono); font-size: var(--text-label);
  letter-spacing: .1em; color: var(--color-text-muted);
  display: flex; align-items: center; gap: 12px;
}
.ag-num__id { color: var(--accent-fg); }
.ag-lede {
  margin: 0; color: var(--color-text-muted); max-width: var(--ag-measure);
  font-size: var(--text-body); line-height: var(--text-body-lh); text-wrap: pretty;
}

.ag-grid { display: grid; gap: 20px; grid-template-columns: 1fr; }
@media (min-width: 640px) { .ag-grid--2, .ag-grid--3, .ag-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 992px) {
  .ag-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .ag-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
/* Au-delà de 1440 px la page ne s'arrête plus : trois cartes étirées sur un
   écran large donnent des pavés de texte de 40 mots par ligne. `auto-fill`
   ajoute donc des colonnes au lieu d'élargir les existantes — cinq services
   se rangent en cinq colonnes sur un 1920, en trois sur un portable. */
@media (min-width: 1440px) {
  .ag-grid--3, .ag-grid--4 { grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); }
}
.ag-split { display: grid; grid-template-columns: 1fr; gap: 40px; align-items: start; }
@media (min-width: 992px) {
  .ag-split { grid-template-columns: 5fr 7fr; gap: 64px; }
  .ag-split--7-5 { grid-template-columns: 7fr 5fr; }
  .ag-split--even { grid-template-columns: 1fr 1fr; }
}

/* Liste à filets : le motif de liste par défaut du système. */
.ag-rows { list-style: none; margin: 0; padding: 0; border-top: var(--ag-rule); }
.ag-rows > li {
  border-bottom: var(--ag-rule); padding: 13px 0;
  display: flex; gap: 14px; align-items: baseline; font-size: var(--text-small);
}
.ag-rows__key {
  font-family: var(--font-mono); font-size: var(--text-label);
  letter-spacing: .08em; color: var(--accent-fg); flex: none; min-width: 2.5em;
}

/* ═════════════════════════════════════════════════════════════════════════
   5. BOUTONS DES PAGES PUBLIQUES
   `.ag-btn` est indépendant du `.btn` du thème : les formulaires gardent le
   bouton dense du thème, les appels à l'action de page prennent celui-ci —
   mono, angle vif, aucune ombre.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-btn {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 13px 18px;
  border-radius: var(--radius-xs);
  border: 1px solid transparent;
  /* Déclaré, et non laissé au défaut. Sur le site public tous les `.ag-btn`
     sont des `<a>`, transparents par nature ; le premier `<button>` posé avec
     la variante « contour » est ressorti en gris système, parce qu'un bouton
     porte un fond tant qu'on ne le lui retire pas. */
  background: transparent;
  font-family: var(--font-mono);
  font-size: var(--text-label);
  letter-spacing: .09em;
  text-transform: uppercase;
  font-weight: 400;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--t-base), color var(--t-base), border-color var(--t-base);
}
.ag-btn i { font-size: 1.15em; }
.ag-btn--solid  { background: var(--color-primary); color: var(--color-on-primary); }
.ag-btn--solid:hover  { background: var(--color-primary-hover); color: var(--color-on-primary); }
.ag-btn--outline { border-color: var(--color-border); color: var(--color-text); }
.ag-btn--outline:hover { border-color: var(--color-text); color: var(--color-text); }
.ag-btn--accent  { border-color: var(--accent-fg); color: var(--accent-fg); }
.ag-btn--accent:hover { background: var(--accent-fg); color: var(--color-bg); }
.ag-btn:focus-visible { outline: 0; box-shadow: var(--shadow-focus); }

/* Lien fléché : le « en savoir plus » du système. */
.ag-link {
  display: inline-flex; align-items: center; gap: 8px;
  color: var(--accent-fg); text-decoration: none;
  font-family: var(--font-mono); font-size: var(--text-label);
  letter-spacing: .08em; text-transform: uppercase;
}
.ag-link i { transition: transform var(--t-base); }
.ag-link:hover { color: var(--accent-fg); }
.ag-link:hover i { transform: translateX(3px); }

/* ═════════════════════════════════════════════════════════════════════════
   6. BANDEAU SUPÉRIEUR
   ═════════════════════════════════════════════════════════════════════════ */
.topbar {
  background: var(--color-bg);
  border-bottom: var(--ag-rule);
  padding: 8px 0;
}
.topbar__inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
}
.topbar__link {
  display: inline-flex; align-items: center; gap: 7px;
  color: var(--color-text-muted); text-decoration: none; max-width: 100%;
}
.topbar__link:hover { color: var(--color-text); }
.topbar__social { font-size: 13px; }
.topbar__right { display: flex; align-items: center; gap: 16px; }
.topbar__langs { display: flex; align-items: center; gap: 1px; margin: 0; }
.topbar__lang {
  font-family: var(--font-mono); font-size: var(--text-label);
  letter-spacing: .1em; border: 0; background: none;
  color: var(--color-text-muted); padding: 2px 5px; cursor: pointer;
}
.topbar__lang:hover { color: var(--color-text); }
.topbar__lang.is-active { color: var(--accent-fg); cursor: default; }

/* ═════════════════════════════════════════════════════════════════════════
   7. BARRE DE NAVIGATION
   Surcharge de `.public-nav` (theme.css). Les crochets que theme.js utilise
   — `.public-nav__hamburger`, `.is-open`, `[data-theme-toggle]` — restent.
   ═════════════════════════════════════════════════════════════════════════ */
body.site-public .public-nav {
  position: sticky; top: 0; z-index: 1030;
  background: color-mix(in srgb, var(--color-bg) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: var(--ag-rule);
  box-shadow: none;
}
body.site-public .public-nav__container {
  width: 100%; max-width: var(--ag-shell); margin-inline: auto;
  padding: 0 var(--ag-gutter);
  height: 68px; display: flex; align-items: center; gap: 28px;
}
body.site-public .public-nav__brand {
  display: inline-flex; align-items: center; flex: none;
  text-decoration: none; margin-right: auto;
}
/* La liste occupe TOUTE la hauteur de la barre, et chaque `li` avec elle.
   Sans cela le `li` ne fait que la hauteur de son lien : il reste 18 px de
   vide entre son bas et le haut du méga-menu, la souris y perd le survol en
   descendant, et le sous-menu se referme avant d'être atteint. Il était
   proprement inaccessible. */
body.site-public .public-nav__menu {
  display: flex; align-items: stretch; align-self: stretch; gap: 2px;
  list-style: none; margin: 0; padding: 0;
}
@media (max-width: 991.98px) { body.site-public .public-nav__menu { display: none; } }

body.site-public .public-nav__link {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 9px 11px;
  color: var(--color-text-muted); text-decoration: none;
  font-family: var(--font-mono); font-size: var(--text-label);
  letter-spacing: .08em; text-transform: uppercase;
  border-radius: var(--radius-xs); position: relative;
}
body.site-public .public-nav__link:hover { color: var(--color-text); background: none; }
/* L'état actif est un filet, pas une pastille. */
body.site-public .public-nav__link.is-active { color: var(--color-text); }
body.site-public .public-nav__link.is-active::after {
  content: ""; position: absolute; left: 11px; right: 11px; bottom: 0;
  height: 2px; background: var(--accent-fg);
}
body.site-public .public-nav__link i { font-size: .75em; opacity: .55; }

body.site-public .public-nav__cta { display: flex; align-items: center; gap: 8px; flex: none; }
body.site-public .public-nav__icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px;
  border: var(--ag-rule); border-radius: var(--radius-xs);
  background: transparent; color: var(--color-text-muted);
  cursor: pointer; font-size: 14px;
}
body.site-public .public-nav__icon-btn:hover { color: var(--color-text); border-color: var(--color-text); }
body.site-public .public-nav__hamburger {
  display: none; border: var(--ag-rule); border-radius: var(--radius-xs);
  background: transparent; color: var(--color-text);
  width: 36px; height: 36px; align-items: center; justify-content: center;
  font-size: 18px; cursor: pointer;
}
@media (max-width: 991.98px) { body.site-public .public-nav__hamburger { display: inline-flex; } }
@media (max-width: 767.98px) { body.site-public .public-nav__cta .ag-btn { display: none; } }

/* Méga-menu : une planche à filets, sans ombre ni rayon. */
body.site-public .public-nav__menu > li {
  position: static;
  display: flex; align-items: center;
}
body.site-public .mega-menu {
  display: none; position: absolute; top: 100%; left: 0; right: 0;
  background: var(--color-surface);
  border-top: var(--ag-rule); border-bottom: var(--ag-rule);
  box-shadow: none; border-radius: 0; padding: 0;
}
/* `:focus-within` en plus du survol : un menu qui ne s'ouvre qu'à la souris
   est inatteignable au clavier, et ses liens sont pourtant dans l'ordre de
   tabulation — on tabulait dans le vide. */
body.site-public .public-nav__menu > li:hover > .mega-menu,
body.site-public .public-nav__menu > li:focus-within > .mega-menu {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 0 40px;
  max-width: var(--ag-shell); margin-inline: auto;
  padding: 30px var(--ag-gutter) 26px;
}
body.site-public .mega-menu__col > h6 {
  font-family: var(--font-mono); font-size: var(--text-label);
  letter-spacing: .09em; text-transform: uppercase;
  color: var(--color-text-muted); font-weight: 400;
  margin: 0 0 10px; padding-bottom: 10px; border-bottom: var(--ag-rule);
}
body.site-public .mega-menu__item {
  display: flex; gap: 12px; padding: 9px 0;
  text-decoration: none; color: var(--color-text); border-bottom: var(--ag-rule);
}
body.site-public .mega-menu__item:last-child { border-bottom: 0; }
body.site-public .mega-menu__item:hover .mega-menu__item-title { color: var(--accent-fg); }
body.site-public .mega-menu__item-icon { color: var(--color-text-muted); flex: none; font-size: 14px; line-height: 1.5; }
body.site-public .mega-menu__item-title { font-size: var(--text-small); font-weight: 500; }
body.site-public .mega-menu__item-desc {
  font-size: var(--text-label); line-height: 1.45;
  color: var(--color-text-muted); margin-top: 3px;
}

/* Menu mobile — public-nav n'embarque ni JS ni CSS pour cela. */
@media (max-width: 991.98px) {
  body.site-public .public-nav.is-open .public-nav__menu {
    display: flex; flex-direction: column; align-items: stretch; align-self: auto;
    position: absolute; top: 100%; left: 0; right: 0;
    background: var(--color-bg); border-bottom: var(--ag-rule);
    padding: 4px var(--ag-gutter) 20px; gap: 0;
    max-height: calc(100vh - 68px); overflow-y: auto;
  }
  body.site-public .public-nav.is-open .public-nav__menu > li {
    width: 100%; border-bottom: var(--ag-rule);
    display: block;
  }
  body.site-public .public-nav.is-open .public-nav__link { width: 100%; padding: 15px 0; }
  body.site-public .public-nav.is-open .public-nav__link.is-active::after { left: 0; right: auto; width: var(--ag-filet-w); bottom: 9px; }
  body.site-public .public-nav.is-open .mega-menu {
    display: block !important; position: static; box-shadow: none;
    border: 0; padding: 0 0 12px; background: none;
  }
}

/* ═════════════════════════════════════════════════════════════════════════
   8. LOGOTYPE
   La zone de protection de la charte (une hauteur de capitale sur les quatre
   côtés) se règle ICI, en marge — jamais dans le fichier image, qui doit
   rester recadré au contenu pour ne pas rapetisser le logo dans une barre.
   ═════════════════════════════════════════════════════════════════════════ */
.theme-logo { height: 32px; width: auto; margin: 0; }
.theme-logo--light { display: inline-block; }
.theme-logo--dark { display: none; }
[data-bs-theme="dark"] .theme-logo--light { display: none; }
[data-bs-theme="dark"] .theme-logo--dark { display: inline-block; }
.site-footer__brand-logo-img { height: 38px; width: auto; }

/* ═════════════════════════════════════════════════════════════════════════
   9. HERO
   Deux colonnes : la parole à gauche, une planche technique à droite. Pas de
   photographie — la charte n'en a pas, et une capture d'écran inventée serait
   un mensonge. La planche affiche de vraies charges utiles.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-hero { padding-block: clamp(48px, 8vw, 100px); border-bottom: var(--ag-rule); }
.ag-hero__grid { display: grid; grid-template-columns: 1fr; gap: 44px; align-items: center; }
@media (min-width: 992px) { .ag-hero__grid { grid-template-columns: 6fr 6fr; gap: 64px; } }

.ag-hero__eyebrow { display: flex; align-items: center; gap: 14px; color: var(--color-text-muted); margin-bottom: 22px; }
.ag-hero__title {
  margin: 0 0 22px;
  font-size: clamp(34px, 5vw, 58px); line-height: 1.02;
  letter-spacing: -.03em; font-weight: 600;
  text-wrap: balance; max-width: 20ch;
}
.ag-hero__title em { font-style: normal; color: var(--accent-fg); }
.ag-hero__desc {
  margin: 0 0 30px; max-width: 52ch;
  font-size: 19px; line-height: 1.6;
  color: var(--color-text-muted); text-wrap: pretty;
}
.ag-hero__actions { display: flex; flex-wrap: wrap; gap: 10px; }

/* Planche technique : cadre à filets, barre de titre en mono, corps en mono. */
.ag-plate {
  border: var(--ag-rule); border-radius: var(--radius-xs);
  background: var(--color-surface); overflow: hidden;
}
.ag-plate__bar {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 11px 14px; border-bottom: var(--ag-rule);
  color: var(--color-text-muted); background: var(--color-surface-muted);
}
.ag-plate__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent-fg); flex: none; }
.ag-plate__body { padding: 18px 16px; font-family: var(--font-mono); font-size: 13.5px; line-height: 1.85; }
.ag-plate__row { display: flex; gap: 12px; white-space: pre; overflow: hidden; }
.ag-plate__ln { color: var(--color-text-muted); opacity: .5; flex: none; width: 2ch; text-align: right; }
.ag-plate__k { color: var(--accent-fg); }
.ag-plate__v { color: var(--color-text); }
.ag-plate__c { color: var(--color-text-muted); }
.ag-plate__foot {
  display: flex; flex-wrap: wrap; gap: 8px 20px;
  padding: 11px 14px; border-top: var(--ag-rule); color: var(--color-text-muted);
}

/* ═════════════════════════════════════════════════════════════════════════
   10. CARTES
   Un filet, un numéro, aucun rayon marqué, aucune ombre. Au survol le filet
   de tête passe en terre cuite : c'est tout le mouvement du système.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-card {
  position: relative; display: flex; flex-direction: column; gap: 11px;
  padding: 24px 22px 22px;
  background: var(--color-bg);
  border: var(--ag-rule); border-radius: var(--radius-xs);
  transition: border-color var(--t-base), background var(--t-base);
}
.ag-section--panel .ag-card { background: var(--color-bg); }
.ag-card::before {
  content: ""; position: absolute; top: -1px; left: -1px;
  width: var(--ag-filet-w); height: 2px;
  background: transparent; transition: background var(--t-base);
}
.ag-card:hover { border-color: var(--color-text-muted); }
.ag-card:hover::before { background: var(--accent-fg); }
.ag-card__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.ag-card__idx { font-family: var(--font-mono); font-size: var(--text-label); letter-spacing: .1em; color: var(--color-text-muted); }
.ag-card__icon { font-size: 18px; color: var(--accent-fg); line-height: 1; }
.ag-card__title { margin: 0; font-size: 18px; line-height: 1.3; letter-spacing: -.012em; font-weight: 600; }
.ag-card__desc { margin: 0; color: var(--color-text-muted); font-size: var(--text-small); line-height: 1.6; text-wrap: pretty; }
.ag-card__foot { margin-top: auto; padding-top: 10px; }

/* ═════════════════════════════════════════════════════════════════════════
   11. CHIFFRES
   Colonnes séparées par un filet vertical, valeurs en mono : un tableau de
   mesures, pas trois pastilles marketing.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-figures { display: grid; grid-template-columns: 1fr; border-top: var(--ag-rule); }
@media (min-width: 640px) { .ag-figures { grid-template-columns: repeat(3, 1fr); } }
.ag-figures__item { padding: 24px 0; border-bottom: var(--ag-rule); }
@media (min-width: 640px) {
  .ag-figures__item { padding: 28px 26px; border-bottom: 0; border-left: var(--ag-rule); }
  .ag-figures__item:first-child { border-left: 0; padding-left: 0; }
}
.ag-figures__value {
  font-family: var(--font-mono);
  font-size: clamp(38px, 5.5vw, 58px); line-height: 1;
  font-weight: 500; letter-spacing: -.035em; font-variant-numeric: tabular-nums;
}
.ag-figures__label { margin-top: 12px; color: var(--color-text-muted); font-size: var(--text-small); line-height: 1.4; }

/* ═════════════════════════════════════════════════════════════════════════
   12. CITATION CLIENT
   Le guillemet géant du thème disparaît : la citation se signale par son
   filet de tête et son corps un cran plus grand.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-quote { display: flex; flex-direction: column; gap: 18px; padding-top: 18px; border-top: 2px solid var(--color-border); }
.ag-quote__rating { display: flex; gap: 3px; color: var(--accent-fg); font-size: 11px; }
.ag-quote__rating .empty { color: var(--color-border); }
.ag-quote__text { margin: 0; font-size: 17px; line-height: 1.6; text-wrap: pretty; }
.ag-quote__author { display: flex; align-items: center; gap: 12px; margin-top: auto; }
.ag-quote__avatar {
  width: 36px; height: 36px; border-radius: 50%; object-fit: cover; flex: none;
  background: var(--color-surface-muted);
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-mono); font-size: var(--text-label);
  color: var(--color-text-muted); border: var(--ag-rule);
}
.ag-quote__name { font-size: var(--text-small); font-weight: 500; }
.ag-quote__meta {
  font-family: var(--font-mono); font-size: var(--text-label); letter-spacing: .06em;
  color: var(--color-text-muted); margin-top: 3px;
}

/* ═════════════════════════════════════════════════════════════════════════
   13. FAQ
   Crochets conservés pour theme.js : `.faq__item.is-open`, `.faq__question`,
   `.faq__answer` (hauteur animée par le script).
   ═════════════════════════════════════════════════════════════════════════ */
/* Le thème dessine chaque question comme une CARTE : `border: 1px solid` sur
   les quatre côtés, coins arrondis, aplat de surface, et `gap: 1px` entre les
   éléments. La surcouche ne redéfinissait que `border-bottom` — les bords
   gauche, droit et haut du thème survivaient, et l'accordéon s'affichait en
   rectangle encadré au milieu d'une page qui n'a que des filets. D'où le
   `border: 0` qui remet tout à plat AVANT de reposer le seul trait voulu.

   Le `gap: 1px` doublait en outre les filets là où deux éléments se touchent. */
body.site-public .faq { border-top: var(--ag-rule); gap: 0; }
body.site-public .faq__item {
  border: 0; border-bottom: var(--ag-rule);
  background: none; border-radius: 0;
}
body.site-public .faq__question {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  gap: 20px; padding: 20px 0;
  background: none; border: 0; text-align: left;
  font-family: var(--font-sans); font-size: 17px; font-weight: 500;
  letter-spacing: -.012em; color: var(--color-text); cursor: pointer;
}
body.site-public .faq__question:hover { color: var(--accent-fg); }
body.site-public .faq__question i { flex: none; font-size: 12px; color: var(--color-text-muted); transition: transform var(--t-base); }
body.site-public .faq__item.is-open .faq__question i { transform: rotate(180deg); }
/* La réponse s'ouvre à sa hauteur RÉELLE. Le thème l'anime avec un plafond
   `max-height: 320px`, hérité d'une époque où la réponse était une ligne de
   texte brut ; elle se saisit désormais en éditeur enrichi, avec des
   paragraphes et des listes, et tout ce qui dépasse 320 px était coupé net —
   sans barre de défilement, donc sans que rien ne le signale.

   La bascule passe par `grid-template-rows: 0fr → 1fr`, la seule façon
   d'animer vers une hauteur automatique. `max-height: none` neutralise le
   plafond du thème dans les deux états, et `min-height: 0` autorise la piste
   de grille à se replier — sans lui, elle garde la hauteur de son contenu et
   la question reste ouverte. */
body.site-public .faq__answer {
  display: grid; grid-template-rows: 0fr;
  max-height: none; overflow: hidden;
  transition: grid-template-rows var(--t-base);
}
body.site-public .faq__item.is-open .faq__answer {
  grid-template-rows: 1fr; max-height: none;
}
/* Aucun REMBOURRAGE sur cette boîte. `min-height: 0` replie le contenu d'un
   élément de grille, jamais son rembourrage : les 22 px du bas subsistaient et
   la piste se stabilisait à 22 px au lieu de 0 — les deux premières lignes de
   chaque réponse restaient donc visibles sous une question fermée. Mesuré,
   pas supposé : `grid-template-rows` valait « 22px ».

   L'air sous le dernier paragraphe est donc posé en MARGE sur celui-ci. Une
   marge est du contenu, elle se replie avec lui. */
body.site-public .faq__answer-inner {
  min-height: 0; overflow: hidden;
  padding: 0; max-width: var(--ag-measure);
  color: var(--color-text-muted); font-size: var(--text-small); line-height: 1.65;
}

/* La réponse vient de l'éditeur enrichi : elle arrive en paragraphes. Leurs
   marges par défaut décollaient le texte de sa question et laissaient un blanc
   sous le dernier paragraphe, au-dessus du filet. */
body.site-public .faq__answer-inner > :first-child { margin-top: 0; }
body.site-public .faq__answer-inner > :last-child { margin-bottom: 22px; }
body.site-public .faq__answer-inner :is(ul, ol) { margin: .6em 0; padding-left: 1.2em; }
body.site-public .faq__answer-inner a { color: var(--accent-fg); }

/* Le chevron : même graisse que le reste de la signalétique. */
body.site-public .faq__question i { font-size: 13px; }

/* ═════════════════════════════════════════════════════════════════════════
   14. BLOC D'APPEL (bas de page)
   ═════════════════════════════════════════════════════════════════════════ */
.ag-cta { border-top: var(--ag-rule); padding-block: clamp(52px, 7vw, 88px); }
.ag-cta__grid { display: grid; grid-template-columns: 1fr; gap: 30px; align-items: end; }
@media (min-width: 992px) { .ag-cta__grid { grid-template-columns: 7fr 5fr; gap: 56px; } }
.ag-cta__eyebrow { display: flex; align-items: center; gap: 14px; color: var(--accent-fg); margin-bottom: 18px; }
.ag-cta__title {
  margin: 0 0 14px; font-size: clamp(28px, 3.4vw, 40px);
  line-height: 1.08; letter-spacing: -.025em; font-weight: 600;
  max-width: 24ch; text-wrap: balance;
}
.ag-cta__desc { margin: 0; color: var(--color-text-muted); max-width: 50ch; line-height: 1.6; text-wrap: pretty; }
.ag-cta__actions { display: flex; flex-wrap: wrap; gap: 10px; }
@media (min-width: 992px) { .ag-cta__actions { justify-content: flex-end; } }

/* ═════════════════════════════════════════════════════════════════════════
   15. PIED DE PAGE
   ═════════════════════════════════════════════════════════════════════════ */
body.site-public .site-footer {
  background: var(--color-surface); color: var(--color-text-muted);
  border-top: var(--ag-rule); padding: 0;
}
body.site-public .site-footer__container {
  width: 100%; max-width: var(--ag-shell); margin-inline: auto;
  padding: 56px var(--ag-gutter) 44px;
  display: grid; grid-template-columns: 1fr; gap: 36px;
}
@media (min-width: 768px) { body.site-public .site-footer__container { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 992px) { body.site-public .site-footer__container { grid-template-columns: 4fr 2fr 2fr 3fr; gap: 44px; } }

body.site-public .site-footer__brand { display: flex; flex-direction: column; gap: 14px; }
body.site-public .site-footer__brand p {
  margin: 0; font-size: var(--text-small); line-height: 1.65;
  color: var(--color-text-muted); max-width: 40ch;
}
body.site-public .site-footer__social { display: flex; gap: 8px; }
body.site-public .site-footer__social a {
  width: 34px; height: 34px; display: inline-flex; align-items: center; justify-content: center;
  border: var(--ag-rule); border-radius: var(--radius-xs);
  color: var(--color-text-muted); text-decoration: none;
}
body.site-public .site-footer__social a:hover { color: var(--color-text); border-color: var(--color-text); }

body.site-public .site-footer__col h6 {
  font-family: var(--font-mono); font-size: var(--text-label);
  letter-spacing: .09em; text-transform: uppercase; font-weight: 400;
  color: var(--color-text-muted);
  margin: 0 0 2px; padding-bottom: 11px; border-bottom: var(--ag-rule);
}
body.site-public .site-footer__col ul { list-style: none; margin: 0; padding: 0; }
body.site-public .site-footer__col li { border-bottom: var(--ag-rule); }
body.site-public .site-footer__col a {
  display: block; padding: 10px 0; color: var(--color-text);
  text-decoration: none; font-size: var(--text-small);
}
body.site-public .site-footer__col a:hover { color: var(--accent-fg); }

body.site-public .site-footer__bottom {
  border-top: var(--ag-rule);
  padding: 18px var(--ag-gutter);
  max-width: var(--ag-shell); margin-inline: auto;
  display: flex; flex-wrap: wrap; gap: 12px; justify-content: space-between;
  font-family: var(--font-mono); font-size: var(--text-label);
  letter-spacing: .04em; color: var(--color-text-muted);
}
body.site-public .site-footer__bottom a { color: var(--color-text-muted); text-decoration: none; }
body.site-public .site-footer__bottom a:hover { color: var(--accent-fg); }
body.site-public .site-footer__bottom strong { font-weight: 400; color: var(--color-text); }

/* ═════════════════════════════════════════════════════════════════════════
   16. LOGOS CLIENTS (Swiper)
   ═════════════════════════════════════════════════════════════════════════ */
/* `.card` (Bootstrap) est display:flex; flex-direction:column : `.clients-slider`
   n'obtient de largeur que par le « stretch » de l'axe transverse — il n'en a
   pas en propre. Swiper mesure clientWidth pour dimensionner ses slides, et
   contre une largeur non explicite la résolution devient circulaire : Chrome
   la borne à sa taille de mise en page interne (~2^25 px), ce qui corrompt le
   calcul de Swiper et laisse chaque slide à zéro. Une largeur explicite casse
   le cycle. */
.clients-slider { padding: 4px 0; width: 100%; min-width: 0; }
.clients-slider .swiper-slide { text-align: center; }
/* Deux bornes, et il faut les deux. `height` décide de la taille des logos
   CARRÉS — la plupart le sont, et 40px les rendait minuscules. `max-width`
   décide de celle des logos LARGES : plafonnée trop bas, elle les encadre et
   leur hauteur réelle retombe sous la borne (Names Legal, 6.6:1, sortait à
   23px de haut pour 40px annoncés). Les deux montent donc ensemble. */
.clients-slider__img {
  height: 52px; width: auto; max-width: 240px; object-fit: contain;
  display: inline-block; vertical-align: middle;
  filter: grayscale(1) invert(0); opacity: .45;
  transition: filter var(--t-base), opacity var(--t-base);
}
[data-bs-theme="dark"] .clients-slider__img { filter: grayscale(1) brightness(2.2); }
.clients-slider__img:hover { filter: none; opacity: 1; }
.ag-clients { display: grid; grid-template-columns: 1fr; gap: 20px; align-items: center; }
@media (min-width: 768px) { .ag-clients { grid-template-columns: auto 1fr; gap: 36px; } }
.ag-clients__caption { color: var(--color-text-muted); flex: none; }

/* ═════════════════════════════════════════════════════════════════════════
   17. GRAPHIQUES D3
   ═════════════════════════════════════════════════════════════════════════ */
.ag-chart { width: 100%; }
.ag-chart__caption { margin-top: 12px; padding-top: 11px; border-top: var(--ag-rule); color: var(--color-text-muted); }

/* ═════════════════════════════════════════════════════════════════════════
   18. CORPS DE TEXTE ENRICHI (rendu du filtre `richtext`)
   Ce que l'éditeur montre doit être ce que le site rend : les mêmes règles
   sont reprises dans la zone d'écriture de Quill (medialibrary/quill.css).
   ═════════════════════════════════════════════════════════════════════════ */
.prose { color: var(--color-text); font-size: var(--text-body); line-height: var(--text-body-lh); }
.prose :is(h2, h3, h4) {
  color: var(--color-text-strong); font-weight: 600;
  letter-spacing: var(--text-h1-track); margin: 1.6em 0 .5em;
}
.prose h2 { font-size: var(--text-h2); line-height: var(--text-h2-lh); }
.prose h3 { font-size: 20px; line-height: 1.3; }
.prose h4 { font-size: var(--text-body); line-height: 1.35; }
.prose p { margin: 0 0 1em; }
.prose ul, .prose ol { margin: 0 0 1em 1.25em; }
.prose li { margin: 0 0 .35em; }
.prose a { color: var(--accent-fg); text-underline-offset: .2em; }
.prose img { max-width: 100%; height: auto; border-radius: var(--radius-xs); }
.prose pre, .prose code { font-family: var(--font-mono); font-size: var(--text-mono); }
.prose pre {
  background: var(--color-surface-muted); border: var(--ag-rule);
  border-radius: var(--radius-xs); padding: var(--space-4); overflow-x: auto;
}
.prose blockquote {
  margin: 1.5em 0; padding: 0 0 0 var(--space-4);
  /* Le filet est terre cuite : c'est le seul endroit du corps de texte où la
     couleur de la marque a droit de cité. */
  border-left: 2px solid var(--accent-fg);
  color: var(--color-text-muted);
}
.prose hr { border: 0; border-top: var(--ag-rule); margin: 2.5em 0; }
.prose table { width: 100%; border-collapse: collapse; font-size: var(--text-small); margin: 0 0 1.5em; }
.prose :is(th, td) { border: var(--ag-rule); padding: var(--space-2) var(--space-3); text-align: left; }
.prose th { font-weight: 500; background: var(--color-surface-muted); }

/* --- Taille et habillage d'un média inséré au fil du texte --------------
   Posés par l'éditeur sous forme de CLASSES et non de style en ligne : seule
   une classe peut retomber pleine largeur sous 600 px, une media query ne
   pouvant pas s'appliquer à un attribut `style`.
   Deux familles de préfixes, et elles doivent rester distinctes :
   `ag-w`/`ag-pos` pour une image (blot en ligne), `ag-wb`/`ag-posb` pour une
   vidéo (blot de bloc). Voir le commentaire de medialibrary/quill.js. */
.prose .ag-w-full,  .prose .ag-wb-full  { width: 100%; }
.prose .ag-w-half,  .prose .ag-wb-half  { width: 50%; }
.prose .ag-w-third, .prose .ag-wb-third { width: 33.333%; }
.prose .ag-pos-center, .prose .ag-posb-center { display: block; margin-left: auto; margin-right: auto; }
.prose .ag-pos-left,  .prose .ag-posb-left  { float: left;  margin: .35em 1.5em 1em 0; }
.prose .ag-pos-right, .prose .ag-posb-right { float: right; margin: .35em 0 1em 1.5em; }

/* Image accompagnée de son crédit. `<span>` passé en bloc et non `<figure>` :
   l'éditeur place toujours l'image dans un `<p>`, où un `<figure>` — contenu
   de bloc — ferait refermer le paragraphe par le navigateur, laissant deux
   trous verticaux dans le texte. */
.prose .ag-inlinefig { display: block; margin: 1.5em 0; }
.prose .ag-inlinefig img { width: 100%; display: block; }
.prose .ag-figure__credit {
  display: block; margin-top: .5em;
  font-family: var(--font-mono); font-size: var(--text-label);
  line-height: var(--text-label-lh); letter-spacing: .08em;
  text-transform: uppercase; color: var(--color-text-muted);
}
.prose iframe { aspect-ratio: 16 / 9; width: 100%; border: 0; border-radius: var(--radius-xs); display: block; margin: 1.5em 0; }

/* Sous 600 px, tout retombe pleine largeur : un tiers de colonne sur un
   téléphone n'est plus une image, c'est une vignette. */
@media (max-width: 600px) {
  .prose :is(.ag-w-half, .ag-w-third, .ag-wb-half, .ag-wb-third, .ag-inlinefig) {
    width: 100%; float: none; margin-left: 0; margin-right: 0;
  }
}

/* ═════════════════════════════════════════════════════════════════════════
   19. EN-TÊTE DE PAGE INTÉRIEURE
   Le pendant, pour une page de second niveau, de ce que `.ag-hero` est pour
   l'accueil : pas un bandeau à image de fond, mais un fil d'Ariane en mono, un
   titre, un chapô, et le filet qui referme. Une page intérieure s'annonce ;
   elle ne se met pas en scène.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-page-head {
  padding-block: clamp(36px, 5vw, 64px) 0;
  border-bottom: var(--ag-rule);
}
.ag-page-head__inner { padding-bottom: clamp(28px, 4vw, 44px); }
.ag-page-head__title { margin: 14px 0 0; }
.ag-page-head__lede { margin: 16px 0 0; }
.ag-page-head__actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 24px; }

/* Fil d'Ariane : mono, capitales, séparateur en barre oblique. Il remplace le
   `.breadcrumb` de Bootstrap, dont les pastilles arrondies n'ont pas cours
   ici. */
.ag-crumbs {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  list-style: none; margin: 0; padding: 0;
  font-family: var(--font-mono); font-size: var(--text-label);
  letter-spacing: .09em; text-transform: uppercase;
  color: var(--color-text-muted);
}
.ag-crumbs a { color: var(--color-text-muted); text-decoration: none; }
.ag-crumbs a:hover { color: var(--accent-fg); }
.ag-crumbs li + li::before { content: "/"; margin-right: 10px; opacity: .45; }
.ag-crumbs .is-current { color: var(--color-text); }

/* ═════════════════════════════════════════════════════════════════════════
   20. ARTICLE ET COLONNE LATÉRALE
   ═════════════════════════════════════════════════════════════════════════ */
/* 8/4 plutôt que le 5/7 des sections : un corps d'article a besoin de la
   largeur, la colonne latérale n'est qu'un index. */
.ag-with-side { display: grid; grid-template-columns: 1fr; gap: 44px; align-items: start; }
@media (min-width: 992px) {
  .ag-with-side { grid-template-columns: minmax(0, 8fr) minmax(0, 4fr); gap: 40px; }
}

/* ═════════════════════════════════════════════════════════════════════════
   21. ARTICLE EN LISTE
   Pas une carte : une entrée. Le filet du haut la sépare de la précédente, et
   la couverture reste un accessoire — c'est le titre qu'on lit.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-posts { display: grid; grid-template-columns: 1fr; gap: 0; }
@media (min-width: 768px) { .ag-posts--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 32px; } }
.ag-post {
  position: relative;
  display: flex; flex-direction: column; gap: 12px;
  padding: 26px 0; border-top: var(--ag-rule);
}
.ag-post__cover {
  display: block; width: 100%; aspect-ratio: 16 / 9; object-fit: cover;
  border: var(--ag-rule); border-radius: var(--radius-xs);
  filter: saturate(.85); transition: filter var(--t-base);
}
.ag-post:hover .ag-post__cover { filter: none; }
.ag-post__title { margin: 0; font-size: 19px; line-height: 1.3; letter-spacing: -.012em; font-weight: 600; }
.ag-post__title a { color: inherit; text-decoration: none; }
.ag-post:hover .ag-post__title a { color: var(--accent-fg); }
.ag-post__desc { margin: 0; color: var(--color-text-muted); font-size: var(--text-small); line-height: 1.6; text-wrap: pretty; }

/* Pastille de rubrique. Rectangulaire et en mono : le système n'a pas de
   pastilles arrondies. */
.ag-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.ag-chip {
  display: inline-block; padding: 4px 9px;
  border: var(--ag-rule); border-radius: var(--radius-xs);
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: .09em; text-transform: uppercase;
  color: var(--color-text-muted); text-decoration: none;
  transition: border-color var(--t-base), color var(--t-base);
}
a.ag-chip:hover { border-color: var(--accent-fg); color: var(--accent-fg); }
.ag-chip--accent { border-color: var(--accent-fg); color: var(--accent-fg); }

/* ═════════════════════════════════════════════════════════════════════════
   22. PAGINATION
   ═════════════════════════════════════════════════════════════════════════ */
.ag-pager {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  margin-top: 36px; padding-top: 22px; border-top: var(--ag-rule);
}
.ag-pager__item {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 36px; height: 36px; padding: 0 10px;
  border: 1px solid transparent; border-radius: var(--radius-xs);
  font-family: var(--font-mono); font-size: var(--text-label);
  letter-spacing: .06em; color: var(--color-text-muted); text-decoration: none;
  transition: border-color var(--t-base), color var(--t-base);
}
.ag-pager__item:hover { border-color: var(--color-border); color: var(--color-text); }
.ag-pager__item.is-active { border-color: var(--accent-fg); color: var(--accent-fg); cursor: default; }
.ag-pager__item.is-disabled { opacity: .35; pointer-events: none; }
.ag-pager__gap { color: var(--color-text-muted); padding: 0 4px; }

/* ═════════════════════════════════════════════════════════════════════════
   23. FORMULAIRES
   Les classes viennent de Python (`form-control`, `form-label`) : on ne les
   renomme pas, on les rhabille sous `.ag-form`. Renommer aurait obligé à
   toucher six fichiers de formulaires pour un changement d'apparence.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-form { display: flex; flex-direction: column; gap: 20px; }
.ag-form__row { display: grid; grid-template-columns: 1fr; gap: 20px; }
@media (min-width: 640px) { .ag-form__row--2 { grid-template-columns: 1fr 1fr; } }
.ag-form__field { display: flex; flex-direction: column; gap: 7px; }

.ag-form :is(.form-label, label) {
  margin: 0;
  font-family: var(--font-mono); font-size: var(--text-label);
  letter-spacing: .09em; text-transform: uppercase;
  color: var(--color-text-muted);
}
.ag-form :is(.form-control, .form-select, input[type="text"], input[type="email"],
              input[type="tel"], input[type="url"], input[type="date"], input[type="file"],
              select, textarea) {
  width: 100%;
  padding: 12px 14px;
  background: var(--color-bg);
  border: var(--ag-rule);
  border-radius: var(--radius-xs);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: var(--text-small);
  line-height: 1.5;
  box-shadow: none;
  transition: border-color var(--t-base);
}
/* Dans un bloc tranché, le champ reprend le fond de la page : sans quoi il
   disparaît dans la surface qui le porte. */
.ag-section--panel .ag-form :is(.form-control, .form-select, textarea, select) {
  background: var(--color-bg);
}
.ag-form :is(.form-control, .form-select, textarea, select):focus {
  outline: 0; border-color: var(--accent-fg); box-shadow: none;
}
.ag-form :is(.form-control, textarea)::placeholder { color: var(--color-text-muted); opacity: .8; }
.ag-form textarea { min-height: 150px; resize: vertical; }
.ag-form .form-text { font-size: 12px; color: var(--color-text-muted); }
.ag-form .invalid-feedback {
  font-family: var(--font-mono); font-size: 11.5px;
  letter-spacing: .05em; color: var(--color-danger);
}
.ag-form__foot { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; }

/* Message d'état. Un filet à gauche, aucun aplat coloré. */
.ag-note {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 13px 16px;
  border: var(--ag-rule); border-left: 2px solid var(--color-text-muted);
  border-radius: var(--radius-xs);
  font-size: var(--text-small); line-height: 1.5;
  color: var(--color-text-muted);
}
.ag-note--error { border-left-color: var(--color-danger); color: var(--color-danger); }
.ag-note--ok { border-left-color: var(--accent-fg); color: var(--color-text); }

/* ═════════════════════════════════════════════════════════════════════════
   24. FICHE TECHNIQUE (informations d'un projet, d'un produit)
   Deux colonnes séparées par un filet : c'est un tableau de valeurs, pas une
   carte. La clé est en mono, la valeur en Archivo.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-specs { list-style: none; margin: 0; padding: 0; border-top: var(--ag-rule); }
.ag-specs > li {
  display: grid; grid-template-columns: 1fr; gap: 4px;
  padding: 13px 0; border-bottom: var(--ag-rule);
}
@media (min-width: 480px) { .ag-specs > li { grid-template-columns: 10em 1fr; gap: 16px; align-items: baseline; } }
.ag-specs__key {
  font-family: var(--font-mono); font-size: var(--text-label);
  letter-spacing: .08em; text-transform: uppercase; color: var(--color-text-muted);
}
.ag-specs__val { font-size: var(--text-small); line-height: 1.5; overflow-wrap: anywhere; }
.ag-specs__val a { color: var(--accent-fg); }

/* ═════════════════════════════════════════════════════════════════════════
   25. GALERIE DE PROJET
   ═════════════════════════════════════════════════════════════════════════ */
.ag-gallery { position: relative; border: var(--ag-rule); border-radius: var(--radius-xs); overflow: hidden; }
.ag-gallery .swiper-slide img { display: block; width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }
.ag-gallery .swiper-button-prev,
.ag-gallery .swiper-button-next { color: var(--accent-fg); }
.ag-gallery .swiper-button-prev::after,
.ag-gallery .swiper-button-next::after { font-size: 20px; font-weight: 700; }
.ag-gallery .swiper-pagination-bullet { background: var(--color-text-muted); border-radius: 0; width: 14px; height: 2px; }
.ag-gallery .swiper-pagination-bullet-active { background: var(--accent-fg); }

/* ═════════════════════════════════════════════════════════════════════════
   26. PAGE D'ERREUR
   Le code d'erreur en mono, à la taille d'un titre : c'est une donnée, pas un
   ornement. Aucun dégradé — le système n'en a aucun ailleurs.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-error { padding-block: clamp(64px, 12vw, 140px); max-width: 56ch; }
.ag-error__code {
  font-family: var(--font-mono); font-weight: 500;
  font-size: clamp(48px, 9vw, 96px); line-height: 1;
  letter-spacing: -.02em; color: var(--accent-fg);
}
.ag-error__title { margin: 24px 0 0; }
.ag-error__desc { margin: 16px 0 0; color: var(--color-text-muted); line-height: 1.6; text-wrap: pretty; }
.ag-error__actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 32px; }

/* ═════════════════════════════════════════════════════════════════════════
   27. AJUSTEMENTS D'ESPACEMENT
   `.ag-section` porte le rythme vertical. Ces deux utilitaires servent aux
   blocs qui vivent DANS une section et n'en sont pas une.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-stack   { display: flex; flex-direction: column; gap: 24px; }
.ag-stack--lg { gap: 44px; }
.ag-measure { max-width: var(--ag-measure); }

/* ═════════════════════════════════════════════════════════════════════════
   28. TABLEAU DE DONNÉES
   Les écrans de dépouillement (contacts reçus, cahiers des charges déposés)
   sont rendus dans la coquille PUBLIQUE. Ils gardent donc son vocabulaire :
   en-têtes en mono, filets horizontaux, aucune bordure verticale ni zébrure —
   un tableau se lit en lignes.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-table-wrap { width: 100%; overflow-x: auto; }
.ag-table { width: 100%; border-collapse: collapse; font-size: var(--text-small); }
.ag-table th {
  text-align: left; white-space: nowrap;
  padding: 0 18px 11px 0; border-bottom: 2px solid var(--color-border);
  font-family: var(--font-mono); font-size: var(--text-label); font-weight: 400;
  letter-spacing: .09em; text-transform: uppercase; color: var(--color-text-muted);
}
.ag-table td {
  padding: 13px 18px 13px 0; border-bottom: var(--ag-rule);
  line-height: 1.45; vertical-align: top;
}
.ag-table tr:hover td { background: var(--color-surface); }
.ag-table :is(th, td):last-child { padding-right: 0; }
.ag-table__num { font-family: var(--font-mono); color: var(--color-text-muted); white-space: nowrap; }
.ag-table__empty { padding: 28px 0; color: var(--color-text-muted); }

/* ═════════════════════════════════════════════════════════════════════════
   29. SOMMAIRE D'ARTICLE
   La colonne entière est collante ET bornée à la hauteur de l'écran
   (`.ag-side`) : le sommaire suit la lecture sans code supplémentaire.

   Il n'a plus d'ascenseur à lui. Il en avait un — `max-height` sur la liste —
   du temps où la colonne débordait librement ; depuis qu'elle défile
   elle-même, deux ascenseurs imbriqués se disputaient la molette, et l'un des
   deux bougeait toujours à la place de l'autre.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-toc__list { list-style: none; margin: 0; padding: 0; }
/* Le niveau 3 est décalé et rapetissé : c'est la seule chose qui distingue une
   sous-partie d'une partie une fois les numéros retirés. */
.ag-toc__item--l3 .ag-toc__link { padding-left: 30px; font-size: 13px; }
/* Un FILET CONTINU, et non une suite de lignes séparées par des traits.
   Les traits horizontaux faisaient de dix titres un tableau ; le filet
   vertical en fait un parcours, et laisse le marqueur de position dire
   quelque chose. */
.ag-toc__list { border-left: var(--ag-rule); }
.ag-toc__link {
  display: block; padding: 9px 0 9px 16px;
  color: var(--color-text-muted); text-decoration: none;
  font-size: var(--text-small); line-height: 1.45;
  border-left: 2px solid transparent; margin-left: -1px;
  transition: color var(--t-base), border-color var(--t-base);
}
.ag-toc__link:hover { color: var(--color-text); }
/* Titre en cours de lecture, posé par main.js. */
.ag-toc__link.is-current { color: var(--accent-fg); border-left-color: var(--accent-fg); }

/* Le titre visé ne doit pas se glisser sous la barre de navigation collante
   quand on suit une ancre. */
.prose :is(h2, h3)[id] { scroll-margin-top: 92px; }

/* ═════════════════════════════════════════════════════════════════════════
   30. CONNEXION AU TABLEAU DE BORD
   L'écran vit dans la coquille PUBLIQUE — c'est la seule page du back-office
   qu'on atteint sans être connecté, et lui donner la coquille applicative
   afficherait une barre latérale de navigation à quelqu'un qui n'a encore le
   droit d'ouvrir aucun de ses écrans.
   ═════════════════════════════════════════════════════════════════════════ */
.db-login { max-width: 380px; padding-block: clamp(40px, 8vw, 90px); }
.db-login__title { margin: 14px 0 0; }

/* ═════════════════════════════════════════════════════════════════════════
   31. RÉALISATION EN LISTE
   Même registre que `.ag-card` — filet, coin d'accent au survol — mais la
   figure déborde jusqu'aux bords : une image de projet coupée par une marge
   intérieure ressemble à une vignette d'illustration, pas à une livraison.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-work {
  position: relative; display: flex; flex-direction: column;
  background: var(--color-bg);
  border: var(--ag-rule); border-radius: var(--radius-xs);
  overflow: hidden;
  transition: border-color var(--t-base);
}
.ag-work::before {
  content: ""; position: absolute; top: -1px; left: -1px; z-index: 2;
  width: var(--ag-filet-w); height: 2px;
  background: transparent; transition: background var(--t-base);
}
.ag-work:hover { border-color: var(--color-text-muted); }
.ag-work:hover::before { background: var(--accent-fg); }

/* ═════════════════════════════════════════════════════════════════════════
   CADRE D'IMAGE — `.ag-figure`
   Quatre gabarits la posaient (équipe, portfolio, à-propos, article) et RIEN
   ne la stylait : ni ici, ni dans `theme.css`. Le commentaire de `.ag-work__fig`
   juste en dessous la décrivait déjà — filet, marge basse — sans qu'elle existe.

   La ligne qui compte est `width: 100%`. Sans elle une image garde sa largeur
   INTRINSÈQUE : le portrait 1024×1024 de l'équipe sortait à 1024 px de large
   dans une colonne de 290, et `aspect-ratio: 4/5` en déduisait 1280 px de haut.
   Il n'y a pas de `img { max-width: 100% }` global dans ce projet pour rattraper
   ça — d'où une seule photo qui poussait la page sur trois écrans.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-figure {
  margin: 0 0 18px;
  border: var(--ag-rule);
  border-radius: var(--radius-xs);
  /* `overflow: hidden` : c'est lui qui fait tenir la promesse de `--crop` et
     du `scale(1.03)` au survol d'une carte de projet. */
  overflow: hidden;
}
.ag-figure img { display: block; width: 100%; height: auto; }
/* Recadrer plutôt que déformer : l'image remplit le cadre et déborde par où
   elle veut, la partie en trop est coupée par l'`overflow` ci-dessus. */
.ag-figure--crop img { object-fit: cover; }

/* La figure porte déjà `.ag-figure`, qui pose un filet et une marge basse : ni
   l'un ni l'autre n'ont de sens à l'intérieur d'une carte qui a son propre
   cadre. */
.ag-work__fig { margin: 0; border: 0; border-bottom: var(--ag-rule); border-radius: 0; }
.ag-work__fig img { transition: transform var(--t-slow, .5s) ease; }
.ag-work:hover .ag-work__fig img { transform: scale(1.03); }

.ag-work__body { display: flex; flex-direction: column; gap: 11px; padding: 22px; }
.ag-work__meta {
  display: flex; justify-content: space-between; gap: 12px;
  padding-top: 10px; border-top: var(--ag-rule);
  color: var(--color-text-muted);
}

/* ═════════════════════════════════════════════════════════════════════════
   32. MEMBRE DE L'ÉQUIPE
   Sans cadre : une colonne de la grille, un portrait, un nom. Le filet du
   haut suffit à séparer — encadrer chaque personne donnerait quatre boîtes
   alignées, ce que la charte réserve aux objets qu'on ouvre.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-person { display: flex; flex-direction: column; gap: 8px; }
.ag-person__fig { margin: 0 0 6px; }
.ag-person__fig img { aspect-ratio: 4 / 5; object-fit: cover; }
.ag-person__role { color: var(--color-text-muted); margin: 0; }
.ag-person__social { display: flex; gap: 12px; margin-top: 6px; }
.ag-person__social a {
  color: var(--color-text-muted); text-decoration: none; font-size: 15px;
  transition: color var(--t-base);
}
.ag-person__social a:hover { color: var(--accent-fg); }

/* ═════════════════════════════════════════════════════════════════════════
   34. PAQUETS LIBRES
   Un index, pas une galerie. Chaque entrée tient sur trois lignes — le nom en
   mono, ce que le paquet fait, où le trouver — et se sépare de la suivante
   par un filet, comme les articles en liste.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-pkgs { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; }
@media (min-width: 900px) { .ag-pkgs { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 40px; } }

.ag-pkg { padding: 22px 0; border-top: var(--ag-rule); }
.ag-pkg__head { display: flex; align-items: baseline; flex-wrap: wrap; gap: 10px; }
.ag-pkg__name { font-size: 15px; color: var(--color-text); letter-spacing: .01em; }
.ag-pkg__ver { color: var(--color-text-muted); }
.ag-pkg__desc { margin: 8px 0 12px; color: var(--color-text-muted); max-width: 52ch; }

.ag-pkg__links { display: flex; flex-wrap: wrap; gap: 16px; align-items: center; }
.ag-pkg__links a {
  color: var(--color-text-muted); text-decoration: none;
  border-bottom: 1px solid var(--color-border);
  transition: color var(--t-base), border-color var(--t-base);
}
.ag-pkg__links a:hover { color: var(--accent-fg); border-bottom-color: var(--accent-fg); }
.ag-pkg__date { color: var(--color-text-muted); opacity: .6; margin-left: auto; }

/* ═════════════════════════════════════════════════════════════════════════
   35. CARROUSEL DES PAQUETS (hero)
   Une planche qui change de contenu, pas un diaporama d'images : le cadre,
   la barre de titre et le pied ne bougent jamais, seul le bloc de code est
   remplacé. C'est ce qui permet à l'œil de revenir au même endroit à chaque
   diapositive au lieu de chercher où l'information a glissé.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-deck__label { display: inline-flex; align-items: center; gap: 8px; }
.ag-deck__nav { display: flex; align-items: center; gap: 4px; }
.ag-deck__count { color: var(--color-text-muted); min-width: 4ch; text-align: center; }
.ag-deck__count b { color: var(--color-text); font-weight: inherit; }

.ag-deck__arrow {
  appearance: none; border: 0; background: transparent; cursor: pointer;
  padding: 2px 6px; border-radius: var(--radius-xs);
  color: var(--color-text-muted); font-size: 13px; line-height: 1;
  transition: color var(--t-base), background var(--t-base);
}
.ag-deck__arrow:hover { color: var(--accent-fg); background: var(--color-primary-bg); }
.ag-deck__arrow:focus-visible { outline: 2px solid var(--accent-fg); outline-offset: 1px; }

.ag-deck__head {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 10px;
  padding: 14px 16px 0;
}
.ag-deck__name { font-size: 15px; color: var(--accent-fg); }
.ag-deck__ver, .ag-deck__lang { color: var(--color-text-muted); }
.ag-deck__lang { margin-left: auto; }

/* Le code des sept paquets n'a pas le même nombre de lignes : sans plancher,
   changer de diapositive ferait sauter le titre du hero, qui est aligné sur
   cette planche. La ligne la plus longue défile plutôt que de déborder. */
.ag-deck .ag-plate__body { min-height: 216px; padding-top: 14px; overflow-x: auto; }

.ag-deck__summary {
  padding: 0 16px 16px; color: var(--color-text-muted);
  font-size: var(--text-small); line-height: 1.5;
}

.ag-deck__dots { display: flex; align-items: center; gap: 7px; }
.ag-deck__dot {
  appearance: none; border: 0; padding: 0; cursor: pointer;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--color-border);
  transition: background var(--t-base), transform var(--t-base);
}
.ag-deck__dot:hover { background: var(--color-text-muted); }
.ag-deck__dot.is-active { background: var(--accent-fg); transform: scale(1.3); }
.ag-deck__dot:focus-visible { outline: 2px solid var(--accent-fg); outline-offset: 2px; }

.ag-deck__links { display: flex; gap: 16px; margin-left: auto; }
.ag-deck__links > span { display: flex; gap: 16px; }
.ag-deck__links a { color: inherit; text-decoration: none; border-bottom: 1px solid transparent; }
.ag-deck__links a:hover { color: var(--accent-fg); border-bottom-color: var(--accent-fg); }

/* Les extraits réels sont plus larges que la planche inventée qu'ils
   remplacent : `print(f"{r.distance_km} km, ...")  # 551.8 km, 681.0 min` fait
   73 caractères. `.ag-plate__row` porte un `overflow: hidden` qui coupait
   chaque ligne net, sans barre de défilement — le lecteur ne voyait même pas
   qu'il manquait quelque chose. Ici la ligne déborde, et c'est le CORPS qui
   défile, une seule barre pour tout le bloc. */
.ag-deck .ag-plate__row { overflow: visible; }
.ag-deck .ag-plate__body { font-size: 12px; line-height: 1.9; }

/* La barre de défilement, discrète mais présente : elle est le seul indice
   qu'une ligne continue à droite. */
.ag-deck .ag-plate__body { scrollbar-width: thin; scrollbar-color: var(--color-border) transparent; }
.ag-deck .ag-plate__body::-webkit-scrollbar { height: 6px; }
.ag-deck .ag-plate__body::-webkit-scrollbar-thumb { background: var(--color-border); border-radius: 3px; }
.ag-deck .ag-plate__body::-webkit-scrollbar-track { background: transparent; }

/* ═════════════════════════════════════════════════════════════════════════
   34. PAGE D'ARTICLE — trois colonnes
   Chacune répond à une question distincte, et c'est ce qui justifie qu'elles
   soient trois plutôt qu'une colonne fourre-tout :

     · à GAUCHE   où j'en suis (sommaire) et où aller ensuite (récents) ;
     · au CENTRE  le texte, borné à la mesure de lecture ;
     · à DROITE   sous quoi CET article est classé.

   La version précédente empilait tout à droite — sommaire, récents, rubriques
   du site, mots-clés du site — soit 1586 px dans un écran de 961, et un
   ascenseur gris en travers de la page pour le rattraper.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-article { display: grid; grid-template-columns: 1fr; gap: 40px; }

@media (min-width: 992px) {
  /* Deux colonnes tant que trois ne tiennent pas. Le classement passe sous le
     texte plutôt que de comprimer la mesure : une ligne trop courte coûte plus
     à la lecture qu'un bloc déplacé. */
  .ag-article {
    grid-template-columns: 230px minmax(0, var(--ag-measure));
    gap: 56px;
    justify-content: center;
    align-items: start;
  }
  .ag-facets { grid-column: 2; }
  /* Le rail colle. Il est TENU COURT pour cela — sommaire plus trois articles
     récents — parce qu'un élément collant plus haut que la fenêtre ne s'épingle
     pas, et que le borner ferait revenir l'ascenseur qu'on vient de retirer. */
  .ag-rail { position: sticky; top: 96px; }
  .ag-reading-head .ag-page-head__inner {
    max-width: calc(230px + 56px + var(--ag-measure));
    margin-inline: auto;
  }
}

@media (min-width: 1280px) {
  .ag-article {
    grid-template-columns: 230px minmax(0, var(--ag-measure)) 210px;
  }
  /* `grid-row: 1` : sans lui, le placement automatique renvoie le classement
     à la ligne suivante et laisse la troisième colonne vide. */
  .ag-facets { grid-column: 3; grid-row: 1; position: sticky; top: 96px; }
  .ag-reading-head .ag-page-head__inner {
    max-width: calc(230px + 56px + var(--ag-measure) + 56px + 210px);
  }
}

.ag-rail__block + .ag-rail__block { margin-top: 40px; }
/* Le bloc des récents sert aussi dans la colonne de la page de liste,
   qui espace ses blocs par `.ag-side__block`. Il porte les deux classes ;
   cette règle empêche les deux marges de s'additionner. */
.ag-rail__block.ag-side__block + .ag-side__block { margin-top: 36px; }
.ag-railtitle {
  margin: 0 0 14px;
  color: var(--color-text-muted); font-size: var(--text-label);
  letter-spacing: .1em; text-transform: uppercase;
}

/* --- Articles récents : des cartes ------------------------------------- */
.ag-recent { display: grid; gap: 22px; }
.ag-recent__card {
  display: block; text-decoration: none; color: inherit;
  padding-top: 14px; border-top: var(--ag-rule);
}
.ag-recent__thumb {
  display: block; width: 100%; aspect-ratio: 16 / 9; object-fit: cover;
  margin-bottom: 10px; border-radius: var(--radius-xs);
}
.ag-recent__title {
  display: block;
  font-size: var(--text-small); line-height: 1.35; color: var(--color-text);
  transition: color var(--t-base);
}
/* La date en pied, en mono : elle se lit d'un coup d'œil et ne se confond
   jamais avec le titre, ce qui était le défaut de la ligne unique. */
.ag-recent__date {
  display: block; margin-top: 8px;
  font-family: var(--font-mono); font-size: var(--text-label);
  letter-spacing: .08em; color: var(--color-text-muted);
}
.ag-recent__card:hover .ag-recent__title { color: var(--accent-fg); }

/* --- Le classement de l'article ---------------------------------------- */
.ag-facets { display: grid; gap: 32px; align-content: start; }
.ag-facet__list { list-style: none; margin: 0; padding: 0; }
.ag-facet__list > li + li { margin-top: 2px; }
.ag-facet__list a {
  display: block; padding: 7px 0;
  color: var(--color-text); text-decoration: none;
  font-size: var(--text-small); line-height: 1.35;
  border-bottom: var(--ag-rule);
  transition: color var(--t-base);
}
.ag-facet__list a:hover { color: var(--accent-fg); }

/* --- Ligne d'identité, sous le titre ----------------------------------- */
.ag-artline {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  color: var(--color-text-muted);
  font-size: var(--text-label); letter-spacing: .08em; text-transform: uppercase;
}
.ag-artline__sep { color: var(--color-border); }

/* --- Le corps ---------------------------------------------------------- */
/* Le premier paragraphe est un chapô sans avoir à être saisi comme tel : un
   champ « chapô » de plus serait un champ de plus à remplir quarante-cinq
   fois, et vide la moitié du temps. */
.ag-prose--article > p:first-of-type {
  font-size: clamp(18px, 1.3vw, 21px); line-height: 1.55;
  color: var(--color-text-strong);
}
/* Le repère de section : un tiret terre cuite au-dessus de chaque titre.
   C'est le filet de la charte réduit à la longueur d'un mot, et le seul
   ornement de la page — ce qui lui laisse sa force. */
.ag-prose--article h2 { position: relative; margin-top: 2.2em; padding-top: .55em; }
.ag-prose--article h2::before {
  content: ""; position: absolute; top: 0; left: 0;
  width: 28px; height: 2px; background: var(--accent-fg);
}

.ag-artfoot {
  margin-top: var(--space-7); padding-top: var(--space-5);
  border-top: var(--ag-rule);
}

/* ═════════════════════════════════════════════════════════════════════════
   35. COLONNE LATÉRALE — styles RESTAURÉS
   Ils avaient été emportés par un nettoyage trop large : la suppression de la
   variante « lecture » de `.ag-with-side` allait jusqu'au commentaire de
   section suivant, et ces règles se trouvaient entre les deux. Effet visible
   uniquement sur la page de LISTE, seule à porter encore `.ag-side` — les
   rubriques y sont ressorties en puces bleues soulignées, c'est-à-dire sans
   feuille de style du tout.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-side__block + .ag-side__block { margin-top: 36px; }
.ag-side__title {
  margin: 0 0 14px; padding-bottom: 10px;
  border-bottom: 2px solid var(--color-border);
  color: var(--color-text-muted);
}
/* Aucune carte, aucun fond : des lignes. C'est le motif de liste du système
   (`.ag-rows`), décliné en liens. */
.ag-side__list { list-style: none; margin: 0; padding: 0; }
.ag-side__list > li { border-bottom: var(--ag-rule); }
.ag-side__link {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 12px 0; color: var(--color-text); text-decoration: none;
  font-size: var(--text-small); line-height: 1.4;
}
.ag-side__link:hover { color: var(--accent-fg); }
.ag-side__count {
  font-family: var(--font-mono); font-size: var(--text-label);
  color: var(--color-text-muted); flex: none;
}

/* ═════════════════════════════════════════════════════════════════════════
   36. RUBRIQUES DU BLOG — une barre de filtre, pas une liste de liens
   Sur un index de quarante-cinq articles, les rubriques sont le premier geste
   de navigation : elles appartiennent au-dessus de la liste, pas au tiers
   inférieur d'une colonne, sous les articles récents, où personne ne les
   cherche.

   Elles disent aussi OÙ L'ON EST : la page d'une rubrique devient un état de
   la liste — l'entrée courante marquée — au lieu d'une page qui lui ressemble
   sans qu'on sache comment y revenir.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-cats {
  display: flex; flex-wrap: wrap;
  border-top: var(--ag-rule); border-bottom: var(--ag-rule);
  margin-bottom: var(--space-6);
}
.ag-cats__item {
  display: inline-flex; align-items: baseline; gap: 8px;
  padding: 14px 0; margin-right: 28px;
  color: var(--color-text-muted); text-decoration: none;
  font-family: var(--font-mono); font-size: var(--text-label);
  letter-spacing: .08em; text-transform: uppercase;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  transition: color var(--t-base), border-color var(--t-base);
}
.ag-cats__item:hover { color: var(--color-text); }
.ag-cats__item.is-current {
  color: var(--accent-fg); border-bottom-color: var(--accent-fg);
}
/* Le compte est un chiffre, pas un libellé : il reste en retrait tant qu'on
   ne le cherche pas. */
.ag-cats__count { color: var(--color-border); }
.ag-cats__item.is-current .ag-cats__count { color: var(--accent-fg); }

/* ═════════════════════════════════════════════════════════════════════════
   37. BANDEAU DE CONSENTEMENT
   Une barre posée au bas de l'écran, du même bois que le reste : fond plein,
   un filet d'un pixel au-dessus, la mono sur les deux boutons. Pas d'ombre
   portée, pas de carte flottante, pas de superposition qui bloque la page —
   on peut continuer à lire sans répondre, et le site fonctionne pendant ce
   temps-là.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-consent {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 1035;   /* sous les modales de Bootstrap (1055), au-dessus du reste */
  /* Le fond DOIT être opaque : la barre couvre le bas de la page. C'est aussi
     la raison du filet — sans lui, deux aplats de la même couleur se
     toucheraient sans qu'on voie où l'un finit. */
  background: var(--color-bg);
  border-top: var(--ag-rule);
}
.ag-consent__inner {
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding-block: 20px;
}
.ag-consent__text { max-width: var(--ag-measure); }
.ag-consent__text p {
  margin: 8px 0 10px;
  font-size: var(--text-small);
  color: var(--color-text-muted);
}
.ag-consent__actions {
  display: flex;
  gap: 10px;
  flex: none;
}
/* Les deux boutons occupent la même largeur. C'est la règle de fond du
   bandeau, écrite ici parce qu'elle se démolit d'un `padding` : refuser doit
   être aussi facile qu'accepter, donc aussi VISIBLE. */
.ag-consent__actions .ag-btn {
  flex: 1 1 0;
  justify-content: center;
}
@media (min-width: 768px) {
  .ag-consent__inner {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 40px;
  }
  .ag-consent__actions .ag-btn { flex: none; }
}

/* Le bas de page ne doit pas finir sous la barre. `:has()` évite d'ajouter une
   classe sur `<body>` depuis le gabarit : la règle suit l'existence du
   bandeau, et disparaît avec lui. */
body.site-public:has(.ag-consent) { padding-bottom: 140px; }
@media (min-width: 768px) {
  body.site-public:has(.ag-consent) { padding-bottom: 96px; }
}

/* Entrée : la barre monte d'un cran. Rien de plus — c'est une question posée,
   pas une notification à faire remarquer. */
@media (prefers-reduced-motion: no-preference) {
  /* `--t-slow` porte la durée ET la courbe : en ajouter une seconde
     invaliderait la déclaration entière. */
  .ag-consent { animation: ag-consent-in var(--t-slow) both; }
  @keyframes ag-consent-in {
    from { transform: translateY(100%); }
    to   { transform: translateY(0); }
  }
}

/* ═════════════════════════════════════════════════════════════════════════
   38. CHOIX EN COURS, SUR LA PAGE DES COOKIES
   Le bandeau disparaît une fois répondu ; sans cet encadré, revenir sur sa
   décision demanderait de vider ses cookies à la main.
   ═════════════════════════════════════════════════════════════════════════ */
.ag-choice {
  margin-top: var(--space-6);
  padding: 22px;
  border: var(--ag-rule);
}
.ag-choice__state {
  display: flex; align-items: baseline; gap: 10px;
  margin: 10px 0 16px;
}
.ag-choice__value { color: var(--accent-fg); }
.ag-choice__actions { display: flex; flex-wrap: wrap; gap: 10px; }
