/* ============================================================================
   Kit UI Evan Bombart — feuille principale
   ----------------------------------------------------------------------------
   Charge tokens.css AVANT ce fichier (ou utilise kit.css qui fait les deux).

   Organisation en @layer : l'ordre de priorite est declare ici une fois pour
   toutes. Consequence concrete pour les 6 projets : le CSS d'une application
   surcharge toujours le kit SANS avoir besoin de !important, meme si son
   selecteur est moins specifique. Support @layer : 95,30 % (caniuse).
   ========================================================================== */

@layer reset, base, composants, utilitaires;

/* ---------------------------------------------------------------- reset -- */
@layer reset {
  *, *::before, *::after { box-sizing: border-box; }
  * { margin: 0; }

  /* `<dialog>` se centre grace a `margin: auto` combine a `inset: 0` — c'est
     le mecanisme natif du navigateur. Le `* { margin: 0 }` ci-dessus le
     detruit et colle la modale en haut a gauche (mesure : ecart de 384px sur
     un viewport de 1280). On le retablit explicitement.
     Piege classique de tout reset CSS : ne pas retirer cette regle. */
  dialog { margin: auto; }

  html {
    -webkit-text-size-adjust: 100%;
    /* Defilement doux sur les ancres. `scroll-behavior` est Baseline widely
       depuis 2022 (webstatus.dev). Neutralise plus bas par
       prefers-reduced-motion : un defilement anime declenche des nausees chez
       les personnes sensibles au mouvement vestibulaire (WCAG 2.2 SC 2.3.3). */
    scroll-behavior: smooth;
    /* La cible d'une ancre ne doit pas se coller au bord haut, ni passer sous
       un en-tete collant. Chaque page ajuste via --eb-ancre-offset. */
    scroll-padding-block-start: var(--eb-ancre-offset, var(--eb-espace-5));
  }

  body {
    min-height: 100svh;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
  }

  /* Les medias sont bornes a leur conteneur : cause n°1 de debordement
     horizontal sur mobile. */
  img, picture, svg, video, canvas {
    display: block;
    max-width: 100%;
    height: auto;
  }

  /* Les champs n'heritent pas de la police par defaut : sans cette regle un
     <input> s'affiche en Arial au milieu d'une page en Inter. */
  input, button, textarea, select { font: inherit; color: inherit; }

  /* Texte insecable (URL, adresses) : mesure qui evite le debordement, voir
     la competence visual-ui-verification. */
  p, li, h1, h2, h3, h4, td, dd { overflow-wrap: break-word; }

  :where(ul, ol)[class] { list-style: none; padding: 0; }
}

/* ----------------------------------------------------------------- base -- */
@layer base {
  body {
    background: var(--eb-fond);
    color: var(--eb-texte);
    font-family: var(--eb-typo-body-police);
    font-size: var(--eb-typo-body-taille);
    line-height: var(--eb-typo-body-interligne);
    font-weight: var(--eb-typo-body-graisse);
  }

  /* Chaque niveau consomme son ROLE typographique, jamais une taille brute :
     retoucher l'echelle se fait dans tokens.json, en un seul endroit.
     Les interlettrages viennent aussi des tokens (charte d'Evan) — les ecrire
     en dur ici les ferait diverger de la source de verite. */
  h1 {
    font-family: var(--eb-typo-h1-police);
    font-size: var(--eb-typo-h1-taille);
    font-weight: var(--eb-typo-h1-graisse);
    line-height: var(--eb-typo-h1-interligne);
    letter-spacing: var(--eb-typo-h1-interlettre);
    text-wrap: balance;     /* evite le mot orphelin en fin de titre */
  }
  h2 {
    font-family: var(--eb-typo-h2-police);
    font-size: var(--eb-typo-h2-taille);
    font-weight: var(--eb-typo-h2-graisse);
    line-height: var(--eb-typo-h2-interligne);
    letter-spacing: var(--eb-typo-h2-interlettre);
    text-wrap: balance;
  }
  h3 {
    font-family: var(--eb-typo-h3-police);
    font-size: var(--eb-typo-h3-taille);
    font-weight: var(--eb-typo-h3-graisse);
    line-height: var(--eb-typo-h3-interligne);
    letter-spacing: var(--eb-typo-h3-interlettre);
  }
  /* h4 bascule sur Inter : regle de la charte. */
  h4 {
    font-family: var(--eb-typo-h4-police);
    font-size: var(--eb-typo-h4-taille);
    font-weight: var(--eb-typo-h4-graisse);
    line-height: var(--eb-typo-h4-interligne);
    letter-spacing: var(--eb-typo-h4-interlettre);
  }
  h5 {
    font-family: var(--eb-typo-h5-police);
    font-size: var(--eb-typo-h5-taille);
    font-weight: var(--eb-typo-h5-graisse);
    line-height: var(--eb-typo-h5-interligne);
  }
  /* h6 est un SUR-TITRE : majuscules, interlettre positive. Pas un h5 en plus
     petit — c'est la lecture erronee que faisait la premiere version du kit. */
  h6 {
    font-family: var(--eb-typo-h6-police);
    font-size: var(--eb-typo-h6-taille);
    font-weight: var(--eb-typo-h6-graisse);
    line-height: var(--eb-typo-h6-interligne);
    letter-spacing: var(--eb-typo-h6-interlettre);
    text-transform: uppercase;
  }

  p { text-wrap: pretty; }

  a { color: var(--eb-accent); text-underline-offset: 0.2em; }
  a:hover { text-decoration-thickness: 2px; }

  code, kbd, samp, pre { font-family: var(--eb-police-mono); font-size: 0.9em; }

  /* Focus visible sur TOUT element focusable, jamais supprime : c'est la
     seule facon de naviguer au clavier. Ratio verifie par les tests. */
  :focus-visible {
    outline: 2px solid var(--eb-accent);
    outline-offset: 2px;
    border-radius: var(--eb-rayon-s);
  }

  ::selection { background: var(--eb-accent-aplat); color: var(--eb-sur-accent); }
}

/* ----------------------------------------------------------- composants -- */
@layer composants {

  /* --- Mises en page ------------------------------------------------------ */

  /* Rythme vertical d'Evan : 80 / 64 / 40 px (Desktop / Tablette / Mobile).
     Deux segments fluides, bascule a 768px — ses reperes ne sont pas alignes
     sur une droite, une interpolation unique donnerait 57,7px au lieu de 64. */
  .eb-section { padding-block: var(--eb-espace-section); }
  @media (min-width: 48rem) {
    .eb-section { padding-block: var(--eb-espace-section-large); }
  }

  /* Gouttiere laterale d'Evan : 12 px, CONSTANTE quel que soit l'ecran.
     Ne jamais l'interpoler — c'est un choix, pas un oubli. */
  .eb-page {
    max-width: var(--eb-page-max);
    margin-inline: auto;
    padding-inline: var(--eb-espace-gouttiere);
  }

  /* Colonne de LECTURE : bornee a ~68 caracteres, et corps agrandi. C'est la
     difference mesuree entre veille (agreable) et une page pleine largeur. */
  .eb-lecture {
    max-width: var(--eb-lecture-max);
    margin-inline: auto;
    font-size: var(--eb-typo-body-l-taille);
    line-height: var(--eb-typo-body-l-interligne);
  }

  /* Gap d'Evan : 24 px des la tablette, 12 px en mobile. */
  .eb-pile    { display: grid; gap: var(--eb-espace-gap); }
  .eb-pile-s  { display: grid; gap: var(--eb-espace-2); }
  .eb-pile-l  { display: grid; gap: var(--eb-espace-6); }

  .eb-rangee {
    display: flex; align-items: center; gap: var(--eb-espace-3); flex-wrap: wrap;
    /* min-width:0 sur les enfants flex : sans lui un contenu long deborde et
       pousse la page entiere (piege mesure le 28/08). */
    & > * { min-width: 0; }
  }
  .eb-rangee-fin { justify-content: flex-end; }
  .eb-rangee-entre { justify-content: space-between; }

  .eb-grille {
    display: grid;
    gap: var(--eb-espace-4);
    grid-template-columns: repeat(auto-fill, minmax(min(18rem, 100%), 1fr));
  }

  /* --- En-tete de page ---------------------------------------------------- */

  /* Le point d'entree visuel obligatoire (MANIFESTE regle 1). */
  .eb-entete { margin-block-end: var(--eb-espace-6); }

  /* Le hero de la charte : trame en fond, respiration verticale genereuse.
     C'est ce qui donne a une page son point d'entree evident. */
  .eb-hero {
    padding-block: var(--eb-espace-7) var(--eb-espace-6);
    border-block-end: 1px solid var(--eb-ligne);
    /* Pas de margin-block-end : elle s'ajouterait au padding et produirait
       4rem de vide subi entre le hero et le contenu (MANIFESTE regle 5).
       C'est au conteneur suivant de poser son propre espacement. */
  }
  .eb-hero__contenu {
    max-width: var(--eb-page-max);
    margin-inline: auto;
    padding-inline: var(--eb-espace-4);
  }
  .eb-hero .eb-sous-titre { max-width: var(--eb-lecture-max); }
  /* Le point framboise apres le titre : signature de la charte. */
  .eb-point { color: var(--eb-accent-aplat); }
  .eb-surtitre {
    font: var(--eb-typo-overline-graisse) var(--eb-typo-overline-taille)/var(--eb-typo-overline-interligne) var(--eb-typo-overline-police);
    letter-spacing: var(--eb-typo-overline-interlettre);
    text-transform: uppercase;
    color: var(--eb-accent);
    margin-block-end: var(--eb-espace-2);
  }
  .eb-sous-titre {
    color: var(--eb-texte-doux);
    font-size: var(--eb-taille-body-s);
    margin-block-start: var(--eb-espace-2);
  }

  /* --- Boutons ------------------------------------------------------------ */

  .eb-bouton {
    display: inline-flex; align-items: center; justify-content: center;
    gap: var(--eb-espace-2);
    min-height: var(--eb-bouton-hauteur);
    padding-inline: var(--eb-bouton-padding-x);
    border-radius: var(--eb-bouton-rayon);
    border: 1px solid transparent;
    font-size: var(--eb-typo-button-taille);
    font-weight: var(--eb-typo-button-graisse);
    text-decoration: none;
    cursor: pointer;
    background: none;
    color: var(--eb-texte);

    @media (prefers-reduced-motion: no-preference) {
      transition:
        background-color var(--eb-duree-courte) var(--eb-courbe-standard),
        border-color     var(--eb-duree-courte) var(--eb-courbe-standard),
        opacity          var(--eb-duree-courte) var(--eb-courbe-standard);
    }
  }

  /* UNE SEULE action primaire par vue (MANIFESTE regle 3). */
  .eb-bouton--primaire {
    background: var(--eb-bouton-fond-primaire);
    color: var(--eb-bouton-texte-primaire);
  }
  .eb-bouton--primaire:hover { opacity: 0.9; }

  .eb-bouton--secondaire {
    border-color: var(--eb-ligne);
    background: var(--eb-surface);
  }
  .eb-bouton--secondaire:hover { border-color: var(--eb-accent); color: var(--eb-accent); }

  .eb-bouton--discret { color: var(--eb-texte-doux); padding-inline: var(--eb-espace-3); }
  .eb-bouton--discret:hover { color: var(--eb-accent); background: var(--eb-surface-2); }

  /* Le rouge n'est utilise QUE si le destructif est l'action primaire. */
  .eb-bouton--danger { background: var(--eb-alerte); color: #fff; }
  .eb-bouton--danger:hover { opacity: 0.9; }

  .eb-bouton:disabled, .eb-bouton[aria-disabled="true"] {
    opacity: 0.5; cursor: not-allowed;
  }

  /* --- Carte -------------------------------------------------------------- */

  .eb-carte {
    background: var(--eb-carte-fond);
    border: 1px solid var(--eb-carte-bordure);
    border-radius: var(--eb-carte-rayon);
    padding: var(--eb-carte-padding);

    @media (prefers-reduced-motion: no-preference) {
      transition:
        border-color var(--eb-duree-courte) var(--eb-courbe-standard),
        transform    var(--eb-duree-courte) var(--eb-courbe-standard);
    }
  }
  /* :has() — 94,07 % (caniuse). La carte ne reagit que si elle est cliquable :
     un survol qui bouge sans rien faire est un mensonge visuel. */
  .eb-carte:has(a):hover { border-color: var(--eb-accent); transform: translateY(-2px); }
  .eb-carte:focus-within { border-color: var(--eb-accent); }

  .eb-carte__titre {
    font: var(--eb-typo-h4-graisse) var(--eb-typo-h4-taille)/var(--eb-typo-h4-interligne) var(--eb-typo-h4-police);
    letter-spacing: var(--eb-typo-h4-interlettre);
    margin-block-end: var(--eb-espace-2);
  }
  /* Le lien de titre depend de l'interligne : a 18px x 1.3 il tombe a 23px,
     sous le minimum de 24px (WCAG 2.2 SC 2.5.8) — mesure faite en 768px le
     02/09/2026. Le padding etend la CIBLE sans decaler le rendu (compense par
     la marge negative), et `inline-block` est indispensable : un <a> inline
     ignore le padding vertical pour le calcul de sa boite. */
  .eb-carte__titre a {
    display: inline-block;
    padding-block: var(--eb-espace-1);
    margin-block: calc(var(--eb-espace-1) * -1);
    color: inherit;
    text-decoration: none;
  }
  .eb-carte__titre a:hover { color: var(--eb-accent); }
  .eb-carte__meta {
    display: flex; align-items: center; gap: var(--eb-espace-2); flex-wrap: wrap;
    font-size: var(--eb-taille-body-xs);
    color: var(--eb-texte-faible);
    margin-block-end: var(--eb-espace-3);
  }
  .eb-carte__corps { color: var(--eb-texte-doux); }
  .eb-carte__pied {
    margin-block-start: var(--eb-espace-4);
    color: var(--eb-accent);
    font-size: var(--eb-taille-body-s);
    font-weight: var(--eb-graisse-forte);
  }

  /* --- Etiquette ---------------------------------------------------------- */

  .eb-etiquette {
    display: inline-flex; align-items: center; gap: var(--eb-espace-1);
    padding: 0.15rem var(--eb-espace-2);
    border-radius: var(--eb-rayon-pilule);
    font-size: var(--eb-taille-body-xs);
    font-weight: var(--eb-graisse-forte);
    background: var(--eb-surface-2);
    color: var(--eb-texte-doux);
  }
  /* color-mix() : Baseline widely depuis 2023. Evite de declarer une variable
     de fond teinte par etat. */
  .eb-etiquette--accent    { background: color-mix(in srgb, var(--eb-accent) 12%, transparent);    color: var(--eb-accent); }
  .eb-etiquette--succes    { background: color-mix(in srgb, var(--eb-succes) 14%, transparent);    color: var(--eb-succes); }
  .eb-etiquette--alerte    { background: color-mix(in srgb, var(--eb-alerte) 14%, transparent);    color: var(--eb-alerte); }
  .eb-etiquette--attention { background: color-mix(in srgb, var(--eb-attention) 16%, transparent); color: var(--eb-attention); }

  /* --- Champs de formulaire ----------------------------------------------- */

  .eb-champ { display: grid; gap: var(--eb-espace-1); }
  .eb-champ__label { font-size: var(--eb-taille-body-s); font-weight: var(--eb-graisse-moyenne); }
  .eb-champ__aide  { font-size: var(--eb-taille-body-xs); color: var(--eb-texte-faible); }

  .eb-champ__saisie {
    min-height: var(--eb-champ-hauteur);
    padding: var(--eb-espace-2) var(--eb-espace-3);
    border: 1px solid var(--eb-champ-bordure);
    border-radius: var(--eb-champ-rayon);
    background: var(--eb-surface);
    color: var(--eb-texte);
    width: 100%;
  }
  .eb-champ__saisie:focus-visible { border-color: var(--eb-accent); }
  .eb-champ__saisie::placeholder { color: var(--eb-texte-faible); }

  .eb-champ__erreur {
    font-size: var(--eb-taille-body-xs);
    color: var(--eb-alerte);
    font-weight: var(--eb-graisse-moyenne);
  }
  /* :has() — le champ en erreur se signale sans classe supplementaire. */
  .eb-champ:has(.eb-champ__erreur) .eb-champ__saisie { border-color: var(--eb-alerte); }

  /* --- Etat vide ---------------------------------------------------------- */

  /* Le contre-exemple de chat : un etat vide DOIT porter son action, ici,
     pas ailleurs dans la page (MANIFESTE regle 4). */
  .eb-vide {
    display: grid;
    justify-items: center;
    gap: var(--eb-espace-4);
    text-align: center;
    padding: var(--eb-espace-7) var(--eb-espace-4);
    max-width: 32rem;
    margin-inline: auto;
  }
  .eb-vide__titre {
    font: var(--eb-typo-h4-graisse) var(--eb-typo-h4-taille)/var(--eb-typo-h4-interligne) var(--eb-typo-h4-police);
  }
  .eb-vide__texte { color: var(--eb-texte-doux); font-size: var(--eb-taille-body-s); }

  /* --- Alerte ------------------------------------------------------------- */

  .eb-alerte {
    display: flex; gap: var(--eb-espace-3);
    padding: var(--eb-espace-3) var(--eb-espace-4);
    border-radius: var(--eb-rayon-m);
    border: 1px solid var(--eb-ligne);
    border-inline-start-width: 3px;
    background: var(--eb-surface);
    font-size: var(--eb-taille-body-s);
  }
  .eb-alerte--succes    { border-inline-start-color: var(--eb-succes); }
  .eb-alerte--attention { border-inline-start-color: var(--eb-attention); }
  .eb-alerte--erreur    { border-inline-start-color: var(--eb-alerte); }

  /* --- Chargement ----------------------------------------------------------
     Nielsen : rien sous 1 s, indicateur entre 1 et 10 s, progression chiffree
     au-dela. Un indicateur affiche immediatement produit un clignotement qui
     donne une impression de lenteur alors que la reponse etait rapide.

     TROIS niveaux, du plus discret au plus present :
       .eb-loader        en ligne, dans un bouton ou a cote d'un texte
       .eb-squelette     la forme du contenu est connue : on la prefigure
       .eb-chargement-page  premiere arrivee sur une page, plein ecran
  */

  /* Anneau en ligne. Prend la couleur du texte courant (currentColor) : dans
     un bouton primaire il devient blanc, dans un paragraphe il suit le texte.
     Le segment colore est en accent, pour marquer la charte. */
  .eb-loader {
    width: 1.15em; height: 1.15em;
    border: 2px solid color-mix(in srgb, currentColor 22%, transparent);
    border-block-start-color: var(--eb-accent);
    border-radius: 50%;
    display: inline-block;
    animation: eb-tourner 700ms linear infinite;
  }
  /* Dans un aplat d'accent, l'accent sur l'accent serait invisible. */
  .eb-bouton--primaire .eb-loader,
  .eb-bouton--danger .eb-loader { border-block-start-color: currentColor; }

  @keyframes eb-tourner { to { transform: rotate(1turn); } }

  /* Chargement de PAGE, plein ecran. Le logo « eb » anime : la marque occupe
     l'attente au lieu d'un cercle anonyme. Les points de la charte tournent
     autour, l'ensemble reste sobre.

     `position: fixed` + `inset: 0` : couvre tout, y compris pendant un
     defilement deja engage. Retirer l'element (ou lui poser [hidden]) suffit
     a le faire disparaitre — aucun JS du kit n'est requis. */
  .eb-chargement-page {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: grid;
    place-items: center;
    gap: var(--eb-espace-4);
    background: var(--eb-fond);
    color: var(--eb-texte);
  }
  .eb-chargement-page[hidden] { display: none; }

  .eb-chargement-page__marque {
    display: grid;
    place-items: center;
    gap: var(--eb-espace-4);
    text-align: center;
  }
  /* L'anneau entoure le logo : 64px de diametre, epaisseur 3px. */
  .eb-chargement-page__anneau {
    position: relative;
    width: 4rem; height: 4rem;
    display: grid; place-items: center;
  }
  .eb-chargement-page__anneau::before {
    content: "";
    position: absolute;
    inset: 0;
    border: 3px solid color-mix(in srgb, var(--eb-accent-aplat) 18%, transparent);
    border-block-start-color: var(--eb-accent-aplat);
    border-radius: 50%;
    animation: eb-tourner 900ms linear infinite;
  }
  .eb-chargement-page__anneau img,
  .eb-chargement-page__anneau svg { width: 2rem; height: 2rem; }
  .eb-chargement-page__texte {
    font: var(--eb-typo-overline-graisse) var(--eb-typo-overline-taille)/1.4 var(--eb-typo-overline-police);
    letter-spacing: var(--eb-typo-overline-interlettre);
    text-transform: uppercase;
    color: var(--eb-texte-faible);
  }

  /* Mouvement reduit : l'anneau ne tourne plus, il pulse. Un indicateur
     totalement fige laisserait croire a une page plantee. */
  @media (prefers-reduced-motion: reduce) {
    .eb-chargement-page__anneau::before,
    .eb-loader { animation: eb-pulser 1.6s ease-in-out infinite !important; }
  }

  /* Squelette : preferable au spinner quand la FORME du contenu est connue —
     l'utilisateur comprend ce qui arrive. */
  .eb-squelette {
    background: linear-gradient(90deg,
      var(--eb-surface-2) 25%,
      color-mix(in srgb, var(--eb-accent-aplat) 9%, var(--eb-surface-2)) 50%,
      var(--eb-surface-2) 75%);
    background-size: 200% 100%;
    border-radius: var(--eb-rayon-s);
    animation: eb-miroiter 1.4s ease-in-out infinite;
    min-height: 1em;
  }
  @keyframes eb-miroiter { to { background-position: -200% 0; } }

  /* --- Boite de dialogue -------------------------------------------------- */

  /* <dialog> natif : 96,11 % (caniuse). Gere seul le focus trap, la touche
     Echap et l'inertie de l'arriere-plan — trois choses qu'une modale maison
     rate presque toujours. */
  .eb-dialogue {
    border: 1px solid var(--eb-ligne);
    border-radius: var(--eb-rayon-l);
    background: var(--eb-surface);
    color: var(--eb-texte);
    padding: var(--eb-espace-5);
    max-width: min(32rem, calc(100vw - 2rem));
    width: 100%;
  }
  .eb-dialogue::backdrop { background: rgb(0 0 0 / 0.45); }

  @media (prefers-reduced-motion: no-preference) {
    /* @starting-style : anime l'apparition d'un element passant de
       display:none a visible — impossible sans lui en CSS pur. */
    .eb-dialogue {
      opacity: 1; transform: translateY(0);
      transition:
        opacity   var(--eb-duree-moyenne) var(--eb-courbe-sortie),
        transform var(--eb-duree-moyenne) var(--eb-courbe-sortie),
        display   var(--eb-duree-moyenne) allow-discrete;
    }
    @starting-style {
      .eb-dialogue[open] { opacity: 0; transform: translateY(8px); }
    }
  }

  /* --- Notification ------------------------------------------------------- */

  .eb-toast {
    position: fixed;
    inset-block-end: var(--eb-espace-4);
    inset-inline-end: var(--eb-espace-4);
    z-index: 50;
    padding: var(--eb-espace-3) var(--eb-espace-4);
    border-radius: var(--eb-rayon-m);
    border: 1px solid var(--eb-ligne);
    background: var(--eb-surface);
    box-shadow: 0 4px 16px rgb(0 0 0 / 0.12);
    font-size: var(--eb-taille-body-s);
    max-width: min(24rem, calc(100vw - 2rem));
  }
  @media (prefers-reduced-motion: no-preference) {
    .eb-toast { animation: eb-apparaitre var(--eb-duree-moyenne) var(--eb-courbe-sortie); }
  }

  /* --- Selecteur de theme --------------------------------------------------
     Trois etats explicites : Auto (suit le systeme), Clair, Sombre.
     « Auto » est le defaut et doit rester atteignable — un selecteur a deux
     positions enferme l'utilisateur dans un choix manuel des le premier clic,
     et la page cesse alors de suivre le passage jour/nuit de son systeme.

     `role=radiogroup` : ce sont des options exclusives, pas des boutons
     d'action. Un lecteur d'ecran annonce « 2 sur 3 » au lieu de trois boutons
     sans relation entre eux. */
  .eb-theme {
    display: inline-flex;
    gap: 2px;
    padding: 3px;
    border: 1px solid var(--eb-ligne);
    border-radius: var(--eb-rayon-pilule);
    background: var(--eb-surface);
  }
  .eb-theme__option {
    display: inline-flex;
    align-items: center;
    gap: var(--eb-espace-1);
    min-height: 34px;          /* + padding du parent = 40px de cible reelle */
    padding-inline: var(--eb-espace-3);
    border: 0;
    border-radius: var(--eb-rayon-pilule);
    background: none;
    color: var(--eb-texte-doux);
    font: var(--eb-typo-overline-graisse) var(--eb-typo-overline-taille)/1 var(--eb-typo-overline-police);
    letter-spacing: 0.06em;
    cursor: pointer;

    @media (prefers-reduced-motion: no-preference) {
      transition:
        background-color var(--eb-duree-courte) var(--eb-courbe-standard),
        color var(--eb-duree-courte) var(--eb-courbe-standard);
    }
  }
  .eb-theme__option:hover { color: var(--eb-texte); background: var(--eb-surface-2); }
  /* L'etat actif se marque par le FOND + la couleur + aria-checked : jamais
     par la couleur seule (SC 1.4.1). */
  .eb-theme__option[aria-checked="true"] {
    background: var(--eb-accent-aplat);
    color: var(--eb-sur-accent);
  }

  .eb-onglets {
    display: flex; gap: var(--eb-espace-1); flex-wrap: wrap;
    border-block-end: 1px solid var(--eb-ligne);
    margin-block-end: var(--eb-espace-5);
  }
  .eb-onglet {
    display: inline-flex; align-items: center;
    min-height: var(--eb-cible-min);
    padding-inline: var(--eb-espace-3);
    color: var(--eb-texte-doux);
    text-decoration: none;
    font-size: var(--eb-taille-body-s);
    font-weight: var(--eb-graisse-moyenne);
    border-block-end: 2px solid transparent;
    margin-block-end: -1px;
  }
  .eb-onglet:hover { color: var(--eb-texte); }
  /* L'onglet actif se distingue par la COULEUR + la GRAISSE + la bordure :
     jamais par la couleur seule (SC 1.4.1, daltonisme). */
  .eb-onglet[aria-current="page"], .eb-onglet[aria-selected="true"] {
    color: var(--eb-accent);
    border-block-end-color: var(--eb-accent);
    font-weight: var(--eb-graisse-forte);
  }
}

/* --------------------------------------------------------- utilitaires -- */
@layer utilitaires {
  /* --- Roles typographiques ------------------------------------------------
     A poser sur n'importe quel element. On choisit un ROLE, jamais une taille :
     `class="eb-typo-body-xs"`, jamais `font-size: 12px`.
     Chaque classe porte le meme nom que son token : .eb-typo-h2 consomme
     --eb-typo-h2-*. Toute autre correspondance serait un piege a maintenance. */
  [class^="eb-typo-"], [class*=" eb-typo-"] { margin: 0; }

  .eb-typo-display {
    font: var(--eb-typo-display-graisse) var(--eb-typo-display-taille)/var(--eb-typo-display-interligne) var(--eb-typo-display-police);
    letter-spacing: var(--eb-typo-display-interlettre);
    text-wrap: balance;
  }
  .eb-typo-h1 {
    font: var(--eb-typo-h1-graisse) var(--eb-typo-h1-taille)/var(--eb-typo-h1-interligne) var(--eb-typo-h1-police);
    letter-spacing: var(--eb-typo-h1-interlettre);
    text-wrap: balance;
  }
  .eb-typo-h2 {
    font: var(--eb-typo-h2-graisse) var(--eb-typo-h2-taille)/var(--eb-typo-h2-interligne) var(--eb-typo-h2-police);
    letter-spacing: var(--eb-typo-h2-interlettre);
    text-wrap: balance;
  }
  .eb-typo-h3 {
    font: var(--eb-typo-h3-graisse) var(--eb-typo-h3-taille)/var(--eb-typo-h3-interligne) var(--eb-typo-h3-police);
    letter-spacing: var(--eb-typo-h3-interlettre);
  }
  .eb-typo-h4 {
    font: var(--eb-typo-h4-graisse) var(--eb-typo-h4-taille)/var(--eb-typo-h4-interligne) var(--eb-typo-h4-police);
    letter-spacing: var(--eb-typo-h4-interlettre);
  }
  .eb-typo-h5 {
    font: var(--eb-typo-h5-graisse) var(--eb-typo-h5-taille)/var(--eb-typo-h5-interligne) var(--eb-typo-h5-police);
  }
  .eb-typo-h6 {
    font: var(--eb-typo-h6-graisse) var(--eb-typo-h6-taille)/var(--eb-typo-h6-interligne) var(--eb-typo-h6-police);
    letter-spacing: var(--eb-typo-h6-interlettre);
    text-transform: uppercase;
  }

  .eb-typo-body-xl { font: var(--eb-typo-body-xl-graisse) var(--eb-typo-body-xl-taille)/var(--eb-typo-body-xl-interligne) var(--eb-typo-body-xl-police); }
  .eb-typo-body-l  { font: var(--eb-typo-body-l-graisse) var(--eb-typo-body-l-taille)/var(--eb-typo-body-l-interligne) var(--eb-typo-body-l-police); }
  .eb-typo-body    { font: var(--eb-typo-body-graisse) var(--eb-typo-body-taille)/var(--eb-typo-body-interligne) var(--eb-typo-body-police); }
  .eb-typo-body-s  { font: var(--eb-typo-body-s-graisse) var(--eb-typo-body-s-taille)/var(--eb-typo-body-s-interligne) var(--eb-typo-body-s-police); }
  .eb-typo-body-xs { font: var(--eb-typo-body-xs-graisse) var(--eb-typo-body-xs-taille)/var(--eb-typo-body-xs-interligne) var(--eb-typo-body-xs-police); color: var(--eb-texte-doux); }

  .eb-typo-overline {
    font: var(--eb-typo-overline-graisse) var(--eb-typo-overline-taille)/var(--eb-typo-overline-interligne) var(--eb-typo-overline-police);
    letter-spacing: var(--eb-typo-overline-interlettre);
    text-transform: uppercase;
    color: var(--eb-accent);
  }
  .eb-typo-button { font: var(--eb-typo-button-graisse) var(--eb-typo-button-taille)/var(--eb-typo-button-interligne) var(--eb-typo-button-police); }
  .eb-typo-quote  { font: var(--eb-typo-quote-graisse) var(--eb-typo-quote-taille)/var(--eb-typo-quote-interligne) var(--eb-typo-quote-police); }
  /* tabular-nums : les chiffres s'alignent en colonne, indispensable des qu'on
     empile des montants ou des durees. */
  .eb-typo-code   { font: var(--eb-typo-code-graisse) var(--eb-typo-code-taille)/var(--eb-typo-code-interligne) var(--eb-typo-code-police); font-variant-numeric: tabular-nums; }

  /* --- Trame de points — element signature de la charte --------------------
     « Une texture discrete pour habiller les fonds (bannieres, sections,
     cartes), qui pose ma couleur sans jamais voler la vedette au contenu. »
     Espacement 20px, point 1.6px (charte, section 03).

     DEUX usages distincts, mesures au pixel sur la charte le 02/09/2026 :

       .eb-trame          sur fond clair ou sombre : framboise a 7 %
                          (mesure : fond #FAFAF8, point #FAEDEE)
       .eb-trame--encre   sur aplat encre : framboise PLEINE #E5195F
                          (mesure : fond #16161A, point #E51A5E)

     Ne pas confondre : diluer la trame sur fond encre la fait disparaitre,
     la poser pleine sur fond papier en fait un decor criard. Ma premiere
     version les melangeait a 55 % — faux dans les deux cas.

     radial-gradient plutot qu'une image : zero requete, net a tout facteur de
     zoom, couleur qui suit le theme. */
  .eb-trame {
    background-image: radial-gradient(
      circle at 1px 1px,
      color-mix(in srgb, var(--eb-accent-aplat) 7%, transparent) 1.6px,
      transparent 0
    );
    background-size: 20px 20px;
  }

  /* Sur aplat encre : banniere, en-tete de section, coin de carte. */
  .eb-trame--encre {
    background-color: var(--eb-couleur-encre);
    background-image: radial-gradient(
      circle at 1px 1px,
      var(--eb-couleur-framboise) 1.6px,
      transparent 0
    );
    background-size: 20px 20px;
    color: var(--eb-couleur-papier);
  }

  /* Le hero : la trame s'estompe vers le bas pour ne pas couper net. */
  .eb-trame--hero {
    background-image: radial-gradient(
      circle at 1px 1px,
      color-mix(in srgb, var(--eb-accent-aplat) 7%, transparent) 1.6px,
      transparent 0
    );
    background-size: 20px 20px;
    -webkit-mask-image: linear-gradient(to bottom, #000 55%, transparent);
    mask-image: linear-gradient(to bottom, #000 55%, transparent);
  }

  /* --- Barre d'accent ------------------------------------------------------
     Le second element signature de la charte : un filet framboise vertical
     qui marque un bloc sans l'encadrer. Moins lourd qu'une bordure complete. */
  .eb-filet {
    border-inline-start: 3px solid var(--eb-accent-aplat);
    padding-inline-start: var(--eb-espace-4);
  }

  /* --- Logo ---------------------------------------------------------------
     Le SVG mono herite de currentColor : une seule ressource pour les deux
     themes, plutot que deux fichiers a maintenir en parallele. */
  .eb-logo { display: inline-flex; align-items: center; gap: var(--eb-espace-2); text-decoration: none; color: inherit; }
  .eb-logo svg, .eb-logo img { width: 2rem; height: 2rem; flex: none; }
  .eb-logo__nom { font: var(--eb-graisse-tres-forte) var(--eb-taille-body-s)/1.2 var(--eb-police-titre); letter-spacing: -0.01em; }

  .eb-muet   { color: var(--eb-texte-doux); }
  .eb-faible { color: var(--eb-texte-faible); }
  .eb-mono   { font-family: var(--eb-police-mono); }
  .eb-petit  { font-size: var(--eb-taille-body-s); }
  .eb-centre { text-align: center; }

  /* Visible pour les lecteurs d'ecran uniquement. Indispensable pour nommer
     une action dont l'intitule visible ne suffit pas. */
  .eb-sr {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap; border: 0;
  }

  @media (prefers-reduced-motion: no-preference) {
    .eb-fondu { animation: eb-apparaitre var(--eb-duree-moyenne) var(--eb-courbe-sortie); }
  }
}

@keyframes eb-apparaitre {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* --- Animations qui portent une information ---------------------------------
   Aucune animation decorative dans ce kit : chacune repond a « qu'est-ce que
   l'utilisateur ne comprendrait pas sans elle ? »

   Ecartees volontairement :
   - scroll-driven animations (apparition au defilement) : Baseline LIMITED
     debut 2026 (webstatus.dev), et surtout du decor pur — le contenu est deja
     visible, l'animer ne dit rien de plus.
   - view transitions : Baseline newly (2025-10), utile entre PAGES ; sans
     interet sur une page unique.
*/

/* Pulsation d'attente : signale qu'une valeur n'est pas encore definitive.
   Une donnee affichee sans nuance passe pour acquise. */
@keyframes eb-pulser {
  50% { opacity: 0.45; }
}
@media (prefers-reduced-motion: no-preference) {
  .eb-attente { animation: eb-pulser 1.6s ease-in-out infinite; }
}

/* Secousse d'erreur : un champ refuse se signale AUSSI par le mouvement, pas
   seulement par le rouge (SC 1.4.1 — jamais la couleur seule). Une seule
   occurrence, jamais en boucle : repeter serait du harcelement visuel. */
@keyframes eb-secouer {
  10%, 90% { transform: translateX(-2px); }
  30%, 70% { transform: translateX(3px); }
  50%      { transform: translateX(-3px); }
}
@media (prefers-reduced-motion: no-preference) {
  .eb-erreur-secousse { animation: eb-secouer 320ms var(--eb-courbe-standard) 1; }
}

/* Surlignage de cible d'ancre : apres un saut, l'oeil a perdu le fil. Un halo
   bref sur la destination dit « c'est ici ». `:target` est natif, donc zero JS.
   Le halo s'efface : un marquage permanent deviendrait un faux etat actif. */
@keyframes eb-cibler {
  from { background-color: color-mix(in srgb, var(--eb-accent-aplat) 14%, transparent); }
  to   { background-color: transparent; }
}
@media (prefers-reduced-motion: no-preference) {
  :target { animation: eb-cibler 1.4s var(--eb-courbe-sortie); }
}

/* Garde-fou global : WCAG 2.2 SC 2.3.3. Une preference systeme d'animation
   reduite desactive TOUT mouvement, y compris celui qu'un projet ajouterait
   plus tard sans y penser, et le defilement doux des ancres. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
