/* ═══════════════════════════════════════════════════════════════
   DigiSync Platform — app.css
   Layout: sidebar + topbar + pages
   ═══════════════════════════════════════════════════════════════ */

/* ── Layout ──────────────────────────────────────────────────── */
body {
  display: flex;
  height: 100vh;
  /* 100dvh suit la barre d'URL mobile : en 100vh pur, le pied de la sidebar
     (utilisateur + Déconnexion) tombe sous le pli et devient inatteignable. */
  height: 100dvh;
  overflow: hidden;
  font-size: 13px;
  background: var(--bg);
  color: var(--t1);
}

/* ── Sidebar ─────────────────────────────────────────────────── */
#sb {
  width: 216px;
  background: var(--sb);
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  flex-shrink: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  transition: transform .18s ease, box-shadow .18s ease;
}
#sb::-webkit-scrollbar { width: 0; }

.sb-brand {
  padding: 14px 13px 12px;
  display: flex; align-items: center; gap: 10px;
  border-bottom: 1px solid rgba(255,255,255,.06);
  flex-shrink: 0;
}
.sb-mark {
  width: 29px; height: 29px;
  /* Voir .login-mark : aplat plein, donc --accent-solid. */
  background: var(--accent-solid); border-radius: 7px;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700; color: var(--on-accent); flex-shrink: 0;
  letter-spacing: .5px;
}
.sb-name { color: rgba(255,255,255,.94); font-size: 13px; font-weight: 600; line-height: 1.2; }
.sb-ver  { color: rgba(255,255,255,.45); font-size: 10px; }

/* Nav sections */
.sb-sec {
  padding: 12px 13px 3px;
  font-size: 9px; font-weight: 600;
  letter-spacing: 1.1px; text-transform: uppercase;
  color: var(--t4);
}
.sb-lnk {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 10px; margin: 1px 6px;
  border-radius: 5px; cursor: pointer;
  color: var(--t3); font-size: 12px;
  transition: background .1s, color .1s;
  user-select: none;
}
.sb-lnk:hover { background: rgba(255,255,255,.06); color: var(--t1); }
.sb-lnk.on    { background: var(--accent-solid); color: var(--on-accent); }

.sb-ico { width: 14px; height: 14px; flex-shrink: 0; opacity: .55; }
.sb-lnk.on .sb-ico, .sb-lnk:hover .sb-ico { opacity: 1; }

.sb-cnt {
  margin-left: auto;
  background: rgba(255,255,255,.05); color: var(--t3);
  font-size: 9px; font-weight: 600;
  padding: 1px 5px; border-radius: 3px;
}
.sb-lnk.on .sb-cnt { background: rgba(255,255,255,.15); color: rgba(255,255,255,.85); }

/* ── Main app ────────────────────────────────────────────────── */
#app {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-width: 0;
}

/* ── Topbar ──────────────────────────────────────────────────── */
.topbar {
  background: var(--card);
  border-bottom: 1px solid var(--border);
  height: 49px;
  display: flex; align-items: center;
  padding: 0 20px; gap: 10px;
  flex-shrink: 0;
}
.tb-nav {
  background: none; border: 1px solid var(--border); border-radius: var(--r2);
  width: 32px; height: 32px; display: none; align-items: center; justify-content: center;
  color: var(--t2); cursor: pointer;
}
.tb-back {
  background: none; border: none; cursor: pointer;
  color: var(--t3); padding: 4px;
  display: flex; align-items: center;
  border-radius: 4px;
  transition: background .1s, color .1s;
}
.tb-back:hover { background: var(--hover); color: var(--t1); }
.tb-title { font-size: 14px; font-weight: 600; }
.tb-r { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.tb-date { font-size: 11px; color: var(--t4); }
.tb-theme {
  background: none; border: 1px solid var(--border); border-radius: var(--r2);
  width: 34px; height: 34px; display: inline-flex; align-items: center; justify-content: center;
  color: var(--t2); cursor: pointer;
  flex-shrink: 0;
}

/* ── Compte : menu déroulant en haut à droite ──────────────────
   L'emplacement conventionnel, et celui qu'on atteint sans faire défiler la
   navigation. Contrairement au pied de barre d'où il vient, la surface est
   ici CLAIRE (--card) : tout passe par les jetons de thème, sans blanc
   translucide qui supposait le bleu nuit de la barre latérale. */
.acct { position: relative; flex-shrink: 0; }
.acct-btn {
  display: flex; align-items: center; gap: 8px;
  padding: 3px 6px 3px 3px; border-radius: 99px;
  background: none; border: 1px solid transparent; cursor: pointer;
  font-family: 'Poppins', sans-serif; color: var(--t2);
  max-width: 220px;
  transition: background var(--t-fast), border-color var(--t-fast);
}
.acct-btn:hover { background: var(--hover); border-color: var(--border); }
.acct-btn[aria-expanded="true"] { background: var(--active); border-color: var(--border); }
.acct-name {
  font-size: 12px; font-weight: 500; line-height: 1.2;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.acct-caret { flex-shrink: 0; color: var(--t4); transition: transform var(--t-fast); }
.acct-btn[aria-expanded="true"] .acct-caret { transform: rotate(180deg); }

/* Calque flottant, aligné sur le bord DROIT du bouton : posé à gauche, il
   sortirait de la fenêtre puisque le bouton touche déjà le bord. */
.acct-menu {
  position: absolute; top: calc(100% + 8px); right: 0;
  z-index: 1100;
  width: 236px;
  background: var(--elev);
  border: 1px solid var(--border); border-radius: var(--r);
  box-shadow: var(--sh-3);
  padding: 6px;
}
.acct-menu[hidden] { display: none; }

.acct-head { padding: 8px 8px 10px; border-bottom: 1px solid var(--b2); margin-bottom: 6px; }
.acct-head-name { font-size: 12.5px; font-weight: 600; color: var(--t1); line-height: 1.3; }
.acct-head-mail {
  font-size: 11px; color: var(--t4); margin-top: 1px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.acct-actions { display: flex; flex-direction: column; }
.acct-item {
  width: 100%; display: flex; align-items: center; gap: 9px;
  padding: 8px; border-radius: var(--r2);
  background: none; border: none; cursor: pointer; text-align: left;
  color: var(--t2); font-size: 12.5px; font-family: 'Poppins', sans-serif;
  transition: background var(--t-fast), color var(--t-fast);
}
.acct-item:hover { background: var(--hover); color: var(--t1); }
.acct-item svg { color: var(--t4); flex-shrink: 0; }
.acct-item:hover svg { color: var(--t2); }

/* --t4 (méta) et non --t5 (placeholder) : à 10px, le gris de saisie vide
   tombe sous 3:1 en thème clair. */
.acct-version {
  color: var(--t4); font-size: 10px; letter-spacing: .2px;
  padding: 8px 8px 2px; margin-top: 4px; border-top: 1px solid var(--b2);
}

/* Badges de rôle. Ils vivaient sur le bleu nuit de la barre latérale, en
   blanc translucide ; sur la carte du menu, ce texte serait illisible.
   Texte posé sur une teinte : c'est `--X-fg` qu'il faut, pas `--X` — l'accent
   brut sur sa propre teinte pâle ne passe pas le seuil AA en thème clair
   (voir docs/THEME.md §5). Le libellé porte le rôle, la couleur ne fait que
   le rappeler. */
#acct-role {
  font-size: 9px; font-weight: 600; letter-spacing: .3px;
  padding: 2px 6px; border-radius: 3px;
  margin-top: 6px; display: inline-block;
}
.r-a { background: var(--bl); color: var(--blue-fg); }
.r-m { background: var(--gl); color: var(--green-fg); }
.r-r { background: var(--b2); color: var(--t3); }

/* Topbar mobile : « jeudi 20 août 2026 » poussait le titre et les actions
   hors écran. On masque la date et on laisse le titre s'élider. */
@media (max-width: 640px) {
  .topbar { padding: 0 12px; gap: 8px; }
  .tb-date { display: none; }
  .tb-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .tb-r { gap: 6px; min-width: 0; }
  .tb-nav, .tb-theme { flex-shrink: 0; }
  /* Le nom mange la largeur d'un petit écran : l'avatar seul suffit à
     désigner le menu, et le nom complet reste dans son en-tête. */
  .acct-name { display: none; }
  .acct-btn { max-width: none; padding: 3px; }
  #tb-act { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
}

/* ── Page area ───────────────────────────────────────────────── */
#pa { flex: 1; overflow-y: auto; padding: 18px 20px; -webkit-overflow-scrolling: touch; }
#pa::-webkit-scrollbar { width: 4px; }
#pa::-webkit-scrollbar-thumb { background: var(--t5); border-radius: 99px; }

/* Voile du drawer : fermeture au tap hors menu. Invisible ET non cliquable
   tant que le menu est fermé, sinon il intercepte les clics de la page. */
#sb-ov {
  position: fixed; inset: 0; z-index: 1100;
  background: rgba(8,20,36,.5);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .18s ease, visibility .18s ease;
}

/* Mobile nav — drawer sous 900px (même seuil que UI.MOBILE_BP côté JS) */
@media (max-width: 900px) {
  #sb {
    position: fixed; z-index: 1200; left: 0; top: 0;
    /* Bornée : lisible sur un 320px, jamais plus de 84% du viewport. */
    width: min(84vw, 260px);
    max-width: 84vw;
    transform: translateX(-100%);
    box-shadow: 0 10px 28px rgba(0,0,0,.35);
    /* Encoche / barre système en PWA plein écran. */
    padding-top: env(safe-area-inset-top, 0px);
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  body.nav-open #sb { transform: translateX(0); }
  body.nav-open #sb-ov { opacity: 1; visibility: visible; pointer-events: auto; }
  .tb-nav { display: inline-flex; }
  /* Cibles tactiles : 40px de haut minimum (WCAG 2.5.8). */
  #sb .sb-lnk { padding: 10px 16px; font-size: 13px; min-height: 40px; }
  #sb .sb-sec { padding: 12px 16px 4px; }
  .acct-item { min-height: 38px; }
}

/* Le voile n'a de sens que pour le drawer : sur desktop la sidebar est en flux. */
@media (min-width: 901px) {
  #sb-ov { display: none; }
}

/* ── Pages ───────────────────────────────────────────────────── */
.page { display: none; }
.page.on { display: block; }

/* ── Project grid ────────────────────────────────────────────── */
.proj-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px; margin-bottom: 14px;
}
.proj-card {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--r); overflow: hidden;
  cursor: pointer; transition: box-shadow .15s, border-color .15s;
}
.proj-card:hover { box-shadow: var(--sh-2); border-color: var(--border-strong); }
.proj-card-bar { height: 4px; }
.proj-card-body { padding: 14px; }
.proj-card-name { font-size: 13px; font-weight: 600; margin-bottom: 4px; }
.proj-card-desc { font-size: 11px; color: var(--t3); margin-bottom: 10px; line-height: 1.5; min-height: 30px; }
.proj-card-foot {
  border-top: 1px solid var(--b2); padding: 9px 14px;
  display: flex; align-items: center; justify-content: space-between;
}

/* ── Kanban ──────────────────────────────────────────────────── */
.kb-grid { display: grid; grid-template-columns: repeat(4,1fr); gap: 10px; }
.kb-col { background: var(--card-sub); border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; }
.kb-col-h {
  padding: 8px 11px;
  display: flex; align-items: center; justify-content: space-between;
  border-bottom: 1px solid var(--border); background: var(--card);
}
.kb-cards { padding: 8px; min-height: 80px; display: flex; flex-direction: column; gap: 6px; }
.kb-card { background: var(--card); border: 1px solid var(--border); border-radius: 5px; padding: 9px 11px; }
.kb-card-t { font-size: 12px; font-weight: 500; margin-bottom: 5px; }

/* ── Comments ────────────────────────────────────────────────── */
.cmt { display: flex; gap: 10px; padding: 12px 0; border-bottom: 1px solid var(--b2); }
.cmt:last-child { border-bottom: none; }
.cmt-body { flex: 1; }
.cmt-hd { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.cmt-name { font-size: 12px; font-weight: 500; }
.cmt-ts { font-size: 10px; color: var(--t4); }
.cmt-text { font-size: 12px; color: var(--t2); line-height: 1.6; }

/* ── Planning ────────────────────────────────────────────────── */
.wk { border: 1px solid var(--border); border-radius: var(--r); margin-bottom: 7px; background: var(--card); overflow: hidden; }
.wk.now { border-color: var(--bll); }
.wk-h { display: flex; align-items: center; gap: 8px; padding: 10px 14px; flex-wrap: wrap; }
.wk-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
.wk-range { font-size: 12px; font-weight: 500; min-width: 190px; }
.wk-chips { display: flex; gap: 5px; flex-wrap: wrap; flex: 1; }
.wk-chip {
  display: flex; align-items: center; gap: 5px;
  padding: 3px 8px; border-radius: 4px; font-size: 11px;
  background: var(--card-sub); border: 1px solid var(--border);
}
.wk-acts { margin-left: auto; display: flex; gap: 4px; flex-wrap: wrap; }

/* ── ICS rows ────────────────────────────────────────────────── */
.ics-row {
  display: flex; align-items: center; gap: 8px;
  padding: 9px 12px; border: 1px solid var(--border);
  border-radius: var(--r); margin-bottom: 6px; background: var(--card);
}
.ics-tok {
  font-family: monospace; font-size: 10px;
  background: var(--card-sub); border: 1px solid var(--border);
  border-radius: 4px; padding: 3px 7px; color: var(--t2);
  flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ── Documents ───────────────────────────────────────────────── */
.doc-card {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--r); padding: 14px;
  display: flex; align-items: flex-start; gap: 12px;
  cursor: pointer; transition: box-shadow .12s, border-color .12s;
  margin-bottom: 8px;
}
.doc-card:hover { box-shadow: var(--sh-2); border-color: var(--border-strong); }
.doc-ico {
  width: 38px; height: 44px; border-radius: 4px;
  display: flex; align-items: center; justify-content: center;
  font-size: 18px; flex-shrink: 0;
}
.doc-meta { flex: 1; min-width: 0; }
.doc-title {
  font-size: 13px; font-weight: 600; color: var(--t1);
  margin-bottom: 3px; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.doc-sub { font-size: 11px; color: var(--t3); margin-bottom: 6px; }
.doc-tags { display: flex; gap: 4px; flex-wrap: wrap; }
.doc-tag {
  font-size: 10px; background: var(--card-sub);
  border: 1px solid var(--border); padding: 1px 6px;
  border-radius: 3px; color: var(--t3);
}

/* ── Discord ─────────────────────────────────────────────────── */
/* Aperçu d'un message Discord : ces couleurs SONT celles de Discord, pas
   celles de la charte. Elles restent en dur des deux côtés — c'est une
   maquette de ce que verra le destinataire, pas un composant du produit. */
.dc-preview { background: #36393f; border-radius: 8px; padding: 16px; max-width: 480px; }
.dc-preview-inner { border-left: 4px solid #5865f2; background: #2f3136; border-radius: 0 4px 4px 0; padding: 12px 14px; }
.dc-author { font-size: 11px; font-weight: 600; color: #b9bbbe; margin-bottom: 5px; }
.dc-title  { font-size: 13px; font-weight: 600; color: #fff; margin-bottom: 6px; }
.dc-desc   { font-size: 12px; color: #dcddde; line-height: 1.6; white-space: pre-line; }
.dc-footer { margin-top: 10px; font-size: 10px; color: #72767d; }
.wh-card {
  border: 1px solid var(--border); border-radius: var(--r);
  padding: 12px 14px; background: var(--card);
  margin-bottom: 8px; display: flex; align-items: flex-start; gap: 12px;
}
.wh-dot { width: 8px; height: 8px; border-radius: 50%; margin-top: 4px; flex-shrink: 0; }

/* ── Settings ────────────────────────────────────────────────── */
.set-l { display: grid; grid-template-columns: 170px 1fr; gap: 14px; }
.sn-sec { font-size: 9px; font-weight: 600; letter-spacing: .8px; text-transform: uppercase; color: var(--t5); padding: 10px 8px 3px; }
.sn-item { padding: 6px 9px; border-radius: 5px; font-size: 12px; color: var(--t3); cursor: pointer; user-select: none; }
.sn-item:hover { background: var(--hover); color: var(--t1); }
.sn-item.on { background: var(--bl); color: var(--blue-fg); font-weight: 500; }
.sc-sec { display: none; }
.sc-sec.on { display: block; }

/* ── Directory (Contacts & référents) ───────────────────────────────────────── */
.dir-filters { display: flex; justify-content: space-between; gap: 10px; align-items: center; flex-wrap: wrap; }
.dir-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.dir-filter-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px,1fr)); gap: 8px; margin-bottom: 10px; }
.dir-company { border: 1px solid var(--border); border-radius: var(--r); padding: 14px; margin-bottom: 12px; background: var(--card); }
.dir-company-head { display:flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.dir-title { font-size: 15px; font-weight: 600; color: var(--t1); }
.dir-sub { font-size: 12px; color: var(--t3); margin: 4px 0; display:flex; gap:6px; align-items:center; flex-wrap:wrap; }
.dir-head-actions { display:flex; gap:8px; flex-wrap:wrap; align-items:center; }
.dir-contacts { margin-top: 10px; display: flex; flex-direction: column; gap: 8px; }
.dir-contact { border:1px solid var(--border); border-radius: var(--r); padding: 10px; background: var(--card); }
.dir-contact-main { display:flex; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.dir-contact-name { font-weight:600; color: var(--t1); }
.dir-contact-job { font-size:12px; color: var(--t3); }
.dir-contact-purpose { font-size:12px; color: var(--t2); margin-top:4px; }
.dir-contact-availability { font-size:12px; color: var(--t3); }
.dir-contact-actions { display:flex; gap:6px; flex-wrap: wrap; align-items:center; }
.dir-contact-actions .btn { min-width: 64px; }
.dir-contact-meta { display:flex; gap:10px; flex-wrap: wrap; font-size:11px; color: var(--t3); margin-top:6px; }

/* Responsive tweaks */
@media (max-width: 900px) {
  /* La largeur du drawer est définie dans « Mobile nav » (min(84vw,260px)) ;
     un `width: 210px` ici l'écrasait puisque déclaré plus bas. */
  .dir-contact-actions .btn { width: 100%; }
}
@media (max-width: 720px) {
  .g2, .g3 { grid-template-columns: 1fr !important; }
  .dir-filter-row { grid-template-columns: 1fr; }
  .dir-company-head { flex-direction: column; }
  .dir-contact-main { flex-direction: column; }
.tw { overflow-x: auto; }
.btn { padding: 10px 12px; }
}

/* Stackable tables for mobile */
@media (max-width: 720px) {
  .tw table { display: block; width: 100%; border-collapse: collapse; }
  .tw thead { display: none; }
  .tw tbody tr {
    display: block;
    border: 1px solid var(--border);
    border-radius: var(--r);
    padding: 10px;
    margin-bottom: 10px;
    background: var(--card);
  }
  .tw td {
    display: flex;
    justify-content: space-between;
    gap: 8px;
    padding: 6px 4px;
    border: none !important;
  }
  .tw td::before {
    content: attr(data-label);
    font-weight: 600;
    color: var(--t2);
    margin-right: 8px;
  }
  /* En cartes empilées il n'y a plus de colonnes à protéger : on rend le
     libellé entier, en coupant les chaînes sans espace plutôt qu'en débordant. */
  .tw td.cell-clip {
    max-width: none; white-space: normal;
    overflow: visible; overflow-wrap: anywhere;
  }
}

/* ── Permission grid ─────────────────────────────────────────── */
.pg-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; margin-top: 4px; }
.pg-chip {
  display: flex; align-items: center; gap: 6px;
  padding: 5px 8px; border: 1px solid var(--border);
  border-radius: 5px; cursor: pointer; font-size: 11px;
  color: var(--t3); user-select: none;
}
.pg-chip.on { background: var(--bl); border-color: var(--bll); color: var(--blue-fg); font-weight: 500; }
.pg-chip input { display: none; }

/* ── Subtasks ────────────────────────────────────────────────── */
.sub-r { display: none; }
.sub-r.open { display: table-row; }
.sub-r td { background: var(--card-sub); padding-left: 28px !important; color: var(--t3); }
.xb {
  background: none; border: none; cursor: pointer;
  color: var(--t4); font-size: 10px; padding: 1px 3px;
  border-radius: 3px; font-family: monospace;
}
.xb:hover { background: var(--hover); color: var(--blue); }

/* ── Skeleton (placeholders de chargement) ───────────────────────
   Utilisé par booking.js (<div class="card skeleton"><div class="sk-line">…).
   Sans ces règles, l'état de chargement était totalement invisible. */
.skeleton { pointer-events: none; }
.sk-line {
  height: 12px;
  border-radius: 6px;
  margin: 10px 0;
  background: linear-gradient(90deg, var(--b2) 25%, var(--hover) 37%, var(--b2) 63%);
  background-size: 400% 100%;
  animation: sk-shimmer 1.4s ease infinite;
}
.sk-line:last-child { width: 60%; }
@keyframes sk-shimmer {
  0%   { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}

/* ── Toast ───────────────────────────────────────────────────── */
#toast-root {
  position: fixed; bottom: 20px; right: 20px;
  display: flex; flex-direction: column; gap: 8px;
  z-index: 9999;
}
.toast {
  background: var(--float-bg); color: var(--float-fg);
  border: 1px solid var(--float-bd);
  padding: 10px 16px; border-radius: var(--r);
  font-size: 12px; font-weight: 500;
  box-shadow: 0 4px 20px rgba(0,0,0,.22);
  display: flex; align-items: center; gap: 8px;
  animation: toast-in .2s ease;
  max-width: 340px;
}
/* Variantes pleines : jetons --*-solid, lisibles sous du blanc dans les
   deux thèmes. L'icône et le libellé portent le sens ; la couleur ne fait
   que le renforcer. */
.toast.success { background: var(--success-solid); color: var(--on-accent); border-color: var(--success-solid); }
.toast.error   { background: var(--danger-solid);  color: var(--on-accent); border-color: var(--danger-solid); }
.toast.warn    { background: var(--warning-solid); color: var(--on-warning); border-color: var(--warning-solid); }
.toast.info    { background: var(--accent-solid);  color: var(--on-accent); border-color: var(--accent-solid); }
@keyframes toast-in { from { transform: translateX(20px); opacity: 0; } }

/* ── Roadmap ─────────────────────────────────────────────────── */
.rm-card {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--r); overflow: hidden;
}
.rm-card-head { padding: 10px 12px; font-size: 12px; font-weight: 600; color: #fff; }
.rm-card-body { padding: 11px 12px; }
.rm-feat { font-size: 11px; color: var(--t2); padding: 3px 0; display: flex; align-items: center; gap: 6px; }
.rm-feat::before { content: ''; width: 5px; height: 5px; border-radius: 50%; background: var(--rm-color, var(--t5)); flex-shrink: 0; }

/* ── PDF invoice viewer modal ────────────────────────────────── */
.mo-pdf { width: 95vw; max-width: 1600px; height: 92vh; display: flex; flex-direction: column; }
.mo-pdf .mo-h { flex-wrap: wrap; gap: 6px; flex-shrink: 0; } .mo-pdf .mo-b { flex: 1; min-height: 0; }
@media (max-width: 640px) { .mo-pdf { width: 98vw; height: 95vh; } }

/* ── PDF watermark preview ───────────────────────────────────── */
.pdf-preview {
  position: relative; background: var(--card);
  border: 1px solid var(--border); border-radius: var(--r);
  min-height: 300px; overflow: hidden;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
}
.pdf-wm {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  pointer-events: none; z-index: 2;
}
.pdf-wm span {
  font-size: 24px; font-weight: 700;
  color: color-mix(in srgb, var(--blue) 16%, transparent); transform: rotate(-35deg);
  white-space: nowrap; user-select: none; letter-spacing: 3px;
}
.pdf-content { position: relative; z-index: 1; text-align: center; color: var(--t4); padding: 20px; }

/* ── Access log rows ─────────────────────────────────────────── */
.acc-row { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--b2); font-size: 12px; }
.acc-row:last-child { border-bottom: none; }

/* ── Responsive ──────────────────────────────────────────────── */
/* â”€â”€ Cartes de visite (stock) â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.stock-kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 10px;
}
.stock-kpi {
  background: var(--card-sub);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 10px 12px;
}
.stock-kpi-label { font-size: 11px; color: var(--t3); text-transform: uppercase; letter-spacing: .5px; }
.stock-kpi-value { font-size: 20px; font-weight: 700; color: var(--t1); }
.stock-kpi-sub { font-size: 11px; color: var(--t4); margin-top: 3px; }

.stock-collab {
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 10px;
  margin-bottom: 10px;
  background: var(--card);
}
.stock-c-head { display: flex; align-items: center; gap: 8px; }
.stock-c-name { font-weight: 600; color: var(--t1); }
.stock-c-role { font-size: 11px; color: var(--t3); }
.stock-c-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.stock-quick { flex: 1; min-width: 110px; height: 36px; font-weight: 600; }

.stock-history { display: flex; flex-direction: column; gap: 8px; }
.stock-move { display: flex; justify-content: space-between; gap: 10px; border-bottom: 1px solid var(--border); padding: 8px 0; }
.stock-m-left { flex: 1; }
.stock-m-meta { font-size: 11px; color: var(--t3); }
.stock-m-comment { font-size: 12px; color: var(--t2); margin-top: 4px; }
.stock-m-right { text-align: right; min-width: 120px; }
.stock-m-qty { font-size: 16px; font-weight: 700; color: var(--t1); }
.stock-m-qty.neg { color: var(--red); }
.stock-m-qty.pos { color: var(--green); }
.stock-m-by { font-size: 11px; color: var(--t4); }

/* Statistiques — répartition par collaborateur */
.stock-stats-range { font-size: 11px; color: var(--t4); }
.stock-bar-row { padding: 8px 0; border-bottom: 1px solid var(--b2); }
.stock-bar-row:last-of-type { border-bottom: none; }
.stock-bar-head { display: flex; align-items: center; gap: 8px; }
.stock-bar-val { margin-left: auto; font-size: 15px; font-weight: 700; color: var(--t1); }
.stock-bar { height: 6px; margin-top: 6px; border-radius: 3px; background: var(--b2); overflow: hidden; }
.stock-bar-fill { height: 100%; border-radius: 3px; background: var(--blue); }
.stock-bar-row.me .stock-bar-fill { background: var(--green); }
.stock-bar-sub { font-size: 11px; color: var(--t4); margin-top: 4px; }
.stock-bar-total { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--border); font-size: 12px; color: var(--t3); }

.form-error { color: var(--red); font-size: 12px; margin-top: 6px; }

/* Calendar */
.cal-grid { display:grid; grid-template-columns:repeat(7,1fr); gap:8px; }
.cal-cell { background:var(--card); border:1px solid var(--border); border-radius:var(--r2); padding:8px; min-height:90px; display:flex; flex-direction:column; gap:6px; }
.cal-cell.empty { background:transparent; border-style:dashed; }
.cal-cell.today { border-color:var(--blue); box-shadow:var(--sh); }
.cal-cell-h { display:flex; align-items:center; justify-content:space-between; font-weight:600; color:var(--t2); }
.cal-evts { display:flex; flex-direction:column; gap:4px; }
.cal-more { font-size:11px; color:var(--t4); }
.cal-week { display:grid; grid-template-columns:repeat(auto-fit,minmax(200px,1fr)); gap:10px; }
.cal-daycard { border:1px solid var(--border); border-radius:var(--r2); padding:8px; background:var(--card-sub); }
.cal-daycard-h { font-weight:600; margin-bottom:6px; }
.cal-daylist { display:flex; flex-direction:column; gap:8px; }
.cal-row { border:1px solid var(--border); border-radius:var(--r2); padding:8px; background:var(--card); display:flex; justify-content:space-between; align-items:center; }
.cal-chip { border:1px solid; border-radius:var(--r2); padding:4px 6px; display:flex; align-items:center; gap:6px; font-size:12px; color:var(--t2); }
.cal-chip.block { box-shadow: inset 0 0 0 1px var(--border); }
.cal-chip-t { font-weight:600; }
.cal-chip-s { font-size:11px; color:var(--t4); }
.cal-chip .cal-badges { display:flex; flex-wrap:wrap; gap:4px; margin-top:4px; }
.cal-badge { padding:2px 6px; border-radius:10px; font-size:10px; border:1px solid var(--border); background: var(--card); color: var(--t3); }
.cal-badge-busy           { color: var(--amber-fg);  border-color: var(--ab); background: var(--al); }
.cal-badge-free           { color: var(--green-fg);  border-color: var(--gb); background: var(--gl); }
.cal-badge-tentative      { color: var(--purple-fg); border-color: var(--pb); background: var(--pl); }
.cal-badge-out_of_office  { color: var(--red-fg);    border-color: var(--rb); background: var(--rl); }
.cal-badge-do_not_disturb { color: var(--red-fg);    border-color: var(--rb); background: var(--rl); }
.cal-badge-block          { color: var(--t3);        border-color: var(--border); background: var(--b2); }
.cal-badge-soft           { color: var(--teal-fg);   border-color: var(--tb); background: var(--tl); }
.cal-badge-conflict       { color: var(--red-fg);    border-color: var(--rb); background: var(--rl); }
.cal-badge-warning        { color: var(--amber-fg);  border-color: var(--ab); background: var(--al); }
.cal-dot { width:10px; height:10px; border-radius:50%; }
.cal-filters { display:flex; flex-wrap:wrap; gap:8px; margin-bottom:8px; font-size:11px; }
.cal-filter { display:flex; align-items:center; gap:5px; padding:4px 6px; border:1px solid var(--border); border-radius:var(--r2); background:var(--card-sub); cursor:pointer; }

@media (max-width: 1100px) {
  .g4 { grid-template-columns: repeat(2,1fr); }
  .proj-grid { grid-template-columns: repeat(2,1fr); }
  .kb-grid { grid-template-columns: repeat(2,1fr); }
  .cal-grid { grid-template-columns: repeat(4,1fr); }
}
@media (max-width: 768px) {
  /* NE PAS réintroduire `#sb { display:none }` ici : sous 900px la sidebar
     est un drawer (voir « Mobile nav »), la masquer rendait le bouton ☰
     inerte sur téléphone — c'était le bug du menu latéral mobile. */
  .g2, .g3, .g4 { grid-template-columns: 1fr; }
  .proj-grid { grid-template-columns: 1fr; }
  .kb-grid   { grid-template-columns: 1fr; }
  .set-l     { grid-template-columns: 1fr; }
  #pa { padding: 12px; }
  .fr { grid-template-columns: 1fr; }
  .stock-c-actions { flex-direction: column; }
  .stock-quick { width: 100%; }
  .cal-grid { grid-template-columns: repeat(2,1fr); }
}

/* Settings */
.set-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.set-tab {
  background: var(--card);
  border: 1px solid var(--border);
  color: var(--t2);
  padding: 8px 10px;
  border-radius: var(--r);
  cursor: pointer;
  font-weight: 600;
}
.set-tab.on { background: var(--accent-solid); border-color: var(--accent-solid); color: var(--on-accent); }
.perm-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px,1fr)); gap: 10px; }
.perm-col { border: 1px solid var(--border); border-radius: var(--r); padding: 10px; background: var(--card); }
.perm-title { font-weight: 600; margin-bottom: 6px; color: var(--t1); }
.perm-modal { grid-template-columns: repeat(auto-fit, minmax(180px,1fr)); }
.chip-line { padding: 6px 8px; border: 1px solid var(--border); border-radius: var(--r); margin-bottom: 6px; display:flex; justify-content: space-between; }
.mob-list .card.sm { margin-bottom: 8px; }
.card.sm { padding: 10px; }
.card-actions { display: flex; gap: 6px; padding: 0 10px 10px; }
.tag { display: inline-block; padding: 2px 8px; border-radius: 999px; background: var(--card-sub); color: var(--t2); font-size: 11px; margin-top: 4px; }
.hide-mobile { display: block; }
.mob-list { display: none; }
.code { font-size: 10px; }

@media (max-width: 768px) {
  .hide-mobile { display: none; }
  .mob-list { display: block; }
  .set-tabs { gap: 4px; }
  .set-tab { flex: 1 1 48%; text-align: center; }
}

/* ── Booking admin (bk-*) ─────────────────────────────── */
.bk-grid { display: grid; grid-template-columns: 1fr; gap: 14px; }
.bk-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 900px) { .bk-grid-2 { grid-template-columns: 1fr; } }
.bk-card { background: var(--card); border: 1px solid var(--border); border-radius: var(--r2); padding: 12px 14px; }
.bk-form { display: flex; flex-direction: column; gap: 8px; }
.bk-avail-row { display: grid; grid-template-columns: 140px 1fr 1fr 60px; gap: 8px; align-items: center; padding: 6px 0; border-bottom: 1px dashed var(--border); }
.bk-avail-row:last-child { border-bottom: 0; }
.bk-avail-day { font-weight: 600; color: var(--t2); font-size: 12px; }
.bk-token { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 12px; background: var(--card-sub); border: 1px solid var(--border); border-radius: var(--r); margin-bottom: 6px; }
.bk-token-info { min-width: 0; flex: 1; }
.bk-token-label { font-weight: 600; color: var(--t1); font-size: 13px; }
.bk-token-meta { font-size: 11px; color: var(--t3); margin-top: 2px; }
.bk-token-acts { display: flex; gap: 6px; flex-shrink: 0; }
.bk-empty { text-align: center; padding: 24px 12px; color: var(--t4); font-size: 12px; }
@media (max-width: 700px) {
  .bk-avail-row { grid-template-columns: 1fr 1fr; }
  .bk-avail-day { grid-column: 1 / -1; }
  .bk-token { flex-direction: column; align-items: flex-start; }
  .bk-token-acts { width: 100%; justify-content: flex-end; }
}

/* ── Planning collaborator chips (wk-*) ─────────────────── */
.wk-chip-name { font-weight: 600; color: var(--t1); }
.wk-chip-flag { font-size: 10px; color: var(--t4); margin-left: 4px; }

/* ── User cards in planning (uv-*) ────────────────────── */
.uv-card { display: flex; align-items: center; gap: 10px; padding: 8px 10px; background: var(--card-sub); border: 1px solid var(--border); border-radius: var(--r); margin-bottom: 6px; }
.uv-info { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.uv-name { font-weight: 600; color: var(--t1); font-size: 13px; }
.uv-meta { font-size: 11px; color: var(--t3); }

/* ── ICS / Integration rows ──────────────────────────── */
.mb12 { margin-bottom: 12px; }
.ics-row { display: flex; align-items: center; gap: 8px; padding: 6px 0; border-bottom: 1px dashed var(--border); }
.ics-row:last-child { border-bottom: 0; }
.ics-label { font-weight: 600; color: var(--t2); font-size: 12px; min-width: 110px; }
.ics-tok { font-family: ui-monospace, monospace; font-size: 11px; background: var(--card-sub); padding: 2px 6px; border-radius: 4px; color: var(--t2); word-break: break-all; }

/* ── Discord config (dc-*) ───────────────────────────── */
.dc-sep { height: 1px; background: var(--border); margin: 10px 0; }
.dc-vars-title { font-weight: 600; color: var(--t2); font-size: 12px; margin-bottom: 4px; }
.dc-color { width: 26px; height: 26px; border: 1px solid var(--border); border-radius: 4px; cursor: pointer; padding: 0; }
.dc-body-ta { min-height: 90px; font-family: ui-monospace, monospace; font-size: 12px; }
.dc-vars-pick { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.dc-var-chip { font-size: 11px; padding: 3px 8px; border-radius: 999px; background: var(--card-sub); border: 1px solid var(--border); color: var(--t2); cursor: pointer; }
.dc-var-chip:hover { background: var(--accent-solid); color: var(--on-accent); border-color: var(--accent-solid); }
.dc-log-date { font-size: 11px; color: var(--t3); white-space: nowrap; }
.dc-log-cell { font-size: 12px; color: var(--t2); }

/* ── Webhooks (wh-*) ─────────────────────────────────── */
.wh-info { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.wh-name { font-weight: 600; color: var(--t1); font-size: 13px; }
.wh-meta { font-size: 11px; color: var(--t3); }
.wh-acts { display: flex; gap: 6px; flex-shrink: 0; }
.wh-vars { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.wh-var { font-size: 10px; padding: 2px 6px; background: var(--card-sub); border-radius: 3px; color: var(--t3); font-family: ui-monospace, monospace; }

/* ── Audit (audit-*) ─────────────────────────────────── */
.audit-date { font-size: 11px; color: var(--t4); white-space: nowrap; }
.audit-cell { font-size: 12px; color: var(--t2); }
.audit-res { font-family: ui-monospace, monospace; font-size: 11px; color: var(--t3); max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.audit-empty { text-align: center; padding: 24px 12px; color: var(--t4); font-size: 12px; }
.audit-mob-card { background: var(--card); border: 1px solid var(--border); border-radius: var(--r); padding: 10px; margin-bottom: 8px; }
.audit-mob-head { display: flex; justify-content: space-between; gap: 8px; margin-bottom: 4px; }
.audit-mob-user { font-weight: 600; color: var(--t1); font-size: 12px; }
.audit-mob-action { font-size: 11px; color: var(--t3); }
.audit-mob-meta { font-size: 11px; color: var(--t4); margin-top: 4px; }

/* ── Roadmap (rm-*) ──────────────────────────────────── */
.rm-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 10px; }
.rm-feat-empty { padding: 20px; text-align: center; color: var(--t4); font-size: 12px; }
.rm-json { font-family: ui-monospace, monospace; font-size: 11px; background: var(--card-sub); padding: 8px; border-radius: 4px; white-space: pre-wrap; word-break: break-all; max-height: 240px; overflow: auto; }
.rm-edit-acts { display: flex; gap: 6px; justify-content: flex-end; margin-top: 8px; }
.rm-err { color: var(--red); font-size: 12px; margin-top: 6px; }

/* ── Calendar loading state ──────────────────────────── */
.cal-loading { padding: 8px 0; }

/* ── Admin health page (hl-*) ────────────────────────── */
.hl-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px; }
.hl-card { background: var(--card); border: 1px solid var(--border); border-radius: var(--r2); padding: 14px; }
.hl-card-h { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.hl-card-t { font-weight: 600; color: var(--t1); font-size: 13px; }
.hl-card-b { font-size: 12px; color: var(--t2); line-height: 1.55; }
.hl-card-b .lbl { font-weight: 600; color: var(--t3); font-size: 11px; text-transform: uppercase; letter-spacing: .3px; display: block; margin-top: 6px; margin-bottom: 2px; }
.hl-ok { color: var(--green); }
.hl-warn { color: var(--amber); }
.hl-err { color: var(--red); }
.hl-pill { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 11px; font-weight: 600; }
.hl-pill.ok   { background: var(--gl); color: var(--green-fg); }
.hl-pill.warn { background: var(--al); color: var(--amber-fg); }
.hl-pill.err  { background: var(--rl); color: var(--red-fg); }

/* ─── Booking — profile selector layout ──────────────────────── */
.bk-profile-switch .bk-switch-row {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
}
.bk-profile-switch select.fc { flex: 1 1 200px; min-width: 0; }

/* ───────────────────────────────────────────────────────────────
   Il y avait ici une trentaine de rustines « body.theme-dark … » qui
   rejouaient en dur, pour le thème sombre, des couleurs que les règles
   de base figeaient en clair (badges du calendrier, page Santé, stock,
   erreurs de formulaire, filigrane PDF, toasts).
   Les règles de base passent désormais par les jetons : elles basculent
   seules, et ces rustines ne faisaient plus que RÉIMPOSER des valeurs
   claires par-dessus. Supprimées.
   ─────────────────────────────────────────────────────────────── */

/* ───────────────────────────────────────────────────────────────
   Targeted mobile pass for modules added recently (booking selector,
   health grid, calendar badges chips). Existing breakpoints already
   cover most layouts; this 640px block is the polish layer.
   ─────────────────────────────────────────────────────────────── */
@media (max-width: 640px) {
  /* Booking profile switcher: stack on small screens */
  .bk-profile-switch .bk-switch-row { flex-direction: column; align-items: stretch; }
  .bk-profile-switch .bk-switch-row .btn { width: 100%; }

  /* Health cards single-column for thumb-scrolling */
  .hl-grid { grid-template-columns: 1fr; }
  .hl-card { padding: 12px; }

  /* Calendar chip badges wrap tightly so they don't overflow the card */
  .cal-chip .cal-badges { gap: 3px; }
  .cal-badge { font-size: 9.5px; padding: 1px 5px; }

  /* Settings tabs go to a 2-up grid (768px sets 48% basis; tighten here) */
  .set-tab { font-size: 12px; padding: 8px 10px; }

  /* Modal bodies should use most of the viewport on phones */
  .modal-card, .mdl-card { width: 95vw; max-width: 95vw; }

  /* Tables in cards — make sure horizontal scroll is the fallback */
  .tw { -webkit-overflow-scrolling: touch; }

  /* Roadmap grid: single column */
  .rm-grid { grid-template-columns: 1fr; }
}

/* ═══════════════════════════════════════════════════════════════
   DigiSync — Charte 2026 (Phase 2B)
   --ds-blue / --ds-blue-dark / --ds-violet sont désormais définis dans
   main.css, adossés à la charte (var(--blue) / var(--bd) / var(--purple)).
   Ils suivent donc le thème ET la couleur de marque configurée.
   Le :root qui les figeait ici gagnait la cascade sur main.css : barre
   latérale, onglets d'administration et sous-menu du calendrier restaient
   en couleurs de thème clair sous thème sombre. Les variantes --*-rgb
   n'avaient aucun usage, elles ne sont pas reprises.
   ═══════════════════════════════════════════════════════════════ */

/* Sidebar : 8 sections compactes — labels lisibles sur fond bleu foncé */
/* Surface de marque, hors échelle de profondeur : bleu nuit en thème clair,
   ardoise très sombre en thème sombre. C'est --sb qui décide ; le dégradé
   n'en est qu'un assombrissement, il suit donc automatiquement. */
#sb {
  background: linear-gradient(180deg, var(--sb) 0%, color-mix(in srgb, var(--sb) 84%, #000) 100%);
}
#sb .sb-sec {
  color: rgba(255,255,255,0.55);
  font-size: 10px;
  text-transform: uppercase;
  font-weight: 600;
  letter-spacing: 0.5px;
  padding: 12px 16px 6px;
}
#sb .sb-lnk {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 16px;
  margin: 1px 6px;
  border-radius: 6px;
  font-size: 12px;
  color: rgba(255,255,255,0.82);
  cursor: pointer;
  transition: background .15s, color .15s;
}
#sb .sb-lnk:hover {
  background: rgba(255,255,255,0.08);
  color: #fff;
}
/* Remplissage plein : --accent-solid, pas --blue — en thème sombre --blue
   est la teinte ÉCLAIRCIE (faite pour du texte), le blanc y tomberait à
   3,3:1. --accent-solid la redescend en profondeur : 5,3:1. */
#sb .sb-lnk.on {
  background: var(--accent-solid);
  color: var(--on-accent);
  font-weight: 500;
}
#sb .sb-lnk.on .sb-ico { color: var(--on-accent); }
/* Module éteint. L'entrée n'est rendue que pour un administrateur — elle est
   retirée de la sidebar des autres — et reste cliquable : il y accède en
   lecture seule, les données n'étant pas supprimées. */
#sb .sb-lnk.disabled {
  opacity: 0.45;
}
#sb .sb-lnk.disabled:hover { opacity: 0.7; }
#sb .sb-lnk-lbl {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
#sb .sb-ico { flex-shrink: 0; opacity: 0.85; }
#sb .sb-cnt {
  background: var(--ds-violet);
  color: var(--on-accent);
  font-size: 10px;
  padding: 1px 6px;
  border-radius: 8px;
  font-weight: 600;
}

/* .btn-p était défini ici puis réécrit trois fois plus bas. Définition
   unique désormais, dans « Boutons » en fin de fichier.
   */

/* Focus ring : violet accent (visibilité accessibilité) */
button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible, a:focus-visible {
  outline: 2px solid var(--ds-violet);
  outline-offset: 1px;
}

/* Page Modules — toggle on/off */
.mod-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 4px;
  border-bottom: 1px solid var(--border);
}
.mod-row:last-child { border-bottom: 0; }
.mod-row.off .mod-info { opacity: 0.55; }
.mod-info { flex: 1; min-width: 0; }
.mod-label { font-weight: 500; font-size: 13px; }
.mod-code { font-size: 10px; color: var(--t4); font-family: monospace; }
.mod-desc { font-size: 11px; color: var(--t3); margin-top: 2px; }
.mod-toggle {
  position: relative;
  display: inline-block;
  width: 42px;
  height: 22px;
  flex-shrink: 0;
}
.mod-toggle input { opacity: 0; width: 0; height: 0; }
.mod-slider {
  position: absolute; cursor: pointer; inset: 0;
  background: var(--t5); border-radius: 22px;
  transition: background var(--t-fast);
}
.mod-slider::before {
  content: ""; position: absolute;
  height: 18px; width: 18px;
  left: 2px; top: 2px;
  background: #fff; border-radius: 50%;
  transition: .2s;
}
.mod-toggle input:checked + .mod-slider { background: var(--accent-solid); }
.mod-toggle input:checked + .mod-slider::before { transform: translateX(20px); }


/* Compactage tablette : uniquement quand la sidebar est encore dans le flux.
   En dessous de 901px c'est un drawer tactile, qui garde ses cibles à 40px. */
@media (min-width: 901px) and (max-width: 1024px) {
  #sb .sb-lnk { padding: 6px 14px; font-size: 11px; }
  #sb .sb-sec { padding: 10px 14px 4px; font-size: 9px; }
}
#sb { overflow-y: auto; overscroll-behavior: contain; }
#sb::-webkit-scrollbar { width: 4px; }
#sb::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.15); border-radius: 2px; }

/* ═══════════════════════════════════════════════════════════════
   DigiSync — Phase 2B FIX (CSS additions)
   Onglets Administration + cleanup modales + form-grid utilitaires
   ═══════════════════════════════════════════════════════════════ */

/* Admin : barre d'onglets horizontaux */
.adm-tabs {
  display: flex; flex-wrap: wrap; gap: 4px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 16px;
  padding: 0 4px;
}
.adm-tab {
  background: transparent; border: 0; border-bottom: 2px solid transparent;
  padding: 10px 14px; font-size: 12px; font-weight: 500;
  color: var(--t3); cursor: pointer;
  font-family: inherit;
  transition: color .15s, border-color .15s;
}
.adm-tab:hover { color: var(--ds-blue); }
.adm-tab.on {
  color: var(--ds-blue);
  border-bottom-color: var(--ds-blue);
}
.adm-pane > [id^="p-"] { display: block !important; }

/* Form-grid utilitaires (à appliquer aux modales / formulaires) */
.form-grid { display: grid; grid-template-columns: 1fr; gap: 12px; }
@media (min-width: 640px) {
  .form-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
  .form-grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
}
.form-row { display: flex; gap: 12px; flex-wrap: wrap; }
.form-row > * { flex: 1; min-width: 0; }
.form-field { display: flex; flex-direction: column; gap: 4px; }
.form-field > label {
  font-size: 11px; font-weight: 500; color: var(--t3);
  text-transform: uppercase; letter-spacing: 0.3px;
}
.form-field input, .form-field textarea, .form-field select {
  width: 100%; box-sizing: border-box;
}

/* Modales — alignement uniforme (sans toucher au HTML existant) */
.mo .fg, .mo .form-field {
  display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px;
}
.mo .fg > label, .mo .form-field > label {
  font-size: 11px; font-weight: 500;
  color: var(--t3);
  text-transform: uppercase; letter-spacing: 0.3px;
}
.mo .fg > input, .mo .fg > select, .mo .fg > textarea,
.mo .form-field > input, .mo .form-field > select, .mo .form-field > textarea {
  width: 100%; box-sizing: border-box;
}
.mo .fr {
  display: grid; grid-template-columns: 1fr; gap: 10px; margin-bottom: 10px;
}
@media (min-width: 600px) {
  .mo .fr { grid-template-columns: 1fr 1fr; }
}
.mo-f {
  display: flex; gap: 8px; justify-content: flex-end;
  padding-top: 12px; flex-wrap: wrap;
}
.mo-f .btn-r { margin-right: auto; }

/* Mobile : modales pleine largeur, padding réduit */
@media (max-width: 640px) {
  .mo { width: 95vw !important; max-width: 95vw !important; }
  .mo-b { padding: 12px !important; }
  .mo-f { padding: 12px; }
  .adm-tabs { overflow-x: auto; flex-wrap: nowrap; }
  .adm-tab { white-space: nowrap; }
}

/* Les modules éteints sont retirés de la sidebar des non-admins par
   Router.itemVisible(), pas par le CSS : un display:none ici masquait aussi
   l'entrée grisée que l'administrateur doit garder pour aller la réactiver. */

/* ═══════════════════════════════════════════════════════════════
   DigiSync — Phase 2D : sous-menu vertical Calendrier (Outlook-style)
   ═══════════════════════════════════════════════════════════════ */
.cal-wrap {
  display: grid;
  grid-template-columns: 220px 1fr;
  gap: 16px;
  align-items: start;
}
.cal-aside {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px 8px;
  font-size: 12px;
  position: sticky;
  top: 12px;
  max-height: calc(100vh - 100px);
  overflow-y: auto;
}
.cal-aside-section {
  margin-bottom: 14px;
  padding-bottom: 10px;
  border-bottom: 1px dashed var(--border);
}
.cal-aside-section:last-child { border-bottom: 0; padding-bottom: 0; }
.cal-aside-h {
  font-size: 10px;
  text-transform: uppercase;
  font-weight: 600;
  letter-spacing: 0.5px;
  color: var(--t4);
  padding: 4px 8px 6px;
}
.cal-aside-item {
  padding: 6px 10px;
  border-radius: 5px;
  cursor: pointer;
  color: var(--t2);
  user-select: none;
  transition: background var(--t-fast), color var(--t-fast);
}
.cal-aside-item:hover { background: var(--hover); color: var(--blue); }
.cal-aside-item.on {
  background: var(--accent-solid);
  color: var(--on-accent);
  font-weight: 500;
}
.cal-aside-flt {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 8px;
  cursor: pointer;
  border-radius: 5px;
  font-size: 12px;
  color: var(--t2);
}
.cal-aside-flt:hover { background: var(--hover); }
.cal-aside-flt input { margin: 0; }
.cal-aside-dot {
  width: 10px; height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}
.cal-aside-btn {
  display: block;
  width: 100%;
  text-align: left;
  background: transparent;
  border: 1px solid var(--border);
  padding: 7px 10px;
  border-radius: 5px;
  font-size: 12px;
  cursor: pointer;
  color: var(--t2);
  margin-bottom: 4px;
  font-family: inherit;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}
.cal-aside-btn:hover {
  background: var(--accent-solid);
  color: var(--on-accent);
  border-color: var(--accent-solid);
}
.cal-aside-toggle { display: none; }


/* Responsive : sur mobile, la sidebar devient un drawer */
@media (max-width: 900px) {
  .cal-wrap { grid-template-columns: 1fr; }
  .cal-aside {
    position: fixed;
    top: calc(49px + env(safe-area-inset-top, 0px));
    left: -280px;
    width: min(80vw, 240px);
    height: calc(100vh - 49px);
    height: calc(100dvh - 49px - env(safe-area-inset-top, 0px));
    overflow-y: auto;
    overscroll-behavior: contain;
    max-height: none;
    z-index: 80;
    transition: left .25s ease;
    box-shadow: 2px 0 8px rgba(0,0,0,0.15);
  }
  .cal-aside.open { left: 0; }
  .cal-aside-toggle { display: inline-flex; align-items:center; justify-content:center; }
}

/* ═══════════════════════════════════════════════════════════════
   DigiSync — Boutons, badges, modales et champs
   ───────────────────────────────────────────────────────────────
   Définition UNIQUE. Ces composants étaient redéfinis quatre fois de
   suite (« fix 2 », « fix 3 », « final pass », « final fix v3 »,
   « badges sober »), chaque passe rejouant ses propres hex et sa
   propre rustine sombre. Conséquences supprimées ici :

     · les badges .bb/.by/.br/.bp/.bg/.bin étaient posés en clair avec
       !important, alors que leur contrepartie sombre ne l'était pas :
       en thème sombre TOUS les badges sauf .bgr restaient des pastilles
       pâles sur fond foncé ;
     · trois palettes de modale coexistaient (#1e293b pour la boîte,
       #0f172a pour ses champs) sans rapport avec --card : une modale
       n'appartenait pas au même thème que la page derrière elle ;
     · .btn-p était figé sur #1470be, donc insensible à la couleur de
       marque configurée dans Administration > Général.

   Le rendu du THÈME CLAIR est celui de la dernière passe, à l'identique ;
   seule la source des valeurs change (jetons au lieu d'hex). Le thème
   sombre en découle sans une seule règle .theme-dark.
   ═══════════════════════════════════════════════════════════════ */

/* ── Boutons ─────────────────────────────────────────────────────
   Deux familles :
     PLEIN    (.btn-p, .btn-gr, .btn-r, .btn-y) — fond soutenu sous du
              blanc. Le fond vient d'un jeton --*-solid, jamais de
              --blue/--green/… : en thème sombre ces derniers sont les
              teintes ÉCLAIRCIES, faites pour du texte, sous lesquelles
              le blanc tomberait sous le seuil AA.
     CONTOUR  (.btn-o, .btn-g, .btn-in) — bordure discrète, texte
              accentué, remplissage léger au survol.
   Le survol APPROFONDIT toujours le remplissage, dans les deux thèmes :
   l'éclaircir en sombre dégraderait le contraste du libellé. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border: 1px solid transparent;
  /* rounded-md du site (.375rem) : son rayon dominant. */
  border-radius: 6px;
  padding: 7px 14px;
  min-height: 30px;
  font-size: 12px;
  font-family: inherit;
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: 0;
  text-shadow: none;
  box-shadow: none;
  cursor: pointer;
  transition: background var(--t-fast), border-color var(--t-fast),
              color var(--t-fast), box-shadow var(--t-fast);
  white-space: nowrap;
  user-select: none;
}
/* Désactivé : l'opacité seule ne suffit pas à l'annoncer — le curseur
   barré porte l'information indépendamment de la couleur. */
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
.btn:focus-visible { outline: 2px solid var(--ds-violet); outline-offset: 1px; }

.btn-sm   { padding: 5px 10px; min-height: 26px; font-size: 11px; }
.btn-xs   { padding: 3px 8px;  min-height: 22px; font-size: 10px; }
.btn-full { width: 100%; }

/* Primaire — suit la couleur de marque configurée. */
.btn-p { background: var(--accent-solid); color: var(--on-accent); border-color: var(--accent-solid); }
.btn-p:hover:not(:disabled) { background: var(--accent-solid-h); border-color: var(--accent-solid-h); }

/* Secondaire au contour — surface de carte, texte accentué. */
.btn-o { background: var(--btn-soft); color: var(--blue-fg); border-color: var(--border-strong); }
.btn-o:hover:not(:disabled) { background: var(--btn-soft-h); border-color: var(--blue); }

/* Neutre (Annuler, Fermer) — pas de remplissage au repos. */
.btn-g { background: transparent; color: var(--t2); border-color: var(--border-strong); }
.btn-g:hover:not(:disabled) { background: var(--hover); color: var(--t1); }

/* Actions métier : TEINTÉES, pas pleines.
   Une seule action remplie par écran — la principale. Une rangée de
   boutons pleins vert / rouge / ambre fait « maquette » plutôt qu'outil
   de gestion, et digisync.fr ne remplit qu'en bleu. Le fond léger, la
   bordure et le texte portent la famille métier ; le survol renforce la
   teinte au lieu de changer de nature.
   .btn-danger (main.css) reste PLEIN : il est réservé à la confirmation
   d'un acte irréversible, où l'insistance est justifiée. */
.btn-gr { background: var(--gl); color: var(--green-fg);  border-color: var(--gb); }
.btn-gr:hover:not(:disabled) { background: var(--gb); border-color: var(--green); }

.btn-r  { background: var(--rl); color: var(--red-fg);    border-color: var(--rb); }
.btn-r:hover:not(:disabled)  { background: var(--rb); border-color: var(--red); }

.btn-y  { background: var(--al); color: var(--amber-fg);  border-color: var(--ab); }
.btn-y:hover:not(:disabled)  { background: var(--ab); border-color: var(--amber); }

/* Accent secondaire (verrouiller, actions mineures) — violet au contour. */
.btn-in { background: var(--btn-soft); color: var(--purple-fg); border-color: var(--pb); }
.btn-in:hover:not(:disabled) { background: var(--pl); border-color: var(--purple); }

/* ── Badges ──────────────────────────────────────────────────────
   Les COULEURS vivent dans main.css (.bg/.bb/.bgr/.br/.by/.bp/.bin/.bt),
   dérivées des triplets --Xl / --X / --Xb : elles basculent donc seules.
   On ne garde ici que la FORME retenue par la dernière passe — étiquette
   plutôt que pastille.
   .bgr redevient vert : c'est le badge de succès du produit (Terminé,
   Validé, Payée, Actif, Confirmé…). Une passe l'avait repeint en bleu
   marine, ce qui le rendait indiscernable de .bb (« En cours »), soit
   deux états opposés au même rendu. */
.b {
  padding: 3px 9px;
  border-radius: 10px;
  font-size: 11px;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: 0.01em;
}

/* ── Modales ─────────────────────────────────────────────────────
   Niveau 3 de l'échelle de profondeur : la boîte est plus claire que la
   page, son pied plus sombre qu'elle, ses champs en creux. Aucun
   !important — les valeurs claires en dur qui en imposaient un ont
   disparu. */
.ov { background: var(--ov-bg); }
.mo {
  background: var(--elev);
  color: var(--t1);
  border: 1px solid var(--border);
  border-radius: var(--r);
  box-shadow: var(--sh-3);
}
.mo-h, .mo-b, .mo-f { color: var(--t1); }
.mo-h { border-bottom: 1px solid var(--border); }
.mo-f { border-top: 1px solid var(--border); background: var(--card-sub); padding: 12px 16px; }
.mo .mo-t { color: var(--t1); font-weight: 600; font-size: 14px; }
.mo .mo-x {
  background: transparent; border: 0; cursor: pointer;
  color: var(--t3); font-size: 18px; padding: 4px 8px;
  border-radius: 4px;
  transition: background var(--t-fast), color var(--t-fast);
}
.mo .mo-x:hover { background: var(--hover); color: var(--t1); }

/* Champs de modale. Les cases à cocher et boutons radio sont exclus :
   ils ne prennent ni la largeur pleine ni le fond des champs texte. */
.mo .fc,
.mo input.fc,
.mo select.fc,
.mo textarea.fc,
.mo input[type="text"],
.mo input[type="email"],
.mo input[type="number"],
.mo input[type="date"],
.mo input[type="time"],
.mo input[type="datetime-local"],
.mo input[type="password"],
.mo input[type="search"],
.mo textarea,
.mo select {
  background: var(--input-bg);
  color: var(--t1);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 7px 10px;
  font-family: inherit;
  font-size: 12px;
  width: 100%;
  box-sizing: border-box;
}
.mo .fc:focus, .mo input:focus, .mo select:focus, .mo textarea:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: var(--ring);
}
.mo label { color: var(--t3); font-size: 11px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.3px; }

/* ── Champs hors modale ──────────────────────────────────────────
   Pour les pages qui rendent directement dans .cb. Mêmes dimensions
   que dans une modale, même fond en creux. */
.fc, .cb input.fc, .cb select.fc, .cb textarea.fc {
  background: var(--input-bg);
  color: var(--t1);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 6px 10px;
  font-family: inherit;
  font-size: 12px;
}

/* Cases à cocher et boutons radio : une seule ligne suffit à les faire
   suivre le thème et la marque, au lieu de rester bleu système. */
input[type="checkbox"], input[type="radio"] { accent-color: var(--blue); }

/* ── Zone de graphique ───────────────────────────────────────────
   La hauteur est portée par le CONTENEUR, jamais par le canvas.

   Chart.js en « maintainAspectRatio: false » mesure la hauteur de son
   parent pour se dimensionner. Tant que le canvas était enfant direct
   de .cb, c'est LUI qui donnait sa hauteur à ce parent : chaque
   redessin renvoyait une mesure légèrement différente et le graphique
   oscillait. Le survol déclenchant un redessin (infobulle), le
   tremblement s'y voyait surtout.

   La règle précédente imposait « height: auto !important » à tout
   canvas — soit exactement cette boucle, puisqu'elle annulait la
   hauteur que Chart.js venait de calculer. */
.chart-box {
  position: relative;
  width: 100%;
  height: 220px;
}
.chart-box > canvas {
  display: block;
  width: 100% !important;
  height: 100% !important;
}
/* Secteurs : bornés et centrés dans leur carte. */
.chart-box-donut {
  height: 200px;
  max-width: 280px;
  margin: 0 auto;
}

/* Filet de sécurité pour un canvas ajouté sans .chart-box : on borne
   la largeur, jamais la hauteur — la borner est ce qui déclenchait la
   boucle. */
.cb canvas { max-width: 100%; }

/* Container des charts : empêcher l'overflow horizontal */
.dashboard-grid,
.dash-charts,
.g2,
.g3 {
  max-width: 100%;
  overflow: hidden;
}

/* Mobile : graphiques plus courts. C'est le CONTENEUR qu'on réduit, pas
   le canvas — plafonner la hauteur du canvas rouvrait la boucle. */
@media (max-width: 768px) {
  .chart-box { height: 180px; }
  .chart-box-donut { height: 170px; }
  .g2, .g3 {
    grid-template-columns: 1fr !important;
    gap: 12px;
  }
}


/* ── POLISH UI START ── */
/* Labels stackés au-dessus dans formulaires ET modales (.mo-b) */
form label, .cb form label, .cb > label,
.mo-b > label,
.mo-b > div > label,
.mo-b > div > div > label {
  display: block;
  margin-bottom: 14px;
  font-size: 12px;
  color: var(--t3);
  font-weight: 500;
}
form label > .inp, form label > input:not([type="checkbox"]):not([type="radio"]),
form label > select, form label > textarea,
.cb form label > input:not([type="checkbox"]):not([type="radio"]),
.cb form label > select, .cb form label > textarea,
.mo-b label > .inp,
.mo-b label > input:not([type="checkbox"]):not([type="radio"]),
.mo-b label > select,
.mo-b label > textarea {
  display: block;
  width: 100%;
  margin-top: 6px;
  padding: 7px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  /* --input-bg, pas --bg : le fond de PAGE donnait un champ qui se
     confondait avec la carte en clair et flottait au mauvais niveau en
     sombre. C'est aussi ce qui obligeait les modales à repasser en
     !important par-dessus. */
  background: var(--input-bg);
  font-size: 13px;
  font-family: inherit;
  color: var(--t1);
}

.mo-b > .g2, .mo-b > .g3,
.cb > .g2, .cb > .g3,
form .g2, form .g3 {
  display: grid;
  gap: 14px;
  margin-bottom: 14px;
}
.mo-b > .g2, .cb > .g2, form .g2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.mo-b > .g3, .cb > .g3, form .g3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 800px) {
  .mo-b > .g2, .mo-b > .g3, .cb > .g2, .cb > .g3, form .g2, form .g3 { grid-template-columns: 1fr; }
}

form label.chk, .cb label.chk, .mo-b label.chk {
  display: flex !important;
  align-items: center;
  gap: 8px;
  margin-bottom: 14px;
  font-size: 13px;
}
form label.chk > input, .cb label.chk > input, .mo-b label.chk > input {
  width: auto !important;
  margin: 0 !important;
}

input[type="file"] {
  padding: 6px;
  font-size: 12px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--input-bg);
  cursor: pointer;
  font-family: inherit;
  color: var(--t2);
}
input[type="file"]::file-selector-button {
  padding: 5px 12px;
  margin-right: 10px;
  background: var(--accent-solid);
  color: var(--on-accent);
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 11px;
  font-weight: 500;
  font-family: inherit;
  transition: background var(--t-fast);
}
input[type="file"]::file-selector-button:hover { background: var(--accent-solid-h); }

.wk-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
.wk-chip {
  display: inline-flex !important;
  align-items: center; gap: 6px;
  padding: 6px 10px;
  background: var(--card-sub);
  border: 1px solid var(--border);
  border-radius: 14px;
  font-size: 12px;
  margin: 0 !important;
  cursor: pointer;
  transition: all 0.15s;
}
.wk-chip:hover { background: var(--hover); border-color: var(--border-strong); }
.wk-chip > input[type="checkbox"] { margin: 0 !important; width: auto !important; }
/* Sélectionné : fond teinté + bordure accentuée + graisse — trois indices,
   la couleur n'est pas seule à porter l'état. */
.wk-chip:has(input:checked) { background: var(--bl); border-color: var(--blue); color: var(--blue-fg); font-weight: 500; }

.card .cb { padding: 16px; }
.card .ch { padding: 12px 16px; }
.mo-b h4 { margin: 18px 0 10px 0; font-size: 13px; font-weight: 600; color: var(--t2); }
.mo-b h4:first-child { margin-top: 0; }
/* ── POLISH UI END ── */


/* ── Classes de composants manquantes (audit 11/06/2026) ────────────────────
   Utilisées par les pages JS mais jamais définies. Les utilitaires génériques
   (marges, alignement, .h2/.lb/.pgld/.page-wrap) vivent dans la section
   « Utility » de main.css avec leurs pairs. */

/* En-tête de page (titre + sous-titre) */
.ph  { margin: 4px 0 16px; }
.pt  { margin: 0; font-size: 20px; font-weight: 600; color: var(--t1); }
.pst { margin-top: 2px; font-size: 12.5px; color: var(--t4); }

/* Slot droit d'un en-tête de carte (.ch > .cl + .chr) */
.chr { display: flex; align-items: center; gap: 8px; margin-left: auto; }

/* Paires label/valeur compactes (statut WHMCS, etc.) */
.t3 { font-size: 11px; color: var(--t4); }
.t2 { font-size: 13px; font-weight: 600; color: var(--t1); }

/* Colonne principale du calendrier — sans min-width:0 le contenu (tables)
   fait déborder la grille .cal-wrap */
.cal-main { min-width: 0; }

/* Lignes audit en vue mobile (planning.js → #audit-mob) */
.audit-mob-date   { font-size: 11px; }
.audit-mob-user   { font-size: 12px; font-weight: 600; margin-top: 2px; }
.audit-mob-row    { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 4px; }
.audit-mob-detail { font-size: 11px; }

/* Nom du collaborateur dans l'historique de stock (cartes de visite) */
.stock-m-user { font-size: 11.5px; color: var(--t2); text-align: right; }

/* ── PARAMÈTRES DE STOCKAGE (modèle WHMCS) START ──────────────────────────── */
/* .sto-tabs affine .set-tabs (main strip d'onglets) — pas de doublon. */
.set-tabs.sto-tabs { gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: 14px; }

/* Bandeau d'information — jetons --bl/--blue/--bd, qui basculent seuls en
   thème sombre (aucune règle .theme-dark nécessaire). */
.sto-info {
  display: flex; align-items: center; gap: 10px;
  background: var(--bl);
  border: 1px solid var(--bll);
  color: var(--blue-fg);
  border-radius: var(--r); padding: 10px 14px;
  font-size: 12.5px; line-height: 1.5; margin-bottom: 14px;
}
.sto-info::before { content: 'ℹ'; font-size: 16px; flex-shrink: 0; }

.sto-rows { border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; }
.sto-row {
  display: grid; grid-template-columns: minmax(180px, 280px) 1fr;
  align-items: center; gap: 14px; padding: 9px 14px;
}
.sto-row:nth-child(odd) { background: var(--card-sub); }
.sto-row-lbl { font-size: 12.5px; font-weight: 500; color: var(--t2); text-align: right; }
.sto-row .fc { max-width: 460px; font-size: 12.5px; }
@media (max-width: 700px) {
  .sto-row { grid-template-columns: 1fr; gap: 4px; }
  .sto-row-lbl { text-align: left; }
}

.sto-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 12px; }
.sto-card { border: 1px solid var(--border); border-radius: 8px; overflow: hidden; background: var(--card); }
.sto-card-h {
  display: flex; align-items: center; justify-content: space-between;
  padding: 8px 12px; font-size: 12.5px; font-weight: 600; color: var(--t1);
  background: var(--card-sub); border-bottom: 1px solid var(--border);
}
.sto-card-acts { display: flex; gap: 2px; }
.sto-card-b { display: flex; align-items: center; gap: 12px; padding: 14px 12px; color: var(--t2); }
.sto-path {
  display: block; font-size: 11.5px; color: var(--t2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;
}
.sto-used { margin-top: 6px; display: flex; flex-wrap: wrap; gap: 4px; }
.sto-card-new { border-style: dashed; }
.sto-card-new .sto-card-b { justify-content: flex-start; }

.sto-mig {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 12px; padding: 6px 0; border-bottom: 1px dashed var(--border);
}
.sto-mig:last-child { border-bottom: none; }
.sto-mig-role { font-weight: 600; color: var(--t2); }
.sto-mig-path { font-size: 11px; color: var(--t4); overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
/* ── PARAMÈTRES DE STOCKAGE END ── */

/* ── PROSPECTION ─────────────────────────────────────────────
   Réutilise les composants existants (.card, .kpi, .tw, .b, .stabs) ;
   on ne décrit ici que la barre de filtres, la ligne cliquable et la
   frise des relances. */
.pros-filters {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 8px; margin-bottom: 12px;
}
.pros-filters .inp { width: 100%; min-width: 0; }

.pros-row { cursor: pointer; }
.pros-owner { display: inline-flex; align-items: center; gap: 6px; }
.pros-comment { color: var(--t3); font-size: 12px; }

/* Fournisseurs — regroupement fournisseur › contrat › services.
   Chaque information n'est écrite qu'au niveau où elle est vraie : le nom du
   fournisseur une fois par groupe, le contrat une fois au-dessus de ses
   services. Le tableau imbriqué reste celui de l'application, aucune refonte
   graphique : mêmes cartes, mêmes badges, mêmes boutons. */
.sup-grp { border: 1px solid var(--border); border-radius: var(--r); margin-bottom: 12px; overflow: hidden; }
.sup-grp-h {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 9px 12px; background: var(--bg2, rgba(127,127,127,.06));
  cursor: pointer; user-select: none; font-size: 13px;
}
.sup-grp-h:hover { background: var(--bg1, rgba(127,127,127,.1)); }
.sup-grp-caret { color: var(--t3); width: 12px; display: inline-block; }
.sup-grp-meta { margin-left: auto; font-size: 11px; color: var(--t3); }
.sup-grp-b { padding: 8px 12px 12px; }
.sup-ct { border-left: 3px solid var(--blue); padding-left: 10px; margin: 10px 0 14px; }
.sup-ct:last-child { margin-bottom: 4px; }
.sup-ct-h { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 6px; font-size: 12.5px; }
.sup-ct-title code { font-size: 11px; color: var(--t3); margin-left: 5px; }
.sup-ct-meta { font-size: 11px; color: var(--t3); }
.sup-ct-h .btn { margin-left: auto; }
.sup-ct tfoot td { font-size: 11.5px; color: var(--t3); border-top: 1px solid var(--border); }

/* Barre de pagination partagée (core/pager.js) — Comptabilité, Prospection… */
.ds-pager, .pros-pager {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; flex-wrap: wrap; margin-top: 12px; font-size: 12px;
}
.ds-pager-info { color: var(--t3); }
/* Barre du haut : collée au tableau qu'elle commande, sans le sélecteur de
   taille (celui du bas suffit — deux menus identiques n'apportent rien). */
.ds-pager-top { margin-top: 0; margin-bottom: 8px; }
.ds-pager-btns, .pros-pager-btns { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.ds-pager-btns .btn { min-width: 28px; padding: 3px 8px; }
/* « ‹ [n] / N › » : les deux flèches encadrent le numéro de page. Le numéro est
   un champ pour pouvoir sauter directement, sans enchaîner les clics. */
.ds-pager-jump { display: inline-flex; align-items: center; gap: 4px; margin: 0 2px; }
.ds-pager-num {
  width: 46px; text-align: center;
  padding: 3px 4px; font-size: 12px;
  border: 1px solid var(--border); border-radius: var(--r);
  background: var(--card); color: var(--t1);
}
.ds-pager-num:focus { outline: none; border-color: var(--blue); }
/* Les flèches de réglage natives volent la place du chiffre. */
.ds-pager-num::-webkit-outer-spin-button,
.ds-pager-num::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.ds-pager-num { -moz-appearance: textfield; appearance: textfield; }
.ds-pager-total { color: var(--t3); font-size: 12px; }
.ds-pager-size { display: inline-flex; align-items: center; gap: 5px; color: var(--t3); margin-right: 8px; }
.ds-pager-size .fc { width: auto; padding: 3px 6px; font-size: 12px; }

/* En-têtes triés côté serveur : le clic redemande la page, il ne réordonne
   pas les lignes déjà affichées. */
th.ds-sortable { cursor: pointer; user-select: none; white-space: nowrap; }
th.ds-sortable:hover { color: var(--blue); }
th.ds-sorted { color: var(--blue); }
.ds-sort-arw { font-size: 9px; }

/* Bandeau de filtres serveur : une ligne compacte au-dessus du tableau. */
.ds-filters {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  margin-bottom: 10px;
}
.ds-filters .fc { font-size: 12px; padding: 5px 7px; width: auto; min-width: 0; }
.ds-filters .ds-f-search { min-width: 190px; flex: 1 1 190px; }
.ds-filters .ds-f-sep { flex-basis: 100%; height: 0; }

.pros-row-info {
  display: grid; grid-template-columns: minmax(140px, 190px) 1fr;
  gap: 12px; align-items: baseline;
  padding: 7px 0; border-bottom: 1px dashed var(--border); font-size: 13px;
}
.pros-row-info:last-child { border-bottom: none; }
.pros-row-lbl { font-size: 11.5px; font-weight: 600; color: var(--t3); }
.pros-note { white-space: pre-wrap; line-height: 1.55; }

.pros-timeline { display: flex; flex-direction: column; gap: 10px; }

/* Une relance PRÉVUE se distingue au premier coup d'œil d'une relance
   effectuée : bordure ambre quand elle approche, rouge quand l'échéance est
   passée, grisée quand elle a été annulée. Le retard n'est pas un statut
   enregistré — il se déduit de la date, côté serveur, à la lecture. */
.pros-fu-late { border-left-color: var(--red); }
.pros-fu-cancelled { opacity: .6; border-left-color: var(--t4); }
.pros-fu-acts { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
.pros-fu {
  border: 1px solid var(--border); border-left: 3px solid var(--blue);
  border-radius: var(--r); padding: 9px 12px; background: var(--card);
}
.pros-fu-h {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: 12px; color: var(--t2);
}
.pros-fu-date { font-weight: 600; color: var(--t1); }
.pros-fu-who  { font-weight: 500; }
.pros-fu-sep  { color: var(--t4); }
.pros-fu-body { margin-top: 6px; font-size: 12.5px; color: var(--t2); line-height: 1.55; white-space: pre-wrap; }
.pros-fu-next { margin-top: 6px; font-size: 11.5px; color: var(--t4); }

@media (max-width: 700px) {
  .pros-filters { grid-template-columns: 1fr; }
  .pros-row-info { grid-template-columns: 1fr; gap: 2px; }
}
/* ── PROSPECTION END ── */
/* ═══════════════════════════════════════════════════════════════
   DigiSync — Menus & PWA mobile
   Placé en fin de fichier : ces règles doivent gagner la cascade sur les
   blocs responsive historiques déclarés plus haut.
   ═══════════════════════════════════════════════════════════════ */

/* Barres d'onglets : elles débordaient en largeur téléphone au lieu de
   défiler, rendant les derniers onglets inatteignables. */
@media (max-width: 900px) {
  .adm-tabs, .set-tabs, .sto-tabs, .stabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .adm-tabs::-webkit-scrollbar,
  .set-tabs::-webkit-scrollbar,
  .sto-tabs::-webkit-scrollbar,
  .stabs::-webkit-scrollbar { height: 0; }
  .adm-tab, .set-tab, .stab { white-space: nowrap; flex: 0 0 auto; min-height: 38px; }
}

/* Modales : 92vh laissait le pied (boutons Enregistrer/Annuler) sous la
   barre d'URL mobile. dvh + marge d'encoche. */
.mo { max-height: min(92vh, calc(100dvh - 24px)); }
@media (max-width: 640px) {
  .ov { padding: 12px; }
  .mo { max-height: calc(100dvh - 24px); }
  .mo-f { padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px)); }
  .mo-f .btn { min-height: 40px; }
}

/* Zone de page : le dernier bloc passait sous la barre système en PWA. */
@media (max-width: 900px) {
  #pa { padding-bottom: calc(18px + env(safe-area-inset-bottom, 0px)); }
}

/* Topbar : respecter l'encoche quand la PWA est en plein écran. */
@supports (padding: env(safe-area-inset-top)) {
  @media (max-width: 900px) {
    .topbar { padding-top: env(safe-area-inset-top, 0px); height: auto; min-height: 49px; }
  }
}

/* ═══════════════════════════════════════════════════════════════
   DigiSync — Sidebar : sections dépliables + favoris
   ═══════════════════════════════════════════════════════════════ */

/* En-tête de section : c'est désormais un <button>, on neutralise les
   styles natifs pour retomber exactement sur le rendu de .sb-sec. */
#sb .sb-sec-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  width: 100%;
  background: none;
  border: 0;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}
#sb .sb-sec-btn:hover { color: rgba(255,255,255,0.8); }
#sb .sb-chev {
  flex-shrink: 0;
  opacity: 0.6;
  transition: transform .15s ease;
}
#sb .sb-sec-btn[aria-expanded="false"] .sb-chev { transform: rotate(-90deg); }
#sb .sb-grp[hidden] { display: none; }

/* Étoile de favori : discrète au repos, révélée au survol du lien.
   Sur écran tactile (aucun survol possible) elle reste visible. */
#sb .sb-fav {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 16px;
  margin-right: -4px;
  padding: 0;
  border: 0;
  border-radius: 4px;
  background: none;
  color: rgba(255,255,255,0.55);
  cursor: pointer;
  opacity: 0;
  transition: opacity .12s, color .12s, background .12s;
}
#sb .sb-fav svg { fill: none; }
#sb .sb-fav.on { opacity: 1; color: var(--fav); }
#sb .sb-fav.on svg { fill: var(--fav); }
#sb .sb-fav:hover { background: rgba(255,255,255,0.12); color: var(--fav); }
#sb .sb-lnk:hover .sb-fav,
#sb .sb-lnk:focus-within .sb-fav,
#sb .sb-fav:focus-visible { opacity: 1; }

/* Sans survol (téléphone, tablette tactile) : l'étoile doit rester
   atteignable, sinon la mise en favori serait impossible au doigt. */
@media (hover: none) {
  #sb .sb-fav { opacity: 1; width: 28px; height: 28px; }
}

/* Le compteur poussait l'étoile hors du lien : c'est le libellé qui
   absorbe l'espace restant. */
#sb .sb-cnt { margin-left: 0; flex-shrink: 0; }

/* ── Favoris : réorganisation au glisser-déposer ─────────────── */
#sb #nav-fav-items .sb-lnk {
  cursor: grab;
  -webkit-touch-callout: none;
}
#sb #nav-fav-items .sb-lnk.sb-drag {
  cursor: grabbing;
  opacity: .7;
  background: rgba(255,255,255,.14);
  box-shadow: 0 4px 14px rgba(0,0,0,.35);
}
/* Pendant le tri, aucune transition ne doit retarder le réagencement. */
#sb .sb-sorting .sb-lnk { transition: none; }

/* En-tête « Favoris » : l'étoile le distingue des autres sections, dont il
   garde par ailleurs exactement la mise en forme. */
#sb .sb-sec-lbl { display: inline-flex; align-items: center; gap: 7px; min-width: 0; }
#sb .sb-sec-ico { flex-shrink: 0; fill: var(--fav); color: var(--fav); }
/* ── Compteur de caractères des champs de saisie libre ───────
   Inséré par js/core/textlimit.js juste APRÈS le champ, en frère : input et
   textarea gardent leur place dans le DOM, sinon les sélecteurs
   « label > input » de la charte cesseraient de s'appliquer.

   height: 0 / overflow: visible — le compteur ne prend AUCUNE hauteur et se
   dessine dans la gouttière déjà réservée sous le champ (margin-bottom des
   labels, gap des grilles .g2/.g3). Sans cela, ajouter une ligne sous chaque
   champ décalerait la mise en page de tous les formulaires de l'application.

   Masqué par défaut, révélé par .tl-show (focus, approche ou dépassement de la
   limite) : affiché en permanence, il transformerait le moindre formulaire en
   mur de chiffres. */
.tl-c {
  display: block;
  width: 100%;
  height: 0;
  overflow: visible;
  position: relative;
  top: 2px;
  text-align: right;
  font-size: 10.5px;
  line-height: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--t4);
  /* Le compteur ne doit jamais intercepter un clic destiné au champ. */
  pointer-events: none;
  opacity: 0;
  transition: opacity .12s ease;
}
/* Parent qui distribue ses enfants (rangée flex, grille) : le compteur y serait
   un ITEM de plus et volerait sa place au champ — mesuré, un textarea en
   `flex:1` tombait de 620 px à 22 px. En position absolue il n'est plus un item
   du tout : la rangée se dispose exactement comme avant lui, et le compteur va
   se ranger juste en dessous, à droite. `.tl-host` n'est posé que sur un parent
   sans ancrage, pour ne pas déplacer celui qu'il avait déjà. */
.tl-host { position: relative; }
.tl-c.tl-out {
  position: absolute;
  top: 100%;
  right: 0;
  width: auto;
  height: auto;
  margin-top: 0;
}

.tl-c.tl-show { opacity: 1; }
.tl-c.tl-warn { color: var(--amber); }
.tl-c.tl-over { color: var(--red); font-weight: 600; }

/* Un texte enregistré AVANT que la limite ne soit abaissée dépasse le seuil
   sans que l'utilisateur y soit pour rien : le champ est signalé, jamais
   tronqué ni bloqué — il reste modifiable pour être raccourci.
   :has() faute de sélecteur de frère précédent en CSS, le compteur étant placé
   après le champ. */
input:has(+ .tl-c.tl-over),
textarea:has(+ .tl-c.tl-over) { border-color: var(--red); }


/* ═══ Maintenances & incidents ═══════════════════════════════════════════
   Deux composants seulement : la grille de cases à cocher du formulaire
   (services et équipements, potentiellement des dizaines) et la ligne de
   signal détecté. Tout le reste réutilise .card / .tw / .stabs / .b.

   Jetons : la grille est un élément INTERNE à une carte ou à une modale, elle
   prend donc --card-sub et jamais --bg (cf. docs/THEME.md, échelle de
   profondeur). Aucun repli en dur : une valeur littérale ici rouvrirait la
   strate que le refactor des jetons vient de refermer. */

.ops-chk {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 2px 12px;
  max-height: 190px;
  overflow-y: auto;
  padding: 8px;
  border: 1px solid var(--border);
  border-radius: var(--r, 6px);
  background: var(--card-sub);
}
.ops-chk label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  font-weight: 400;
  color: var(--t2);
  margin: 0;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ops-chk input { flex: 0 0 auto; margin: 0; }

/* Barre au-dessus du tableau unique : le résumé à gauche, l'interrupteur
   d'archives à droite. Elle remplace la rangée d'onglets. */
.ops-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 0 0 8px;
  font-size: 12.5px;
}
.ops-switch {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  font-weight: 400;
  color: var(--t2);
  cursor: pointer;
  margin: 0;
  white-space: nowrap;
}
.ops-switch input { margin: 0; cursor: pointer; }

.ops-signal {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 5px 0;
  border-bottom: 1px solid var(--b2);
}
.ops-signal:last-child { border-bottom: none; }

/* Dans une modale, `.mo label` met en capitales tout ce qu'il contient. C'est
   juste pour un intitulé de champ, jamais pour du CONTENU : un nom d'hôte doit
   se lire tel qu'il est, et un aperçu de message tel qu'il sera publié — sans
   quoi l'aperçu ment sur ce que le client va voir. */
.mo .ops-chk label,
.mo .ops-value,
.mo .ops-pre {
  text-transform: none;
  letter-spacing: normal;
}
.mo .ops-chk label {
  font-size: 12.5px;
  color: var(--t2);
}

@media (max-width: 640px) {
  .ops-chk { grid-template-columns: 1fr; max-height: 240px; }
  /* Les boutons d'un signal passent sous son libellé plutôt que de le
     comprimer : « Créer un incident » doit rester lisible en entier. */
  .ops-signal { align-items: flex-start; }
  .ops-signal > span[style] { flex-basis: 100%; }
}
