/* ═══════════════════════════════════════════════════════════════════════════
   CARBOPTI — jetons de design. Source unique.

   Registre : sombre, vivant, peps. L'écologie par un vert électrique, pas par
   un vert forêt : le produit s'adresse à des conducteurs de travaux de trente
   ans, pas à un cabinet de conseil en RSE.

   Aucun littéral de couleur, d'espace, de taille, de rayon ou d'ombre ne doit
   exister ailleurs. Avant ce fichier : ~130 couleurs, ~60 espacements,
   ~50 tailles, ~25 rayons sur les trois surfaces. Il en tient 20 / 9 / 9 / 4.

   Tous les contrastes en commentaire sont CALCULÉS (WCAG 2.x), pas estimés.
   Sur fond sombre, les néons passent très au-dessus du minimum : la contrainte
   se déplace vers l'encre posée SUR un aplat néon, qui doit rester noire.
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  /* ── Les fonds ──────────────────────────────────────────────────────── */
  --nuit:      #08120E;   /* fond principal, légèrement teinté vert (blanc dessus : 19,04:1) */
  --nuit-2:    #0C1A15;   /* surface élevée : carte, panneau */
  --nuit-3:    #122520;   /* surface la plus haute, survol */
  --nuit-trait:#1E3B32;   /* bordure sur fond sombre */

  /* ── Encre ──────────────────────────────────────────────────────────── */
  --encre:     #ECFDF5;   /* texte principal (18,2:1) */
  --encre-2:   #A7C4B8;   /* texte secondaire (8,6:1) */
  --encre-3:   #7B9A8D;   /* texte tertiaire, mentions (6,2:1 sur nuit, 4,9:1 sur nuit-3) */
  --sur-neon:  #04140C;   /* l'encre posée SUR un aplat néon. Jamais du blanc. */

  /* ── Statut : trois rôles, toujours doublés d'un mot ──────────────────
     La couleur ne porte jamais seule une information : un daltonien doit
     pouvoir lire chaque verdict. */
  --ok:      #4ADE80;  --ok-fond:      rgba(74,222,128,.12);   /* sous le seuil, gain */
  --reserve: #FACC15;  --reserve-fond: rgba(250,204,21,.12);   /* estimation, à compléter */
  --alerte:  #FB7185;  --alerte-fond:  rgba(251,113,133,.12);  /* dépassement, erreur */

  /* ── Grands écrans ──────────────────────────────────────────────────────
     Tout est réglé pour 1440 px. Au-delà, chaque taille grandit avec la fenêtre jusqu'à +30 % à 2560 px, et
     la largeur utile jusqu'à +45 % : sinon un écran de 2560 px laisse deux marges de 660 px (Brice, 27/10/2026).
     --k vaut 0 jusqu'à 1440 px, 1120px à 2560 px ; chaque coefficient = taille × 0,3 / 1120. */
  --k: clamp(0px, 100vw - 1440px, 1120px);

  /* ── Espacement : base 4, neuf pas ──────────────────────────────────── */
  --e-1: calc(4px + var(--k) * .00107);  --e-2: calc(8px + var(--k) * .00214);
  --e-3: calc(12px + var(--k) * .00321); --e-4: calc(16px + var(--k) * .00429);
  --e-5: calc(24px + var(--k) * .00643); --e-6: calc(32px + var(--k) * .00857);
  --e-7: calc(48px + var(--k) * .01286); --e-8: calc(64px + var(--k) * .01714);
  --e-9: calc(96px + var(--k) * .02571);

  /* ── Typographie : neuf pas, trois graisses ─────────────────────────────
     IBM Plex Sans s'arrête à Bold 700 : un font-weight 800 produirait une
     graisse synthétique baveuse. La dominance vient de la TAILLE. */
  --t-1: calc(13px + var(--k) * .00348);  --t-2: calc(15px + var(--k) * .00402);
  --t-3: calc(17px + var(--k) * .00455);  --t-4: calc(20px + var(--k) * .00536);
  --t-5: calc(24px + var(--k) * .00643);  --t-6: calc(32px + var(--k) * .00857);
  --t-7: clamp(30px, 3.4vw, calc(46px + var(--k) * .0123));
  --t-8: clamp(42px, 6vw, calc(84px + var(--k) * .0225));
  --t-9: clamp(56px, 8vw, calc(116px + var(--k) * .0311));
  --g-normale: 400; --g-forte: 600; --g-titre: 700;
  --ls-titre: -.028em;
  --ls-label: .16em;
  --discours: "IBM Plex Sans", system-ui, -apple-system, Segoe UI, sans-serif;
  --donnee:   "IBM Plex Mono", ui-monospace, SFMono-Regular, monospace;

  /* ── Rayon (4) ──────────────────────────────────────────────────────── */
  --r-controle: 10px;
  --r-objet:    16px;
  --r-pilule:   999px;
  --r-point:    50%;

  /* ── Élévation : sur fond sombre, une ombre ne se voit pas. C'est la
     LUEUR qui élève. ──────────────────────────────────────────────────── */
  --lueur-1: 0 0 0 1px var(--nuit-trait);
  --lueur-2: 0 0 0 1px var(--nuit-trait), 0 24px 64px rgba(0,0,0,.55);
  --lueur-neon: 0 0 24px rgba(var(--accent-rvb), .38), 0 0 64px rgba(var(--accent-rvb), .16);
  --focus: 0 0 0 3px var(--nuit), 0 0 0 6px var(--accent);

  /* ── Mise en page ───────────────────────────────────────────────────── */
  --max: calc(1240px + var(--k) * .5);
  --gouttiere: var(--e-5);
}

/* ═══════════ ACCENT — menthe et violet ═══════════
   Retenu le 02/10/2026 après comparaison avec une variante lime + cyan, plus
   criarde. La menthe garde le peps sans tomber dans l'arcade, et le violet
   est le complément qui tient sur un fond sombre sans concurrencer le vert. */
:root {
  --accent:      #34D399;  --accent-rvb: 52,211,153;    /* 9,90:1 sur la nuit */
  --accent-2:    #A78BFA;  --accent-2-rvb: 167,139,250; /* 6,99:1 */
  --accent-doux: rgba(52,211,153,.14);
}

/* ═══════════ la règle de chasse, écrite une fois ═══════════
   Grotesque pour le discours, monospace pour la donnée machine. Elle n'était
   tenue nulle part : le site ne chargeait même pas IBM Plex Mono. */
body, .discours { font-family: var(--discours); }
.mono, [data-donnee] { font-family: var(--donnee); font-variant-numeric: tabular-nums; }
/* .mono : montants, kg CO₂, pourcentages, m², seuils, codes, noms de fichier.
   Un mot écrit par un humain n'y est jamais. */

/* ═══════════ le bouton, une fois ═══════════ */
.btn {
  display: inline-flex; align-items: center; gap: var(--e-2);
  font: var(--g-forte) var(--t-3)/1 var(--discours);
  padding: var(--e-3) var(--e-5); min-height: 44px;
  border-radius: var(--r-pilule);
  background: var(--accent); color: var(--sur-neon);
  border: 1.5px solid transparent;
  text-decoration: none; cursor: pointer;
  transition: transform .16s cubic-bezier(.2,.9,.3,1), box-shadow .16s, filter .16s;
}
.btn:hover { transform: translateY(-2px); box-shadow: var(--lueur-neon); filter: brightness(1.06); }
.btn:active { transform: translateY(0); }
.btn--second {
  background: transparent; color: var(--encre); border-color: var(--encre-3);
}
.btn--second:hover { background: var(--nuit-3); border-color: var(--accent); box-shadow: none; filter: none; }
.btn--petit { padding: var(--e-2) var(--e-4); font-size: var(--t-2); }
.btn:focus-visible, a:focus-visible, button:focus-visible, [tabindex]:focus-visible {
  outline: 3px solid var(--accent); outline-offset: 3px;
}

/* ═══════════ la carte, une fois ═══════════ */
.carte {
  background: var(--nuit-2);
  border: 1px solid var(--nuit-trait);
  border-radius: var(--r-objet);
  padding: var(--e-5);
}
.carte--ok      { border-left: 3px solid var(--ok);      background: var(--ok-fond); }
.carte--reserve { border-left: 3px solid var(--reserve); background: var(--reserve-fond); }
.carte--alerte  { border-left: 3px solid var(--alerte);  background: var(--alerte-fond); }
.carte--accent  { border-left: 3px solid var(--accent); }

/* ═══════════ la pastille ═══════════
   Elle ne dit jamais un mot d'ambiance : seulement quelque chose de vérifiable. */
.pastille {
  display: inline-flex; align-items: center; gap: var(--e-2);
  background: var(--accent-doux); color: var(--accent);
  border: 1px solid rgba(var(--accent-rvb), .3);
  border-radius: var(--r-pilule);
  padding: var(--e-2) var(--e-4);
  font: var(--g-forte) var(--t-1)/1 var(--discours);
  letter-spacing: .04em;
}
.pastille i {
  width: 7px; height: 7px; border-radius: var(--r-point); background: currentColor;
  box-shadow: 0 0 8px currentColor;
}

/* ═══════════ révélation au défilement, en CSS natif ═══════════
   Chrome 115+, Safari 26+ — 87 % des visites. Firefox ne l'a pas en stable :
   sous @supports, un visiteur Firefox voit simplement le contenu posé.
   Jamais pour révéler une information. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .rv { animation: rv linear both; animation-timeline: view(); animation-range: entry 6% cover 30%; }
  }
}
@keyframes rv { from { opacity: 0; transform: translateY(32px) } to { opacity: 1; transform: none } }

/* ═══════════ mouvement réduit ═══════════ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important; scroll-behavior: auto !important;
  }
}

.evitement { position: absolute; left: -9999px; top: var(--e-2); z-index: 99; }
.evitement:focus { left: var(--e-4); }
