/* ═══════════════════════════════════════════════════════════════════════════
   console.css — Feuille de style de la console de parrainage Fun City.

   La première partie est la feuille du PROTOTYPE VALIDÉ, reprise caractère
   pour caractère : mêmes variables, mêmes dimensions, mêmes points de rupture.
   Ne rien y modifier — c'est elle qui garantit que chaque vue s'affiche au
   millimètre près comme la maquette approuvée.

   La seconde partie, clairement séparée, n'ajoute que les composants absents
   du prototype (messages, dialogues, pagination, journal des messages).
   ═══════════════════════════════════════════════════════════════════════════ */

:root{
  --blue:#005CA9; --blue-700:#0a4d8c; --blue-050:#EAF2FB;
  --purple:#A863A5; --purple-700:#8b4d88; --purple-050:#F6EDF5;
  --ink:#182031; --slate:#586274; --slate-400:#8a93a2;
  --line:#E7EAF1; --line-2:#EEF1F6;
  --canvas:#F4F6FA; --surface:#FFFFFF;
  --ok:#1F9E6B; --ok-bg:#E7F5EE;
  --warn:#B27A18; --warn-bg:#FAF0DC;
  --info:#1E6FB8; --info-bg:#E7F1FB;
  --mut:#6B7382; --mut-bg:#EEF0F5;
  --r:16px; --r-sm:10px; --r-xs:8px; --pill:999px;
  --sh:0 1px 2px rgba(20,30,50,.04), 0 10px 30px rgba(20,30,50,.05);
  --sh-sm:0 1px 2px rgba(20,30,50,.05);
  --gap:24px;
  /* Tonalités nommées : chaque couleur en dur de la feuille y est rattachée,
     le thème sombre ci-dessous n'a plus qu'à les redéfinir. */
  --danger:#c0503f; --line-strong:#ccd4e1; --mark:#9aa3b2; --soft:#c3c9d3;
  --ok-bd:#cdeadd; --ok-tx:#125c3f; --ok-bg2:#ECFDF3; --ok-bd2:#A6E9C5; --ok-tx2:#14532D;
  --err-bg:#FBECEA; --err-bd:#F0CFC9; --err-tx:#8d3327;
  --err-bg2:#FEF1F0; --err-bd2:#F3B8B3; --err-tx2:#7A271A;
  --warn-bd:#EEDDB4; --warn-tx:#7a5310; --warn-bg2:#FFFBEB; --warn-bd2:#F5DC9A;
  --warn-tx2:#713F12; --warn-bg3:#FFFDF8;
  --info-bd:#d3e4f5; --info-tx:#123f66; --info-bg2:#EFF6FF; --info-bd2:#BFDBFE;
  --info-tx2:#1E3A5F; --info-bd3:#c9ddf2; --info-tx3:#1a4a7a;
  --purple-bd:#e6cfe4; --purple-bd2:#EADCE9; --purple-tx:#5f2e5c;
  --row-hover:#fbfcfe; --ghost-hover:#fcfdff; --canvas-2:#EDEFF4; --tick:#2f9bd8;
  --link:#005CA9;
  /* Infobulle calendrier : sombre assumée dans les deux thèmes (lisible
     sur fond clair comme sur fond sombre). */
  --tip-bg:#182031; --tip-tx:#ffffff; --tip-mut:#c9d2e0;
  --sel-bg:#182031; --sel-tx:#ffffff;
  color-scheme:light;
}
/* ═══════════════════════════════════════════════════════════════════════════
   Thème sombre NATIF (pas d'inversion) : fonds bleu nuit, encres claires,
   pastilles conservées mais adoucies, bleu de marque gardé en remplissage.
   Activé par data-theme="dark" sur <html> (bascule manuelle ou système).
   ═══════════════════════════════════════════════════════════════════════════ */
[data-theme="dark"]{
  color-scheme:dark;
  --canvas:#0E1322; --surface:#161D31; --canvas-2:#101729;
  --line:#2A3550; --line-2:#202945; --line-strong:#3B4A6E;
  --ink:#E9EEF7; --slate:#A9B3C7; --slate-400:#7E8AA3;
  --mark:#4C5A7D; --soft:#66708A;
  --blue:#2E7CC4; --blue-700:#2E7CC4; --blue-050:#13273F;
  --purple:#A86BB0; --purple-700:#C99BD0; --purple-050:#241E38;
  --purple-bd:#4C3766; --purple-bd2:#423058; --purple-tx:#D6AEE2;
  --ok:#3BC88B; --ok-bg:#0F2E24; --ok-bd:#1E5C40; --ok-tx:#82D9AB;
  --ok-bg2:#0D2A20; --ok-bd2:#1E5C40; --ok-tx2:#82D9AB;
  --warn:#DFA83E; --warn-bg:#33270C; --warn-bd:#6E5416; --warn-tx:#EDC87E;
  --warn-bg2:#2E230B; --warn-bd2:#6E5416; --warn-tx2:#EDC87E; --warn-bg3:#2A2009;
  --err-bg:#331916; --err-bd:#6E2F28; --err-tx:#EFA79D;
  --err-bg2:#2E1512; --err-bd2:#6E2F28; --err-tx2:#EFA79D;
  --info-bg:#10222F; --info-bd:#23465F; --info-tx:#9CC6E8;
  --info-bg2:#0E1E33; --info-bd2:#2A4E76; --info-tx2:#9CC6E8;
  --info-bd3:#2A4E76; --info-tx3:#9CC6E8;
  --danger:#E0685A; --tick:#53BDEB;
  --row-hover:#1B2440; --ghost-hover:#1B2440;
  --link:#7FB5E8; --info:#6FA8E0;
  --sel-bg:#2E7CC4; --sel-tx:#ffffff;
  --cal-client:#5B9BD9; --cal-fournisseur:#DFA83E; --cal-facture:#C99BD0;
  --viz-serie:#4E9BD6; --viz-enc:#3BC88B; --viz-dec:#DFA83E;
  --mut:#9AA3B8; --mut-bg:#1D2640;
  --sh:0 1px 2px rgba(0,0,0,.35), 0 10px 30px rgba(0,0,0,.4);
  --sh-sm:0 1px 2px rgba(0,0,0,.4);
}
/* Impression : toujours claire (le papier ne connaît pas le sombre). */
@media print{
  [data-theme="dark"]{
    color-scheme:light;
    --canvas:#F4F6FA; --surface:#FFFFFF; --canvas-2:#EDEFF4;
    --line:#E7EAF1; --line-2:#EEF1F6; --line-strong:#ccd4e1;
    --ink:#182031; --slate:#586274; --slate-400:#8a93a2;
    --mark:#9aa3b2; --soft:#c3c9d3;
    --blue:#005CA9; --blue-700:#0a4d8c; --blue-050:#EAF2FB;
    --link:#005CA9; --tick:#2f9bd8; --danger:#c0503f;
  }
}
*{box-sizing:border-box}
html,body{margin:0}
html{background:var(--canvas)}
body{
  font-family:"Inter",system-ui,-apple-system,Segoe UI,Roboto,sans-serif;
  color:var(--ink); background:var(--canvas);
  font-size:14.5px; line-height:1.55; -webkit-font-smoothing:antialiased;
}
h1,h2,h3,h4{font-family:"Manrope",Inter,system-ui,sans-serif; margin:0; color:var(--ink); letter-spacing:-.01em}
a{color:var(--link); text-decoration:none}
.num{font-variant-numeric:tabular-nums}
::selection{background:var(--purple-050)}
:focus-visible{outline:2px solid var(--blue); outline-offset:2px; border-radius:6px}
.login-logo .mark svg,.brand .mark svg,.pcard .p-logo svg{display:block;height:100%;width:auto}

/* ============ LOGIN ============ */
.login{position:fixed; inset:0; display:flex; align-items:center; justify-content:center; padding:24px; background:var(--canvas); z-index:50}
.login-card{background:var(--surface); border:1px solid var(--line); border-radius:22px; box-shadow:var(--sh); width:100%; max-width:420px; padding:38px 36px}
.login-logo{display:flex; align-items:center; gap:13px; margin-bottom:28px}
.login-logo .mark{height:44px; width:auto; display:block}
.login-logo .wm{font-family:"Manrope"; font-weight:800; font-size:18px; line-height:1.1}
.login-logo .wm small{display:block; font-weight:600; font-size:12px; color:var(--slate); letter-spacing:.02em}
.login h1{font-size:22px; margin-bottom:6px}
.login .sub{color:var(--slate); margin-bottom:26px; font-size:14px}
.field{margin-bottom:16px}
.field label{display:block; font-size:12.5px; font-weight:600; color:var(--slate); margin-bottom:7px}
.input{width:100%; background:var(--surface); border:1px solid var(--line); border-radius:var(--r-sm); padding:12px 13px; font:inherit; color:var(--ink)}
.input::placeholder{color:var(--slate-400)}
.input:focus{border-color:var(--blue); box-shadow:0 0 0 3px var(--blue-050); outline:none}
.role-pick{display:grid; grid-template-columns:1fr 1fr; gap:10px; margin:22px 0 8px}
.role-btn{border:1px solid var(--line); background:var(--surface); border-radius:var(--r-sm); padding:14px; cursor:pointer; text-align:left; transition:border-color .15s, background .15s}
.role-btn:hover{border-color:var(--line-strong)}
.role-btn .t{font-weight:700; font-family:"Manrope"}
.role-btn .d{font-size:12px; color:var(--slate); margin-top:2px}
.role-btn[data-r="superadmin"]:hover{border-color:var(--blue)}
.role-btn[data-r="caissier"]:hover{border-color:var(--purple)}
.login .hint{font-size:12px; color:var(--slate-400); margin-top:16px; text-align:center}

/* ============ APP SHELL ============ */
.app{display:none; min-height:100vh}
.app.on{display:grid; grid-template-columns:264px 1fr}

.sidebar{background:var(--surface); border-right:1px solid var(--line); min-height:100vh; position:sticky; top:0; height:100vh; overflow-y:auto; padding:22px 16px}
.brand{display:flex; align-items:center; gap:11px; padding:6px 8px 20px}
.brand .mark{height:38px; width:auto; display:block}
.brand .wm{font-family:"Manrope"; font-weight:800; font-size:15.5px; line-height:1.05}
.brand .wm small{display:block; font-weight:600; font-size:11px; color:var(--slate); letter-spacing:.02em}

.navsec{margin-top:14px}
.navsec .lbl{font-size:10.5px; font-weight:700; letter-spacing:.12em; color:var(--slate-400); text-transform:uppercase; padding:0 10px 8px}
.nav{display:flex; flex-direction:column; gap:2px}
.nav a{display:flex; align-items:center; gap:11px; padding:9.5px 10px; border-radius:var(--r-sm); color:var(--slate); font-weight:600; font-size:13.5px; position:relative; transition:background .14s, color .14s}
.nav a svg{width:18px; height:18px; flex:none; stroke:currentColor}
.nav a:hover{background:var(--line-2); color:var(--ink)}
.nav a.active{background:var(--blue-050); color:var(--blue-700)}
.nav a.active::before{content:""; position:absolute; left:-16px; top:8px; bottom:8px; width:3px; border-radius:0 3px 3px 0; background:var(--blue)}
.nav a .cnt{margin-left:auto; font-size:11px; background:var(--mut-bg); color:var(--mut); border-radius:var(--pill); padding:1px 8px; font-weight:700}

.main{min-width:0; display:flex; flex-direction:column}
.topbar{position:sticky; top:0; z-index:20; background:var(--canvas); background:color-mix(in srgb, var(--canvas) 84%, transparent); backdrop-filter:blur(8px); border-bottom:1px solid var(--line); padding:16px 30px; display:flex; align-items:center; gap:18px}
/* Bouton thème : toujours visible, bureau comme mobile (il n'hérite pas du
   display:none de .icon-btn réservé au burger). */
.topbar #btn-theme{display:inline-flex; flex:none}
/* Même bouton en flottant sur les pages publiques (connexion, mot de passe). */
.theme-flottant{position:fixed; top:14px; right:14px; z-index:60; display:inline-flex}
.topbar .titles{min-width:0}
.topbar h1{font-size:20px}
.topbar .crumb{font-size:12.5px; color:var(--slate); margin-top:1px}
.topbar .spacer{flex:1}
.seg{display:inline-flex; background:var(--surface); border:1px solid var(--line); border-radius:var(--pill); padding:3px; max-width:100%}
.seg button{border:0; background:transparent; font:inherit; font-weight:600; font-size:12.5px; color:var(--slate); padding:6px 13px; border-radius:var(--pill); cursor:pointer; flex:none; white-space:nowrap}
.seg button.on{background:var(--sel-bg); color:var(--sel-tx)}
/* Filtres nombreux (Tous/Actifs/Brouillons/Résiliés/Expirés…) : sur petit
   écran la barre défile au doigt au lieu de pousser la page. */
@media (max-width:640px){
  .seg{overflow-x:auto; scrollbar-width:none; -webkit-overflow-scrolling:touch}
  .seg::-webkit-scrollbar{display:none}
}
.who{display:flex; align-items:center; gap:10px}
.avatar{width:34px; height:34px; border-radius:var(--pill); background:var(--purple-050); color:var(--purple-700); display:flex; align-items:center; justify-content:center; font-weight:800; font-size:13px; font-family:"Manrope"}
.who .meta{font-size:12px; line-height:1.2}
.who .meta b{font-size:13px; display:block; font-weight:700}
.who .meta span{color:var(--slate)}
.icon-btn{width:36px;height:36px;border:1px solid var(--line);background:var(--surface);border-radius:var(--r-sm);display:none;align-items:center;justify-content:center;cursor:pointer;flex:none}
.icon-btn svg{width:18px;height:18px;stroke:var(--ink)}
/* Loupe de recherche mobile : cachée au bureau, la recherche en ligne reste. */
#btn-search{display:none}
/* ---- recherche en popup sur téléphone ----
   La barre inline prenait toute une rangée ; la loupe ouvre un panneau qui
   accueille la VRAIE barre (déplacée, pas dupliquée : écouteurs intacts). */
.search-popup{position:fixed;inset:0;z-index:115;background:rgba(24,32,49,.45);padding:14px;
  display:flex;align-items:flex-start;justify-content:center;overflow-y:auto}
.sp-card{background:var(--surface);border-radius:14px;width:100%;max-width:560px;padding:14px;box-shadow:var(--sh)}
.sp-head{display:flex;align-items:center;gap:10px;margin-bottom:12px;font-size:15px;font-weight:700}
.sp-head .sp-x{margin-left:auto}
.search-popup .gsearch{display:flex;width:100%}
.search-popup .gsearch .input{width:100%;max-width:none}
.search-popup .gsearch .suggest{left:0;right:0;width:100%;max-width:none}
/* Bouton repli (créé en JS devant .titles) : style de base AVANT les médias
   pour que les surcharges mobiles gagnent sans course à la spécificité. */
#btn-sidebar-toggle{width:28px;height:28px;border:1px solid var(--line);background:transparent;border-radius:var(--r-xs);cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--slate);flex:none;margin-top:-8px}
#btn-sidebar-toggle:hover{background:var(--line-2);color:var(--ink)}
#btn-sidebar-toggle svg{width:14px;height:14px;stroke:currentColor}

.content{padding:28px 30px 60px; width:100%; min-width:0}
.view{display:none; animation:fade .22s ease}
.view.on{display:block}
@keyframes fade{from{opacity:0; transform:translateY(4px)}to{opacity:1; transform:none}}
@media (prefers-reduced-motion:reduce){.view.on{animation:none}}

/* ============ PRIMITIVES ============ */
.card{background:var(--surface); border:1px solid var(--line); border-radius:var(--r); box-shadow:var(--sh-sm); padding:24px}
.card + .card{margin-top:var(--gap)}
.card-h{display:flex; align-items:center; gap:14px; margin-bottom:18px}
.card-h h3{font-size:16px}
.card-h .sub{font-size:12.5px; color:var(--slate); margin-top:2px}
.card-h .spacer{flex:1}
.grid{display:grid; gap:var(--gap)}
.g-4{grid-template-columns:repeat(4,1fr)}
.g-3{grid-template-columns:repeat(3,1fr)}
.g-2{grid-template-columns:repeat(2,1fr)}
.split{display:grid; grid-template-columns:1.6fr 1fr; gap:var(--gap); align-items:start}

.btn{font:inherit; font-weight:600; font-size:13.5px; border-radius:var(--r-sm); padding:11px 16px; border:1px solid transparent; cursor:pointer; display:inline-flex; align-items:center; gap:8px; transition:background .14s, border-color .14s, color .14s; white-space:nowrap}
.btn svg{width:16px;height:16px;stroke:currentColor}
.btn-primary{background:var(--blue); color:#fff}
.btn-primary:hover{background:var(--blue-700)}
/* Ancien violet supprimé (demande client : tout en bleu). Classe conservée
   en alias vers le bleu pour compatibilité ascendante : aucun bouton violet
   ne doit subsister, même en cas d'oubli dans un gabarit. */
.btn-accent{background:var(--blue); color:#fff}
.btn-accent:hover{background:var(--blue-700)}
.btn-ghost{background:var(--surface); border-color:var(--line); color:var(--ink)}
.btn-ghost:hover{border-color:var(--line-strong); background:var(--ghost-hover)}
.btn-sm{padding:8px 12px; font-size:12.5px; border-radius:var(--r-xs)}
.btn-block{width:100%; justify-content:center}

.chip{display:inline-flex; align-items:center; gap:6px; font-size:12px; font-weight:600; padding:3px 10px; border-radius:var(--pill); line-height:1.6}
.chip::before{content:""; width:6px; height:6px; border-radius:50%; background:currentColor; opacity:.9}
.c-ok{background:var(--ok-bg); color:var(--ok)}
.c-info{background:var(--info-bg); color:var(--info)}
.c-warn{background:var(--warn-bg); color:var(--warn)}
.c-mut{background:var(--mut-bg); color:var(--mut)}
.c-pur{background:var(--purple-050); color:var(--purple-700)}

table{width:100%; border-collapse:collapse; font-size:13.5px}
thead th{text-align:left; font-size:11px; font-weight:700; letter-spacing:.06em; text-transform:uppercase; color:var(--slate-400); padding:0 14px 12px; border-bottom:1px solid var(--line)}
tbody td{padding:14px; border-bottom:1px solid var(--line-2); vertical-align:middle}
tbody tr:last-child td{border-bottom:0}
tbody tr:hover{background:var(--row-hover)}
td .mono,.mono{font-family:"Manrope"; font-weight:700; letter-spacing:.02em}
.tbl-wrap{overflow-x:auto}
.muted{color:var(--slate)}
.right{text-align:right}
.tools{display:flex; gap:10px; flex-wrap:wrap; align-items:center}

/* KPI */
.kpi{background:var(--surface); border:1px solid var(--line); border-radius:var(--r); padding:20px; box-shadow:var(--sh-sm)}
.kpi .k-lbl{font-size:12.5px; color:var(--slate); font-weight:600}
.kpi .k-val{font-family:"Manrope"; font-weight:800; font-size:30px; margin-top:8px; letter-spacing:-.02em}
.kpi .k-sub{font-size:12px; margin-top:6px; color:var(--slate)}
.kpi .k-sub b.up{color:var(--ok)} .kpi .k-sub b.dn{color:var(--danger)}
.kpi .k-top{display:flex; align-items:center; justify-content:space-between}
.kpi .k-ic{width:34px;height:34px;border-radius:var(--r-sm);display:flex;align-items:center;justify-content:center}
.kpi .k-ic svg{width:18px;height:18px}

/* rate cards */
.rate{border:1px solid var(--line); border-radius:var(--r); padding:20px; background:var(--surface)}
.rate .r-top{display:flex; justify-content:space-between; align-items:baseline}
.rate .r-name{font-weight:700; font-family:"Manrope"; font-size:14px}
.rate .r-val{font-family:"Manrope"; font-weight:800; font-size:22px}
.rate .bar{height:8px; border-radius:var(--pill); background:var(--line-2); margin-top:14px; overflow:hidden}
.rate .bar > i{display:block; height:100%; border-radius:var(--pill)}
.rate .r-note{font-size:12px; color:var(--slate); margin-top:10px}
.dot-ok{color:var(--ok)} .dot-warn{color:var(--warn)}

/* funnel bars */
.funnel{display:flex; flex-direction:column; gap:12px}
.fn-row{display:grid; grid-template-columns:130px 1fr 56px; align-items:center; gap:14px}
.fn-row .fl{font-size:13px; color:var(--slate); font-weight:600}
.fn-track{height:34px; background:var(--line-2); border-radius:10px; overflow:hidden}
.fn-fill{height:100%; border-radius:10px; display:flex; align-items:center; padding-left:12px; color:#fff; font-weight:700; font-family:"Manrope"; font-size:13px}
.fn-row .fv{text-align:right; font-family:"Manrope"; font-weight:800}

/* activity list */
.feed{display:flex; flex-direction:column}
.feed .it{display:flex; gap:13px; padding:13px 0; border-bottom:1px solid var(--line-2)}
.feed .it:last-child{border-bottom:0}
.feed .it .dot{width:9px;height:9px;border-radius:50%;margin-top:6px;flex:none}
.feed .it .tx{font-size:13.5px}
.feed .it .tx b{font-weight:700}
.feed .it .tm{margin-left:auto; font-size:12px; color:var(--slate-400); white-space:nowrap}

/* forms */
.form-grid{display:grid; grid-template-columns:1fr 1fr; gap:16px}
.form-grid .full{grid-column:1/-1}
textarea.input{min-height:74px; resize:vertical}
select.input{appearance:none; background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23586274' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E"); background-repeat:no-repeat; background-position:right 12px center; padding-right:36px}
.help{font-size:12px; color:var(--slate); margin-top:6px}
.switch{display:flex; align-items:center; gap:10px; font-size:13.5px; font-weight:600; color:var(--ink); cursor:pointer; user-select:none}
.switch input{display:none}
.switch .track{width:40px; height:23px; border-radius:var(--pill); background:var(--line); position:relative; transition:background .16s}
.switch .track::after{content:""; position:absolute; top:2.5px; left:2.5px; width:18px; height:18px; border-radius:50%; background:var(--surface); box-shadow:0 1px 2px rgba(0,0,0,.2); transition:transform .16s}
.switch input:checked + .track{background:var(--blue)}
.switch input:checked + .track::after{transform:translateX(17px)}

/* card generator preview */
.preview-wrap{background:var(--canvas-2); border:1px solid var(--line); border-radius:var(--r); padding:30px; display:flex; align-items:center; justify-content:center; min-height:330px}
.pcard{position:relative; width:340px; background:var(--surface); border-radius:16px; box-shadow:0 10px 30px rgba(20,30,50,.14); padding:22px; display:flex; gap:18px; align-items:center}
.pcard.bleed{outline:2px dashed var(--mark); outline-offset:9px}
.pcard .crop i{position:absolute; width:12px; height:12px; border:0}
.pcard.crop i.tl{top:-13px;left:-13px;border-top:1px solid var(--mark);border-left:1px solid var(--mark)}
.pcard.crop i.tr{top:-13px;right:-13px;border-top:1px solid var(--mark);border-right:1px solid var(--mark)}
.pcard.crop i.bl{bottom:-13px;left:-13px;border-bottom:1px solid var(--mark);border-left:1px solid var(--mark)}
.pcard.crop i.br{bottom:-13px;right:-13px;border-bottom:1px solid var(--mark);border-right:1px solid var(--mark)}
.pcard .p-qr{width:96px;height:96px;flex:none;border-radius:8px;overflow:hidden;background:#fff;display:flex;align-items:center;justify-content:center}
.pcard .p-qr img,.pcard .p-qr canvas{width:96px!important;height:96px!important;display:block}
.pcard .p-qr.ph{background:repeating-conic-gradient(#182031 0 25%, #fff 0 50%) 0 0/16px 16px}
.pcard .p-body{min-width:0}
.pcard .p-logo{height:22px;width:auto;display:block;margin-bottom:8px}
.pcard .p-title{font-family:"Manrope";font-weight:800;font-size:16.5px;line-height:1.2;color:var(--ink)}
.pcard .p-sub{font-size:12px;color:var(--slate);margin-top:4px;line-height:1.35}
.pcard .p-code{margin-top:11px;display:inline-block;font-family:"Manrope";font-weight:800;font-size:13px;letter-spacing:.06em;color:var(--purple-700);background:var(--purple-050);border-radius:6px;padding:3px 9px}
.pcard .p-by{margin-top:10px;font-size:10px;color:var(--slate-400);border-top:1px solid var(--line-2);padding-top:8px}
.planche{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}
.planche .mini{border:1px dashed var(--mark);border-radius:8px;padding:8px;display:flex;gap:8px;align-items:center;background:var(--surface)}
.planche .mini .mq{width:40px;height:40px;flex:none;border-radius:5px;background:repeating-conic-gradient(#182031 0 25%,#fff 0 50%) 0 0/7px 7px}
.planche .mini .mt{font-size:9px;line-height:1.25}
.planche .mini .mc{font-family:"Manrope";font-weight:800;font-size:10px;color:var(--purple-700)}

/* link rows */
.linkrow{display:flex;align-items:center;gap:16px;padding:16px;border:1px solid var(--line);border-radius:var(--r);background:var(--surface)}
.linkrow + .linkrow{margin-top:12px}
.linkrow .lq{width:56px;height:56px;flex:none;border-radius:9px;overflow:hidden;background:#fff;border:1px solid var(--line-2);display:flex;align-items:center;justify-content:center}
.linkrow .lq img,.linkrow .lq canvas{width:54px!important;height:54px!important}
.linkrow .lq.ph{background:repeating-conic-gradient(#182031 0 25%,#fff 0 50%) 0 0/9px 9px}
.linkrow .lmain{min-width:0;flex:1}
.linkrow .lname{font-weight:700;font-family:"Manrope";font-size:13.5px}
.linkrow .lurl{display:flex;align-items:center;gap:8px;margin-top:5px}
.linkrow .lurl code{font-family:"Manrope";font-weight:600;font-size:13px;color:var(--blue-700);background:var(--blue-050);border-radius:7px;padding:4px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.linkrow .lstat{display:flex;gap:22px;flex:none}
.linkrow .lstat .s .v{font-family:"Manrope";font-weight:800;font-size:17px}
.linkrow .lstat .s .k{font-size:11px;color:var(--slate)}
.copybtn{border:1px solid var(--line);background:var(--surface);border-radius:var(--r-xs);padding:8px 10px;cursor:pointer;display:inline-flex;align-items:center;gap:7px;font:inherit;font-weight:600;font-size:12.5px;color:var(--ink)}
.copybtn:hover{border-color:var(--line-strong)}
.copybtn svg{width:15px;height:15px;stroke:currentColor}
.copybtn.done{color:var(--ok);border-color:var(--ok-bg);background:var(--ok-bg)}

/* callout */
.note{display:flex;gap:12px;background:var(--blue-050);border:1px solid var(--info-bd);border-radius:var(--r);padding:15px 17px;font-size:13.5px;color:var(--info-tx)}
.note svg{width:19px;height:19px;flex:none;stroke:var(--blue);margin-top:1px}
.note.pur{background:var(--purple-050);border-color:var(--purple-bd);color:var(--purple-tx)}
.note.pur svg{stroke:var(--purple)}

/* settings template list */
.tpl{display:flex;align-items:center;gap:14px;padding:14px 0;border-bottom:1px solid var(--line-2)}
.tpl:last-child{border-bottom:0}
.tpl .tn{font-weight:600}
.tpl .tc{font-size:12px;color:var(--slate)}
.sectitle{font-size:12px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--slate-400);margin:26px 0 12px}

/* caisse big actions */
.cash-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--gap);align-items:start}
.stepnum{width:26px;height:26px;border-radius:8px;background:var(--blue);color:#fff;display:inline-flex;align-items:center;justify-content:center;font-family:"Manrope";font-weight:800;font-size:13px;flex:none}
.result{margin-top:16px;padding:15px;border-radius:var(--r-sm);background:var(--ok-bg);border:1px solid var(--ok-bd);font-size:13.5px;display:none}
.result.on{display:block}
.result b{font-family:"Manrope"}

@media (max-width:1080px){
  .g-4{grid-template-columns:repeat(2,1fr)} .g-3{grid-template-columns:1fr} .split,.cash-grid,.cash-grid,.g-2{grid-template-columns:1fr}
  .planche{grid-template-columns:repeat(2,1fr)}
}
.sidebar-close{display:none}
.brand{cursor:pointer}
@media (max-width:820px){
  .app.on{grid-template-columns:1fr}
  /* Le mode replié n'existe pas sur mobile : on neutralise la classe au cas
     où elle aurait été posée sur bureau avant de réduire la fenêtre. */
  .app.on.sidebar-collapse{grid-template-columns:1fr}
  .app.on.sidebar-collapse .sidebar{padding:22px 16px;overflow-x:visible}
  .app.on.sidebar-collapse .sidebar .lbl,
  .app.on.sidebar-collapse .sidebar .wm,
  .app.on.sidebar-collapse .sidebar .nav a span,
  .app.on.sidebar-collapse .sidebar .nav a .cnt{display:revert}
  .app.on.sidebar-collapse .brand{justify-content:flex-start}
  .app.on.sidebar-collapse .nav a{justify-content:flex-start}
  #btn-sidebar-toggle{display:none}
  .sidebar{position:fixed; z-index:40; width:min(100%,340px); transform:translateX(-100%); transition:transform .2s; box-shadow:var(--sh)}
  .sidebar.open{transform:none}
  /* Plein écran + croix visible : le menu mobile se ferme d'un geste. */
  .sidebar.open{width:100%}
  .sidebar-close{display:none; position:absolute; top:12px; right:12px; width:36px; height:36px;
    border:1px solid var(--line); background:var(--surface); border-radius:10px; font-size:20px; font-weight:700;
    color:var(--slate); cursor:pointer; align-items:center; justify-content:center; z-index:2}
  .sidebar.open .sidebar-close{display:inline-flex}
  .icon-btn{display:inline-flex}
  .content,.topbar{padding-left:18px;padding-right:18px}
  .form-grid{grid-template-columns:1fr}
  .linkrow{flex-wrap:wrap}
  .g-4{grid-template-columns:1fr 1fr}
}

/* ═══════════════════════════════════════════════════════════════════════════
   AJOUTS DU SYSTÈME
   Tout ce qui précède est la feuille du prototype, reprise sans modification.
   Ce qui suit ne fait qu'ajouter : messages, boîtes de dialogue, pagination,
   états vides, journal des messages. Aucune règle ci-dessous ne redéfinit une
   propriété déjà posée plus haut — le rendu des vues validées est intact.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ---- accessibilité (Paramètres) ----
   Police : zoom du contenu seul (barre, modales et toasts gardent leur taille
   tactile). Contraste : encres et filets renforcés. Calme : aucun mouvement. */
html[data-police="112"] .content{zoom:1.12}
html[data-police="125"] .content{zoom:1.25}
html[data-contraste="1"]{
  --ink:#000000; --slate:#2E3542; --slate-400:#4A5468; --line:#7E8AA3;
}
html[data-contraste="1"] a{text-decoration:underline}
html[data-calme="1"] *, html[data-calme="1"] *::before, html[data-calme="1"] *::after{
  animation:none !important; transition:none !important;
}

/* ---- bouton Filtres : pastille du nombre de filtres actifs ---- */
.badge-filtre{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:20px;
  padding:0 6px;border-radius:var(--pill);background:var(--blue);color:#fff;font-size:11.5px;font-weight:800}
.btn.actifs{border-color:var(--blue);color:var(--blue-700)}

/* ---- bouton d'actions rapides (flottant bas-droite) + toasts remontés ----
   Le + ouvre la popup de toutes les opérations du quotidien. Les toasts
   passent au-dessus pour ne jamais être masqués pendant leurs 5 secondes. */
#fab-actions{position:fixed; right:22px; bottom:22px; z-index:115; width:56px; height:56px;
  border-radius:50%; border:0; background:var(--blue); color:#fff; font-size:30px; font-weight:300;
  line-height:1; cursor:pointer; box-shadow:0 8px 24px rgba(0,92,169,.35);
  display:flex; align-items:center; justify-content:center; padding-bottom:4px}
#fab-actions:hover{background:var(--blue-700)}
.toasts{bottom:90px}
.actions-rapides{display:grid; grid-template-columns:1fr 1fr; gap:10px}
.actions-rapides .btn{justify-content:flex-start}
@media (max-width:640px){
  #fab-actions{right:14px; bottom:14px}
  .toasts{bottom:82px}
  .actions-rapides{grid-template-columns:1fr}
}

/* ---- variantes du bandeau .note ---- */
.note.note-ok{background:var(--ok-bg);border-color:var(--ok-bd);color:var(--ok-tx)}
.note.note-ok svg{stroke:var(--ok)}
.note.note-err{background:var(--err-bg);border-color:var(--err-bd);color:var(--err-tx)}
.note.note-err svg{stroke:var(--danger)}
.note.note-warn{background:var(--warn-bg);border-color:var(--warn-bd);color:var(--warn-tx)}
.note.note-warn svg{stroke:var(--warn)}
.note.note-info{background:var(--blue-050);border-color:var(--info-bd2);color:var(--info-tx2)}
.note.note-info svg{stroke:var(--blue)}

/* ---- messages éphémères ---- */
.toasts{position:fixed;right:22px;bottom:22px;z-index:120;display:flex;flex-direction:column;gap:10px;max-width:min(420px,calc(100vw - 36px))}
/* Notification bien visible : fond teinté par type, pastille d'icône,
   croix de fermeture tactile (32 px), 5 s d'affichage côté JS. */
.toast{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-sm);box-shadow:var(--sh);padding:12px 12px 12px 14px;font-size:13.5px;display:flex;gap:11px;align-items:flex-start;animation:toastIn .18s ease;border-left-width:4px}
.toast{background:var(--info-bg2);border-color:var(--info-bd2);color:var(--info-tx2)}
.toast svg{width:17px;height:17px;flex:none;margin-top:1px;stroke:var(--blue)}
.toast .tico{width:28px;height:28px;border-radius:50%;background:var(--blue);display:flex;align-items:center;justify-content:center;flex:none}
.toast .tico svg{width:15px;height:15px;stroke:#fff;margin:0}
.toast.ok{background:var(--ok-bg2);border-color:var(--ok-bd2);color:#14532D}
.toast.ok .tico{background:var(--ok)}
.toast.err{background:var(--err-bg2);border-color:var(--err-bd2);color:var(--err-tx2)}
.toast.err .tico{background:var(--danger)}
.toast.warn{background:var(--warn-bg2);border-color:var(--warn-bd2);color:var(--warn-tx2)}
.toast.warn .tico{background:var(--warn)}
.toast b{font-family:"Manrope";font-weight:700;display:block;margin-bottom:2px;color:inherit}
.toast .tclose{margin-left:auto;border:0;background:transparent;cursor:pointer;color:inherit;opacity:.55;font-size:17px;font-weight:700;min-width:32px;min-height:32px;display:flex;align-items:center;justify-content:center;border-radius:8px;flex:none}
.toast .tclose:hover{opacity:1;background:rgba(0,0,0,.06)}
@keyframes toastIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.toast{animation:none}}
@media (max-width:820px){.toasts{right:12px;left:12px;bottom:88px}.toast{font-size:14px}}

/* ---- boîte de dialogue ---- */
.modal{position:fixed;inset:0;z-index:110;display:none;align-items:center;justify-content:center;padding:22px;background:rgba(24,32,49,.38);backdrop-filter:blur(2px)}
.modal.on{display:flex}
.modal-card{background:var(--surface);border:1px solid var(--line);border-radius:20px;box-shadow:var(--sh);width:100%;max-width:520px;max-height:calc(100vh - 44px);overflow-y:auto;padding:26px 26px 24px}
.modal-card.wide{max-width:760px}
.modal-h{display:flex;align-items:flex-start;gap:14px;margin-bottom:18px}
.modal-h h3{font-size:17px}
.modal-h .sub{font-size:12.5px;color:var(--slate);margin-top:3px}
.modal-h .spacer{flex:1}
.modal-x{width:32px;height:32px;border:1px solid var(--line);background:var(--surface);border-radius:var(--r-xs);display:flex;align-items:center;justify-content:center;cursor:pointer;flex:none}
.modal-x svg{width:16px;height:16px;stroke:var(--slate)}
.modal-x:hover{border-color:var(--line-strong)}
.modal-f{display:flex;gap:10px;justify-content:flex-end;margin-top:22px;flex-wrap:wrap}

/* ---- déconnexion, dans le bloc identité ---- */
/* la pastille d'identité mène au changement de mot de passe : c'est un lien,
   il ne doit pas se distinguer visuellement de la pastille du prototype */
a.avatar{text-decoration:none}
a.avatar:hover{filter:brightness(.97)}
.who .out{width:34px;height:34px;border:1px solid var(--line);background:var(--surface);border-radius:var(--r-sm);display:flex;align-items:center;justify-content:center;cursor:pointer;flex:none}
.who .out svg{width:17px;height:17px;stroke:var(--slate)}
.who .out:hover{border-color:var(--line-strong);background:var(--ghost-hover)}
.who .out:hover svg{stroke:var(--ink)}

/* ---- pagination ---- */
.pager{display:flex;align-items:center;gap:8px;justify-content:flex-end;margin-top:16px;flex-wrap:wrap}
.pager .pinfo{margin-right:auto;font-size:12.5px;color:var(--slate)}
.pager button{border:1px solid var(--line);background:var(--surface);border-radius:var(--r-xs);padding:7px 12px;font:inherit;font-weight:600;font-size:12.5px;color:var(--ink);cursor:pointer}
.pager button:hover:not(:disabled){border-color:var(--line-strong)}
.pager button:disabled{opacity:.45;cursor:default}
.pager button.on{background:var(--sel-bg);color:var(--sel-tx);border-color:var(--sel-bg)}

/* ---- état vide ---- */
.empty{text-align:center;padding:40px 20px;color:var(--slate)}
.empty svg{width:34px;height:34px;stroke:var(--slate-400);margin-bottom:12px}
.empty .t{font-family:"Manrope";font-weight:700;font-size:14.5px;color:var(--ink);margin-bottom:5px}
.empty .d{font-size:13px;max-width:380px;margin:0 auto}

/* ---- chargement ---- */
.loading{display:inline-block;width:15px;height:15px;border:2px solid var(--line);border-top-color:var(--blue);border-radius:50%;animation:spin .7s linear infinite;vertical-align:-2px}
@keyframes spin{to{transform:rotate(360deg)}}
.btn[disabled]{opacity:.6;cursor:default;pointer-events:none}
.is-busy{position:relative;opacity:.55;pointer-events:none}

/* ---- message d'erreur de connexion ---- */
.login .erreur{background:var(--err-bg);border:1px solid var(--err-bd);color:var(--err-tx);border-radius:var(--r-sm);padding:11px 13px;font-size:13px;margin-bottom:18px}
.login .avis{background:var(--info-bg);border:1px solid var(--info-bd);color:var(--info-tx);border-radius:var(--r-sm);padding:11px 13px;font-size:13px;margin-bottom:18px}
.role-btn[disabled]{opacity:.6;cursor:default}

/* ---- QR servi par le serveur ---- */
.qrimg{display:block;width:100%;height:100%;object-fit:contain;image-rendering:auto}
.linkrow .lq img.qrimg{width:54px!important;height:54px!important}
.pcard .p-qr img.qrimg{width:96px!important;height:96px!important}
.planche .mini .mq img.qrimg{width:40px;height:40px;display:block}

/* ---- téléversement du logo ---- */
.drop{display:block;border:1.5px dashed var(--mark);border-radius:var(--r);padding:20px;text-align:center;background:var(--row-hover);cursor:pointer;transition:border-color .15s,background .15s}
.drop svg{display:inline-block}
.drop:hover,.drop.over{border-color:var(--blue);background:var(--blue-050)}
.drop svg{width:22px;height:22px;stroke:var(--slate-400);margin-bottom:8px}
.drop .t{font-size:13px;font-weight:600}
.drop .d{font-size:11.5px;color:var(--slate);margin-top:3px}
.drop input{display:none}
.logo-actuel{display:flex;align-items:center;gap:14px;padding:12px 0}
.logo-actuel .box{width:64px;height:44px;border:1px solid var(--line-2);border-radius:var(--r-xs);display:flex;align-items:center;justify-content:center;padding:6px;background:var(--surface);flex:none}
.logo-actuel .box svg,.logo-actuel .box img{max-width:100%;max-height:100%;width:auto;height:auto;display:block}

.tpl-sync-note{display:block;margin-top:5px;font-size:11.5px;color:var(--slate-400)}
.tpl-sync-note.bad{color:var(--warn)}

/* Colonne étroite : le bouton et le statut passent sous le nom du modèle
   plutôt que de déborder du bord de la carte. Le flex-wrap est indispensable :
   sans lui, le flex:1 1 100% du premier enfant pousse les deux autres hors
   du cadre au lieu de les renvoyer à la ligne. */
.tpl{flex-wrap:wrap}
.tpl > div:first-child{flex:1 1 100%}
.tpl > .btn{margin-top:10px}
.tpl > .chip{margin-top:10px;margin-left:8px}

.tv{margin-top:5px;display:flex;flex-wrap:wrap;gap:4px 6px;font-size:11.5px;color:var(--slate-400)}
.tv .mono{color:var(--purple-700)}

/* ---- groupes de réglages ----
   Un titre net et une phrase qui dit à quoi sert le bloc : l'équipe qui
   paramètre n'a pas construit le système. */
.gtitre{grid-column:1/-1;font-family:"Manrope";font-weight:800;font-size:14.5px;color:var(--ink);
  margin:26px 0 0;padding-top:18px;border-top:1px solid var(--line-2)}
.form-grid > .gtitre:first-child{margin-top:0;padding-top:0;border-top:0}
.gnote{grid-column:1/-1;font-size:12.5px;line-height:1.55;color:var(--slate);margin:5px 0 4px}
/* ---- groupes repliables (Paramètres) ----
   Le <details> reprend la grille 2 colonnes du formulaire ; le sommaire
   porte le chevron, le premier groupe naît ouvert. */
details.gbloc{grid-column:1/-1;display:grid;grid-template-columns:1fr 1fr;gap:0 16px;
  border:1px solid var(--line-2);border-radius:var(--r-sm);padding:0 16px 16px;margin-top:14px;background:var(--surface)}
details.gbloc summary.gtitre{grid-column:1/-1;cursor:pointer;list-style:none;display:flex;align-items:center;gap:10px;
  margin:0;padding:14px 0;user-select:none}
details.gbloc summary.gtitre::-webkit-details-marker{display:none}
details.gbloc summary.gtitre::after{content:"+";margin-left:auto;font-size:18px;font-weight:700;color:var(--blue);flex:none}
details.gbloc[open] summary.gtitre::after{content:"−"}
details.gbloc summary.gtitre:hover{color:var(--blue-700)}
details.gbloc .gnote{margin:0 0 10px}
.lbl-champ{display:block;font-size:12px;font-weight:600;color:var(--slate);margin-bottom:6px}

/* ---- jauge des crédits de messages ----
   Une barre plutôt qu'un simple pourcentage : on voit d'un coup d'œil où en
   est le mois, sans avoir à comparer deux nombres. */
/* Une pastille ne doit jamais se couper en deux : « 100 % » sur deux lignes
   dans une colonne étroite se lit très mal. */
.chip{white-space:nowrap}
.mois-cell{white-space:nowrap}

.jauge{height:14px;background:var(--line-2);border-radius:var(--pill);overflow:hidden}
.jauge-barre{height:100%;background:var(--ok);border-radius:var(--pill);transition:width .3s}
.jauge-barre.haute{background:var(--warn)}
.jauge-barre.pleine{background:var(--danger)}

/* ---- bloc de l'affiche à QR, dans la vue des liens ---- */
.affiche{display:flex;gap:22px;align-items:flex-start;flex-wrap:wrap}
.af-qr{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-sm);padding:12px;line-height:0;flex:none}
.af-qr img{display:block;width:190px;height:190px}
.af-txt{flex:1;min-width:240px}
.af-txt p{font-size:13.5px;color:var(--slate);line-height:1.6;margin:0 0 14px}
.af-url{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:10px}
.af-url code{background:var(--line-2);border-radius:var(--r-xs);padding:8px 11px;font-size:12.5px;word-break:break-all}


/* ---- page publique d'inscription (devenir.php) ----
   La console utilise .login, un calque fixe qui ne défile pas : la fiche du
   parrain est plus haute qu'un écran de téléphone, il lui faut donc son
   propre conteneur. Le carton reprend l'apparence de .login-card. */
.pub{min-height:100vh;background:var(--canvas);padding:22px 16px 40px;display:flex;justify-content:center}
.pub-card{background:var(--surface);border:1px solid var(--line);border-radius:22px;box-shadow:var(--sh);
  width:100%;max-width:440px;padding:30px 26px;align-self:flex-start}
.pub-card h1{font-size:21px;margin-bottom:6px;line-height:1.25}
.pub-card .sub{color:var(--slate);margin-bottom:22px;font-size:14px;line-height:1.55}
.pub-card .erreur{background:var(--err-bg);border:1px solid var(--err-bd);color:var(--err-tx);border-radius:var(--r-sm);
  padding:11px 13px;font-size:13px;margin-bottom:18px}
.pub-card .avis{background:var(--ok-bg);border:1px solid var(--ok-bd);color:var(--ok-tx2);border-radius:var(--r-sm);
  padding:11px 13px;font-size:13px;margin-bottom:18px}
.pub-card .hint{font-size:12px;color:var(--slate-400);margin-top:16px;text-align:center;line-height:1.5}

/* Case de consentement : assez grande pour un pouce. */
.consent{display:flex;gap:11px;align-items:flex-start;margin-top:16px;font-size:13px;
  color:var(--slate);line-height:1.5;cursor:pointer}
.consent input{margin-top:2px;width:18px;height:18px;flex:none}
.consent.ko{color:var(--err-tx)}

/* ---- la fiche remise au parrain ---- */
.pcarte{border:1px solid var(--line);border-radius:var(--r);padding:18px;background:var(--canvas);
  display:flex;flex-direction:column;align-items:center;gap:14px;text-align:center}
.pcarte .k{display:block;font-size:10.5px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  color:var(--slate-400);margin-bottom:4px}
.pc-code b{font-family:"Manrope";font-size:30px;font-weight:800;letter-spacing:.08em;color:var(--purple-700)}
.pc-qr{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-sm);padding:10px;line-height:0}
.pc-qr img{display:block;width:150px;height:150px}
.pc-lien{width:100%;min-width:0}
.pc-lien code{display:block;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-sm);
  padding:10px 12px;font-size:12.5px;word-break:break-all;color:var(--ink)}
.pc-actions{display:flex;flex-direction:column;gap:8px;width:100%}
.pc-stat{display:flex;gap:10px;margin-top:14px}
.pc-stat > div{flex:1;background:var(--canvas);border:1px solid var(--line);border-radius:var(--r-sm);
  padding:12px;text-align:center}
.pc-stat b{display:block;font-family:"Manrope";font-weight:800;font-size:20px}
.pc-stat span{font-size:11.5px;color:var(--slate)}
.pc-mode{margin-top:20px}
.pc-titre{font-family:"Manrope";font-weight:800;font-size:14px;margin-bottom:10px}
.pc-mode ol{margin:0;padding-left:20px;color:var(--slate);font-size:13px;line-height:1.65}
.pc-mode li{margin-bottom:7px}
.pc-mode b{color:var(--ink)}

/* ---- champ piège du formulaire de connexion ----
   Sorti de l'écran plutôt que display:none : certains automates ignorent ce
   qui est explicitement masqué, mais remplissent ce qui existe. */
.pot{position:absolute;left:-9999px;top:auto;width:1px;height:1px;overflow:hidden}

/* ---- recherche globale du bandeau ---- */
.gsearch{position:relative;display:flex;align-items:center;gap:8px;min-width:0}
.gsearch > svg{position:absolute;left:11px;width:16px;height:16px;color:var(--slate-400);pointer-events:none}
.gsearch .input{width:240px;max-width:34vw;padding-left:34px;height:38px}
.gsearch .suggest{position:absolute;top:calc(100% + 6px);right:0;left:auto;width:340px;max-width:80vw;z-index:60}
.gsearch .suggest .grp{font-size:10.5px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;
  color:var(--slate-400);padding:9px 13px 5px}
.gsearch .suggest .it{display:flex;align-items:center;gap:9px;padding:8px 13px;cursor:pointer}
.gsearch .suggest .it:hover,.gsearch .suggest .it.on{background:var(--line-2)}
.gsearch .suggest .it .t{flex:1;min-width:0}
/* Enfants DIRECTS : sans le combinateur, la regle du sous-titre frappait
   aussi le .mono place a l'interieur du titre, et cassait la ligne. */
.gsearch .suggest .it .t > b{display:block;font-size:13.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.gsearch .suggest .it .t > span{display:block;font-size:11.5px;color:var(--slate-400);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.gsearch .suggest .it .t b .mono{color:var(--purple-700);font-size:12.5px}
.gsearch .suggest .vide{padding:14px 13px;font-size:13px;color:var(--slate-400);text-align:center}
@media (max-width:820px){.gsearch .input{width:150px}}

/* ---- fiche du filleul au comptoir ----
   Le caissier doit LIRE la remise avant de l'appliquer : elle occupe donc le
   centre de la fiche, en gros, avec sa date de validité. */
.fiche{border:1px solid var(--line);border-radius:var(--r);padding:18px;background:var(--surface);margin-top:12px}
.fiche + .fiche{margin-top:12px}
.fiche.expire{border-color:var(--warn-bd);background:var(--warn-bg3)}
.fiche-h{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:14px}
.fiche-h .fc{font-family:"Manrope";font-size:17px;font-weight:800;letter-spacing:.06em;
  color:var(--purple-700);background:var(--purple-050);border-radius:7px;padding:3px 10px}
.fiche-h .tel{font-weight:600;color:var(--slate);font-size:13.5px}
.fiche-h .spacer{flex:1}
.fiche .offre{background:var(--ok-bg);border:1px solid var(--ok-bd);border-radius:var(--r-sm);
  padding:14px 16px;margin-bottom:14px}
.fiche.expire .offre{background:var(--warn-bg);border-color:var(--warn-bd)}
.fiche .offre .k{font-size:10.5px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--slate)}
.fiche .offre .v{font-family:"Manrope";font-weight:800;font-size:19px;line-height:1.25;margin-top:5px;color:var(--ink)}
.fiche .offre .d{font-size:12.5px;color:var(--slate);margin-top:5px}
.fiche .kv{margin-bottom:16px;font-size:13px}
.fiche .rappel{font-size:12px;color:var(--slate-400);margin-top:10px;text-align:center}

/* ---- liste de suggestions (recherche de code en caisse) ---- */
.suggest-wrap{position:relative}
.suggest{position:absolute;left:0;right:0;top:calc(100% + 5px);z-index:30;background:var(--surface);
  border:1px solid var(--line);border-radius:var(--r-sm);box-shadow:var(--sh);
  max-height:236px;overflow-y:auto;display:none}
.suggest.on{display:block}
.suggest button{display:flex;width:100%;align-items:center;gap:10px;border:0;background:transparent;
  font:inherit;text-align:left;padding:9px 12px;cursor:pointer;border-bottom:1px solid var(--line-2)}
.suggest button:last-child{border-bottom:0}
.suggest button:hover,.suggest button.on{background:var(--blue-050)}
.suggest button .mono{font-weight:700;letter-spacing:.02em}
.suggest button .k{margin-left:auto;font-size:11.5px;color:var(--slate-400)}
.suggest .vide{padding:12px 13px;font-size:13px;color:var(--slate)}

/* ---- listes à qualifier ---- */
.qrow{display:flex;gap:14px;align-items:flex-start;padding:14px 0;border-bottom:1px solid var(--line-2)}
.qrow:last-child{border-bottom:0}
.qrow .qb{flex:1;min-width:0}
.qrow .qtxt{font-size:13.5px;margin-top:4px;color:var(--slate);word-break:break-word}
.qrow .qact{flex:none;display:flex;gap:8px;align-items:center}

/* ---- tableau : colonne d'action compacte ---- */
tbody td .rowbtns{display:inline-flex;gap:8px;justify-content:flex-end}
th.sortable{cursor:pointer;user-select:none;white-space:nowrap}
th.sortable:hover{color:var(--slate)}
th.sortable .ar{opacity:.45;font-size:9px;margin-left:3px}
th.sortable.on .ar{opacity:1}

/* ---- barre de recherche avec icône ---- */
.searchbox{position:relative;display:inline-flex;align-items:center}
.searchbox svg{position:absolute;left:11px;width:16px;height:16px;stroke:var(--slate-400);pointer-events:none}
.searchbox .input{padding-left:34px}

/* ---- détail d'un parrain ---- */
.kv{display:grid;grid-template-columns:auto 1fr;gap:9px 18px;font-size:13.5px}
.kv dt{color:var(--slate);font-weight:600}
.kv dd{margin:0;font-weight:600}
.minikpi{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin:18px 0}
.minikpi .m{border:1px solid var(--line);border-radius:var(--r-sm);padding:13px;text-align:center}
.minikpi .m .v{font-family:"Manrope";font-weight:800;font-size:21px}
.minikpi .m .k{font-size:11.5px;color:var(--slate);margin-top:2px}

/* ═══════════════ JOURNAL DES MESSAGES (inbox) ═══════════════
   Reprend la charte de la console : mêmes variables, mêmes rayons, mêmes
   ombres. L'inbox historique fonctionnait avec sa propre feuille ; elle est
   ici alignée sur le reste sans perdre une seule de ses fonctions. */
.inbox{display:grid;grid-template-columns:320px 1fr;gap:0;border:1px solid var(--line);border-radius:var(--r);background:var(--surface);box-shadow:var(--sh-sm);overflow:hidden;height:calc(100vh - 190px);min-height:460px}
.ibx-list{border-right:1px solid var(--line);display:flex;flex-direction:column;min-width:0}
.ibx-search{padding:14px;border-bottom:1px solid var(--line-2)}
.ibx-convs{overflow-y:auto;flex:1}
.ibx-conv{display:flex;gap:12px;padding:13px 14px;cursor:pointer;border-bottom:1px solid var(--line-2);align-items:flex-start}
.ibx-conv:hover{background:var(--row-hover)}
.ibx-conv.on{background:var(--blue-050)}
.ibx-conv .av{width:38px;height:38px;border-radius:var(--pill);background:var(--purple-050);color:var(--purple-700);display:flex;align-items:center;justify-content:center;font-family:"Manrope";font-weight:800;font-size:13px;flex:none}
.ibx-conv .cb{min-width:0;flex:1}
.ibx-conv .cn{font-weight:700;font-size:13.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ibx-conv .cp{font-size:12.5px;color:var(--slate);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:2px}
.ibx-conv .cm{flex:none;text-align:right}
.ibx-conv .ct{font-size:11px;color:var(--slate-400);white-space:nowrap}
.ibx-conv .cu{display:inline-block;margin-top:5px;min-width:19px;padding:1px 6px;border-radius:var(--pill);background:var(--ok);color:#fff;font-size:11px;font-weight:700;text-align:center}
.ibx-thread{display:flex;flex-direction:column;min-width:0}
.ibx-head{display:flex;align-items:center;gap:12px;padding:14px 18px;border-bottom:1px solid var(--line-2);flex:none}
.ibx-head .av{width:36px;height:36px;border-radius:var(--pill);background:var(--blue-050);color:var(--blue-700);display:flex;align-items:center;justify-content:center;font-family:"Manrope";font-weight:800;font-size:13px;flex:none}
.ibx-head .hn{font-weight:700;font-size:14px}
.ibx-head .hs{font-size:12px;color:var(--slate)}
.ibx-head .spacer{flex:1}
.ibx-msgs{flex:1;overflow-y:auto;padding:20px 18px;background:var(--canvas);display:flex;flex-direction:column;gap:8px}
.ibx-day{align-self:center;background:var(--surface);border:1px solid var(--line);border-radius:var(--pill);padding:3px 12px;font-size:11.5px;color:var(--slate);font-weight:600;margin:10px 0 4px}
.msg{max-width:min(76%,560px);border-radius:14px;padding:9px 13px 7px;font-size:13.5px;line-height:1.45;position:relative;word-wrap:break-word;overflow-wrap:anywhere}
.msg.in{align-self:flex-start;background:var(--surface);border:1px solid var(--line);border-bottom-left-radius:5px}
.msg.out{align-self:flex-end;background:var(--blue-050);border:1px solid var(--info-bd);border-bottom-right-radius:5px}
.msg .mt{display:flex;align-items:center;gap:5px;justify-content:flex-end;margin-top:3px;font-size:10.5px;color:var(--slate-400)}
.msg .mt .tick{letter-spacing:-2px;font-weight:700}
.msg .mt .tick.lu{color:var(--tick)}
.msg .mt .tick.err{color:var(--danger);letter-spacing:0}
.msg .cap{margin-top:6px}
.msg img.media,.msg video.media{max-width:100%;border-radius:9px;display:block;cursor:zoom-in}
.msg audio.media{width:260px;max-width:100%;display:block}
.msg .doc{display:flex;align-items:center;gap:10px;text-decoration:none;color:inherit;padding:4px 0}
.msg .doc .di{width:34px;height:34px;border-radius:8px;background:var(--mut-bg);display:flex;align-items:center;justify-content:center;flex:none}
.msg .doc .di svg{width:17px;height:17px;stroke:var(--slate)}
.msg .doc .dn{font-weight:600;font-size:13px;word-break:break-all}
.msg .doc .ds{font-size:11.5px;color:var(--slate)}
.msg .indispo{font-style:italic;color:var(--slate-400);font-size:12.5px}
.ibx-compose{border-top:1px solid var(--line-2);padding:12px 14px;display:flex;gap:10px;align-items:flex-end;flex:none;background:var(--surface)}
.ibx-compose textarea{flex:1;resize:none;max-height:130px;min-height:42px;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-sm);padding:11px 13px;font:inherit;color:var(--ink)}
.ibx-compose textarea:focus{border-color:var(--blue);box-shadow:0 0 0 3px var(--blue-050);outline:none}
.ibx-compose .cbtn{width:42px;height:42px;border:1px solid var(--line);background:var(--surface);border-radius:var(--r-sm);display:flex;align-items:center;justify-content:center;cursor:pointer;flex:none}
.ibx-compose .cbtn svg{width:18px;height:18px;stroke:var(--slate)}
.ibx-compose .cbtn:hover{border-color:var(--line-strong)}
.ibx-compose .send{background:var(--blue);border-color:var(--blue)}
.ibx-compose .send svg{stroke:#fff}
.ibx-compose .send:hover{background:var(--blue-700)}
.ibx-fenetre{padding:9px 14px;font-size:12.5px;background:var(--warn-bg);color:var(--warn);border-top:1px solid var(--warn-bd);display:flex;gap:8px;align-items:center}
.ibx-fenetre svg{width:15px;height:15px;stroke:currentColor;flex:none}
.ibx-progress{height:3px;background:var(--line-2);border-radius:var(--pill);overflow:hidden;margin:0 14px 8px}
.ibx-progress i{display:block;height:100%;background:var(--blue);width:0;transition:width .18s}
.ibx-vide{flex:1;display:flex;align-items:center;justify-content:center;background:var(--canvas)}
.ibx-drop{position:absolute;inset:0;background:rgba(0,92,169,.06);border:2px dashed var(--blue);border-radius:var(--r);display:none;align-items:center;justify-content:center;font-weight:700;color:var(--blue-700);z-index:5}
.ibx-drop.on{display:flex}
.lightbox{position:fixed;inset:0;background:rgba(12,17,28,.9);z-index:130;display:none;align-items:center;justify-content:center;padding:30px}
.lightbox.on{display:flex}
.lightbox img,.lightbox video{max-width:100%;max-height:100%;border-radius:10px}
.lightbox .lx{position:absolute;top:18px;right:20px;width:38px;height:38px;border:0;border-radius:var(--pill);background:rgba(255,255,255,.14);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center}
.lightbox .lx svg{width:19px;height:19px;stroke:#fff}
@media (max-width:820px){
  .inbox{grid-template-columns:1fr;height:calc(100vh - 150px)}
  .inbox.montre-fil .ibx-list{display:none}
  .inbox:not(.montre-fil) .ibx-thread{display:none}
  .ibx-back{display:inline-flex!important}
}
.ibx-back{display:none;width:34px;height:34px;border:1px solid var(--line);background:var(--surface);border-radius:var(--r-xs);align-items:center;justify-content:center;cursor:pointer;flex:none}
.ibx-back svg{width:17px;height:17px;stroke:var(--ink);transform:rotate(180deg)}

/* ---- les colonnes ne doivent pas être élargies par leur contenu ----
   Un élément de grille vaut par défaut min-width:auto : un tableau un peu
   large ou un champ à largeur fixe repousse alors toute la colonne au-delà de
   l'écran, et c'est la page entière qui défile latéralement. Avec min-width:0,
   la colonne reprend la main et le débordement reste dans le conteneur prévu
   pour ça (.tbl-wrap défile déjà tout seul). Sans effet sur grand écran, où la
   place ne manque pas. */
.split > *,.cash-grid > *,.grid > *{min-width:0}

/* ---- barre du haut sur petit écran ----
   Le prototype laisse la barre en une seule ligne : sur un téléphone, le
   sélecteur de rôle et le bloc d'identité la poussent au-delà de l'écran et
   toute la page défile latéralement. On la laisse passer à la ligne — rien
   n'est masqué, le caissier garde tout sous la main. Le rendu au-dessus de
   820 px est inchangé. */
@media (max-width:820px){
  .topbar{flex-wrap:wrap; row-gap:10px; padding-top:12px; padding-bottom:12px}
  .topbar .spacer{display:none}
  .topbar .titles{flex:1 1 auto; min-width:0; order:1}
  .topbar h1{font-size:18px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
  .topbar .crumb{white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
  .topbar .who{order:2; flex:0 0 auto}
  /* La recherche prend toute la largeur, sur sa propre ligne : coincee
     entre le menu et le titre, elle ecrasait les deux. */
  .gsearch{order:4; flex:1 0 100%; margin-top:2px}
  .gsearch .input{width:100%; max-width:none}
  .gsearch .suggest{width:100%; left:0; right:0}
  .topbar .seg{order:3; flex:0 0 auto}
  .who .meta{max-width:120px}
  .who .meta b,.who .meta span{white-space:nowrap; overflow:hidden; text-overflow:ellipsis; display:block}
}
@media (max-width:420px){
  .who .meta{display:none}   /* à cette largeur, la pastille suffit à identifier */
  .topbar .seg button{padding:6px 10px}
}
/* ---- zéro défilement horizontal, partout ----
   Garde-fou global (clip préserve le sticky, hidden en repli) + images/SVG
   contenus + KPI en une colonne sur téléphone (les montants à 30 px
   débordaient en 2 colonnes et poussaient toute la page, dashboard inclus).
   Les tableaux gardent leur défilement INTERNE (.tbl-wrap), jamais la page. */
/* clip seul (jamais hidden) : hidden casse le sticky de la barre sur
   certains mobiles, clip non. Vieux navigateurs = sans garde, mais intacts. */
@supports (overflow:clip){html,body{overflow-x:clip}}
img,svg{max-width:100%}
@media (max-width:640px){
  .g-4{grid-template-columns:1fr}
}
/* ---- téléphone : le sous-titre de page écrase l'en-tête ----
   « Tableau de bord / Vue d'ensemble de l'activité » collés prenaient deux
   lignes pour rien et déformaient la barre. Sur téléphone, le titre seul
   suffit : le fil d'Ariane est masqué, le titre rétrécit avec ellipsis. */
@media (max-width:640px){
  .topbar .crumb{display:none}
  .topbar h1{font-size:17px}
  /* Ligne 1 insécable : burger + titre (rogné, jamais pousseur) + loupe +
     avatar. La recherche vit dans un popup (plus de rangée dédiée). */
  .topbar{flex-wrap:nowrap; gap:10px; padding:10px 14px}
  .topbar .titles{flex:1 1 auto; min-width:0; width:0}
  .topbar .who{flex:none}
  .topbar .seg{flex:none}
  /* Burger et toggle : visibilité verrouillée par ID (devant tout le reste).
     Le toggle reste masqué, le burger toujours affiché. */
  .topbar #burger{display:inline-flex; flex:none}
  .topbar #btn-sidebar-toggle{display:none}
  .topbar .gsearch{display:none}
  .topbar #btn-search{display:inline-flex; flex:none}
}

/* ---- en-têtes de carte sur petit écran ----
   Le titre et les outils de recherche tiennent sur une ligne au bureau, jamais
   sur un téléphone : on les empile plutôt que de forcer la carte à s'élargir. */
@media (max-width:820px){
  .card-h{flex-wrap:wrap}
  .card-h .tools{width:100%}
  .card-h .tools .searchbox,.card-h .searchbox{width:100%}
  .card-h .tools .input,.card-h .searchbox .input{width:100%!important}
  .linkrow .lmain{flex:1 1 100%}
  .linkrow .lurl code{max-width:100%}
  /* ligne de modèle Meta : le libellé prend la largeur, le bouton et la
     pastille passent en dessous plutôt que de déborder */
  .tpl{flex-wrap:wrap}
  .tpl > :first-child{flex:1 1 100%}
}

/* ---- impression ----
   Deux cas. Par défaut, la console s'efface pour laisser le contenu.
   Avec la classe « impr-carte », posée par le bouton « Imprimer l'aperçu »,
   SEUL l'aperçu de la carte est rendu : sans cela le navigateur imprime toute
   la vue — le formulaire, le logo, les explications — ce qui ne sert à rien.
   Rappel : pour un vrai tirage, c'est l'export PDF qu'il faut utiliser, lui
   seul porte le fond perdu et les traits de coupe. */
@media print{
  .sidebar,.topbar,.toasts,.tools,.btn,.seg,.pager{display:none!important}
  .app.on{grid-template-columns:1fr}
  .content{padding:0;max-width:none}
  .card{border:0;box-shadow:none;padding:0}
  .preview-wrap{background:var(--surface);border:0;padding:0}
  body{background:var(--surface)}

  body.impr-carte *{visibility:hidden}
  body.impr-carte #cg-stage,body.impr-carte #cg-stage *{visibility:visible}
  body.impr-carte #cg-stage{position:absolute;left:0;top:0;width:100%;
    min-height:0;background:var(--surface);border:0;padding:0;box-shadow:none}
  body.impr-carte #pcard{box-shadow:none;outline:none;margin:0 auto}
  body.impr-carte .modal,body.impr-carte .lightbox,body.impr-carte .toasts{display:none!important}
}

/* ---- pas de zoom automatique à la saisie, sur téléphone ----
   iOS agrandit la page dès qu'on entre dans un champ dont la police descend
   sous 16 px — la nôtre est à 14,5 px, héritée du corps. La page reste ensuite
   dézoomée de travers, et le formulaire d'inscription en souffrait.

   On corrige la cause plutôt que le symptôme : passer le viewport en
   user-scalable=no ferait disparaître le zoom à deux doigts, dont on a besoin
   pour lire. Sur écran tactile, les champs passent donc à 16 px ; l'apparence
   du prototype est conservée telle quelle sur ordinateur. */
@media (pointer: coarse), (max-width: 820px) {
  .input, input[type="text"], input[type="tel"], input[type="email"],
  input[type="password"], input[type="search"], input[type="number"],
  select, textarea { font-size: 16px; }
  /* .ibx-compose textarea l'emporte sur un simple « textarea » : la zone de
     réponse du journal des messages doit être nommée pour être atteinte. */
  .ibx-compose textarea { font-size: 16px; }
  /* La barre de recherche a une hauteur fixe, trop courte pour 16 px. */
  .gsearch .input { height: auto; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   AJOUTS GESTION COMMERCIALE
   La feuille ci-dessus est celle du design system validé (parrainage), reprise
   sans modification. Ce qui suit n'ajoute que les composants propres à cette
   application : onglets de fiche, en-têtes de section de liste, pastille de
   conversion. Aucune règle ci-dessous ne redéfinit une propriété déjà posée.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ---- onglets d'une fiche (modal) ---- */
.tabs{display:flex;gap:4px;border-bottom:1px solid var(--line);margin:0 0 18px;flex-wrap:wrap}
.tabs button{border:0;background:transparent;font:inherit;font-weight:600;font-size:13px;color:var(--slate);
  padding:9px 13px;cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1px}
.tabs button:hover{color:var(--ink)}
.tabs button.on{color:var(--blue-700);border-bottom-color:var(--blue)}
.tabpane{display:none}
.tabpane.on{display:block}

/* ---- liste de contacts dans la fiche ---- */
.contact-row{display:flex;align-items:center;gap:12px;padding:11px 0;border-bottom:1px solid var(--line-2)}
.contact-row:last-child{border-bottom:0}
.contact-row .cn{flex:1;min-width:0}
.contact-row .cn b{display:block;font-size:13.5px}
.contact-row .cn span{font-size:12px;color:var(--slate)}
.contact-row .cc{font-size:12.5px;color:var(--slate);white-space:nowrap}

/* ---- filtres par segment dans l'en-tête de carte ---- */
.card-h .seg{flex:none}

/* ---- logo global : images matricielles servies par logo.php ---- */
.brand .mark img,.login-logo .mark img{display:block;height:100%;width:auto}
/* Borne de largeur : une marque très allongée (logo horizontal avec
   signature) gardait sa largeur naturelle et sortait de la barre latérale,
   qui ne fait que 264 px moins ses marges. */
.brand .mark,.login-logo .mark{flex:none;max-width:100%;overflow:hidden}
.brand .mark img,.brand .mark svg,
.login-logo .mark img,.login-logo .mark svg{max-width:100%;object-fit:contain}
/* Quand un logo personnalisé remplace la marque, il peut prendre un peu
   plus de place : le texte n'est plus là pour l'équilibrer. */
.brand .mark.seul{height:44px;max-width:216px}
.brand .mark.seul img,.brand .mark.seul svg{height:44px}

/* ---- sidebar repliable sur PC ---- */
.app.on.sidebar-collapse{grid-template-columns:56px 1fr}
.app.on.sidebar-collapse .sidebar{padding:22px 6px;overflow-x:hidden}
.app.on.sidebar-collapse .sidebar .lbl,
.app.on.sidebar-collapse .sidebar .wm,
.app.on.sidebar-collapse .sidebar .nav a span,
.app.on.sidebar-collapse .sidebar .nav a .cnt{display:none}
.app.on.sidebar-collapse .brand{justify-content:center;padding-bottom:14px}
.app.on.sidebar-collapse .brand .mark svg{height:32px}
.app.on.sidebar-collapse .nav a{justify-content:center;padding:10px 4px}
.app.on.sidebar-collapse .nav a svg{width:20px;height:20px;flex:none}
/* ---- modales plus larges (80% PC) + scroll arrière bloqué ---- */
.modal-card.wide{max-width:min(80vw, 1100px)}
body.modal-open{overflow:hidden}
@media (min-width:1200px){.modal-card.wide{max-width:80vw;max-height:88vh}}
@media (min-width:1600px){.modal-card.wide{max-width:75vw}}

/* ---- graphiques du tableau de bord -----------------------------------------
   Barres en pourcentage, libellés en pixels : le graphique suit la largeur de
   la carte sans jamais déformer son texte (ce que faisait le SVG mis à
   l'échelle). Les couleurs de série sont validées pour le daltonisme —
   vert #1F9E6B / ambre #B27A18, ΔE deutan 8,8 — et jamais portées par du
   texte : seule la pastille colorée porte l'identité. */
:root{
  --viz-serie:#005CA9;      /* série unique : CA, top clients */
  --viz-enc:#1F9E6B;        /* encaissements */
  --viz-dec:#B27A18;        /* paiements fournisseurs */
  --viz-h:190px;            /* hauteur du tracé, hors axe des mois */
}

/* --- bandeau de synthèse --- */
.viz-resume{display:flex; flex-wrap:wrap; gap:10px 34px; margin:-4px 0 20px}
.viz-r{display:flex; flex-direction:column; gap:2px}
.viz-r-lbl{font-size:12px; color:var(--slate); font-weight:600}
.viz-r-val{font-family:"Manrope"; font-weight:800; font-size:17px; letter-spacing:-.01em}

/* --- légende : la pastille porte la couleur, jamais le mot --- */
.viz-legende{display:flex; flex-wrap:wrap; gap:8px 20px; margin-bottom:14px; font-size:12.5px; color:var(--slate)}
.viz-legende span{display:inline-flex; align-items:center; gap:7px}
.viz-cle{width:11px; height:11px; border-radius:3px; flex:none}
.viz-cle.s-enc{background:var(--viz-enc)}
.viz-cle.s-dec{background:var(--viz-dec)}

/* --- tracé : graduations à gauche, colonnes à droite --- */
.viz{display:flex; gap:12px; align-items:stretch}
.viz-axe{display:flex; flex-direction:column; justify-content:space-between;
  height:var(--viz-h); font-size:11px; color:var(--slate-400); text-align:right;
  font-variant-numeric:tabular-nums; flex:none; padding-bottom:0}
.viz-axe span{line-height:1; transform:translateY(-50%)}
.viz-axe span:first-child{transform:none}
.viz-axe span:last-child{transform:translateY(-100%)}

/* Les lignes de repère sont un dégradé du fond : traits pleins d'un pixel,
   une nuance au-dessus de la surface — jamais de pointillés, qui se lisent
   comme un seuil alors que ce n'est qu'une grille. */
.viz-cols{flex:1; min-width:0; display:flex; gap:2px; align-items:flex-end;
  height:var(--viz-h); border-bottom:1px solid var(--line);
  background-image:repeating-linear-gradient(to top, var(--line-2) 0 1px, transparent 1px 25%)}

.viz-col{flex:1; min-width:0; height:100%; display:flex; flex-direction:column;
  justify-content:flex-end; position:relative; cursor:default; border-radius:6px 6px 0 0}
.viz-col:hover,.viz-col:focus-visible{background:var(--line-2); outline:none}
.viz-piste{flex:1; display:flex; align-items:flex-end; justify-content:center; gap:2px; min-height:0}

/* Barre : 24 px au plus, coin haut arrondi, pied carré posé sur la ligne zéro. */
.viz-barre{width:100%; max-width:24px; background:var(--viz-serie); border-radius:4px 4px 0 0;
  min-height:2px; transition:filter .12s}
.viz-barre.est-max{background:var(--blue-700)}
.viz-barre.s-enc{background:var(--viz-enc)}
.viz-barre.s-dec{background:var(--viz-dec)}
.viz-duo .viz-barre{max-width:14px}
.viz-col:hover .viz-barre,.viz-col:focus-visible .viz-barre{filter:brightness(1.12)}

/* Étiquette directe : posée au-dessus de la barre, seulement là où elle compte. */
/* Posee sur la barre, jamais en haut du trace : une etiquette detachee de sa
   colonne ne se rattache plus a rien. */
.viz-barre{position:relative}
.viz-val{position:absolute; bottom:calc(100% + 4px); left:50%; transform:translateX(-50%);
  font-size:11px; font-weight:700; color:var(--ink); font-variant-numeric:tabular-nums;
  white-space:nowrap; pointer-events:none}
.viz-x{font-size:11px; color:var(--slate-400); text-align:center; padding-top:7px;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis}

/* Infobulle : elle complète, elle ne détient pas la valeur (le tableau l'a aussi).
   display:none (pas opacity/visibility) : un élément à visibility:hidden reste
   dans le calcul d'overflow de son ancêtre et pouvait, sur une colonne proche
   du bord droit, faire apparaître un défilement horizontal sur toute la page
   alors même que l'infobulle n'était jamais visible. */
.viz-tip{position:absolute; bottom:calc(100% - 2px); left:50%; transform:translateX(-50%);
  background:var(--tip-bg); color:var(--tip-tx); font-size:12px; padding:6px 10px; border-radius:8px;
  white-space:nowrap; display:none; z-index:30;
  pointer-events:none; box-shadow:var(--sh-sm)}
.viz-col:hover .viz-tip,.viz-col:focus-visible .viz-tip,
.viz-rang:hover .viz-tip,.viz-rang:focus-visible .viz-tip{display:block}

/* --- classement horizontal (top clients) --- */
.viz-rangs{display:flex; flex-direction:column; gap:4px}
.viz-rang{display:grid; grid-template-columns:minmax(70px,1.1fr) minmax(60px,2.4fr) auto auto;
  align-items:center; gap:12px; padding:7px 8px; border-radius:var(--r-xs); cursor:default}
.viz-rang:hover,.viz-rang:focus-visible{background:var(--line-2); outline:none}
.viz-nom{font-size:13px; font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.viz-piste-h{display:block; background:var(--line-2); border-radius:var(--pill); height:10px; min-width:0}
.viz-barre-h{display:block; height:100%; background:var(--viz-serie); border-radius:var(--pill)}
.viz-montant{font-size:13px; font-weight:700; text-align:right; white-space:nowrap}
.viz-part{font-size:12px; color:var(--slate); text-align:right; white-space:nowrap; min-width:44px}

/* --- phrase de lecture + tableau des valeurs exactes --- */
.viz-note{font-size:12.5px; color:var(--slate); margin:16px 0 0}
.viz-details{margin-top:10px; font-size:13px}
.viz-details summary{cursor:pointer; color:var(--link); font-weight:600; font-size:12.5px;
  list-style:none; display:inline-flex; align-items:center; gap:6px; padding:4px 0}
.viz-details summary::-webkit-details-marker{display:none}
.viz-details summary::before{content:"▸"; font-size:10px; transition:transform .12s}
.viz-details[open] summary::before{transform:rotate(90deg)}
.viz-details table{margin-top:8px; font-size:13px}
.viz-details tbody tr:last-child td{font-weight:700; border-top:1px solid var(--line)}

@media (max-width:820px){
  :root{--viz-h:150px}
  .viz-resume{gap:10px 20px}
  .viz-x{font-size:10px}
  .viz-rang{grid-template-columns:minmax(60px,1fr) minmax(40px,1.6fr) auto; gap:8px}
  .viz-part{display:none}
}

/* ---- favicon ---- */

/* ---- tableau de bord : un rythme vertical unique ----------------------------
   Tous les blocs du tableau de bord sont enfants directs de .stack : même
   largeur, même gouttière. Une marge posée en ligne sur un bloc finit
   toujours par le désaligner des autres — d'où l'absence de
   style="margin-top" dans la vue dashboard. */
.stack{display:flex; flex-direction:column; gap:var(--gap)}
.stack > *{min-width:0}
.stack > .card + .card{margin-top:0}
.card-note{font-size:13.5px; margin:-4px 0 14px}
.actions-col{display:flex; flex-direction:column; gap:10px}
.chip[hidden]{display:none}
/* icone() enveloppe son <svg> dans un <span> : c'est LUI le flex-item. */
.note > span{flex:none}
/* ---- solde net : barres de part et d'autre d'une ligne de zéro ----
   La ligne ne se place pas au milieu par principe : --viz-haut porte la part
   de hauteur revenant aux excédents, calculée sur les valeurs réelles. Une
   série entièrement positive occupe donc tout le cadre. */
.viz-diverge .viz-cols{background-image:none; border-bottom:0; position:relative}
.viz-diverge .viz-col{justify-content:flex-start}
.viz-net-haut{height:var(--viz-haut,50%); display:flex; align-items:flex-end; justify-content:center}
.viz-net-bas{height:calc(100% - var(--viz-haut,50%)); display:flex; align-items:flex-start; justify-content:center;
  border-top:1px solid var(--line)}
.viz-net .viz-barre{width:100%; max-width:24px}
.viz-net-haut .viz-barre{border-radius:4px 4px 0 0}
.viz-net-bas .viz-barre{border-radius:0 0 4px 4px}
.viz-barre.s-pos{background:var(--viz-enc)}
.viz-barre.s-neg{background:var(--danger)}
.viz-val-bas{bottom:auto; top:calc(100% + 4px)}
/* ---- ligne de total dans une liste ----
   Une depense s'ecrit en rouge et signee : la colonne doit se lire dans le
   meme sens que le total qui la soustrait. */
.ligne-total td{background:var(--line-2); border-top:1px solid var(--line); border-bottom:0}
.ligne-total:hover td{background:var(--line-2)}
tbody td.dn{color:var(--danger)}
/* Un montant coupe en deux lignes se relit mal : la colonne s'elargit. */
tbody td.right.num{white-space:nowrap}
/* ---- cartes d'indicateurs cliquables (tableau de bord) ---- */
.kpi.kpi-lien{cursor:pointer; transition:border-color .12s, box-shadow .12s, transform .12s}
.kpi.kpi-lien:hover{border-color:var(--blue); box-shadow:var(--sh)}
.kpi.kpi-lien:active{transform:translateY(1px)}
.kpi.kpi-lien:focus-visible{outline:2px solid var(--blue); outline-offset:2px}

/* ═══════════════════════════════════════════════════════════════════════════
   FORMULAIRES — saisie lisible au bureau comme sur téléphone
   ═══════════════════════════════════════════════════════════════════════════ */

/* L'attribut hidden doit gagner contre tout display posé ailleurs : sans cette
   règle, un panneau muni d'un display en ligne restait visible bien que
   « caché » — c'était le cas du sélecteur d'article de l'éditeur. */
[hidden]{display:none!important}

/* ---- boîtes de dialogue : les boutons restent à portée ----
   Un formulaire long (une proforma de douze lignes) repoussait « Créer » tout
   en bas : il fallait redescendre pour valider, et on ne savait plus s'il
   existait. Le pied colle désormais au bas de la boîte. Sauf quand il porte
   beaucoup d'actions (fiche d'un document) : collé, il couvrirait le contenu
   — modal() pose alors .pied-long et le pied reprend sa place en fin de boîte. */
.modal-card{padding-bottom:0}
.modal-card .modal-f{position:sticky; bottom:0; z-index:3; background:var(--surface);
  margin:22px -26px 0; padding:14px 26px 22px; border-top:1px solid var(--line-2)}
.modal-card.pied-long .modal-f{position:static; border-top:0; padding-top:4px}

/* ---- éditeur de lignes (proforma, commande, facture, achats) ---------------
   Une carte par ligne, sur deux étages : la désignation en pleine largeur, puis
   les chiffres, chacun sous son libellé. La grille passe de 7 colonnes au
   bureau à 4 sur tablette et 2 sur téléphone, sans jamais descendre sous une
   largeur où l'on voit ce qu'on tape. */
.le-vide{padding:18px 16px; border:1px dashed var(--line); border-radius:var(--r-sm);
  background:var(--canvas); color:var(--slate); font-size:13.5px; text-align:center}
.le-ligne{border:1px solid var(--line); border-radius:12px; background:var(--surface); padding:12px; margin-bottom:10px;
  transition:border-color .14s, box-shadow .14s}
.le-ligne:focus-within{border-color:var(--blue); box-shadow:0 0 0 3px var(--blue-050)}
.le-haut{display:flex; align-items:flex-end; gap:10px}
.le-rang{flex:none; width:26px; height:26px; margin-bottom:6px; border-radius:8px; background:var(--line-2);
  color:var(--slate); font-family:"Manrope"; font-weight:800; font-size:12px;
  display:flex; align-items:center; justify-content:center}
.le-c{display:flex; flex-direction:column; gap:5px; min-width:0}
.le-desig{flex:1 1 auto}
.le-l{font-size:10.5px; font-weight:700; letter-spacing:.05em; text-transform:uppercase;
  color:var(--slate-400); white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.le-ligne .input{padding:9px 10px; border-radius:var(--r-xs); min-width:0}
.le-ligne .input.num{text-align:right; font-variant-numeric:tabular-nums}
.le-suppr{flex:none; width:38px; height:38px; border:1px solid var(--line); background:var(--surface);
  border-radius:var(--r-xs); display:flex; align-items:center; justify-content:center;
  cursor:pointer; color:var(--slate)}
.le-suppr svg{width:17px; height:17px; stroke:currentColor}
.le-suppr:hover,.le-suppr:focus-visible{color:var(--danger); border-color:var(--err-bd); background:var(--err-bg)}

.le-chiffres{display:grid; grid-template-columns:repeat(7, minmax(0, 1fr)); gap:10px; margin-top:10px; padding-left:36px}
.le-chiffres.sans-interne{grid-template-columns:repeat(5, minmax(0, 1fr))}
/* Valeurs calculées (marge, total) : alignées sur la hauteur des champs. */
.le-calc .le-v{display:flex; align-items:center; justify-content:flex-end; min-height:38px;
  font-size:14px; white-space:nowrap}
/* Prix d'achat et marge : informations INTERNES, jamais imprimées. Le fond
   violet pâle les distingue de ce que le client verra. */
.le-interne .le-l{color:var(--purple-700)}
.le-interne .input{background:var(--purple-050); border-color:var(--purple-bd2)}
.le-interne .input:focus{background:var(--surface)}
.le-total .le-v{font-size:14.5px}

@media (max-width:1100px){
  .le-chiffres{grid-template-columns:repeat(4, minmax(0, 1fr))}
  .le-chiffres.sans-interne{grid-template-columns:repeat(3, minmax(0, 1fr))}
  .le-total{grid-column:span 2}
  .le-chiffres.sans-interne .le-total{grid-column:span 2}
}
@media (max-width:560px){
  .le-ligne{padding:12px 10px}
  .le-chiffres,.le-chiffres.sans-interne{grid-template-columns:repeat(2, minmax(0, 1fr)); padding-left:0; gap:10px 8px}
  /* Le total de la ligne se lit comme une conclusion : libellé à gauche,
     montant à droite, sous un trait. */
  .le-total,.le-chiffres.sans-interne .le-total{grid-column:1 / -1; flex-direction:row; align-items:center;
    justify-content:space-between; border-top:1px dashed var(--line); padding-top:8px}
  .le-total .le-v{min-height:0}
  .le-rang{display:none}
}

/* Sélecteur d'article et pied de l'éditeur */
.ed-pick{display:flex; gap:8px; margin-top:10px; flex-wrap:wrap; align-items:flex-start;
  background:var(--line-2); border-radius:var(--r-sm); padding:10px 12px}
.ed-pick select{flex:1 1 220px; min-width:0}
.ed-pick .suggest-wrap{flex:1 1 240px; min-width:0}
.ed-pick .suggest-wrap .input{width:100%}
.ed-pied{display:flex; gap:14px 20px; margin-top:12px; flex-wrap:wrap; align-items:flex-start; justify-content:space-between}
.ed-ajouts{display:flex; gap:8px; flex-wrap:wrap}
.ed-ajouts .btn svg{width:15px; height:15px}
.ed-totaux{min-width:250px; margin:0; padding:12px 14px; background:var(--canvas); border-radius:var(--r-sm)}
.ed-totaux dd{text-align:right; white-space:nowrap}

/* ---- tableaux de saisie (livrer, facturer, créditer, affecter) ----
   Le rembourrage d'un tableau de lecture (14 px par cellule) ne laisse pas de
   place à un champ : on le resserre, et la colonne à saisir garde une largeur
   où un montant tient en entier. */
.tbl-saisie thead th{padding:0 8px 10px}
.tbl-saisie tbody td{padding:10px 8px}
.tbl-saisie .col-saisie{width:140px}
.tbl-saisie .input.num{min-width:100px; padding:9px 10px; text-align:right; font-variant-numeric:tabular-nums}
tbody td .input{padding:9px 10px}

/* ---- mini-éditeur riche (lignes, conditions) ----
   Barre d'outils sobre + aperçu fidèle au PDF (même syntaxe ** _ -). */
.rich-bar{display:flex; gap:6px; margin:2px 0 6px; grid-column:1 / -1}
.rich-bar button{border:1px solid var(--line); background:var(--surface); border-radius:8px;
  min-width:32px; min-height:30px; padding:4px 10px; font-size:12.5px; cursor:pointer; color:var(--ink)}
.rich-bar button:hover{border-color:var(--blue); color:var(--blue-700)}
.rich-preview{border:1px dashed var(--line-2); border-radius:8px; padding:8px 10px; margin-top:6px;
  font-size:13px; background:var(--canvas); grid-column:1 / -1}
.rich-preview .rich-corps{margin-top:2px}
.le-desc{margin-top:10px}
.le-desc textarea{width:100%; min-height:52px}

/* ---- téléphone : les tableaux .tbl-cards deviennent des cartes ----
   Chaque ligne à data-* est une carte (titre = cellule data-titre, sans
   étiquette), chaque autre cellule une ligne « Étiquette : valeur » via
   data-th. Les lignes sans data-* (totaux, états vides) restent des lignes
   normales. Pour passer un tableau en cartes : class="tbl-cards" sur table
   + data-th="…" sur chaque td (+ data-titre sur la cellule titre). */
@media (max-width:640px){
  table.tbl-cards thead{display:none}
  table.tbl-cards, table.tbl-cards tbody{display:block}
  table.tbl-cards tbody tr[data-tier], table.tbl-cards tbody tr[data-produit],
  table.tbl-cards tbody tr[data-document], table.tbl-cards tbody tr[data-contrat],
  table.tbl-cards tbody tr[data-reglement], table.tbl-cards tbody tr[data-mouvement],
  table.tbl-cards tbody tr[data-utilisateur], table.tbl-cards tbody tr[data-site],
  table.tbl-cards tbody tr[data-sauvegarde]{
    display:block; background:var(--surface); border:1px solid var(--line); border-radius:var(--r-sm);
    padding:12px 14px; margin-bottom:10px; box-shadow:var(--sh-sm)}
  table.tbl-cards tbody td{display:flex; align-items:baseline; gap:10px; padding:5px 0; border:0; font-size:13.5px}
  table.tbl-cards tbody td::before{content:attr(data-th); flex:0 0 96px; font-size:11px; font-weight:700;
    letter-spacing:.05em; text-transform:uppercase; color:var(--slate-400)}
  table.tbl-cards tbody td:not([data-th])::before{display:none}
  table.tbl-cards tbody td[data-titre]{font-size:15.5px; padding-bottom:7px; margin-bottom:3px; border-bottom:1px dashed var(--line)}
  table.tbl-cards tbody td[data-titre]::before{display:none}
  table.tbl-cards tbody tr:hover{background:var(--surface)}
  table.tbl-cards .rowbtns{justify-content:flex-start}
}

/* ---- téléphone : la boîte devient un panneau plein écran ----
   Une boîte centrée avec 22 px de marge tout autour perdait près d'un
   cinquième de la largeur d'un téléphone. Elle monte désormais du bas, sur
   toute la largeur, et ses boutons prennent la place d'un pouce. */
@media (max-width:640px){
  .modal{padding:0; align-items:flex-end}
  .modal-card,.modal-card.wide{width:100%; max-width:100%; border-radius:18px 18px 0 0;
    max-height:calc(100vh - 8px); max-height:calc(100dvh - 8px); padding:18px 16px 0}
  .modal-h{margin-bottom:14px; gap:10px}
  .modal-h h3{font-size:16px}
  .modal-card .modal-f{margin:18px -16px 0; padding:12px 16px calc(12px + env(safe-area-inset-bottom, 0px))}
  .modal-card .modal-f .btn{flex:1 1 auto; justify-content:center; min-height:44px}
  .modal-card.pied-long .modal-f .btn{flex:1 1 calc(50% - 5px)}
  .form-grid{gap:12px}
  .btn-sm{min-height:40px}
  .ed-ajouts{width:100%}
  .ed-ajouts .btn{flex:1 1 0; justify-content:center}
  .ed-totaux{width:100%; min-width:0}
  .ed-pick .btn{flex:1 1 0; justify-content:center}
  /* Le filtre de classement, comme la recherche, prend toute la largeur. */
  .card-h .tools select.input.filtre-liste{width:100%}
}

/* ---- filtre de classement et pastille ---- */
select.input.filtre-liste{width:auto; padding:8px 34px 8px 12px; font-size:13px; border-radius:var(--r-xs)}
.chip-classement{margin-left:4px; max-width:190px; overflow:hidden; text-overflow:ellipsis; vertical-align:middle}

/* ═══════════════════════════════════════════════════════════════════════════
   ÉCHÉANCIER 12 MOIS (tableau de bord)
   ═══════════════════════════════════════════════════════════════════════════ */

/* Couleurs des familles : slots validés en toutes paires (bleu, ambre, violet),
   y compris sous protanopie et deutéranopie. Elles ne portent jamais seules
   l'information — la légende les nomme et chaque pastille garde sa place. */
:root{
  --cal-client:#005CA9;
  --cal-fournisseur:#B27A18;
  --cal-facture:#A863A5;
  --cal-case:30px;
}
.s-client{--c:var(--cal-client)}
.s-fournisseur{--c:var(--cal-fournisseur)}
.s-facture{--c:var(--cal-facture)}

.cal{position:relative}

/* ---- légende = filtre ---- */
.cal-barre{display:flex; flex-wrap:wrap; gap:10px 16px; align-items:center; margin:-4px 0 14px}
.cal-legende{display:flex; flex-wrap:wrap; gap:8px}
.cal-filtre{display:inline-flex; align-items:center; gap:7px; padding:6px 11px 6px 9px; border:1px solid var(--line);
  border-radius:var(--pill); font-size:12.5px; font-weight:600; color:var(--slate); cursor:pointer; user-select:none;
  background:var(--surface); transition:border-color .12s, background .12s}
.cal-filtre:hover{border-color:var(--line-strong)}
.cal-filtre input{position:absolute; opacity:0; pointer-events:none}
.cal-filtre.focus{outline:2px solid var(--blue); outline-offset:2px}
.cal-filtre.off{background:var(--line-2); color:var(--slate-400); text-decoration:line-through}
.cal-filtre.off .cal-cle{background:transparent; box-shadow:inset 0 0 0 1.5px var(--c)}
.cal-cle{display:inline-block; width:10px; height:10px; border-radius:3px; background:var(--c); flex:none}
.cal-nb{font-variant-numeric:tabular-nums; color:var(--ink); font-weight:700}

/* ---- retards ---- */
.cal-retard{display:flex; align-items:center; gap:10px; width:100%; margin:0 0 14px; padding:10px 14px;
  border:1px solid var(--err-bd); background:var(--err-bg); color:var(--err-tx); border-radius:var(--r-sm);
  font:inherit; font-size:13.5px; text-align:left; cursor:pointer}
.cal-retard svg{width:18px; height:18px; stroke:var(--danger); flex:none}
.cal-retard span:nth-child(2){flex:1}
.cal-retard-voir{font-weight:700; white-space:nowrap; font-size:12.5px}
.cal-retard:hover,.cal-retard.sel{border-color:var(--danger)}

/* ---- corps : grille des mois + panneau ---- */
.cal-corps{display:grid; grid-template-columns:minmax(0, 1fr) 320px; gap:var(--gap); align-items:start}
.cal-mois-grille{display:grid; grid-template-columns:repeat(auto-fill, minmax(214px, 1fr)); gap:18px 20px}

.cal-mois header{display:flex; align-items:center; gap:8px; margin-bottom:6px}
.cal-mois-t{border:0; background:none; padding:2px 4px; margin-left:-4px; font:inherit; font-family:"Manrope";
  font-weight:800; font-size:13.5px; color:var(--ink); cursor:pointer; border-radius:6px}
.cal-mois-t span{color:var(--slate-400); font-weight:700}
.cal-mois-t:hover,.cal-mois-t.sel{background:var(--blue-050); color:var(--blue-700)}
.cal-mois-nb{margin-left:auto; font-size:11.5px; font-weight:700; color:var(--slate); background:var(--line-2);
  border-radius:var(--pill); padding:1px 8px; font-variant-numeric:tabular-nums}

.cal-sem,.cal-grille{display:grid; grid-template-columns:repeat(7, 1fr); gap:2px}
.cal-sem span{font-size:10px; font-weight:700; color:var(--slate-400); text-align:center; padding-bottom:3px}

/* Une case = une zone cliquable entière (≥ 28 px), jamais le seul point. */
.cal-j{position:relative; height:var(--cal-case); display:flex; flex-direction:column; align-items:center;
  justify-content:center; border-radius:6px; font-size:11.5px; color:var(--slate); font-variant-numeric:tabular-nums;
  border:0; background:transparent; padding:0; font-family:inherit}
.cal-j.vide{visibility:hidden}
.cal-j.passe{color:var(--soft)}
.cal-j .n{line-height:1}
.cal-j.a-evt{cursor:pointer; color:var(--ink); font-weight:700; background:var(--line-2)}
.cal-j.a-evt:hover,.cal-j.a-evt:focus-visible{background:var(--blue-050); outline:1px solid var(--blue); outline-offset:0}
.cal-j.auj{box-shadow:inset 0 0 0 1.5px var(--ink)}
.cal-j.sel{background:var(--blue); color:#fff}
.cal-j.sel .pts i{box-shadow:0 0 0 1.5px #fff}

/* Pastilles : trois emplacements fixes (client, fournisseur, facture). Une
   famille absente garde sa place — la position reste un repère fiable. */
.cal-j .pts{display:flex; gap:2px; margin-top:3px; height:5px}
.cal-j .pts i{width:5px; height:5px; border-radius:50%; background:var(--c)}
.cal-j .pts i.absent{visibility:hidden}
.cal.sans-client .pts i.s-client,
.cal.sans-fournisseur .pts i.s-fournisseur,
.cal.sans-facture .pts i.s-facture{visibility:hidden}
/* Toutes ses familles masquées : le jour redevient ordinaire. */
.cal-j.a-evt.filtre-vide{background:transparent; color:var(--slate); font-weight:400; cursor:default; pointer-events:none}

/* ---- panneau de détail ---- */
.cal-panneau{border:1px solid var(--line); border-radius:var(--r-sm); background:var(--canvas); padding:14px 14px 8px;
  position:sticky; top:12px; max-height:calc(100vh - 40px); overflow-y:auto}
.cal-panneau-h{display:flex; align-items:center; gap:8px; margin-bottom:8px}
.cal-panneau-h b{font-family:"Manrope"; font-size:14px; flex:1}
.cal-panneau-raz{border:1px solid var(--line); background:var(--surface); border-radius:var(--pill); padding:3px 10px;
  font:inherit; font-size:11.5px; font-weight:600; color:var(--slate); cursor:pointer; white-space:nowrap}
.cal-liste{list-style:none; margin:0; padding:0}
.cal-ev button{display:flex; align-items:flex-start; gap:10px; width:100%; text-align:left; border:0;
  background:transparent; padding:9px 6px; border-radius:8px; font:inherit; cursor:pointer; color:var(--ink)}
.cal-ev + .cal-ev button{border-top:1px solid var(--line-2); border-radius:0}
.cal-ev button:hover,.cal-ev button:focus-visible{background:var(--surface)}
.cal-ev .cal-cle{margin-top:4px}
.cal-ev-t{flex:1; min-width:0; display:flex; flex-direction:column; gap:2px; font-size:13px}
.cal-ev-t b{font-weight:600; line-height:1.3}
.cal-ev-d{font-size:11px; font-weight:700; color:var(--slate); font-variant-numeric:tabular-nums}
.cal-ev-s{font-size:12px; color:var(--slate); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.cal-ev-m{font-size:12.5px; font-weight:700; white-space:nowrap; padding-top:1px}
.cal-liste-vide{font-size:13px; color:var(--slate); padding:10px 4px 12px}

/* ---- infobulle ---- */
.cal-info{position:absolute; z-index:20; width:270px; max-width:calc(100% - 8px); background:var(--tip-bg); color:var(--tip-tx);
  border-radius:10px; padding:10px 12px; box-shadow:0 10px 30px rgba(24,32,49,.25); pointer-events:none; font-size:12.5px}
.cal-info-h{font-weight:700; font-size:12px; color:var(--tip-mut); margin-bottom:6px}
.cal-info-l{display:grid; grid-template-columns:12px 1fr; column-gap:8px; row-gap:1px; padding:4px 0}
.cal-info-l + .cal-info-l{border-top:1px solid rgba(255,255,255,.1)}
.cal-info-l b{font-weight:600}
.cal-info-l span{grid-column:2; color:var(--tip-mut); font-size:11.5px}
/* Clé en trait court, pas en carré : à cette densité une surface pleine
   ferait le travail d'une étiquette. */
.cal-trait{width:12px; height:3px; border-radius:2px; background:var(--c); margin-top:7px}
.cal-info-plus{color:var(--tip-mut); font-size:11.5px; padding-top:4px}

/* ---- tablette : le panneau passe sous la grille ---- */
@media (max-width:1100px){
  .cal-corps{grid-template-columns:1fr}
  .cal-panneau{position:static; max-height:none}
}
/* ---- téléphone : les mois défilent à l'horizontale ----
   Douze mois empilés feraient trois mètres de page. Une rangée qu'on fait
   glisser du doigt garde la vue d'ensemble à portée, un mois à la fois, avec
   des cases assez grandes pour être touchées. */
@media (max-width:640px){
  :root{--cal-case:38px}
  .cal-mois-grille{display:flex; overflow-x:auto; scroll-snap-type:x mandatory; gap:14px;
    padding-bottom:6px; margin:0 -4px; padding-left:4px; padding-right:4px}
  .cal-mois{flex:0 0 calc(100% - 28px); scroll-snap-align:start}
  .cal-j{font-size:13px}
  .cal-j .pts i{width:6px; height:6px}
  .cal-filtre{font-size:12px}
  .cal-info{display:none}
}

/* ═══════════════════════════════════════════════════════════════════════════
   BANDEAUX DE SANTÉ (mise à jour de la base, cron)
   ═══════════════════════════════════════════════════════════════════════════ */
.bandeau-systeme{align-items:flex-start}
.bandeau-systeme > svg{margin-top:2px}
.bandeau-corps{flex:1; min-width:0; line-height:1.5}
.bandeau-systeme > .btn{flex:none; align-self:center}
.bandeau-details{margin-top:6px}
.bandeau-details summary{cursor:pointer; font-weight:600; font-size:13px; width:max-content; max-width:100%}
.bandeau-details p{margin:6px 0}
.bandeau-details ul{margin:6px 0 0; padding-left:20px; font-size:12.5px}
.bandeau-code{display:block; margin:6px 0; padding:8px 10px; background:rgba(255,255,255,.7); border:1px solid rgba(0,0,0,.08);
  border-radius:8px; font-size:12px; font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  white-space:pre-wrap; word-break:break-all; user-select:all}
@media (max-width:640px){
  .bandeau-systeme{flex-wrap:wrap}
  .bandeau-systeme > .btn{width:100%; justify-content:center}
}
