/* ============================================================================
   Plateforme sendmart : place de marché interne.
   Direction visuelle : voir DESIGN.md (l'utilisateur en est l'auteur).
   Cadrans tenus par cette feuille : ENERGY 2 / RHYTHM 2 / MOTION 1.
   Audit appliqué : anti-slop/audit-001-2026-10-03.md
   ========================================================================= */

/* Archivo, servie depuis ce VPS et non depuis Google : l'interface ne doit pas
   dépendre d'un tiers, et l'IP des utilisateurs n'a pas à partir chez Google.
   Police variable, axe de largeur 62% à 125% : c'est la coupe large qui donne
   du poids aux titres sans devoir les grossir, dans une interface dense. */
@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url("fonts/archivo-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url("fonts/archivo-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  /* ---- Fonds et bordures : presque noir verté, conservé ---- */
  --bg: #0E1210;
  --panel: #161B18;
  --panel-raised: #1C2320;
  --border: #262E29;
  --border-soft: #1E2521;
  --console-bg: #0B0F0D;

  /* ---- Texte ----
     --text-dim est passé de #5C6862 à #828E88 : l'ancien échouait AA partout
     (2,76:1 à 3,32:1 pour 4,5:1 requis) alors qu'il porte toute l'explication
     du modèle de tokens. Le nouveau donne 4,71:1 dans le pire cas. Mesuré. */
  --text: #E7ECE9;
  --text-muted: #8B9691;
  --text-dim: #828E88;
  --text-on-accent: #0E1210;

  /* ---- Accent unique : le vert signal, et il reste rare ----
     --accent-dim est passé de #2E7550 à #3C9266 : l'ancien servait d'anneau de
     focus et de bordure à 2,88:1, sous les 3:1 exigés pour un indicateur non
     textuel. Le nouveau donne 4,19:1. */
  --accent: #4FBF7B;
  --accent-dim: #3C9266;
  --accent-wash: rgba(79, 191, 123, 0.10);
  --focus-ring: var(--accent);

  /* ---- Couleurs d'état : elles signalent, elles ne sont pas l'accent ---- */
  --warn: #D9A441;
  --warn-edge: rgba(217, 164, 65, 0.35);
  --danger: #D9605A;
  --danger-text: #F0A9A5;
  --danger-wash: rgba(217, 96, 90, 0.12);
  --danger-edge: rgba(217, 96, 90, 0.35);

  /* ---- Familles ----
     Titres : Archivo en coupe large. Contrôles et texte : sans système.
     Données : monospace, parce que numéros, soldes et chronos s'alignent en
     colonne et se comparent ligne à ligne. */
  --font-display: "Archivo", "Segoe UI", -apple-system, system-ui, sans-serif;
  --font-ui: "Segoe UI", -apple-system, "Inter", system-ui, sans-serif;
  --font-mono: ui-monospace, "Cascadia Code", "Consolas", "SFMono-Regular", monospace;

  /* ---- Échelle : 6 marches au lieu de 10 tailles sans rapport entre elles.
     Le titre d'écran passe à 1,93 fois le corps, contre 1,18 avant : c'est ce
     qui crée un point focal. Plancher à 12px. ---- */
  --t-micro: 12px;
  --t-body: 13.5px;
  --t-strong: 15px;
  --t-title: 19px;
  --t-display: 26px;
  --t-figure: 34px;

  /* ---- Espacement ---- */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 24px;
  --s6: 32px;
  --s7: 48px;

  /* ---- Rayons : variés à dessein, pas tous en gélule (R-11) ---- */
  --r-sm: 4px;
  --r-md: 6px;
  --r-lg: 10px;
  --r-pill: 999px;

  /* ---- Élévation : deux niveaux seulement, pour marquer une hiérarchie,
     pas pour faire flotter la page ---- */
  --lift-1: 0 1px 2px rgba(0, 0, 0, 0.45);
  --lift-2: 0 6px 20px rgba(0, 0, 0, 0.55);

  /* Hauteur réelle de la console de journal. À 0 tant qu'elle est fermée :
     plus de 220px réservés en permanence pour un journal souvent vide. */
  --console-h: 0px;
  --sidebar-w: 232px;
  /* Hauteur réelle de la barre du haut quand la barre latérale devient un
     tiroir. Mesurée par le JS : devinée, le bandeau de créneau passerait
     dessous et le chrono payé serait caché. */
  --topbar-h: 0px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  min-height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: var(--t-body);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

.hidden { display: none !important; }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ===== Focus : un seul anneau, partout, et il est visible =====
   L'ancienne règle ne visait que les champs, avec un vert à 2,88:1. Les
   boutons et les onglets n'avaient rien. */
:is(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

/* Souris : pas d'anneau. Clavier : anneau. Jamais outline:none sans remplacement. */
:is(button, summary):focus:not(:focus-visible) { outline: none; }

button {
  font-family: inherit;
  font-size: inherit;
  cursor: pointer;
}

input[type="checkbox"] {
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
  flex-shrink: 0;
  margin: 0;
}

/* MOTION 1 : le mouvement sert, ou il n'existe pas. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}

/* ===== Écrans d'entrée (connexion) ===== */
.screen--center {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--s5);
  background: var(--bg);
}

.gate-card {
  width: 100%;
  max-width: 400px;
  padding: var(--s6) var(--s5) var(--s5);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--lift-2);
  display: flex;
  flex-direction: column;
  gap: var(--s3);
}

.gate-mark {
  width: 40px;
  height: 40px;
  border-radius: var(--r-md);
  background: var(--accent-wash);
  border: 1px solid var(--accent-dim);
  color: var(--accent);
  font-family: var(--font-display);
  font-stretch: 112%;
  font-weight: 700;
  font-size: var(--t-strong);
  display: flex;
  align-items: center;
  justify-content: center;
}

.gate-title {
  font-family: var(--font-display);
  font-stretch: 112%;
  font-weight: 700;
  font-size: var(--t-display);
  line-height: 1.15;
  letter-spacing: -0.015em;
  margin: 0;
}

.gate-status {
  color: var(--text-muted);
  margin: 0;
}

.gate-form {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
}

.gate-field {
  display: flex;
  flex-direction: column;
  gap: var(--s1);
}

.gate-error {
  padding: var(--s3);
  background: var(--danger-wash);
  border: 1px solid var(--danger-edge);
  border-radius: var(--r-md);
  color: var(--danger-text);
  font-size: var(--t-micro);
}

.qr-box {
  min-height: 220px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #fff;
  border-radius: var(--r-md);
  padding: var(--s3);
}

.qr-box canvas, .qr-box img { display: block; max-width: 100%; }

/* ===== Charpente ===== */
.shell {
  display: flex;
  min-height: 100vh;
}

/* ===== Barre latérale : groupée par parcours =====
   Les numéros 00 à 11 ont disparu. Ils n'encodaient rien, et ils mentaient dès
   qu'un rôle masquait des entrées : un collaborateur lisait « 00 » puis « 05 ». */
.sidebar {
  width: var(--sidebar-w);
  flex-shrink: 0;
  background: var(--panel);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  padding: var(--s4) var(--s2);
  gap: var(--s2);
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s1) var(--s2) var(--s4);
  border-bottom: 1px solid var(--border-soft);
}

.brand-mark {
  width: 30px;
  height: 30px;
  border-radius: var(--r-md);
  background: var(--accent-wash);
  border: 1px solid var(--accent-dim);
  color: var(--accent);
  font-family: var(--font-display);
  font-stretch: 112%;
  font-size: var(--t-micro);
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.brand-name {
  font-family: var(--font-display);
  font-stretch: 110%;
  font-size: var(--t-body);
  font-weight: 700;
  letter-spacing: -0.005em;
}

.brand-sub {
  font-size: var(--t-micro);
  color: var(--accent);
  font-family: var(--font-mono);
}

.brand-sub.is-disconnected { color: var(--danger-text); }

.nav-groups {
  display: flex;
  flex-direction: column;
  gap: var(--s4);
  flex: 1;
}

.nav-group {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.nav-group-title {
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-dim);
  padding: 0 var(--s2) var(--s2);
}

.nav-item {
  display: flex;
  align-items: center;
  gap: var(--s2);
  width: 100%;
  padding: 9px var(--s3);
  background: transparent;
  border: none;
  border-left: 2px solid transparent;
  border-radius: 0 var(--r-md) var(--r-md) 0;
  color: var(--text-muted);
  text-align: left;
  transition: background-color 120ms ease, color 120ms ease;
}

.nav-item:hover { background: var(--panel-raised); color: var(--text); }

.nav-item.is-active {
  background: var(--accent-wash);
  border-left-color: var(--accent);
  color: var(--text);
  font-weight: 500;
}

.nav-count {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

.nav-item.is-active .nav-count { color: var(--accent); }

/* Le solde de tokens est ce qui commande tout pour un membre : il n'est plus un
   badge de 10,5px perdu dans le pied de la barre. */
.sidebar-balance {
  margin-top: auto;
  padding: var(--s3);
  background: var(--panel-raised);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.sidebar-balance .amount {
  font-family: var(--font-display);
  font-stretch: 112%;
  font-weight: 700;
  font-size: var(--t-title);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}

.sidebar-balance .unit {
  font-size: var(--t-micro);
  color: var(--text-dim);
  font-family: var(--font-mono);
}

.sidebar-footer {
  padding-top: var(--s3);
  border-top: 1px solid var(--border-soft);
  font-size: var(--t-micro);
  color: var(--text-dim);
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  align-items: flex-start;
}

.role-label {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  color: var(--text-dim);
}

/* Bouton de menu : visible seulement quand la barre devient un tiroir. */
.menu-toggle { display: none; }

/* ===== Zone principale ===== */
.main {
  flex: 1;
  min-width: 0;
  padding: var(--s5) var(--s6) calc(var(--console-h) + var(--s6));
}

/* ===== Bandeau des créneaux : collant =====
   Le temps est payé à la minute. Il était dans la zone défilable, donc il
   disparaissait au premier scroll, dans un panneau Campagnes qui fait
   plusieurs hauteurs d'écran. */
.lease-bar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  align-items: center;
  padding: var(--s2) var(--s3);
  margin: calc(var(--s5) * -1) calc(var(--s6) * -1) var(--s4);
  background: #12201A;
  border-bottom: 1px solid var(--accent-dim);
  box-shadow: var(--lift-1);
  font-size: var(--t-micro);
}

/* Un créneau et le bouton qui le prolonge restent solidaires, y compris quand
   le bandeau passe à la ligne. */
.lease-bar .lease-item {
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
  flex-wrap: nowrap;
}

.lease-bar .lease-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
  padding: 3px var(--s2);
  border-radius: var(--r-pill);
  border: 1px solid var(--border);
  background: var(--panel);
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  font-variant-numeric: tabular-nums;
}

/* Fin de créneau imminente : visible sans animation agressive, l'utilisateur
   est peut-être en train d'envoyer. */
.lease-bar .lease-chip.is-ending {
  border-color: var(--warn);
  color: var(--warn);
}

/* ===== Panneaux ===== */
.panel { display: none; }
.panel.is-active { display: block; max-width: 860px; }

.panel-head {
  margin-bottom: var(--s5);
  display: flex;
  flex-direction: column;
  gap: var(--s1);
}

.panel-head h2 {
  font-family: var(--font-display);
  font-stretch: 112%;
  font-weight: 700;
  font-size: var(--t-display);
  line-height: 1.15;
  letter-spacing: -0.015em;
  margin: 0;
  text-wrap: balance;
}

.panel-head p {
  margin: 0;
  color: var(--text-muted);
  max-width: 68ch;
}

/* Sous-titre de section dans un panneau. Remplace les .field-label détournés
   en titres de section. */
.section-title {
  font-family: var(--font-display);
  font-stretch: 110%;
  font-weight: 700;
  font-size: var(--t-title);
  margin: var(--s6) 0 var(--s2);
  letter-spacing: -0.01em;
}

.section-title:first-child { margin-top: 0; }

/* ===== Formulaires ===== */
.field-label {
  display: block;
  font-size: var(--t-micro);
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin: var(--s5) 0 var(--s2);
}

.field-row {
  display: flex;
  align-items: center;
  gap: var(--s3);
  margin-top: var(--s3);
  flex-wrap: wrap;
}

.field-row--tight { margin-top: var(--s2); }

/* Le bouton qui enregistre toute la campagne se détache du dernier cadre :
   collé dessous, il passait pour un réglage de ce cadre. */
.field-row--apart { margin-top: var(--s5); }

.textarea, .select, .text-input, .number-input {
  background: var(--panel-raised);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: var(--t-body);
  padding: 9px var(--s3);
}

.textarea {
  width: 100%;
  resize: vertical;
  line-height: 1.6;
}

.select { width: 100%; margin-top: var(--s2); }
.select--auto { width: auto; margin-top: 0; }

.text-input { flex: 1; min-width: 200px; }
.text-input--block { width: 100%; flex: none; }

.number-input {
  width: 92px;
  flex: none;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}
.number-input--wide { width: 120px; }

input::placeholder, textarea::placeholder { color: var(--text-dim); opacity: 1; }

.file-chip {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  color: var(--text-muted);
}

.file-chip input[type="file"] {
  font-family: var(--font-ui);
  font-size: var(--t-micro);
  color: var(--text-muted);
  max-width: 100%;
}

.check-row {
  display: flex;
  align-items: center;
  gap: var(--s2);
  margin-top: var(--s3);
  color: var(--text-muted);
  cursor: pointer;
}

.check-row--inline { margin: 0; }

.check-list {
  margin-top: var(--s3);
  max-height: 240px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--panel-raised);
}

.check-list label {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s2) var(--s3);
  border-bottom: 1px solid var(--border-soft);
  cursor: pointer;
}
.check-list label:last-child { border-bottom: none; }
.check-list label:hover { background: var(--panel); }

.toggle-row {
  display: flex;
  gap: var(--s1);
  margin-top: var(--s2);
}

.toggle-btn {
  padding: 7px var(--s3);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  color: var(--text-muted);
  font-size: var(--t-micro);
  transition: color 120ms ease, border-color 120ms ease;
}

.toggle-btn:hover { color: var(--text); }

.toggle-btn.is-active {
  background: var(--accent-wash);
  border-color: var(--accent-dim);
  color: var(--accent);
}

/* ===== Boutons =====
   Trois poids, et ils veulent dire trois choses :
   .btn           action neutre
   .btn--primary  action principale du panneau
   .btn--commit   l'action qui dépense des tokens ou lance un envoi. Un seul
                  par écran : c'est le point focal. */
.btn {
  padding: 9px var(--s4);
  min-height: 38px;
  background: var(--panel-raised);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  color: var(--text);
  font-weight: 500;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  transition: border-color 120ms ease, background-color 120ms ease;
}
.btn:hover { border-color: var(--text-dim); }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn:disabled:hover { border-color: var(--border); }

.btn--primary {
  background: var(--accent-wash);
  border-color: var(--accent-dim);
  color: var(--accent);
}
.btn--primary:hover { border-color: var(--accent); background: rgba(79, 191, 123, 0.16); }

.btn--commit {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--text-on-accent);
  font-size: var(--t-strong);
  font-weight: 600;
  padding: 11px var(--s5);
  min-height: 44px;
  box-shadow: var(--lift-1);
}
.btn--commit:hover { background: #5FD08B; border-color: #5FD08B; }
.btn--commit:disabled { box-shadow: none; }

.btn--danger {
  background: var(--danger-wash);
  border-color: var(--danger-edge);
  color: var(--danger-text);
}
.btn--danger:hover { border-color: var(--danger); }

.btn--ghost {
  background: transparent;
  border-color: transparent;
  color: var(--text-muted);
}
.btn--ghost:hover { color: var(--text); border-color: var(--border); }

.btn--tiny {
  padding: 4px var(--s2);
  min-height: 30px;
  font-size: var(--t-micro);
  font-weight: 500;
}

.btn--block { width: 100%; }

/* ===== Cartes de compte =====
   Trois contextes, trois questions, donc trois variantes. L'uniformité
   d'avant mettait le prix, le chrono et le statut au même poids. */
.accounts-list {
  margin-top: var(--s4);
  display: flex;
  flex-direction: column;
  gap: var(--s3);
}

.account-card {
  padding: var(--s4);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--lift-1);
}

.account-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  flex-wrap: wrap;
}

.account-name {
  font-family: var(--font-display);
  font-stretch: 110%;
  font-weight: 700;
  font-size: var(--t-strong);
  letter-spacing: -0.005em;
}

.account-id {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  color: var(--text-dim);
  margin-left: var(--s1);
}

/* Variante catalogue : le prix est la question, il passe devant. */
.account-card--market { border-color: var(--border); }

.account-card--market .account-price {
  font-family: var(--font-display);
  font-stretch: 112%;
  font-weight: 700;
  font-size: var(--t-title);
  color: var(--text);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}

.account-card--market .account-price .unit {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  font-weight: 400;
  color: var(--text-dim);
  letter-spacing: 0;
}

.account-card--market .account-price.is-free { color: var(--accent); }

/* Variante créneau en cours : le chrono est la question. */
.account-card--lease {
  border-color: var(--accent-dim);
  background: linear-gradient(to right, rgba(79, 191, 123, 0.06), transparent 40%), var(--panel);
}

.account-card--lease .account-countdown {
  font-family: var(--font-mono);
  font-size: var(--t-figure);
  font-weight: 500;
  line-height: 1;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

.account-card--lease .account-countdown.is-ending { color: var(--warn); }

.account-status {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  padding: 3px var(--s2);
  border-radius: var(--r-pill);
  border: 1px solid var(--border);
  color: var(--text-muted);
  white-space: nowrap;
}

.account-status.is-connected { color: var(--accent); border-color: var(--accent-dim); }
.account-status.is-pending { color: var(--warn); border-color: var(--warn-edge); }
.account-status.is-error { color: var(--danger-text); border-color: var(--danger-edge); }

.account-qr {
  margin-top: var(--s3);
  display: flex;
  align-items: center;
  gap: var(--s4);
  flex-wrap: wrap;
}

.account-qr img {
  border-radius: var(--r-md);
  background: #fff;
  padding: var(--s2);
  max-width: 100%;
}

.account-remove { margin-top: var(--s3); }

.account-badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s1);
  margin-top: var(--s3);
}

.badge {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  padding: 3px var(--s2);
  border-radius: var(--r-pill);
  border: 1px solid var(--border);
  color: var(--text-muted);
  background: var(--panel-raised);
  font-variant-numeric: tabular-nums;
}

.badge--accent { color: var(--accent); border-color: var(--accent-dim); }
.badge--warn { color: var(--warn); border-color: var(--warn-edge); }

.account-history { margin-top: var(--s3); }

.account-history summary {
  cursor: pointer;
  font-size: var(--t-micro);
  color: var(--text-dim);
  font-family: var(--font-mono);
}

.account-history .table-wrap { margin-top: var(--s2); }

/* Réglages de mise à disposition : même présentation que le bloc d'accès
   partagé juste en dessous, pour qu'ils se lisent comme deux sections du
   même panneau. */
.account-settings[open] {
  padding-top: var(--s3);
  border-top: 1px solid var(--border-soft);
}

.account-settings summary {
  cursor: pointer;
  font-size: var(--t-micro);
  color: var(--text-dim);
  font-family: var(--font-mono);
  padding: var(--s1) 0;
}

.account-settings [data-save-settings] { margin-top: var(--s2); }

.account-assign {
  margin-top: var(--s3);
  padding-top: var(--s3);
  border-top: 1px solid var(--border-soft);
}

.account-assign .badge a {
  color: var(--danger-text);
  text-decoration: none;
  margin-left: var(--s1);
}

.quality-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s1);
  margin-top: var(--s1);
}

/* ===== Chiffre dominant d'un écran ===== */
.figure {
  display: flex;
  align-items: baseline;
  gap: var(--s2);
}

.figure .n {
  font-family: var(--font-display);
  font-stretch: 112%;
  font-weight: 700;
  font-size: var(--t-figure);
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}

.figure .u { font-family: var(--font-mono); font-size: var(--t-micro); color: var(--text-dim); }

.figure-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s5);
  padding: var(--s4);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  margin-top: var(--s4);
}

/* ===== Tableaux ===== */
.table-wrap {
  margin-top: var(--s3);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow-x: auto;
}

table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  font-variant-numeric: tabular-nums;
}

caption {
  text-align: left;
  font-family: var(--font-ui);
  font-size: var(--t-micro);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-dim);
  padding: var(--s2) var(--s3);
}

th {
  text-align: left;
  padding: var(--s2) var(--s3);
  color: var(--text-dim);
  font-weight: 500;
  white-space: nowrap;
  border-bottom: 1px solid var(--border);
  background: var(--panel-raised);
}

td {
  padding: 7px var(--s3);
  color: var(--text-muted);
  border-bottom: 1px solid var(--border-soft);
}

tr:last-child td { border-bottom: none; }

.table-note {
  padding: var(--s2) 0;
  font-size: var(--t-micro);
  color: var(--text-dim);
  line-height: 1.6;
  max-width: 72ch;
}

.table-note strong { color: var(--text-muted); font-weight: 600; }

/* Une zone d'annonce vide reste dans le DOM pour être lue au lecteur d'écran,
   mais ne doit pas creuser un trou dans la page. */
.table-note:empty { padding: 0; }

.table-wrap .table-note { padding: var(--s2) var(--s3); }

.progress-inline {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* ===== Barre de progression =====
   Une campagne tourne une heure sur un créneau payé. Une chaîne de texte ne
   suffit pas à dire où elle en est. */
.progress-bar {
  margin-top: var(--s2);
  height: 6px;
  background: var(--panel-raised);
  border-radius: var(--r-pill);
  overflow: hidden;
}

.progress-bar > span {
  display: block;
  height: 100%;
  background: var(--accent);
  border-radius: var(--r-pill);
  transition: width 240ms ease;
}

/* ===== Erreur et état au contact de l'action =====
   82 chemins d'erreur partaient dans la console du bas et 4 seulement
   s'affichaient là où l'utilisateur regarde. */
.inline-note {
  display: flex;
  align-items: flex-start;
  gap: var(--s2);
  margin-top: var(--s3);
  padding: var(--s3);
  border-radius: var(--r-md);
  font-size: var(--t-micro);
  line-height: 1.6;
  border: 1px solid var(--border);
  background: var(--panel-raised);
  color: var(--text-muted);
}

.inline-note--error {
  border-color: var(--danger-edge);
  background: var(--danger-wash);
  color: var(--danger-text);
}

.inline-note--ok {
  border-color: var(--accent-dim);
  background: var(--accent-wash);
  color: var(--accent);
}

.inline-note--warn {
  border-color: var(--warn-edge);
  background: rgba(217, 164, 65, 0.1);
  color: var(--warn);
}

.inline-note .mark {
  font-family: var(--font-mono);
  flex-shrink: 0;
}

/* État de chargement sur un bouton */
.btn.is-busy { position: relative; color: transparent; }

.btn.is-busy::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 14px;
  height: 14px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin 700ms linear infinite;
  color: var(--accent);
}

.btn--commit.is-busy::after { color: var(--text-on-accent); }

@keyframes spin { to { transform: rotate(360deg); } }

/* ===== Boîte de dialogue =====
   window.confirm() portait les décisions qui déplacent des tokens. Chrome
   propose de bloquer ces boîtes, et un confirm() bloqué renvoie false en
   silence : le membre ne pouvait plus louer sans comprendre pourquoi. */
.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: rgba(5, 8, 7, 0.72);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--s5);
}

.modal-card {
  width: 100%;
  max-width: 440px;
  max-height: 86vh;
  overflow-y: auto;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--lift-2);
  padding: var(--s5);
  display: flex;
  flex-direction: column;
  gap: var(--s3);
}

.modal-title {
  font-family: var(--font-display);
  font-stretch: 112%;
  font-weight: 700;
  font-size: var(--t-title);
  margin: 0;
  letter-spacing: -0.01em;
}

.modal-body { color: var(--text-muted); margin: 0; }

.modal-lines {
  display: flex;
  flex-direction: column;
  gap: var(--s1);
  padding: var(--s3);
  background: var(--panel-raised);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  font-variant-numeric: tabular-nums;
}

.modal-lines .row { display: flex; justify-content: space-between; gap: var(--s4); }
.modal-lines .row .k { color: var(--text-dim); }
.modal-lines .row .v { color: var(--text); }
.modal-lines .row .v.is-cost { color: var(--warn); }

.modal-actions {
  display: flex;
  gap: var(--s2);
  justify-content: flex-end;
  flex-wrap: wrap;
  margin-top: var(--s1);
}

/* ===== Flux IA ===== */
.ai-feed {
  margin-top: var(--s4);
  display: flex;
  flex-direction: column;
  gap: var(--s2);
}

.ai-feed-item {
  padding: var(--s3);
  background: var(--panel-raised);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  font-size: var(--t-micro);
  line-height: 1.6;
}

/* --info supprimé : une cinquième couleur pour un seul élément. */
.ai-feed-item .jid {
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: var(--t-micro);
}

/* ===== Journal en direct : le motif d'identité =====
   Des sessions WhatsApp qui se connectent et qui tombent, ça se raconte dans un
   flux horodaté. Il est repliable et agrandissable, et il ne reçoit plus les
   erreurs qui doivent s'afficher à côté de l'action. */
.log-console {
  position: fixed;
  bottom: 0;
  left: var(--sidebar-w);
  right: 0;
  z-index: 30;
  height: var(--console-h);
  background: var(--console-bg);
  border-top: 1px solid var(--accent-dim);
  display: flex;
  flex-direction: column;
  transition: height 160ms ease;
}

.log-console-head {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s2) var(--s4);
  border-bottom: 1px solid var(--border-soft);
  font-size: var(--t-micro);
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  flex-shrink: 0;
}

.log-console-title {
  display: flex;
  align-items: center;
  gap: var(--s2);
  font-weight: 600;
}

.log-pulse {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  flex-shrink: 0;
}

.log-console-actions { margin-left: auto; display: flex; gap: var(--s1); }

.log-lines {
  flex: 1;
  overflow-y: auto;
  padding: var(--s2) var(--s4) var(--s3);
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  line-height: 1.75;
}

.log-console.is-collapsed .log-lines { display: none; }

.log-line { white-space: pre-wrap; color: var(--text-muted); }
.log-line .ts { color: var(--text-dim); margin-right: var(--s2); }
.log-line.ok { color: var(--accent); }
.log-line.err { color: var(--danger-text); }
.log-line.info { color: var(--text-muted); }

/* ============================================================================
   Responsive. Avant : zéro media query, une barre figée à 216px et
   overflow:hidden sur body, donc sous 900px le contenu était coupé et non
   défilable. La responsivité fait partie du design, pas d'un lot ultérieur.
   ========================================================================= */

/* Portable étroit et tablette en paysage : on resserre sans changer la forme. */
@media (max-width: 1100px) {
  :root { --sidebar-w: 200px; }
  .main { padding-left: var(--s5); padding-right: var(--s5); }
  .lease-bar { margin-left: calc(var(--s5) * -1); margin-right: calc(var(--s5) * -1); }
  .panel.is-active { max-width: none; }
}

/* Tablette portrait et téléphone : la barre latérale devient un tiroir, la
   charpente passe en colonne, et la page redevient défilable. */
@media (max-width: 860px) {
  .shell { flex-direction: column; }

  .menu-toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--s2);
    margin-left: auto;
    padding: 8px var(--s3);
    min-height: 44px;
    background: var(--panel-raised);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    color: var(--text);
    font-size: var(--t-micro);
  }

  .sidebar {
    width: 100%;
    height: auto;
    position: sticky;
    top: 0;
    z-index: 40;
    border-right: none;
    border-bottom: 1px solid var(--border);
    padding: var(--s2) var(--s3);
    gap: 0;
    overflow: visible;
  }

  .brand {
    padding: var(--s1) 0;
    border-bottom: none;
    width: 100%;
  }

  /* Le tiroir est fermé par défaut : seuls la marque et le bouton restent. */
  .sidebar .nav-groups,
  .sidebar .sidebar-balance,
  .sidebar .sidebar-footer {
    display: none;
  }

  .sidebar.is-open {
    padding-bottom: var(--s4);
    max-height: 100vh;
    overflow-y: auto;
  }

  .sidebar.is-open .nav-groups {
    display: flex;
    margin-top: var(--s3);
    padding-top: var(--s3);
    border-top: 1px solid var(--border-soft);
  }

  .sidebar.is-open .sidebar-balance,
  .sidebar.is-open .sidebar-footer {
    display: flex;
    margin-top: var(--s3);
  }

  .nav-item { min-height: 44px; border-radius: var(--r-md); border-left-width: 3px; }

  .main { padding: var(--s4) var(--s4) calc(var(--console-h) + var(--s5)); }

  .lease-bar {
    margin: calc(var(--s4) * -1) calc(var(--s4) * -1) var(--s4);
    top: var(--topbar-h);
  }

  .log-console { left: 0; }

  .panel-head h2 { font-size: 22px; }

  .figure-row { gap: var(--s4); }
}

/* Téléphone : une colonne, et chaque cible tactile fait au moins 44px. */
@media (max-width: 560px) {
  :root { --t-figure: 28px; --t-display: 22px; }

  .main { padding-left: var(--s3); padding-right: var(--s3); }

  .lease-bar {
    margin-left: calc(var(--s3) * -1);
    margin-right: calc(var(--s3) * -1);
  }

  .field-row {
    flex-direction: column;
    align-items: stretch;
    gap: var(--s2);
  }

  .field-row .btn,
  .field-row .text-input,
  .field-row .number-input,
  .field-row .select {
    width: 100%;
    min-width: 0;
  }

  .field-row .btn--tiny { width: auto; align-self: flex-start; }

  .check-row--inline { margin-top: var(--s2); }

  .btn { min-height: 44px; }
  .btn--tiny { min-height: 36px; }

  .account-card { padding: var(--s3); border-radius: var(--r-md); }

  .account-card-head { align-items: flex-start; }

  .account-card--lease .account-countdown { font-size: var(--t-display); }

  .gate-card { padding: var(--s5) var(--s4); }

  .modal-card { padding: var(--s4); max-height: 92vh; }

  .modal-actions .btn { flex: 1; }
}


/* Modificateurs utilisés par le rendu JS, à la place des styles en dur qui
   contournaient le système de tokens. */
.number-input--narrow { width: 64px; }

.badge--danger { color: var(--danger-text); border-color: var(--danger-edge); }

.table-note--danger { color: var(--danger-text); }
.table-note--warn { color: var(--warn); }
.table-note--accent { color: var(--accent); }
.table-note strong.is-danger { color: var(--danger-text); }

.check-item-label { flex: 1; min-width: 0; }

.estimate-total { margin-top: var(--s1); }

label.file-chip { cursor: pointer; }

/* Écran court : le journal ne doit pas manger la moitié de la hauteur. */
@media (max-height: 620px) {
  .log-console { max-height: 40vh; }
}

/* Pointeur grossier (tactile) : on élargit les cibles, quelle que soit la
   largeur de l'écran. */
@media (pointer: coarse) {
  .btn { min-height: 44px; }
  .nav-item { min-height: 44px; }
  .check-list label { padding: var(--s3); }
  input[type="checkbox"] { width: 20px; height: 20px; }
}

/* ===== Un contenu par client (admin) =====
   Mille factures, mille vocaux, mille textes à apparier avant d'envoyer. La
   décision que l'admin prend ici est une seule : « est-ce que ça peut
   partir ? ». Toute la composition sert cette question, donc le nombre de
   contacts prêts est le point focal du bloc, et le tableau trie les
   incomplets en premier au lieu de l'ordre alphabétique. */

/* Les quatre natures attendues forment UNE décision, pas quatre cases
   égarées dans la page : elles sont donc encadrées ensemble. */
.field-group {
  margin-top: var(--s4);
  padding: var(--s3) var(--s4) var(--s4);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--panel-raised);
}

/* Le titre se range dans le cadre, pas à cheval sur la bordure : posé sur le
   trait, il paraissait sorti de la boîte. Le float est ce qui sort la légende
   du rendu propre aux fieldsets. */
.field-group legend {
  float: left;
  width: 100%;
  margin: 0 0 var(--s3);
  padding: 0;
  color: var(--text);
  font-size: var(--t-micro);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.field-group > legend + * { clear: both; }

/* Bordure tiretée : le seul endroit de l'interface qui en porte une, et elle
   dit « il n'y a rien ici, dépose quelque chose ». */
.drop-zone {
  margin-top: var(--s4);
  padding: var(--s5) var(--s4);
  border: 1px dashed var(--border);
  border-radius: var(--r-lg);
  background: var(--panel);
  text-align: center;
}

.drop-zone-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  justify-content: center;
}

.drop-zone .table-note { margin: var(--s3) auto 0; text-align: left; }

/* Un survol de dépôt doit dire que le dossier SERA accepté, sinon l'admin
   lâche son dossier dans le vide. Changement d'état, pas animation. */
.drop-zone.is-over {
  border-color: var(--accent-dim);
  border-style: solid;
  background: var(--accent-wash);
}

.drop-zone label.btn { cursor: pointer; }

/* L'input de fichier est masqué pour que son label porte le style du bouton.
   Masqué ne veut pas dire hors du parcours clavier : l'anneau de focus doit
   donc apparaître sur le label, sinon la tabulation passe par un arrêt
   invisible. */
.drop-zone input[type="file"]:focus-visible + .btn {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

/* Le compte-rendu d'appariement. Le nombre de contacts prêts est le seul
   chiffre de ce bloc à porter l'accent : c'est lui qui décide du lancement. */
.tally {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s4);
  margin-top: var(--s4);
  padding: var(--s3) var(--s4);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--panel-raised);
}

.tally-main {
  display: flex;
  align-items: baseline;
  gap: var(--s2);
}

.tally-figure {
  font-family: var(--font-mono);
  font-size: var(--t-figure);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
  color: var(--accent);
}

.tally-label { font-size: var(--t-body); color: var(--text-muted); }

.tally-side {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s1) var(--s4);
  font-size: var(--t-micro);
  color: var(--text-muted);
}

.tally-side b {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--text);
  font-weight: 600;
}

.tally-side .is-warn b { color: var(--warn); }
.tally-side .is-danger b { color: var(--danger-text); }

/* Ce qui manque, nature par nature : un état, donc l'ambre, jamais l'accent.
   Le mot « manque » porte l'information, pas seulement la couleur. */
.cell-missing { color: var(--warn); }
.cell-present { color: var(--text-muted); }

.items-row-actions {
  display: flex;
  gap: var(--s1);
  flex-wrap: wrap;
}

/* Relire avant d'envoyer : la facture du client à côté de son numéro. */
.preview-card {
  margin-top: var(--s4);
  padding: var(--s4);
  border: 1px solid var(--accent-dim);
  border-radius: var(--r-lg);
  background: var(--panel);
}

.preview-card h4 {
  margin: 0 0 var(--s2);
  font-family: var(--font-display);
  font-stretch: 112%;
  font-size: var(--t-strong);
  font-weight: 700;
}

.preview-number {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  color: var(--text-muted);
}

.preview-text {
  margin: var(--s3) 0;
  padding: var(--s3);
  border-left: 2px solid var(--border);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  background: var(--panel-raised);
  font-size: var(--t-body);
  color: var(--text);
  white-space: pre-wrap;
}

.preview-media img {
  display: block;
  max-width: 100%;
  max-height: 320px;
  border-radius: var(--r-md);
  border: 1px solid var(--border);
}

.preview-media audio { width: 100%; max-width: 420px; margin-top: var(--s3); }
