  :root{
    --bg:#eef1f7;
    --blob-blue:#a9c8ff;
    --blob-mint:#b7f0dd;
    --blob-pink:#ffc9de;
    --glass:rgba(255,255,255,0.55);
    --glass-strong:rgba(255,255,255,0.72);
    --glass-border:rgba(255,255,255,0.75);
    --glass-solid:rgba(255,255,255,0.94);
    --line:rgba(148,163,184,0.28);
    --accent:#5a7dfa;
    --accent-soft:#eef1ff;
    --accent-deep:#3d57c9;
    --mint:#22b892;
    --coral:#ef7d6b;
    --text-hi:#1c2333;
    --text:#495066;
    --text-mute:#8790a8;
    --font-display:'Manrope', sans-serif;
    --font-body:'Inter', sans-serif;
    --font-mono:'JetBrains Mono', monospace;
    color-scheme: light;
  }
  html.theme-dark{
    color-scheme: dark;
    --bg:#11151f;
    --glass:rgba(255,255,255,0.10);
    --glass-strong:rgba(255,255,255,0.14);
    --glass-border:rgba(255,255,255,0.13);
    --glass-solid:#161c29;
    --line:rgba(255,255,255,0.12);
    --text-hi:#f5f7fb;
    --text:#b9c1d4;
    --text-mute:#7c8598;
  }
  html.theme-dark .blob{ opacity:0.32; }
  *{box-sizing:border-box; margin:0; padding:0;}
  html,body{
    width:100%; min-height:100vh;
    background:var(--bg);
    color:var(--text);
    font-family:var(--font-body);
    overflow-x:hidden;
  }
  a{color:inherit; text-decoration:none;}
  .hidden{display:none !important;}

  /* ====================================================================
     BASE GÉNÉRIQUE DES CHAMPS DE FORMULAIRE — filet de sécurité valable
     pour TOUT le site : jusqu'ici chaque zone (panneau de config, console
     staff, salons vocaux, recherche de commandes, chat…) réinventait son
     propre style de champ (rayons différents, anneau de focus tantôt
     présent tantôt absent, flèche de <select> jamais custom en dehors du
     panneau de config…), et certains champs sans classe dédiée (ex :
     #cmdSearchInput avant son wrapper, tout futur champ oublié) retombaient
     carrément sur le rendu par défaut du navigateur.

     Cette règle couvre tout input texte / select / textarea SANS classe
     spécifique, avec le vocabulaire visuel commun (var(--glass),
     var(--line), var(--accent)…). Elle est volontairement écrite avec
     :where() pour avoir une spécificité DE ZÉRO : n'importe quelle classe
     dédiée (.cfg-input, .cfg-ob-input, .nrchat-input, .cmd-search-box
     input, etc. — cf. plus bas) continue de l'emporter sans avoir besoin
     de !important ni de sur-spécifier ses sélecteurs. Les cases à cocher/
     radio/couleur/fichier/range ont leurs propres traitements dédiés
     ailleurs (.toggle, .cfg-ob-role-chip, input[type="color"]…) et sont
     donc exclues ici. */
  :where(
    input[type="text"], input[type="email"], input[type="password"],
    input[type="search"], input[type="url"], input[type="tel"],
    input[type="number"], input[type="date"], input[type="datetime-local"],
    input:not([type]), select, textarea
  ){
    font-family:var(--font-body); font-size:12.5px; color:var(--text-hi);
    background:var(--glass); border:1px solid var(--line); border-radius:10px;
    padding:9px 12px; outline:none; width:100%;
    transition:border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
  }
  :where(input, textarea)::placeholder{ color:var(--text-mute); opacity:0.75; }
  :where(
    input[type="text"], input[type="email"], input[type="password"],
    input[type="search"], input[type="url"], input[type="tel"],
    input[type="number"], input:not([type]), select, textarea
  ):hover{ border-color:rgba(148,163,184,0.5); }
  :where(
    input[type="text"], input[type="email"], input[type="password"],
    input[type="search"], input[type="url"], input[type="tel"],
    input[type="number"], input:not([type]), select, textarea
  ):focus{
    border-color:var(--accent); background:var(--glass-strong);
    box-shadow:0 0 0 3px rgba(90,125,250,0.15);
  }
  :where(input, select, textarea):disabled{ opacity:0.5; cursor:not-allowed; }
  :where(textarea){ resize:vertical; line-height:1.45; }
  :where(select){
    appearance:none; -webkit-appearance:none; cursor:pointer;
    background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none'><path d='M5.5 7.5l4.5 4.5 4.5-4.5' stroke='%237c8598' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/></svg>");
    background-repeat:no-repeat; background-position:right 10px center; padding-right:30px;
  }
  /* Filet en complément de color-scheme (cf. :root/html.theme-dark plus haut) :
     color-scheme pilote le thème des popups natifs de <select> dans la plupart
     des navigateurs, mais certains (Firefox notamment) respectent aussi le
     style direct posé sur <option> — sans ce filet, ces navigateurs af-
     fichaient encore un popup clair par défaut même avec color-scheme correct.
     Couvre TOUS les <select> du site, y compris ceux générés dynamiquement
     par script.js (.cfg-input, .cfg-picker-select, etc.) puisque c'est
     l'élément <option> lui-même qui est ciblé, pas une classe de wrapper. */
  select option{ background:var(--glass-solid); color:var(--text-hi); }

  /* Anneau de focus générique pour les barres de recherche "en pilule" où
     c'est le conteneur (pas l'input, transparent par design) qui porte la
     bordure — ex: .gestion-search, .cmd-search-box. Sans ça, taper dans ces
     champs ne donnait ABSOLUMENT aucun retour visuel de focus, contrairement
     à tous les autres champs du site. */
  .gestion-search:focus-within,
  .cmd-search-box:focus-within{
    border-color:var(--accent); box-shadow:0 0 0 3px rgba(90,125,250,0.15);
  }

  /* ---- Scrollbar custom (remplace les flèches natives du navigateur) ---- */
  *{ scrollbar-width:thin; scrollbar-color:rgba(120,130,150,0.45) transparent; }
  *::-webkit-scrollbar{ width:8px; height:8px; }
  *::-webkit-scrollbar-track{ background:transparent; }
  *::-webkit-scrollbar-thumb{ background:rgba(120,130,150,0.35); border-radius:8px; border:2px solid transparent; background-clip:padding-box; }
  *::-webkit-scrollbar-thumb:hover{ background:rgba(120,130,150,0.55); background-clip:padding-box; }
  *::-webkit-scrollbar-button{ display:none; width:0; height:0; }
  *::-webkit-scrollbar-corner{ background:transparent; }


  .blobs{ position:fixed; inset:0; z-index:0; overflow:hidden; pointer-events:none; }
  .blob{ position:absolute; border-radius:50%; filter:blur(70px); opacity:0.55; }
  .blob.b1{ width:520px; height:520px; background:var(--blob-blue); top:-160px; left:-120px; animation:drift1 22s ease-in-out infinite; }
  .blob.b2{ width:460px; height:460px; background:var(--blob-mint); bottom:-140px; right:-100px; animation:drift2 26s ease-in-out infinite; }
  .blob.b3{ width:380px; height:380px; background:var(--blob-pink); top:38%; right:12%; animation:drift3 20s ease-in-out infinite; }
  @keyframes drift1{ 0%,100%{transform:translate(0,0);} 50%{transform:translate(40px,50px);} }
  @keyframes drift2{ 0%,100%{transform:translate(0,0);} 50%{transform:translate(-40px,-30px);} }
  @keyframes drift3{ 0%,100%{transform:translate(0,0);} 50%{transform:translate(-30px,40px);} }

  .screen{ position:relative; z-index:1; width:100%; min-height:100vh; }

  /* ================= INTRO ================= */
  #intro{
    display:flex; flex-direction:column; align-items:center; justify-content:center;
    padding:6vh 24px; text-align:center;
    transition:opacity 0.6s ease, filter 0.6s ease;
  }
  #intro.leaving{ opacity:0; filter:blur(10px); }

  .intro-card{
    background:var(--glass);
    border:1px solid var(--glass-border);
    backdrop-filter:blur(24px);
    -webkit-backdrop-filter:blur(24px);
    border-radius:28px;
    padding:52px 56px;
    max-width:560px;
    box-shadow:0 20px 60px -20px rgba(90,125,250,0.25);
    opacity:0; animation:rise 0.8s ease forwards 0.1s;
  }

  .badge{
    width:64px; height:64px; margin:0 auto 20px;
    border-radius:20px;
    background:linear-gradient(135deg, var(--accent), #8fa5ff);
    display:flex; align-items:center; justify-content:center;
    box-shadow:0 10px 24px -8px rgba(90,125,250,0.55);
  }
  .badge span{ font-family:var(--font-display); font-weight:800; font-size:19px; color:#fff; letter-spacing:0.02em; }

  .intro-logo-crest{
    display:block; height:92px; width:auto; margin:0 auto 20px;
    filter:drop-shadow(0 10px 24px rgba(20,30,60,0.4));
  }

  .eyebrow{
    font-size:11px; font-weight:600; letter-spacing:0.16em; text-transform:uppercase;
    color:var(--accent-deep); margin-bottom:10px;
  }

  h1.wordmark{
    font-family:var(--font-display); font-weight:800;
    font-size:clamp(34px, 5vw, 44px);
    color:var(--text-hi); letter-spacing:-0.01em; line-height:1.1;
  }

  .lede{
    font-size:14.5px; line-height:1.7; color:var(--text);
    max-width:400px; margin:14px auto 0;
  }

  .stat-strip{
    display:flex; justify-content:center; gap:10px;
    margin-top:28px; flex-wrap:wrap;
  }
  .stat-pill{
    background:var(--glass-strong); border:1px solid var(--line);
    border-radius:14px; padding:10px 18px; min-width:86px;
  }
  .stat-pill .num{ font-family:var(--font-mono); font-size:17px; font-weight:500; color:var(--text-hi); }
  .stat-pill .lbl{ font-size:10px; color:var(--text-mute); margin-top:2px; }

  .cta{
    margin-top:30px;
    font-family:var(--font-body); font-size:14px; font-weight:600;
    color:#fff;
    background:linear-gradient(135deg, var(--accent), var(--accent-deep));
    border:none; padding:15px 34px; border-radius:16px; cursor:pointer;
    box-shadow:0 14px 30px -10px rgba(90,125,250,0.55);
    transition:transform 0.2s ease, box-shadow 0.2s ease;
    position:relative;
  }
  .cta:hover{ transform:translateY(-2px); box-shadow:0 18px 34px -8px rgba(90,125,250,0.65); }
  .cta:active{ transform:translateY(0) scale(0.98); }
  .cta:focus-visible{ outline:2px solid var(--accent-deep); outline-offset:3px; }
  .cta.sealing::after{
    content:''; position:absolute; inset:0; border-radius:16px;
    background:rgba(255,255,255,0.5); animation:flash 0.55s ease forwards;
  }

  .cta-sub{ margin-top:14px; font-size:11.5px; color:var(--text-mute); display:flex; align-items:center; justify-content:center; gap:7px; }
  .dot-live{ width:6px; height:6px; border-radius:50%; background:var(--mint); box-shadow:0 0 0 3px rgba(34,184,146,0.18); }
  .cta-sub.status-warn .dot-live{ background:#f5a623; box-shadow:0 0 0 3px rgba(245,166,35,0.2); }
  .cta-sub.status-critical .dot-live{ background:#ef4444; box-shadow:0 0 0 3px rgba(239,68,68,0.18); }

  footer.intro-foot{
    position:absolute; bottom:20px; left:0; right:0; text-align:center;
    font-size:10.5px; color:var(--text-mute); z-index:1;
  }
  footer.intro-foot a, .dash-copyright a{
    color:var(--text-mute); text-decoration:none; border-bottom:1px solid transparent;
    transition:color 0.15s ease, border-color 0.15s ease;
  }
  footer.intro-foot a:hover, .dash-copyright a:hover{ color:var(--accent-deep); border-color:var(--accent-deep); }

  @keyframes rise{ from{opacity:0; transform:translateY(16px);} to{opacity:1; transform:translateY(0);} }
  @keyframes flash{ from{opacity:1;} to{opacity:0;} }

  /* ================= SERVER SELECT ================= */
  #server-select{
    display:none; flex-direction:column; align-items:center; justify-content:center;
    padding:6vh 24px; text-align:center;
    transition:opacity 0.5s ease, filter 0.5s ease;
  }
  #server-select.active{ display:flex; }
  #server-select.entering{ opacity:0; filter:blur(10px); animation:sRise 0.55s ease forwards; }
  #server-select.leaving{ opacity:0; filter:blur(10px); }
  @keyframes sRise{ from{opacity:0; filter:blur(10px);} to{opacity:1; filter:blur(0);} }

  .select-head{ margin-bottom:30px; opacity:0; animation:rise 0.7s ease forwards 0.05s; }
  .select-head .eyebrow{ font-size:11px; font-weight:600; letter-spacing:0.16em; text-transform:uppercase; color:var(--accent-deep); margin-bottom:8px; }
  .select-head h2{ font-family:var(--font-display); font-weight:800; font-size:clamp(26px,4vw,32px); color:var(--text-hi); letter-spacing:-0.01em; }
  .select-head p{ font-size:13.5px; color:var(--text-mute); margin-top:8px; }

  .select-body{
    width:100%; max-width:1180px; margin:0 auto;
    display:grid; grid-template-columns:236px minmax(0,1fr) 236px;
    align-items:start; gap:24px; text-align:left;
  }

  .select-aside{
    position:relative; overflow:hidden;
    background:var(--glass); border:1px solid var(--glass-border);
    backdrop-filter:blur(24px); -webkit-backdrop-filter:blur(24px);
    border-radius:22px; padding:20px 18px; display:flex; flex-direction:column; gap:16px;
    box-shadow:0 24px 46px -30px rgba(20,26,46,0.28);
    opacity:0; animation:rise 0.6s ease forwards 0.16s;
  }
  .select-aside::before{
    content:''; position:absolute; top:0; left:0; right:0; height:3px;
    background:linear-gradient(90deg, var(--aside-accent), var(--aside-accent-b));
  }
  .select-stats{ --aside-accent:#5a7dfa; --aside-accent-b:#8fa5ff; }
  .select-quick{ --aside-accent:#f5b942; --aside-accent-b:#ffd27a; }

  .select-aside-head{ display:flex; align-items:center; gap:12px; }
  .select-aside-icon{
    width:38px; height:38px; border-radius:12px; flex:0 0 auto;
    display:flex; align-items:center; justify-content:center;
    background:linear-gradient(135deg, var(--aside-accent), var(--aside-accent-b));
    box-shadow:0 10px 20px -9px color-mix(in srgb, var(--aside-accent) 65%, transparent);
  }
  .select-aside-icon svg{ width:17px; height:17px; stroke:#fff; }
  .select-aside-head-text{ min-width:0; }
  .select-aside-eyebrow{ font-size:10px; font-weight:600; letter-spacing:0.14em; text-transform:uppercase; color:var(--accent-deep); margin-bottom:2px; }
  .select-aside-title{ font-family:var(--font-display); font-weight:800; font-size:15.5px; color:var(--text-hi); display:flex; align-items:center; gap:8px; }
  .select-aside-count{
    font-family:var(--font-mono); font-size:10px; font-weight:600; color:var(--accent-deep);
    background:var(--accent-soft); padding:2px 7px; border-radius:8px; line-height:1.5;
  }
  html.theme-dark .select-aside-count{ background:rgba(90,125,250,0.16); }

  /* ---- Stats ---- */
  .stat-row{
    --stat-accent: var(--accent);
    display:flex; align-items:center; gap:12px; padding:11px 12px;
    border-radius:15px; background:rgba(255,255,255,0.38); border:1px solid var(--glass-border);
    transition:transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease;
  }
  html.theme-dark .stat-row{ background:rgba(255,255,255,0.045); }
  .stat-row:hover{
    transform:translateY(-2px);
    box-shadow:0 14px 26px -18px color-mix(in srgb, var(--stat-accent) 60%, transparent);
    border-color:color-mix(in srgb, var(--stat-accent) 35%, var(--glass-border));
  }
  .stat-row-icon{
    width:36px; height:36px; border-radius:12px; flex:0 0 auto;
    display:flex; align-items:center; justify-content:center;
    background:color-mix(in srgb, var(--stat-accent) 16%, var(--glass-strong));
    color:var(--stat-accent);
    box-shadow:0 0 0 3px color-mix(in srgb, var(--stat-accent) 12%, transparent);
  }
  html.theme-dark .stat-row-icon{ background:color-mix(in srgb, var(--stat-accent) 22%, transparent); }
  .stat-row-icon svg{ width:16px; height:16px; }
  .stat-row-info{ min-width:0; }
  .stat-row-num{ font-family:var(--font-mono); font-size:17px; font-weight:600; color:var(--text-hi); display:flex; align-items:center; gap:6px; }
  .stat-row-lbl{ font-size:10.5px; color:var(--text-mute); margin-top:2px; }

  /* ---- Actions rapides (favoris) ---- */
  .quick-list{ display:flex; flex-direction:column; gap:9px; }
  .quick-item{
    --qa-accent: var(--accent); --qa-accent-b: #8fa5ff;
    position:relative;
    display:flex; align-items:center; gap:11px; width:100%; padding:10px 12px 10px 14px;
    border-radius:15px; background:rgba(255,255,255,0.38); border:1px solid var(--glass-border);
    box-shadow:inset 3px 0 0 0 var(--qa-accent);
    cursor:pointer; text-align:left; font-family:inherit;
    transition:transform 0.22s cubic-bezier(.2,.8,.2,1), box-shadow 0.22s ease, border-color 0.22s ease;
  }
  html.theme-dark .quick-item{ background:rgba(255,255,255,0.045); }
  .quick-item:hover{
    transform:translateY(-3px);
    box-shadow:inset 3px 0 0 0 var(--qa-accent), 0 16px 28px -18px color-mix(in srgb, var(--qa-accent) 55%, transparent), 0 8px 16px -12px rgba(20,26,46,0.18);
    border-color:color-mix(in srgb, var(--qa-accent) 42%, var(--glass-border));
  }
  .quick-item:active{ transform:translateY(-1px) scale(0.99); }
  .quick-item-icon{
    width:36px; height:36px; border-radius:11px; flex:0 0 auto;
    display:flex; align-items:center; justify-content:center;
    font-family:var(--font-display); font-weight:700; font-size:11px; color:#fff; letter-spacing:0.01em;
    background:linear-gradient(135deg, var(--qa-accent), var(--qa-accent-b));
    border:2px solid var(--glass-strong);
    box-shadow:0 6px 14px -6px color-mix(in srgb, var(--qa-accent) 55%, transparent);
  }
  .quick-item-info{ min-width:0; flex:1; }
  .quick-item-name{ font-size:12.5px; font-weight:600; color:var(--text-hi); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .quick-item-sub{ font-size:10px; color:var(--text-mute); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; margin-top:1px; }
  .quick-item-arrow{ flex:0 0 auto; color:var(--text-mute); transition:transform 0.22s ease, color 0.22s ease; }
  .quick-item-arrow svg{ width:13px; height:13px; display:block; }
  .quick-item:hover .quick-item-arrow{ transform:translateX(3px); color:var(--accent-deep); }

  .quick-empty{
    display:none; flex-direction:column; align-items:center; text-align:center; gap:9px;
    padding:22px 10px; color:var(--text-mute); font-size:11px; line-height:1.55;
    border:1.5px dashed var(--glass-border); border-radius:15px;
    background:rgba(255,255,255,0.18);
  }
  html.theme-dark .quick-empty{ background:rgba(255,255,255,0.02); }
  .quick-empty.active{ display:flex; }
  .quick-empty svg{ width:22px; height:22px; opacity:0.55; stroke:#f5b942; }
  .quick-empty-star{ color:#f5b942; font-style:normal; }

  @media (max-width:980px){
    .select-body{ grid-template-columns:1fr; max-width:520px; }
    .select-aside{ width:100%; }
  }

  .select-main{ display:flex; flex-direction:column; align-items:center; gap:20px; min-width:0; }

  .server-grid{
    display:grid; grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
    gap:20px; width:100%; max-width:780px; align-items:start;
  }
  .server-card.gp-hidden{ display:none; }

  .server-grid-empty{
    display:flex; flex-direction:column; align-items:center; text-align:center; gap:10px;
    width:100%; max-width:420px; padding:40px 24px; margin:0 auto;
    color:var(--text-mute); opacity:0; animation:rise 0.6s ease forwards 0.1s;
  }
  .server-grid-empty[hidden]{ display:none; }
  .sge-icon{
    width:44px; height:44px; display:flex; align-items:center; justify-content:center;
    border-radius:14px; background:var(--panel-2, rgba(135,144,168,0.14)); color:var(--accent);
  }
  .sge-icon svg{ width:22px; height:22px; }
  .sge-title{ font-weight:700; font-size:15px; color:var(--text); }
  .sge-text{ font-size:13px; line-height:1.5; }

  /* ---- Pagination de la grille de serveurs ---- */
  .grid-pagination{
    display:flex; align-items:center; justify-content:center; gap:14px;
    opacity:0; animation:rise 0.6s ease forwards 0.2s;
  }
  .grid-pagination.gp-single{ display:none; }
  .gp-arrow{
    width:34px; height:34px; border-radius:50%; flex:0 0 auto;
    display:flex; align-items:center; justify-content:center;
    background:var(--glass); border:1px solid var(--glass-border);
    backdrop-filter:blur(20px); -webkit-backdrop-filter:blur(20px);
    color:var(--text-hi); cursor:pointer;
    transition:transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease, opacity 0.2s ease;
  }
  .gp-arrow svg{ width:15px; height:15px; }
  .gp-arrow:hover:not(:disabled){ transform:translateY(-2px); box-shadow:0 12px 22px -14px rgba(20,26,46,0.25); border-color:color-mix(in srgb, var(--accent) 40%, var(--glass-border)); }
  .gp-arrow:active:not(:disabled){ transform:translateY(0) scale(0.96); }
  .gp-arrow:disabled{ opacity:0.35; cursor:not-allowed; }

  .gp-dots{ display:flex; align-items:center; gap:8px; }
  .gp-dot{
    width:8px; height:8px; border-radius:50%; padding:0; border:none;
    background:var(--line); cursor:pointer;
    transition:transform 0.2s ease, background 0.2s ease, width 0.2s ease;
  }
  .gp-dot:hover{ background:color-mix(in srgb, var(--accent) 55%, var(--line)); }
  .gp-dot.active{ width:22px; border-radius:5px; background:var(--accent); }

  @media (max-width:640px){
    .grid-pagination{ gap:10px; }
  }

  .server-card{
    --card-accent: var(--accent);
    --card-accent-b: #8fa5ff;
    --card-accent-soft: rgba(90,125,250,0.16);
    position:relative; isolation:isolate; overflow:hidden;
    background:var(--glass); border:1px solid var(--glass-border);
    backdrop-filter:blur(24px); -webkit-backdrop-filter:blur(24px);
    border-radius:24px; padding:0 0 20px; text-align:left;
    cursor:pointer; transition:transform 0.32s cubic-bezier(.2,.8,.2,1), box-shadow 0.32s ease, border-color 0.32s ease;
    opacity:0; animation:rise 0.6s ease forwards;
    display:flex; flex-direction:column; gap:14px;
  }
  .server-card:nth-child(1){ animation-delay:0.12s; }
  .server-card:nth-child(2){ animation-delay:0.20s; }
  .server-card:nth-child(3){ animation-delay:0.28s; }
  .server-card:hover{ transform:translateY(-7px); box-shadow:0 26px 50px -20px var(--card-accent-soft), 0 10px 22px -14px rgba(20,26,46,0.18); border-color:color-mix(in srgb, var(--card-accent) 45%, var(--glass-border)); }
  .server-card:active{ transform:translateY(-3px) scale(0.99); }
  .server-card.featured{
    border-color:color-mix(in srgb, var(--card-accent) 40%, var(--glass-border));
    box-shadow:0 20px 44px -22px var(--card-accent-soft), 0 0 0 1px var(--card-accent-soft) inset;
  }
  .server-card.featured::before{
    content:""; position:absolute; inset:-1px; z-index:-1; border-radius:25px; padding:1px;
    background:linear-gradient(135deg, var(--card-accent), transparent 35%, transparent 65%, var(--card-accent-b));
    opacity:0.55; animation:featuredGlow 5s ease-in-out infinite;
  }
  @keyframes featuredGlow{ 0%,100%{ opacity:0.35; } 50%{ opacity:0.7; } }
  .server-card.favorited{ border-color:color-mix(in srgb, var(--card-accent) 50%, var(--glass-border)); }
  .server-card.disabled{ cursor:not-allowed; }
  .server-card.disabled .sc-cover,
  .server-card.disabled .sc-icon{ filter:grayscale(0.5); }
  .server-card.disabled .sc-body{ opacity:0.65; }
  .server-card.disabled:hover{ transform:translateY(-2px); box-shadow:0 14px 30px -20px rgba(20,26,46,0.25); border-color:var(--glass-border); }

  /* ---- État "bot absent du serveur" : distinct du rôle, carte grisée ---- */
  .server-card.no-bot{ cursor:not-allowed; }
  .server-card.no-bot .sc-cover{ filter:grayscale(0.85); opacity:0.55; }
  .server-card.no-bot .sc-icon{ background:linear-gradient(135deg, #b7bece, #ced4e0); box-shadow:none; filter:grayscale(0.4); }
  .server-card.no-bot .sc-name, .server-card.no-bot .sc-desc{ color:var(--text-mute); }
  .server-card.no-bot .sc-fav{ opacity:0.5; pointer-events:none; }
  .server-card.no-bot:hover{ transform:translateY(-2px); box-shadow:0 14px 30px -20px rgba(20,26,46,0.25); border-color:var(--glass-border); }
  .no-bot-badge{
    display:flex; align-items:center; gap:5px; font-size:10.5px; font-weight:700;
    color:var(--text-mute); background:rgba(135,144,168,0.16); padding:3px 9px; border-radius:8px; width:fit-content;
  }
  .no-bot-badge svg{ width:10px; height:10px; }
  .no-bot-note{ font-size:11px; color:var(--text-mute); font-style:italic; }
  .sc-invite-cta{
    display:flex; align-items:center; justify-content:center; gap:7px;
    margin:2px 0 -4px; padding:9px 16px; border-radius:12px; border:none; cursor:pointer;
    font-family:var(--font-body); font-size:11.5px; font-weight:700; color:#fff; text-align:center;
    background:linear-gradient(135deg, var(--card-accent), var(--card-accent-b));
    box-shadow:0 8px 18px -8px var(--card-accent-soft);
    opacity:1; transition:opacity 0.22s ease, transform 0.22s ease, box-shadow 0.22s ease;
  }
  .sc-invite-cta:hover{ transform:translateY(-1px); box-shadow:0 12px 22px -8px var(--card-accent-soft); }
  .sc-invite-cta svg{ width:14px; height:14px; }

  .sc-cover{
    position:relative; height:86px; width:100%; flex-shrink:0;
    background:linear-gradient(120deg, var(--card-accent) 0%, var(--card-accent-b) 55%, var(--blob-mint) 130%);
    background-size:200% 200%; background-position:0% 50%;
    overflow:hidden; transition:background-position 0.6s ease;
  }
  .server-card:hover .sc-cover{ background-position:100% 50%; }
  .sc-cover::after{
    content:""; position:absolute; inset:0;
    background-image:radial-gradient(rgba(255,255,255,0.55) 1px, transparent 1px);
    background-size:14px 14px; opacity:0.32;
  }
  .sc-cover::before{
    content:""; position:absolute; inset:0; z-index:1; pointer-events:none;
    background:linear-gradient(180deg, rgba(0,0,0,0) 40%, rgba(0,0,0,0.14) 100%);
  }
  .sc-cover.has-banner::after{ display:none; }
  .sc-cover.has-banner{ background-color:transparent; }

  .sc-ribbon{
    display:none;
    position:absolute; top:10px; right:-30px; z-index:3;
    background:linear-gradient(135deg, #ffcf6b, #ff9d5c); color:#5a3a10;
    font-size:9.5px; font-weight:800; letter-spacing:0.06em; text-transform:uppercase;
    padding:4px 34px; transform:rotate(38deg); box-shadow:0 4px 10px -2px rgba(255,157,92,0.5);
  }
  .server-card.favorited .sc-ribbon{ display:block; }

  .sc-top{ display:flex; align-items:flex-end; gap:12px; padding:0 20px; margin-top:-32px; position:relative; z-index:2; }

  .sc-fav{
    margin-left:auto; align-self:flex-start; margin-bottom:2px;
    width:30px; height:30px; border-radius:50%; flex-shrink:0;
    display:flex; align-items:center; justify-content:center;
    background:var(--glass-strong); border:1px solid var(--glass-border);
    cursor:pointer; transition:transform 0.18s ease, background 0.18s ease, border-color 0.18s ease;
    position:relative; z-index:2;
  }
  .sc-fav:hover{ transform:scale(1.08); border-color:rgba(255,157,92,0.6); }
  .sc-fav svg{ width:15px; height:15px; stroke:var(--text-mute); fill:none; transition:stroke 0.18s ease, fill 0.18s ease; }
  .sc-fav.active{ background:rgba(255,157,92,0.16); border-color:rgba(255,157,92,0.55); }
  .sc-fav.active svg{ stroke:#ff9d5c; fill:#ffcf6b; }
  .server-card.disabled .sc-fav{ opacity:0.55; }
  .sc-icon{
    width:58px; height:58px; border-radius:18px; flex-shrink:0;
    display:flex; align-items:center; justify-content:center;
    font-family:var(--font-display); font-weight:800; font-size:15px; color:#fff;
    background:linear-gradient(135deg, var(--card-accent), var(--card-accent-b));
    border:3px solid var(--glass-strong);
    box-shadow:0 8px 18px -6px var(--card-accent-soft), 0 0 0 3px var(--card-accent-soft);
    transition:transform 0.28s cubic-bezier(.2,.8,.2,1);
  }
  .server-card:hover .sc-icon{ transform:translateY(-2px) scale(1.04); }
  .server-card.disabled .sc-icon{ background:linear-gradient(135deg, #b7bece, #ced4e0); box-shadow:none; }
  .sc-name-wrap{ padding-bottom:2px; }
  .sc-name{ font-family:var(--font-display); font-weight:800; font-size:16px; color:var(--text-hi); display:flex; align-items:center; gap:6px; letter-spacing:-0.01em; }
  .sc-sub{ font-size:11px; color:var(--text-mute); margin-top:2px; }
  .sc-body{ display:flex; flex-direction:column; gap:14px; padding:0 20px; }
  .sc-desc{ font-size:12px; line-height:1.55; color:var(--text); }
  .sc-foot{ display:flex; align-items:center; justify-content:space-between; margin-top:auto; }
  .sc-members{ font-size:11px; color:var(--text-mute); display:flex; align-items:center; gap:6px; }
  .sc-status{ font-size:10.5px; font-weight:700; padding:3px 9px; border-radius:8px; display:flex; align-items:center; gap:5px; }
  .sc-status.online{ background:rgba(34,184,146,0.14); color:var(--mint); }
  .sc-status.locked{ background:rgba(135,144,168,0.16); color:var(--text-mute); }
  .sc-status .dot-live{ width:5px; height:5px; }
  .sc-status.online .dot-live{ animation:pulseDot 1.6s ease-in-out infinite; }
  .sc-status.role-owner{ background:rgba(255,207,107,0.26); color:#8a5a12; }
  .sc-status .role-crown{ font-size:10px; line-height:1; }
  .sc-status.role-admin{ background:rgba(239,125,107,0.16); color:var(--coral); }
  .sc-status.role-mod{ background:rgba(90,125,250,0.14); color:var(--accent-deep); }
  .sc-status.role-user{ background:rgba(135,144,168,0.16); color:var(--text-mute); }
  .sc-status svg.role-lock{ width:9px; height:9px; }
  @keyframes pulseDot{ 0%,100%{ box-shadow:0 0 0 0 rgba(34,184,146,0.35);} 50%{ box-shadow:0 0 0 4px rgba(34,184,146,0);} }

  .sc-cta{
    display:flex; align-items:center; justify-content:center; gap:6px;
    margin:2px 0 -4px; padding:9px 16px; border-radius:12px;
    font-size:11.5px; font-weight:700; color:#fff; text-align:center;
    background:linear-gradient(135deg, var(--card-accent), var(--card-accent-b));
    box-shadow:0 8px 18px -8px var(--card-accent-soft);
    opacity:0.92; transform:translateY(0); transition:opacity 0.22s ease, transform 0.22s ease, box-shadow 0.22s ease;
  }
  .server-card:hover .sc-cta{ opacity:1; transform:translateY(-1px); box-shadow:0 12px 22px -8px var(--card-accent-soft); }
  .server-card.disabled .sc-cta{ display:none; }
  .sc-cta svg{ transition:transform 0.22s ease; }
  .server-card:hover .sc-cta svg{ transform:translateX(3px); }


  .sc-lock{
    display:flex; align-items:center; gap:6px; font-size:11px; font-weight:600; color:var(--text-mute);
  }

  /* ================= JOINING ================= */
  #joining{
    display:none; flex-direction:column; align-items:center; justify-content:center;
    padding:6vh 24px; text-align:center;
    transition:opacity 0.5s ease, filter 0.5s ease;
  }
  #joining.active{ display:flex; }
  #joining.entering{ opacity:0; filter:blur(10px); animation:sRise 0.55s ease forwards; }
  #joining.leaving{ opacity:0; filter:blur(10px); }

  .joining-card{
    background:var(--glass); border:1px solid var(--glass-border);
    backdrop-filter:blur(24px); -webkit-backdrop-filter:blur(24px);
    border-radius:28px; padding:48px 52px; max-width:420px; width:100%;
    box-shadow:0 20px 60px -20px rgba(90,125,250,0.25);
  }
  .joining-ring{
    width:74px; height:74px; margin:0 auto 22px; position:relative;
  }
  .joining-ring .track{
    position:absolute; inset:0; border-radius:50%;
    border:3px solid color-mix(in srgb, var(--join-accent, var(--accent)) 15%, transparent);
  }
  .joining-ring .spin{
    position:absolute; inset:0; border-radius:50%;
    border:3px solid transparent;
    border-top-color:var(--join-accent, var(--accent)); border-right-color:var(--join-accent, var(--accent));
    animation:jspin 0.9s linear infinite;
  }
  .joining-ring .glyph{
    position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
    font-family:var(--font-display); font-weight:800; font-size:13px; color:var(--accent-deep);
  }
  .joining-ring .joining-icon-img{
    position:absolute; inset:7px; width:calc(100% - 14px); height:calc(100% - 14px);
    border-radius:50%; object-fit:cover; display:none;
    box-shadow:0 0 0 1px rgba(20,26,46,0.06);
  }
  .joining-ring.has-icon .glyph{ display:none; }
  .joining-ring.has-icon .joining-icon-img{ display:block; }
  @keyframes jspin{ to{ transform:rotate(360deg); } }

  .joining-title{ font-family:var(--font-display); font-weight:800; font-size:19px; color:var(--text-hi); }
  .joining-sub{ font-size:12.5px; color:var(--text-mute); margin-top:6px; }

  .joining-steps{ margin-top:26px; display:flex; flex-direction:column; gap:11px; text-align:left; }
  .jstep{ display:flex; align-items:center; gap:10px; font-size:12.5px; color:var(--text-mute); opacity:0.5; transition:opacity 0.3s ease, color 0.3s ease; }
  .jstep.done{ opacity:1; color:var(--text-hi); }
  .jstep .jmark{
    width:16px; height:16px; border-radius:50%; flex-shrink:0;
    border:1.5px solid var(--line); display:flex; align-items:center; justify-content:center;
    font-size:9px; color:transparent; transition:all 0.3s ease;
  }
  .jstep.done .jmark{ background:var(--mint); border-color:var(--mint); color:#fff; }

  .joining-bar{ margin-top:22px; height:5px; border-radius:4px; background:rgba(90,125,250,0.12); overflow:hidden; }
  .joining-bar .fill{ height:100%; width:0%; border-radius:4px; background:linear-gradient(90deg, var(--accent), var(--mint)); transition:width 0.4s ease; }

  /* ================= DASHBOARD ================= */
  #dashboard{ display:none; opacity:0; }
  #dashboard.entering{ display:block; animation:fadeIn 0.6s ease forwards 0.05s; }
  @keyframes fadeIn{ from{opacity:0;} to{opacity:1;} }

  .dash-layout{ display:flex; min-height:100vh; }

  .sidebar{
    width:236px; flex-shrink:0; padding:20px 14px;
    background:var(--glass-strong); border-right:1px solid var(--line);
    backdrop-filter:blur(20px); -webkit-backdrop-filter:blur(20px);
    display:flex; flex-direction:column; gap:20px;
  }
  .side-brand{ display:flex; align-items:center; gap:10px; padding:2px 6px; }
  .side-brand .mini-badge{
    width:34px; height:34px; border-radius:11px; flex-shrink:0;
    background:linear-gradient(135deg, var(--accent), #8fa5ff);
    display:flex; align-items:center; justify-content:center;
    font-family:var(--font-display); font-weight:800; font-size:11px; color:#fff;
  }
  .brand-name{ font-family:var(--font-display); font-weight:800; font-size:14.5px; color:var(--text-hi); }
  .brand-sub{ font-size:10px; color:var(--text-mute); }

  .side-server-card{
    width:100%; position:relative; overflow:hidden;
    background:linear-gradient(165deg, rgba(255,255,255,0.95), rgba(237,242,255,0.65));
    border:1px solid rgba(255,255,255,0.9);
    border-radius:16px; padding:9px 11px 6px;
    box-shadow:0 6px 18px -12px rgba(31,41,88,0.35), inset 0 1px 0 rgba(255,255,255,0.8);
  }
  .side-bot-logo-header{ display:flex; align-items:center; justify-content:center; padding:4px 0 8px; }
  .side-bot-logo-wrap{ display:flex; align-items:center; justify-content:center; }
  .side-bot-logo{ height:56px; width:auto; display:block; filter:drop-shadow(0 3px 6px rgba(20,30,70,0.25)); }
  .side-server-banner{
    height:54px; margin:-9px -11px 0 -11px;
    background:linear-gradient(100deg, var(--accent), var(--mint) 55%, var(--coral));
    position:relative;
  }
  .side-server-top-row{ display:flex; align-items:center; gap:10px; margin-top:-20px; position:relative; z-index:2; }
  .side-server-avatar{
    width:46px; height:46px; border-radius:13px; flex-shrink:0;
    background:linear-gradient(135deg, var(--coral), #ffb199);
    display:flex; align-items:center; justify-content:center;
    font-family:var(--font-display); font-weight:800; font-size:11px; color:#fff;
    box-shadow:0 4px 10px -3px rgba(255,111,80,0.55), inset 0 1px 0 rgba(255,255,255,0.4), 0 0 0 3px rgba(255,255,255,0.95);
  }
  /* Comme pour .cat-empty[hidden] plus haut : .side-server-avatar force
     display:flex, ce qui annule l'effet de l'attribut [hidden] posé par
     profil.js (avatarImg.hidden / avatarFallback.hidden) — les deux
     ronds (photo réelle + repli "?") restaient donc affichés côte à côte
     au lieu que l'un masque l'autre. */
  .side-server-avatar[hidden]{ display:none; }
  .side-server-info{ min-width:0; }
  .side-server-name{
    display:flex; align-items:center; gap:6px;
    font-size:12.5px; font-weight:800; letter-spacing:-0.01em; color:var(--text-hi);
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  }
  .side-server-dot{ width:7px; height:7px; border-radius:50%; background:var(--mint); flex-shrink:0; animation:pulseDot 1.8s ease-in-out infinite; }
  .side-server-members{ font-size:10.5px; color:var(--text-mute); margin-top:1px; font-weight:500; }
  .side-server-divider{ height:1px; background:linear-gradient(90deg, transparent, var(--line) 20%, var(--line) 80%, transparent); margin:9px 0 6px; }

  .side-premium-badge{
    display:flex; align-items:center; gap:8px; position:relative; overflow:hidden;
    background:linear-gradient(120deg, rgba(255,205,90,0.28), rgba(255,150,50,0.14) 55%, rgba(255,205,90,0.24));
    border:1px solid rgba(255,167,38,0.4); border-radius:13px;
    padding:6px 9px; cursor:pointer;
    transition:transform 0.2s ease, box-shadow 0.2s ease;
    box-shadow:0 4px 12px -7px rgba(255,140,20,0.55), inset 0 1px 0 rgba(255,255,255,0.6);
  }
  .side-premium-badge:hover{ transform:translateY(-1px); box-shadow:0 8px 18px -8px rgba(255,140,20,0.6), inset 0 1px 0 rgba(255,255,255,0.6); }
  .side-premium-badge:active{ transform:translateY(0) scale(0.98); }
  .side-premium-badge:focus-visible{ outline:2px solid var(--accent-deep); outline-offset:2px; }
  .side-premium-badge.status-actif::after{
    content:''; position:absolute; top:0; left:-60%; width:40%; height:100%;
    background:linear-gradient(115deg, transparent, rgba(255,255,255,0.55), transparent);
    animation:badgeShine 3.2s ease-in-out infinite;
  }
  .side-premium-badge .icon{
    width:21px; height:21px; flex-shrink:0; border-radius:8px;
    background:linear-gradient(135deg, #ffda7a, #ff9f43);
    display:flex; align-items:center; justify-content:center;
    font-size:11.5px; line-height:1;
    box-shadow:0 2px 6px -2px rgba(255,159,67,0.7), inset 0 1px 0 rgba(255,255,255,0.5);
  }
  .side-premium-badge .txt{ flex:1; font-size:11.5px; font-weight:800; color:#a85e08; letter-spacing:-0.01em; }
  .side-premium-badge .txt small{ display:block; font-size:9px; font-weight:600; color:#c07a1f; opacity:0.85; }

  /* ---- variantes de statut ---- */
  .side-premium-badge.status-inactif{
    background:linear-gradient(120deg, rgba(148,163,184,0.24), rgba(148,163,184,0.1));
    border-color:rgba(148,163,184,0.4);
    box-shadow:0 4px 12px -7px rgba(100,116,139,0.4), inset 0 1px 0 rgba(255,255,255,0.5);
  }
  .side-premium-badge.status-inactif .icon{ background:linear-gradient(135deg,#cbd5e1,#94a3b8); box-shadow:0 2px 6px -2px rgba(100,116,139,0.5), inset 0 1px 0 rgba(255,255,255,0.4); }
  .side-premium-badge.status-inactif .txt{ color:#64748b; }
  .side-premium-badge.status-inactif .txt small{ color:#94a3b8; }

  .side-premium-badge.status-attente{
    background:linear-gradient(120deg, rgba(90,125,250,0.2), rgba(90,125,250,0.08));
    border-color:rgba(90,125,250,0.35);
    box-shadow:0 4px 12px -7px rgba(90,125,250,0.4), inset 0 1px 0 rgba(255,255,255,0.5);
  }
  .side-premium-badge.status-attente .icon{ background:linear-gradient(135deg,#8fa5ff,var(--accent)); box-shadow:0 2px 6px -2px rgba(90,125,250,0.5), inset 0 1px 0 rgba(255,255,255,0.4); }
  .side-premium-badge.status-attente .txt{ color:var(--accent-deep); }
  .side-premium-badge.status-attente .txt small{ color:var(--accent); opacity:0.85; }

  .side-premium-badge.status-quarantaine{
    background:linear-gradient(120deg, rgba(249,115,22,0.24), rgba(249,115,22,0.1));
    border-color:rgba(249,115,22,0.4);
    box-shadow:0 4px 12px -7px rgba(249,115,22,0.45), inset 0 1px 0 rgba(255,255,255,0.5);
  }
  .side-premium-badge.status-quarantaine .icon{ background:linear-gradient(135deg,#fdba74,#f97316); box-shadow:0 2px 6px -2px rgba(249,115,22,0.55), inset 0 1px 0 rgba(255,255,255,0.4); }
  .side-premium-badge.status-quarantaine .txt{ color:#c2410c; }
  .side-premium-badge.status-quarantaine .txt small{ color:#ea580c; opacity:0.85; }

  .side-premium-badge.status-cancelled{
    background:linear-gradient(120deg, rgba(249,115,22,0.24), rgba(249,115,22,0.1));
    border-color:rgba(249,115,22,0.4);
    box-shadow:0 4px 12px -7px rgba(249,115,22,0.45), inset 0 1px 0 rgba(255,255,255,0.5);
  }
  .side-premium-badge.status-cancelled .icon{ background:linear-gradient(135deg,#fdba74,#f97316); box-shadow:0 2px 6px -2px rgba(249,115,22,0.55), inset 0 1px 0 rgba(255,255,255,0.4); }
  .side-premium-badge.status-cancelled .txt{ color:#c2410c; }
  .side-premium-badge.status-cancelled .txt small{ color:#ea580c; opacity:0.85; }

  .side-premium-badge.status-suspendu{
    background:linear-gradient(120deg, rgba(239,68,68,0.24), rgba(239,68,68,0.1));
    border-color:rgba(239,68,68,0.4);
    box-shadow:0 4px 12px -7px rgba(239,68,68,0.45), inset 0 1px 0 rgba(255,255,255,0.5);
  }
  .side-premium-badge.status-suspendu .icon{ background:linear-gradient(135deg,#fca5a5,#ef4444); box-shadow:0 2px 6px -2px rgba(239,68,68,0.55), inset 0 1px 0 rgba(255,255,255,0.4); }
  .side-premium-badge.status-suspendu .txt{ color:#b91c1c; }
  .side-premium-badge.status-suspendu .txt small{ color:#dc2626; opacity:0.85; }

  @keyframes badgeShine{ 0%,60%,100%{ left:-60%; } 30%{ left:120%; } }

  .side-search{
    font-size:12.5px; color:var(--text-mute); font-weight:500;
    background:linear-gradient(165deg, rgba(255,255,255,0.85), rgba(240,244,255,0.55));
    border:1px solid var(--line);
    border-radius:13px; padding:9px 12px;
    box-shadow:0 2px 8px -5px rgba(31,41,88,0.18), inset 0 1px 0 rgba(255,255,255,0.7);
  }
  .search-icon-chip{
    width:22px; height:22px; border-radius:8px; flex-shrink:0;
    background:var(--accent-soft);
    display:flex; align-items:center; justify-content:center;
    transition:background 0.15s ease;
  }
  .side-search:hover .search-icon-chip{ background:rgba(90,125,250,0.22); }
  .side-search svg{ width:12px; height:12px; }

  .side-group-label{ font-size:10px; letter-spacing:0.1em; text-transform:uppercase; color:var(--text-mute); padding:0 6px 3px; }
  .side-nav{ display:flex; flex-direction:column; gap:2px; }
  .side-link{
    display:flex; align-items:center; justify-content:space-between;
    padding:8px 10px; border-radius:10px; font-size:13px; color:var(--text);
    cursor:pointer; transition:background 0.15s ease, color 0.15s ease;
  }
  .side-link:hover{ background:rgba(255,255,255,0.7); color:var(--text-hi); }
  .side-link.active{ background:var(--accent-soft); color:var(--accent-deep); font-weight:600; }
  .badge-new{ font-size:9px; font-weight:600; padding:1px 6px; border-radius:6px; background:rgba(34,184,146,0.16); color:var(--mint); }
  .badge-dev{ font-size:9px; font-weight:600; padding:1px 6px; border-radius:6px; background:rgba(255,167,38,0.18); color:#b6690a; }
  .side-subdivider{ height:1px; background:var(--line); margin:6px 8px; opacity:0.7; }

  .side-foot{
    margin-top:auto; display:flex; align-items:center; gap:10px; padding:10px;
    border-top:1px solid var(--line); border-radius:12px; cursor:pointer;
    transition:background 0.15s ease;
  }
  .side-foot:hover{ background:rgba(90,125,250,0.07); }
  .side-foot.menu-open{ background:rgba(90,125,250,0.1); }
  .side-foot .avatar{
    width:30px; height:30px; border-radius:50%;
    background:linear-gradient(135deg, var(--coral), #ffb199);
    display:flex; align-items:center; justify-content:center;
    font-size:11px; font-weight:700; color:#fff;
  }
  .side-foot .who{ font-size:12px; color:var(--text-hi); font-weight:500; }
  .side-foot .role{ font-size:10px; color:var(--accent-deep); }
  .side-foot .foot-chevron{
    margin-left:auto; width:14px; height:14px; stroke:var(--text-mute); flex-shrink:0;
    transition:transform 0.28s cubic-bezier(.16,.84,.44,1);
  }
  .side-foot.menu-open .foot-chevron{ transform:rotate(180deg); }

  /* ---- Menu utilisateur (popup au clic sur le pseudo) ---- */
  .user-menu-overlay{
    position:fixed; inset:0; z-index:78; background:transparent;
    opacity:0; pointer-events:none; transition:opacity 0.25s ease;
  }
  .user-menu-overlay.open{ opacity:1; pointer-events:auto; }

  .user-menu-panel{
    position:fixed; z-index:80; width:220px;
    background:var(--glass-strong); border:1px solid var(--glass-border);
    backdrop-filter:blur(22px); -webkit-backdrop-filter:blur(22px);
    border-radius:16px; padding:8px;
    box-shadow:0 22px 50px -18px rgba(31,41,88,0.4), inset 0 1px 0 rgba(255,255,255,0.6);
    opacity:0; pointer-events:none; transform-origin:bottom left;
    transform:translateY(14px) scale(0.97);
    transition:opacity 0.38s cubic-bezier(.16,.84,.44,1), transform 0.38s cubic-bezier(.16,.84,.44,1);
  }
  .user-menu-panel.open{ opacity:1; pointer-events:auto; transform:translateY(0) scale(1); }

  .user-menu-head{ display:flex; align-items:center; gap:10px; padding:6px 8px 10px; }
  .user-menu-head .avatar{
    width:32px; height:32px; border-radius:50%; flex-shrink:0;
    background:linear-gradient(135deg, var(--coral), #ffb199);
    display:flex; align-items:center; justify-content:center;
    font-size:11px; font-weight:700; color:#fff;
  }
  .user-menu-head .who{ font-size:12.5px; font-weight:700; color:var(--text-hi); }
  .user-menu-head .role{ font-size:10px; color:var(--accent-deep); margin-top:1px; }
  .user-menu-divider{ height:1px; background:var(--line); margin:4px 6px; opacity:0.8; }

  .user-menu-item{
    display:flex; align-items:center; gap:10px; padding:9px 10px; border-radius:10px;
    font-size:12.5px; font-weight:600; color:var(--text-hi); cursor:pointer;
    transition:background 0.15s ease, color 0.15s ease;
  }
  .user-menu-item svg{ width:15px; height:15px; stroke:currentColor; flex-shrink:0; opacity:0.75; }
  .user-menu-item:hover{ background:var(--accent-soft); color:var(--accent-deep); }
  .user-menu-item.danger:hover{ background:rgba(239,68,68,0.12); color:#dc2626; }

  /* focus clavier (accessibilité) */
  .side-foot:focus-visible,
  .status-btn:focus-visible,
  .user-menu-item:focus-visible{
    outline:2px solid var(--accent-deep); outline-offset:2px;
  }

  /* pastille de statut sur l'avatar */
  .avatar-wrap{ position:relative; flex-shrink:0; display:inline-flex; }
  .status-ring{
    position:absolute; right:-1px; bottom:-1px; width:10px; height:10px;
    border-radius:50%; border:2px solid #fff; background:#22b892;
    transition:background 0.2s ease;
  }
  .side-foot .status-ring{ width:9px; height:9px; }

  /* sélecteur de statut */
  .user-menu-label{
    font-size:9.5px; font-weight:700; letter-spacing:0.08em; text-transform:uppercase;
    color:var(--text-mute); padding:2px 8px 5px;
  }
  .user-menu-status-row{ display:flex; gap:4px; padding:0 4px 4px; }
  .status-btn{
    flex:1; display:flex; flex-direction:column; align-items:center; gap:4px;
    background:none; border:1px solid transparent; border-radius:10px; padding:6px 2px;
    cursor:pointer; font-family:inherit; font-size:8.5px; font-weight:600; color:var(--text-mute);
    transition:background 0.15s ease, border-color 0.15s ease, color 0.15s ease, transform 0.15s ease;
  }
  .status-btn:hover{ background:rgba(90,125,250,0.08); transform:translateY(-1px); }
  .status-btn.active{ background:var(--accent-soft); border-color:rgba(90,125,250,0.3); color:var(--accent-deep); }
  .status-btn .swatch{ width:13px; height:13px; border-radius:50%; box-shadow:0 0 0 1px var(--line); }
  .status-btn[data-status="online"] .swatch{ background:#22b892; }
  .status-btn[data-status="idle"] .swatch{ background:#f5a623; }
  .status-btn[data-status="dnd"] .swatch{ background:#ef4444; }
  .status-btn[data-status="invisible"] .swatch{ background:#94a3b8; }

  /* statut désormais lecture seule : reflète le statut Discord réel (via
     GUILD_PRESENCES), il ne se règle plus depuis le site — cf. auth.js
     (applyRealDiscordStatus) et /api/me + /api/presence côté serveur. */
  .user-menu-status-row.is-readonly .status-btn{ cursor:default; }
  .user-menu-status-row.is-readonly .status-btn:hover{ background:none; transform:none; }
  .user-menu-status-row.is-readonly .status-btn:disabled{ opacity:0.45; }
  .user-menu-status-row.is-readonly .status-btn.active:disabled{ opacity:1; }
  .user-menu-sync-note{
    display:flex; align-items:center; gap:5px; padding:0 8px 6px;
    font-size:9px; color:var(--text-mute);
  }
  .user-menu-sync-note svg{ width:11px; height:11px; stroke:currentColor; flex-shrink:0; opacity:0.7; }

  /* tag de tier dans "Mon Premium" (menu utilisateur) */
  .user-menu-premium-tag{
    font-size:9.5px; font-weight:700; padding:2px 7px; border-radius:99px;
    background:rgba(148,163,184,0.16); color:var(--text-mute); flex-shrink:0;
  }
  .user-menu-premium-tag.tag-pro{ background:rgba(56,189,248,0.14); color:#0284c7; }
  .user-menu-premium-tag.tag-ultra{ background:rgba(251,191,36,0.16); color:#b45309; }

  /* copier l'ID */
  .user-menu-item.copied{ background:rgba(34,184,146,0.12); color:#1a9c78; }
  .user-menu-item .icon-check{ stroke:#1a9c78; }

  /* pied du menu */
  .user-menu-footer{
    text-align:center; font-size:9px; color:var(--text-mute); opacity:0.7;
    padding:8px 6px 2px; margin-top:2px; border-top:1px solid var(--line);
  }
  .user-menu-footer span{ font-family:var(--font-mono); }

  /* apparition en cascade des éléments du menu */
  .user-menu-panel > *{
    opacity:0; transform:translateY(6px);
    transition:opacity 0.3s ease, transform 0.3s ease;
  }
  .user-menu-panel.open > *{ opacity:1; transform:translateY(0); }

  /* ================= POPUP ABONNEMENT (PLANS) ================= */
  .plans-overlay{
    position:fixed; inset:0; z-index:90;
    background:rgba(20,26,41,0.38); backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px);
    opacity:0; pointer-events:none; transition:opacity 0.3s ease;
  }
  .plans-overlay.open{ opacity:1; pointer-events:auto; }

  .plans-modal{
    position:fixed; z-index:92; top:50%; left:50%;
    width:min(760px, 92vw); max-height:88vh; overflow-y:auto;
    background:var(--glass-strong); border:1px solid var(--glass-border);
    backdrop-filter:blur(26px); -webkit-backdrop-filter:blur(26px);
    border-radius:26px; padding:34px 38px 30px;
    box-shadow:0 30px 70px -20px rgba(20,26,60,0.45), inset 0 1px 0 rgba(255,255,255,0.6);
    opacity:0; pointer-events:none;
    transform:translate(-50%,-48%) scale(0.94);
    transition:opacity 0.36s cubic-bezier(.16,.84,.44,1), transform 0.36s cubic-bezier(.16,.84,.44,1);
  }
  .plans-modal.open{ opacity:1; pointer-events:auto; transform:translate(-50%,-50%) scale(1); }

  .plans-close{
    position:absolute; top:16px; right:16px; width:32px; height:32px; border-radius:10px;
    border:1px solid var(--line); background:rgba(255,255,255,0.6); color:var(--text-mute);
    font-size:16px; line-height:1; cursor:pointer; display:flex; align-items:center; justify-content:center;
    transition:background 0.15s ease, color 0.15s ease;
  }
  .plans-close:hover{ background:rgba(239,68,68,0.12); color:#dc2626; }

  .plans-step{ display:none; }
  .plans-step.active{ display:block; animation:plansFade 0.4s ease; }
  @keyframes plansFade{ from{opacity:0; transform:translateY(8px);} to{opacity:1; transform:translateY(0);} }

  .plans-head{ text-align:center; margin-bottom:26px; }
  .plans-head h3{ font-family:var(--font-display); font-weight:800; font-size:clamp(20px,3vw,25px); color:var(--text-hi); letter-spacing:-0.01em; margin-top:6px; }
  .plans-head p{ font-size:13px; color:var(--text-mute); margin-top:6px; }
  .plans-slots-note{
    text-align:center; font-size:11.5px; color:var(--accent-deep); background:var(--accent-soft);
    border-radius:9px; padding:7px 12px; margin:-8px auto 20px; max-width:420px; line-height:1.5;
  }
  #plansCancelNote{ background:transparent; color:var(--text-mute); padding:0 12px; margin:-10px auto 18px; }
  .plans-cancel-sub-link{ color:var(--text-mute); text-decoration:underline; cursor:pointer; }
  .plans-cancel-sub-link:hover{ color:#ef4444; }

  .plans-grid{ display:flex; gap:16px; align-items:stretch; flex-wrap:wrap; }
  .plan-card{
    flex:1 1 190px; position:relative; isolation:isolate; overflow:hidden;
    display:flex; flex-direction:column; gap:14px;
    background:linear-gradient(165deg, rgba(255,255,255,0.9), rgba(237,242,255,0.55));
    border:1.5px solid var(--glass-border); border-radius:20px; padding:20px 18px 18px;
    transition:transform 0.25s cubic-bezier(.2,.8,.2,1), box-shadow 0.25s ease, border-color 0.25s ease;
  }
  .plan-card:hover{ transform:translateY(-4px); box-shadow:0 20px 38px -20px rgba(31,41,88,0.35); }

  .plan-card.featured{ border-color:rgba(255,167,38,0.55); box-shadow:0 16px 34px -18px rgba(255,140,20,0.4); }
  .plan-card.current{ border-color:var(--accent); box-shadow:0 0 0 3px rgba(90,125,250,0.18), 0 16px 34px -18px rgba(90,125,250,0.4); }
  .plan-card.current:hover{ transform:none; }

  .plan-card.current.expiring{
    border-color:rgba(249,115,22,0.6);
    box-shadow:0 0 0 3px rgba(249,115,22,0.2), 0 16px 34px -18px rgba(249,115,22,0.45);
    animation:expiringPulse 2.2s ease-in-out infinite;
  }
  .plan-card.current.expiring:hover{ transform:translateY(-4px); }
  @keyframes expiringPulse{
    0%,100%{ box-shadow:0 0 0 3px rgba(249,115,22,0.2), 0 16px 34px -18px rgba(249,115,22,0.45); }
    50%{ box-shadow:0 0 0 5px rgba(249,115,22,0.32), 0 16px 34px -18px rgba(249,115,22,0.55); }
  }
  .plan-card.current.expiring .plan-btn{
    background:linear-gradient(135deg, #fdba74, #f97316) !important; color:#5a2a06 !important;
  }

  .plan-ribbon{
    display:none; position:absolute; top:12px; right:-30px; z-index:3;
    background:linear-gradient(135deg, #ffcf6b, #ff9d5c); color:#5a3a10;
    font-size:9px; font-weight:800; letter-spacing:0.05em; text-transform:uppercase;
    padding:3px 32px; transform:rotate(38deg); box-shadow:0 4px 10px -2px rgba(255,157,92,0.5);
  }
  .plan-card.featured .plan-ribbon{ display:block; }

  .plan-current-tag{
    display:none; align-items:center; gap:5px;
    font-size:10px; font-weight:700; color:var(--accent-deep);
    background:var(--accent-soft); border-radius:8px; padding:4px 8px; width:fit-content;
    transition:background 0.2s ease, color 0.2s ease;
  }
  .plan-card.current .plan-current-tag{ display:flex; }
  .plan-current-tag.warn{ background:rgba(249,115,22,0.16); color:#c2410c; }

  .plan-icon-box{
    width:38px; height:38px; border-radius:12px; display:flex; align-items:center; justify-content:center;
    font-size:18px; background:rgba(255,255,255,0.7); border:1px solid var(--line);
  }
  .plan-name{ font-family:var(--font-display); font-weight:800; font-size:15px; color:var(--text-hi); margin-top:2px; }
  .plan-price{ display:flex; align-items:baseline; gap:3px; }
  .plan-price .amount{ font-family:var(--font-mono); font-size:22px; font-weight:600; color:var(--text-hi); }
  .plan-price .period{ font-size:11px; color:var(--text-mute); }

  .plan-feats{ list-style:none; display:flex; flex-direction:column; gap:7px; flex:1; }
  .plan-feats li{ font-size:12px; color:var(--text); display:flex; align-items:flex-start; gap:7px; line-height:1.4; }
  .plan-feats li::before{ content:'✓'; color:var(--mint); font-weight:700; flex-shrink:0; }

  .plan-btn{
    font-family:var(--font-body); font-size:12.5px; font-weight:700; color:#fff;
    background:linear-gradient(135deg, var(--accent), var(--accent-deep));
    border:none; border-radius:12px; padding:10px 12px; cursor:pointer;
    transition:transform 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease;
  }
  .plan-btn:hover{ transform:translateY(-1px); }
  .plan-card[data-plan="Free"] .plan-btn{ background:rgba(148,163,184,0.18); color:var(--text-hi); }
  .plan-card.featured .plan-btn{ background:linear-gradient(135deg, #ffcf6b, #ff9d5c); color:#5a3a10; }
  .plan-btn:disabled{ opacity:0.55; cursor:default; transform:none !important; }

  /* -- étape paiement -- */
  .plans-back{
    display:flex; align-items:center; gap:6px; background:none; border:none; cursor:pointer;
    font-size:12.5px; font-weight:600; color:var(--text-mute); padding:4px 2px; margin-bottom:18px;
    transition:color 0.15s ease;
  }
  .plans-back:hover{ color:var(--accent-deep); }

  .checkout-head{ display:flex; align-items:center; gap:14px; margin-bottom:22px; }
  .checkout-plan-icon{
    width:46px; height:46px; border-radius:14px; flex-shrink:0;
    background:linear-gradient(135deg, var(--accent), #8fa5ff);
    display:flex; align-items:center; justify-content:center; font-size:20px;
  }
  .checkout-plan-name{ font-family:var(--font-display); font-weight:800; font-size:16px; color:var(--text-hi); }
  .checkout-plan-price{ font-family:var(--font-mono); font-size:13px; color:var(--text-mute); margin-top:2px; }
  .checkout-renew-note{ font-size:10.5px; color:var(--accent-deep); margin-top:3px; }

  .checkout-form{ display:none; flex-direction:column; gap:14px; max-width:420px; margin:0 auto; }
  .checkout-form.active{ display:flex; animation:plansFade 0.35s ease; }
  .checkout-form label{ font-size:11.5px; font-weight:600; color:var(--text); display:flex; flex-direction:column; gap:6px; }
  .checkout-row{ display:flex; gap:12px; }
  .checkout-row label{ flex:1; }
  .checkout-form input{
    font-family:var(--font-body); font-size:13px; color:var(--text-hi);
    background:rgba(255,255,255,0.75); border:1px solid var(--line); border-radius:12px;
    padding:11px 13px; outline:none; transition:border-color 0.15s ease, box-shadow 0.15s ease;
  }
  .checkout-form input:focus{ border-color:var(--accent); box-shadow:0 0 0 3px rgba(90,125,250,0.15); }

  .checkout-pay-btn{
    margin-top:6px; font-family:var(--font-body); font-size:14px; font-weight:700; color:#fff;
    background:linear-gradient(135deg, var(--accent), var(--accent-deep));
    border:none; padding:13px 20px; border-radius:14px; cursor:pointer;
    box-shadow:0 14px 26px -10px rgba(90,125,250,0.5);
    transition:transform 0.2s ease, opacity 0.2s ease;
  }
  .checkout-pay-btn:hover{ transform:translateY(-1px); }
  .checkout-pay-btn.loading{ opacity:0.75; cursor:wait; }
  .checkout-note{ text-align:center; font-size:10.5px; color:var(--text-mute); }
  .checkout-hint{
    text-align:center; font-size:10px; color:var(--accent-deep); background:var(--accent-soft);
    border-radius:9px; padding:7px 10px; line-height:1.5;
  }

  /* -- étape traitement -- */
  .plans-step-processing{ text-align:center; padding:44px 10px 10px; }
  .processing-spinner{
    width:52px; height:52px; margin:0 auto 22px; border-radius:50%;
    border:4px solid rgba(90,125,250,0.16); border-top-color:var(--accent);
    animation:spin 0.85s linear infinite;
  }
  @keyframes spin{ to{ transform:rotate(360deg); } }
  .plans-step-processing h3{ font-family:var(--font-display); font-weight:800; font-size:17px; color:var(--text-hi); }
  .plans-step-processing p{ font-size:12.5px; color:var(--text-mute); margin-top:6px; }

  /* -- étape échec -- */
  .plans-step-error{ text-align:center; padding:20px 10px 6px; }
  .error-check{
    width:64px; height:64px; margin:0 auto 18px; border-radius:50%;
    background:linear-gradient(135deg, #fb7185, #ef4444);
    display:flex; align-items:center; justify-content:center;
    font-size:26px; color:#fff; box-shadow:0 14px 30px -12px rgba(239,68,68,0.55);
    animation:errorShake 0.5s cubic-bezier(.36,.07,.19,.97);
  }
  @keyframes errorShake{
    10%,90%{ transform:translateX(-1px); } 20%,80%{ transform:translateX(2px); }
    30%,50%,70%{ transform:translateX(-4px); } 40%,60%{ transform:translateX(4px); }
  }
  .plans-step-error h3{ font-family:var(--font-display); font-weight:800; font-size:19px; color:var(--text-hi); }
  .plans-step-error p{ font-size:13px; color:var(--text-mute); margin-top:6px; max-width:360px; margin-left:auto; margin-right:auto; }
  .plans-error-actions{ display:flex; gap:10px; justify-content:center; margin-top:20px; }
  .plans-retry-btn{
    font-family:var(--font-body); font-size:13px; font-weight:700; color:#fff;
    background:linear-gradient(135deg, var(--accent), var(--accent-deep));
    border:none; padding:11px 24px; border-radius:13px; cursor:pointer;
    transition:transform 0.15s ease;
  }
  .plans-retry-btn:hover{ transform:translateY(-1px); }
  .plans-cancel-btn{
    font-family:var(--font-body); font-size:13px; font-weight:700; color:var(--text-mute);
    background:rgba(148,163,184,0.16); border:none; padding:11px 20px; border-radius:13px; cursor:pointer;
    transition:background 0.15s ease, color 0.15s ease;
  }
  .plans-cancel-btn:hover{ background:rgba(148,163,184,0.28); color:var(--text-hi); }

  .paypal-fail-link{
    display:block; margin:2px auto 0; background:none; border:none; cursor:pointer;
    font-family:var(--font-body); font-size:10.5px; font-weight:600; color:var(--text-mute);
    text-decoration:underline; text-underline-offset:2px; opacity:0.75;
    transition:color 0.15s ease, opacity 0.15s ease;
  }
  .paypal-fail-link:hover{ color:#dc2626; opacity:1; }

  /* -- sélecteur méthode de paiement -- */
  .pay-method-tabs{
    display:flex; gap:8px; max-width:420px; margin:0 auto 18px; padding:4px;
    background:rgba(148,163,184,0.14); border-radius:14px;
  }
  .pay-method-tab{
    flex:1; display:flex; align-items:center; justify-content:center; gap:7px;
    font-family:var(--font-body); font-size:12px; font-weight:700; color:var(--text-mute);
    background:transparent; border:none; border-radius:11px; padding:9px 10px; cursor:pointer;
    transition:background 0.18s ease, color 0.18s ease, box-shadow 0.18s ease;
  }
  .pay-method-tab svg{ flex-shrink:0; opacity:0.8; }
  .pay-method-tab:hover{ color:var(--text-hi); }
  .pay-method-tab.active{
    background:#fff; color:var(--text-hi);
    box-shadow:0 6px 16px -8px rgba(31,41,88,0.35), inset 0 1px 0 rgba(255,255,255,0.6);
  }
  .pay-method-tab.active svg{ opacity:1; }

  /* -- paiement PayPal -- */
  .paypal-panel{ display:none; flex-direction:column; gap:16px; max-width:420px; margin:0 auto; }
  .paypal-panel.active{ display:flex; animation:plansFade 0.35s ease; }
  .paypal-box{
    background:linear-gradient(165deg, rgba(0,48,135,0.06), rgba(0,112,186,0.09));
    border:1px solid rgba(0,112,186,0.22); border-radius:16px; padding:22px 20px;
    display:flex; flex-direction:column; align-items:center; gap:10px; text-align:center;
  }
  .paypal-mark{ font-family:var(--font-display); font-weight:800; font-size:22px; letter-spacing:-0.02em; color:#003087; }
  .paypal-mark span{ color:#0070ba; }
  .paypal-box p{ font-size:12px; color:var(--text-mute); line-height:1.5; max-width:320px; }
  .paypal-pay-btn{
    background:linear-gradient(135deg, #0070ba, #003087) !important;
    box-shadow:0 14px 26px -10px rgba(0,48,135,0.5) !important;
  }
  .paypal-pay-btn.loading{ opacity:0.75; cursor:wait; }

  /* -- étape choix des serveurs -- */
  .servers-head{ display:flex; align-items:flex-start; gap:14px; margin-bottom:20px; }
  .servers-head-icon{
    width:46px; height:46px; border-radius:14px; flex-shrink:0;
    background:linear-gradient(135deg, var(--accent), #8fa5ff);
    display:flex; align-items:center; justify-content:center; font-size:20px;
  }
  .servers-head-text h3{ font-family:var(--font-display); font-weight:800; font-size:16px; color:var(--text-hi); }
  .servers-head-text p{ font-size:12.5px; color:var(--text-mute); margin-top:4px; line-height:1.5; }
  .servers-head-text p span{ font-family:var(--font-mono); font-weight:700; color:var(--accent-deep); }

  .servers-pick-list{ display:flex; flex-direction:column; gap:10px; max-width:460px; margin:0 auto; }
  .server-pick-item{
    display:flex; align-items:center; gap:12px; cursor:pointer;
    background:rgba(255,255,255,0.7); border:1.5px solid var(--line); border-radius:14px;
    padding:12px 14px; transition:border-color 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease;
  }
  .server-pick-item:hover{ border-color:var(--accent); }
  .server-pick-item.checked{ border-color:var(--accent); box-shadow:0 0 0 3px rgba(90,125,250,0.14); }
  .server-pick-item.limit-reached{ opacity:0.5; cursor:not-allowed; }
  .server-pick-item input[type="checkbox"]{ width:17px; height:17px; accent-color:var(--accent); flex-shrink:0; cursor:pointer; }
  .server-pick-item.limit-reached input[type="checkbox"]{ cursor:not-allowed; }
  .server-pick-name{ font-size:13px; font-weight:700; color:var(--text-hi); }
  .server-pick-sub{ font-size:11px; color:var(--text-mute); margin-top:1px; }

  .servers-empty-note{
    text-align:center; font-size:12px; color:var(--text-mute); background:rgba(148,163,184,0.14);
    border-radius:12px; padding:14px; max-width:420px; margin:0 auto;
  }

  .success-servers-note{
    font-size:12px; color:var(--text-mute); background:var(--accent-soft); border-radius:10px;
    padding:8px 12px; margin-top:10px; display:inline-block; position:relative; z-index:1;
  }

  /* -- étape succès -- */
  .plans-step-success{ text-align:center; padding:20px 10px 6px; position:relative; overflow:visible; }
  .plans-step-success.active{ animation:successStepIn 0.55s cubic-bezier(.16,.84,.44,1); }
  @keyframes successStepIn{ from{ opacity:0; transform:translateY(16px) scale(0.96); } to{ opacity:1; transform:translateY(0) scale(1); } }

  .success-check{
    position:relative; width:72px; height:72px; margin:0 auto 20px; border-radius:50%;
    background:linear-gradient(135deg, var(--mint), #34d399);
    display:flex; align-items:center; justify-content:center;
    box-shadow:0 14px 30px -12px rgba(34,184,146,0.55);
    animation:successPop 0.55s cubic-bezier(.16,.84,.44,1);
  }
  .success-check::before, .success-check::after{
    content:''; position:absolute; inset:0; border-radius:50%;
    border:2px solid rgba(34,184,146,0.5); animation:successRing 1.3s ease-out infinite;
  }
  .success-check::after{ animation-delay:0.45s; }
  @keyframes successRing{ 0%{ transform:scale(0.85); opacity:0.75; } 100%{ transform:scale(1.9); opacity:0; } }
  @keyframes successPop{ 0%{transform:scale(0.4); opacity:0;} 70%{transform:scale(1.08); opacity:1;} 100%{transform:scale(1);} }

  .success-check-svg{ width:32px; height:32px; position:relative; z-index:1; }
  .success-check-path{
    fill:none; stroke:#fff; stroke-width:4.5; stroke-linecap:round; stroke-linejoin:round;
    stroke-dasharray:40; stroke-dashoffset:40;
    animation:successDraw 0.45s 0.32s cubic-bezier(.65,0,.45,1) forwards;
  }
  @keyframes successDraw{ to{ stroke-dashoffset:0; } }

  .success-confetti{ position:absolute; inset:0; pointer-events:none; overflow:visible; z-index:0; }
  .confetti-piece{
    position:absolute; top:6px; opacity:0; border-radius:2px;
    animation-name:confettiFall; animation-timing-function:ease-in; animation-fill-mode:forwards;
  }
  @keyframes confettiFall{
    0%{ opacity:1; transform:translateY(0) rotate(0deg); }
    100%{ opacity:0; transform:translateY(190px) rotate(560deg); }
  }

  .plans-step-success h3{ font-family:var(--font-display); font-weight:800; font-size:19px; color:var(--text-hi); position:relative; z-index:1; }
  .plans-step-success p{ font-size:13px; color:var(--text-mute); margin-top:6px; position:relative; z-index:1; }
  .plans-done-btn{
    margin-top:20px; font-family:var(--font-body); font-size:13px; font-weight:700; color:#fff;
    background:linear-gradient(135deg, var(--accent), var(--accent-deep));
    border:none; padding:11px 26px; border-radius:13px; cursor:pointer;
    transition:transform 0.15s ease; position:relative; z-index:1;
  }
  .plans-done-btn:hover{ transform:translateY(-1px); }

  @media (max-width:640px){
    .plans-modal{ padding:26px 20px 22px; }
    .plans-grid{ flex-direction:column; }
    .checkout-row{ flex-direction:column; }
  }

  .main{ flex:1; min-width:0; padding:26px 34px 60px; }

  .topbar{ display:flex; align-items:center; justify-content:flex-end; margin-bottom:20px; }
  .top-status{ display:flex; align-items:center; gap:8px; font-size:12px; color:var(--mint); font-weight:500; }

  .banner{
    background:rgba(34,184,146,0.10); border:1px solid rgba(34,184,146,0.28);
    border-radius:14px; padding:11px 16px;
    display:flex; flex-direction:column;
    margin-bottom:20px; font-size:12.5px;
  }
  .banner-row{ display:flex; align-items:center; justify-content:space-between; width:100%; }
  .banner .left{ display:flex; align-items:center; gap:9px; color:var(--text-hi); font-weight:500; }
  .banner .right{ color:var(--text-mute); }
  .banner .right-stack{ text-align:right; line-height:1.4; }
  .banner .right-stack .top-updated{ font-size:12px; font-weight:600; color:var(--text-hi); }
  .banner .right-stack .top-status{ font-size:11px; color:var(--text-mute); display:block; }
  .banner-divider{ height:1px; background:rgba(34,184,146,0.25); margin:9px 0; width:100%; }
  .banner .dash-copyright{ text-align:center; font-size:11px; color:var(--text-mute); padding:0; }
  .banner-sub{ opacity:0.85; font-weight:500; }

  /* -- avertissement : le bot/le backend a redémarré depuis le chargement
     de la page (déploiement, maintenance, crash-restart PM2...) — cf.
     scripts/auth.js#loadRealStatus, comparaison du bootId renvoyé par
     /api/status. Masqué par défaut (attribut [hidden]), affiché par JS. -- */
  .banner-reboot-notice{
    display:flex; align-items:center; justify-content:space-between; gap:14px;
    flex-wrap:wrap;
    margin:2px 0 10px; padding:10px 14px;
    background:rgba(245,166,35,0.12); border:1px solid rgba(245,166,35,0.4);
    border-radius:12px;
    font-size:12.5px; font-weight:600; color:var(--text-hi);
    transition:opacity 0.4s ease;
  }
  .banner-reboot-notice[hidden]{ display:none; }
  .banner-reboot-notice.is-hiding{ opacity:0; }
  .banner-reboot-btn{
    flex-shrink:0; border:none; border-radius:10px; padding:8px 14px;
    background:#f5a623; color:#1a1200; font-weight:700; font-size:12px;
    cursor:pointer; transition:filter 0.15s ease;
  }
  .banner-reboot-btn:hover{ filter:brightness(1.08); }

  /* -- écran d'accueil : message affiché quand la session a été invalidée
     par un redémarrage du bot (et non par une simple navigation/refresh) --
     cf. scripts/auth.js#checkSession, sessionExpiredReason === 'reboot'. */
  .banner-session-expired{
    display:flex; align-items:center; justify-content:center; gap:10px;
    margin:0 0 18px; padding:10px 16px;
    background:rgba(245,166,35,0.12); border:1px solid rgba(245,166,35,0.4);
    border-radius:12px;
    font-size:12.5px; font-weight:600; color:var(--text-hi);
    max-width:520px;
  }
  .banner-session-expired[hidden]{ display:none; }

  /* -- annonce staff (patch notes, maintenance planifiée, info) : même
     emplacement/structure que .banner-reboot-notice, couleur selon le
     type choisi côté console staff. Masqué par défaut, affiché par JS
     (cf. scripts/auth.js#applyAnnouncement) quand /api/status renvoie une
     annonce active et que son id n'est pas déjà dans nr_dismissed_announcements. -- */
  .banner-announcement{
    display:flex; align-items:center; justify-content:space-between; gap:14px;
    flex-wrap:wrap;
    margin:2px 0 10px; padding:10px 14px;
    background:rgba(90,125,250,0.10); border:1px solid rgba(90,125,250,0.35);
    border-radius:12px;
    font-size:12.5px; color:var(--text-hi);
  }
  .banner-announcement[hidden]{ display:none; }
  .banner-announcement-text{ display:flex; align-items:baseline; flex-wrap:wrap; gap:8px; min-width:0; }
  .banner-announcement-tag{
    flex-shrink:0; font-size:10px; font-weight:700; text-transform:uppercase; letter-spacing:0.05em;
    padding:2px 8px; border-radius:7px;
    background:rgba(90,125,250,0.16); color:var(--accent-deep);
  }
  .banner-announcement-title{ font-weight:700; flex-shrink:0; }
  .banner-announcement-message{ color:var(--text-mute); font-weight:500; }
  .banner-announcement-close{
    flex-shrink:0; width:22px; height:22px; border:none; border-radius:8px;
    background:transparent; color:var(--text-mute); font-size:16px; line-height:1;
    cursor:pointer; transition:background 0.15s ease, color 0.15s ease;
  }
  .banner-announcement-close:hover{ background:rgba(90,125,250,0.12); color:var(--text-hi); }

  .banner-announcement.type-patch{ background:rgba(34,184,146,0.10); border-color:rgba(34,184,146,0.32); }
  .banner-announcement.type-patch .banner-announcement-tag{ background:rgba(34,184,146,0.18); color:#0f7a5c; }

  .banner-announcement.type-maintenance{ background:rgba(245,166,35,0.10); border-color:rgba(245,166,35,0.32); }
  .banner-announcement.type-maintenance .banner-announcement-tag{ background:rgba(245,166,35,0.2); color:#a5670f; }

  .banner-announcement.type-warning{ background:rgba(239,68,68,0.09); border-color:rgba(239,68,68,0.3); }
  .banner-announcement.type-warning .banner-announcement-tag{ background:rgba(239,68,68,0.18); color:#b53434; }

  /* -- variantes d'état du système (par défaut : opérationnel) -- */
  .banner.status-warn{ background:rgba(245,166,35,0.10); border-color:rgba(245,166,35,0.32); }
  .banner.status-warn .banner-divider{ background:rgba(245,166,35,0.28); }
  .banner.status-warn .left .dot-live{ background:#f5a623; box-shadow:0 0 0 3px rgba(245,166,35,0.2); }
  .banner.status-warn .left{ color:#a5670f; }

  .banner.status-critical{ background:rgba(239,68,68,0.09); border-color:rgba(239,68,68,0.3); }
  .banner.status-critical .banner-divider{ background:rgba(239,68,68,0.25); }
  .banner.status-critical .left .dot-live{ background:#ef4444; box-shadow:0 0 0 3px rgba(239,68,68,0.18); }
  .banner.status-critical .left{ color:#b53434; }

  .dash-footer{ margin-top:24px; padding-top:20px; border-top:1px solid var(--line); }
  .dash-footer .banner{ margin-bottom:14px; }
  .dash-copyright{ text-align:center; font-size:11px; color:var(--text-mute); padding-bottom:4px; }

  .hero-card{
    background:var(--glass-strong); border:1px solid var(--glass-border);
    backdrop-filter:blur(20px); -webkit-backdrop-filter:blur(20px);
    border-radius:20px; padding:24px 28px;
    display:flex; align-items:center; justify-content:space-between;
    margin-bottom:18px; box-shadow:0 16px 40px -22px rgba(90,125,250,0.35);
  }
  .hero-left{ display:flex; align-items:center; gap:16px; }
  .hero-badge{
    width:50px; height:50px; border-radius:16px;
    background:linear-gradient(135deg, var(--accent), #8fa5ff);
    display:flex; align-items:center; justify-content:center;
    font-family:var(--font-display); font-weight:800; font-size:14px; color:#fff;
  }
  .hero-id{ font-family:var(--font-mono); font-size:12.5px; font-weight:600; color:var(--text); margin-top:0; }
  .pill-row{ display:flex; gap:8px; margin-top:9px; }
  .pill{ font-size:10.5px; padding:3px 11px; border-radius:20px; font-weight:600; }
  .pill.gold{ background:var(--accent-soft); color:var(--accent-deep); }
  .pill.green{ background:rgba(34,184,146,0.14); color:var(--mint); }
  .hero-btn{
    font-size:12.5px; font-weight:600; color:#fff;
    background:linear-gradient(135deg, var(--accent), var(--accent-deep));
    padding:10px 18px; border-radius:12px; border:none; cursor:pointer;
  }

  .kpi-row{ display:grid; grid-template-columns:repeat(4,1fr); gap:14px; margin-bottom:18px; }
  .kpi{
    background:var(--glass); border:1px solid var(--glass-border);
    backdrop-filter:blur(16px); -webkit-backdrop-filter:blur(16px);
    border-radius:16px; padding:16px 18px;
  }
  .kpi-num{ font-family:var(--font-mono); font-size:23px; color:var(--text-hi); font-weight:500; }
  .kpi-lbl{ font-size:11.5px; color:var(--text-mute); margin-top:3px; }

  .grid-2{ display:grid; grid-template-columns:1.6fr 1fr; gap:16px; margin-bottom:16px; }

  .card{
    background:var(--glass); border:1px solid var(--glass-border);
    backdrop-filter:blur(16px); -webkit-backdrop-filter:blur(16px);
    border-radius:18px; padding:18px 20px;
  }
  .card-head{ display:flex; align-items:center; justify-content:space-between; margin-bottom:14px; }
  .card-title{ font-size:13.5px; font-weight:700; color:var(--text-hi); display:flex; align-items:center; gap:8px; }
  .card-title .swatch{ width:6px; height:6px; border-radius:50%; background:var(--accent); }
  .card-link{ font-size:11.5px; color:var(--text-mute); }

  .mini-stats{ display:grid; grid-template-columns:repeat(4,1fr); gap:10px; margin-bottom:16px; }
  .mini-stat .n{ font-family:var(--font-mono); font-size:16.5px; color:var(--accent-deep); font-weight:600; }
  .mini-stat .l{ font-size:10.5px; color:var(--text-mute); margin-top:2px; }

  .chart-wrap{ height:120px; margin-top:6px; }

  .top-list{ list-style:none; display:flex; flex-direction:column; }
  .top-list li{
    display:flex; align-items:center; justify-content:space-between;
    padding:8px 0; border-bottom:1px solid var(--line); font-size:12.5px;
  }
  .top-list li:last-child{ border-bottom:none; }
  .top-list .name{ display:flex; align-items:center; gap:8px; color:var(--text); }
  .top-list .rank{ width:16px; font-family:var(--font-mono); color:var(--text-mute); font-size:11px; }
  .top-list .val{ color:var(--accent-deep); font-family:var(--font-mono); font-size:12px; font-weight:500; }

  .module-list{ display:flex; flex-direction:column; }
  .module-row{
    display:flex; align-items:center; justify-content:space-between;
    padding:11px 4px; border-bottom:1px solid var(--line); font-size:13px;
  }
  .module-row:last-child{ border-bottom:none; }
  .m-name{ display:flex; align-items:center; gap:9px; color:var(--text); }
  .status-dot{ width:6px; height:6px; border-radius:50%; }
  .status-dot.on{ background:var(--mint); }
  .status-dot.off{ background:var(--text-mute); }
  .status-txt{ font-size:11px; font-weight:500; }
  .status-txt.on{ color:var(--mint); }
  .status-txt.off{ color:var(--text-mute); }

  .quick-actions{ display:grid; grid-template-columns:1fr 1fr; gap:10px; }
  .qa-btn{
    background:rgba(255,255,255,0.55); border:1px solid var(--line);
    border-radius:14px; padding:12px 14px; cursor:pointer; text-align:left;
    transition:border-color 0.15s ease, transform 0.15s ease;
  }
  .qa-btn:hover{ border-color:var(--accent); transform:translateY(-1px); }
  .qa-t{ font-size:12.5px; color:var(--text-hi); font-weight:600; }
  .qa-s{ font-size:10.5px; color:var(--text-mute); margin-top:2px; }

  @media (max-width: 980px){
    .sidebar{ display:none; }
    .kpi-row{ grid-template-columns:repeat(2,1fr); }
    .grid-2{ grid-template-columns:1fr; }
    .main{ padding:20px; }
    .intro-card{ padding:36px 28px; }
  }

  /* ================= CATEGORY COVER PAGES ================= */
  .cat-hero{
    display:flex; align-items:flex-start; gap:16px;
    background:var(--glass); border:1px solid var(--glass-border);
    backdrop-filter:blur(16px); -webkit-backdrop-filter:blur(16px);
    border-radius:18px; padding:20px 22px;
  }
  .cat-hero-icon{
    width:46px; height:46px; flex-shrink:0; border-radius:14px;
    background:linear-gradient(135deg, var(--accent), #8fa5ff);
    display:flex; align-items:center; justify-content:center;
    box-shadow:0 10px 22px -10px rgba(90,125,250,0.55);
  }
  .cat-hero-icon svg{ width:22px; height:22px; stroke:#fff; }
  .cat-hero-eyebrow{ font-size:10.5px; font-weight:600; letter-spacing:0.14em; text-transform:uppercase; color:var(--accent-deep); margin-bottom:4px; }
  .cat-hero-title{ font-family:var(--font-display); font-weight:800; font-size:19px; color:var(--text-hi); letter-spacing:-0.01em; }
  .cat-hero-desc{ font-size:12.5px; line-height:1.6; color:var(--text-mute); margin-top:6px; max-width:640px; }
  .cat-hero-dev{
    display:inline-block; margin-left:8px; font-size:9px; font-weight:700; letter-spacing:0.06em; text-transform:uppercase;
    background:rgba(245,166,35,0.16); color:#b7791f; padding:2px 8px; border-radius:8px; vertical-align:middle;
  }

  .cat-stats{ grid-template-columns:repeat(3,1fr); }

  .cat-empty{
    display:flex; flex-direction:column; align-items:center; justify-content:center;
    gap:8px; text-align:center; padding:34px 20px; color:var(--text-mute); font-size:12.5px;
  }
  .cat-empty svg{ width:26px; height:26px; stroke:var(--text-mute); opacity:0.7; }
  /* Sans cette règle, l'attribut [hidden] posé par le JS (ex.
     renderMemberList/renderEconomy dans script.js : `empty.hidden = true`
     dès qu'il y a des données) n'a AUCUN effet visuel : `display:flex`
     ci-dessus est une règle auteur, qui l'emporte toujours sur le
     `display:none` par défaut du navigateur pour [hidden] (règle UA,
     origine plus faible dans la cascade CSS) — d'où les états vides
     "Aucune donnée..." qui restaient affichés SOUS des lignes de données
     bien réelles (Liste des membres, Économie interne...). Même correctif
     déjà appliqué ailleurs dans ce fichier pour d'autres classes
     (.server-grid-empty[hidden], .banner-reboot-notice[hidden]...) mais
     manquant ici, alors que .cat-empty est la classe la plus utilisée du
     dashboard (20 occurrences : Analytiques, Activité, Commandes,
     Incidents, Factures...). */
  .cat-empty[hidden]{ display:none; }

  @media (max-width: 980px){
    .cat-stats{ grid-template-columns:repeat(1,1fr); }
  }

  /* ================= JEUX (cards) ================= */
  .games-grid{
    display:grid; grid-template-columns:repeat(auto-fill, minmax(220px, 1fr)); gap:14px;
  }
  .game-card{
    position:relative; display:flex; flex-direction:column; gap:10px;
    background:var(--glass-strong); border:1.5px solid var(--glass-border);
    border-radius:16px; padding:16px; cursor:pointer;
    transition:transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
    text-decoration:none; color:inherit;
  }
  .game-card:hover{ transform:translateY(-2px); box-shadow:0 14px 26px -14px rgba(90,125,250,0.35); border-color:var(--accent); }
  .game-card-top{ display:flex; align-items:flex-start; justify-content:space-between; gap:8px; }
  .game-card-icon{
    width:38px; height:38px; border-radius:11px; flex-shrink:0;
    background:linear-gradient(135deg, var(--accent), #8fa5ff);
    display:flex; align-items:center; justify-content:center; font-size:18px;
    box-shadow:0 8px 18px -8px rgba(90,125,250,0.55);
  }
  .game-card-name{ font-family:var(--font-display); font-weight:700; font-size:13.5px; color:var(--text-hi); }
  .game-card-desc{ font-size:11.5px; line-height:1.5; color:var(--text-mute); flex:1 1 auto; }
  .game-card-foot{ display:flex; align-items:center; justify-content:space-between; gap:8px; padding-top:8px; border-top:1px solid var(--glass-border); }
  .game-card-stat{ font-family:var(--font-mono); font-size:10.5px; color:var(--accent-deep); }
  .game-card.is-off{ opacity:0.6; }

  /* ================= MODULES DE CATÉGORIE (cards) ================= */
  .module-card-grid{
    display:grid; grid-template-columns:repeat(auto-fill, minmax(230px, 1fr)); gap:14px;
  }
  .module-card2{
    position:relative; display:flex; flex-direction:column; gap:10px;
    background:var(--glass-strong); border:1.5px solid var(--glass-border);
    border-radius:16px; padding:16px; cursor:pointer;
    transition:transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease, opacity 0.15s ease;
  }
  .module-card2.is-active-row:hover{ transform:translateY(-2px); box-shadow:0 14px 26px -14px rgba(90,125,250,0.35); border-color:var(--accent); }
  .module-card2.is-off-row{ cursor:default; opacity:0.62; }
  .module-card2-top{ display:flex; align-items:flex-start; justify-content:space-between; gap:8px; }
  .module-card2-icon{
    position:relative; overflow:visible;
    width:38px; height:38px; border-radius:11px; flex-shrink:0;
    background:linear-gradient(135deg, var(--accent), #8fa5ff);
    display:flex; align-items:center; justify-content:center;
    box-shadow:0 8px 18px -8px rgba(90,125,250,0.55);
    transition:background 0.2s ease, box-shadow 0.2s ease;
  }
  .module-card2-icon svg{ width:18px; height:18px; stroke:#fff; }
  .module-card2.is-off-row .module-card2-icon{ background:linear-gradient(135deg, #b7bece, #ced4e0); box-shadow:none; }

  /* ============ FLASH D'ACTIVATION / DÉSACTIVATION SUR L'ICÔNE DU MODULE ============
     Déclenché par flip()/applyLocally() dans script.js (classe .is-flash-on
     ou .is-flash-off posée un court instant sur .module-card2-icon) : le
     glyphe du module s'efface, un badge ✓ (vert, activation) ou ✕ (rouge,
     désactivation) apparaît avec un anneau qui se dilate autour de l'icône,
     puis tout revient au glyphe normal. Complète le voile grisé/flouté
     existant (.module-lockable, plus lent, sur toute la carte) par un
     accusé de réception immédiat et sans ambiguïté au niveau de l'icône. */
  .module-card2-icon-glyph{ transition:opacity 0.2s ease, transform 0.2s ease; }
  .module-card2-icon-badge{
    position:absolute; top:0; left:0; right:0; bottom:0; margin:auto;
    width:14px; height:14px; opacity:0; pointer-events:none;
  }
  .module-card2-icon-badge path{ stroke-dasharray:26; stroke-dashoffset:26; }

  .module-card2-icon.is-flash-on .module-card2-icon-glyph{ animation:modIconGlyphSwap 0.85s ease; }
  .module-card2-icon.is-flash-on .module-card2-icon-badge-on{ animation:modIconBadgeSwap 0.85s ease; }
  .module-card2-icon.is-flash-on .module-card2-icon-badge-on path{ animation:modIconBadgeDraw 0.35s 0.28s cubic-bezier(.65,0,.45,1) forwards; }
  .module-card2-icon.is-flash-on::after{
    content:''; position:absolute; inset:-5px; border-radius:12px; pointer-events:none;
    border:2px solid rgba(34,184,146,0.55);
    animation:modIconRing 0.7s ease-out;
  }

  .module-card2-icon.is-flash-off .module-card2-icon-glyph{ animation:modIconGlyphSwap 0.7s ease; }
  .module-card2-icon.is-flash-off .module-card2-icon-badge-off{ animation:modIconBadgeSwap 0.7s ease; }
  .module-card2-icon.is-flash-off .module-card2-icon-badge-off path{ animation:modIconBadgeDraw 0.3s 0.22s cubic-bezier(.65,0,.45,1) forwards; }
  .module-card2-icon.is-flash-off::after{
    content:''; position:absolute; inset:-5px; border-radius:12px; pointer-events:none;
    border:2px solid rgba(220,100,100,0.5);
    animation:modIconRing 0.6s ease-out;
  }

  @keyframes modIconGlyphSwap{
    0%{ opacity:1; transform:scale(1); }
    30%{ opacity:0; transform:scale(0.55); }
    70%{ opacity:0; transform:scale(0.55); }
    100%{ opacity:1; transform:scale(1); }
  }
  @keyframes modIconBadgeSwap{
    0%{ opacity:0; transform:scale(0.4); }
    30%{ opacity:0; transform:scale(0.4); }
    50%{ opacity:1; transform:scale(1.2); }
    65%{ opacity:1; transform:scale(1); }
    88%{ opacity:1; transform:scale(1); }
    100%{ opacity:0; transform:scale(0.75); }
  }
  @keyframes modIconBadgeDraw{ to{ stroke-dashoffset:0; } }
  @keyframes modIconRing{
    0%{ transform:scale(0.8); opacity:0.9; }
    100%{ transform:scale(1.7); opacity:0; }
  }
  .module-card2-name{ font-family:var(--font-display); font-weight:700; font-size:13.5px; color:var(--text-hi); }
  .module-card2-desc{
    font-size:11.5px; line-height:1.5; color:var(--text-mute); flex:1 1 auto;
    display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical; overflow:hidden;
  }
  .module-card2-intro{ font-size:10.5px; line-height:1.45; padding:7px 9px; border-radius:8px; }
  .module-card2-intro:empty{ display:none; }
  .module-card2-intro code{ font-size:10px; padding:1px 4px; border-radius:4px; background:rgba(0,0,0,0.08); }
  .module-card2.is-active-row .module-card2-intro{ color:var(--mint); background:rgba(34,184,146,0.10); }
  .module-card2.is-off-row .module-card2-intro{ color:var(--text-mute); background:rgba(120,130,150,0.10); font-style:italic; }
  .module-card2-foot{ display:flex; align-items:center; justify-content:space-between; gap:8px; padding-top:8px; border-top:1px solid var(--glass-border); }
  .module-card2-status{ font-size:10.5px; font-weight:600; display:flex; align-items:center; gap:6px; }
  .module-card2-status .dot{ width:6px; height:6px; border-radius:50%; background:var(--text-mute); flex-shrink:0; }
  .module-card2.is-active-row .module-card2-status{ color:var(--mint); }
  .module-card2.is-active-row .module-card2-status .dot{ background:var(--mint); box-shadow:0 0 0 3px rgba(34,184,146,0.18); }
  .module-card2.is-off-row .module-card2-status{ color:var(--text-mute); }
  .module-card2-hint{ font-size:10px; color:var(--accent-deep); opacity:0; transform:translateX(-3px); transition:opacity 0.18s ease, transform 0.18s ease; }
  .module-card2.is-active-row:hover .module-card2-hint{ opacity:1; transform:translateX(0); }

  /* ================= OVERLAY GÉNÉRIQUE "FONCTIONNALITÉ (DÉS)ACTIVÉE" =================
     Réutilisable sur n'importe quel bloc de module : le conteneur porte
     .module-lockable (+ position:relative, déjà présent sur .module-card2 /
     .game-card), le contenu à griser est enveloppé dans .module-lockable-body,
     et un .module-lockable-overlay contenant .module-lockable-overlay-text
     est ajouté en frère. La bascule est pilotée par la classe .is-locked
     (+ .is-success pendant l'animation d'activation) — voir la fonction
     setModuleLockState() dans script.js. */
  .module-lockable-body{
    transition:filter 0.55s ease, opacity 0.55s ease;
    filter:grayscale(0) blur(0);
  }
  .module-lockable.is-locked .module-lockable-body{
    filter:grayscale(1) blur(3px);
    opacity:0.72;
    pointer-events:none;
  }
  .module-lockable-overlay{
    position:absolute; inset:0; z-index:4;
    display:flex; align-items:center; justify-content:center;
    overflow:hidden; border-radius:inherit;
    pointer-events:none;
    opacity:0;
    transition:opacity 0.55s ease;
  }
  .module-lockable.is-locked .module-lockable-overlay{ opacity:1; }
  .module-lockable-overlay-text{
    display:inline-block;
    font-family:var(--font-display); font-weight:800; font-size:10.5px;
    letter-spacing:0.03em; text-transform:uppercase; white-space:nowrap;
    color:#fff; padding:5px 34px;
    background:rgba(30,34,48,0.80);
    box-shadow:0 6px 16px -6px rgba(0,0,0,0.45);
    transform:rotate(-28deg);
    transition:background 0.3s ease, color 0.3s ease;
  }
  .module-lockable-overlay-text.is-success{
    background:rgba(28,168,124,0.94);
  }
  /* Bandeau "Module désactivé" (état par défaut du voile, cf. is-off posée
     par setModuleLockState()/renderCategoryPage) — rouge, pour se distinguer
     sans ambiguïté du bandeau vert "activé" et du bandeau doré "premium". */
  .module-lockable-overlay-text.is-off{
    background:rgba(196,58,58,0.92);
  }
  /* Variante "fonctionnalité premium" : même mécanique de voile grisé/
     flouté + bandeau diagonal, mais habillage doré distinct de la variante
     "désactivé" (celle-ci ne se lève jamais au clic du toggle — seul un
     passage au tier requis la débloque, cf. .module-card2.is-premium-locked
     dans script.js#renderCategoryPage). */
  .module-lockable-overlay-text.is-premium{
    background:linear-gradient(135deg, #caa24a, #f3d27a);
    color:#3a2705;
    box-shadow:0 6px 16px -6px rgba(202,162,74,0.55);
  }
  /* Variante field-level du voile générique .module-lockable, posée par
     script.js#renderField sur un champ précis de configSchema (f.premiumTier
     non couvert par le tier effectif de la guild) — .module-lockable seul
     n'a pas de position:relative (les autres usages l'héritent de
     .module-card2 / .game-card), donc ce wrapper le fournit lui-même ; le
     bandeau est aussi resserré pour rester lisible sur un champ étroit. */
  .module-config-field-lockable{ position:relative; border-radius:10px; cursor:pointer; }
  .module-config-field-lockable .module-lockable-overlay-text{ font-size:9.5px; padding:4px 20px; }

  /* Champ dont l'utilité dépend d'un toggle du même onglet (f.dependsOn,
     cf. script.js#renderField/syncFieldDependencies) : pas de bandeau ni de
     flou (ce n'est pas un verrou premium, juste "ce réglage ne sert à rien
     tant que ce toggle est off"). Un simple grisage seul étant jugé trop
     ambigu (retour utilisateur : un champ grisé sans aucune mention visible
     ressemble à un bug d'affichage, pas à un état "désactivé" volontaire),
     un badge explicite est ajouté en ::after — position:relative posé ici
     profite automatiquement aussi bien aux champs qu'aux titres de section
     (les deux portent cette même classe, cf. script.js#renderFieldsWithSections). */
  .module-config-field-dependent{ position:relative; transition:opacity 0.3s ease, filter 0.3s ease, max-height 0.35s ease; }
  .module-config-field-dependent.is-dependency-off{
    opacity:0.42;
    filter:grayscale(0.6);
    pointer-events:none;
    max-height:52px;
    overflow:hidden;
    cursor:pointer;
  }
  /* Repli auto par défaut (retour utilisateur : pas la peine d'occuper toute
     la hauteur d'un bloc qui ne sert à rien tant que son toggle-maître est
     éteint) — cliquer dessus (cf. script.js#syncFieldDependencies) le
     déplie pour consultation seule, jamais édition : pointer-events reste
     none sur les champs eux-mêmes, seul le wrapper capte le clic. */
  .module-config-field-dependent.is-dependency-off.is-expanded{
    max-height:2000px;
    /* Redonne un pointeur "main" cohérent tant qu'on peut re-cliquer pour
       replier — le pointer-events:none plus haut bloque déjà l'édition des
       champs, mais laisse remonter le clic jusqu'à ce wrapper (cf. cascade
       pointer-events : un enfant "none" rend son parent directement la
       cible du clic). */
    cursor:pointer;
  }
  .module-config-field-dependent.is-dependency-off::after{
    content:'Fonctionnalité désactivée — cliquer pour afficher';
    position:absolute; top:4px; right:4px; z-index:5;
    font-family:var(--font-display); font-weight:700; font-size:8.5px;
    letter-spacing:0.02em; text-transform:uppercase; white-space:nowrap;
    color:rgba(255,255,255,0.85);
    padding:3px 8px; border-radius:20px;
    background:rgba(20,22,32,0.85);
    border:1px solid rgba(255,255,255,0.12);
  }
  /* Contenu du badge une fois déplié : même position/style que ci-dessus
     (hérité, seule la mention change) — spécificité (3 classes) volontairement
     plus élevée que la règle générique ET que la variante section-group
     ci-dessous, pour gagner sur `content` sans devoir dupliquer tout le
     reste (position/rotation/etc. suivent la cascade normale). */
  .module-config-field-dependent.is-dependency-off.is-expanded::after{
    content:'Fonctionnalité désactivée — cliquer pour réduire';
  }
  /* .module-config-section-group (script.js#renderFieldsWithSections) :
     regroupe TOUS les champs consécutifs d'un même bloc de section qui
     dependsOn le même toggle-maître dans UN SEUL wrapper — avant, chaque
     champ (+ le titre + sectionDesc) posait sa propre classe
     .module-config-field-dependent, et syncFieldDependencies() togglait
     is-dependency-off indépendamment sur chacun : le badge ci-dessus
     s'affichait donc une fois par champ, empilé sur toute la hauteur du bloc
     au lieu d'un seul bandeau (retour utilisateur, capture à l'appui). Cette
     règle plus spécifique remplace le badge "coin" par UN bandeau centré et
     légèrement pivoté, à la manière de .module-lockable-overlay-text, qui
     couvre tout le sous-bloc grisé d'un coup. Le toggle-maître du bloc (sans
     dependsOn) reste toujours EN DEHORS de ce wrapper, donc jamais grisé ni
     désactivé — sinon impossible de le rallumer une fois éteint. */
  .module-config-section-group.is-dependency-off::after{
    top:50%; right:auto; left:50%; bottom:auto;
    transform:translate(-50%, -50%) rotate(-14deg);
    padding:5px 26px; font-size:9px;
    box-shadow:0 6px 16px -6px rgba(0,0,0,0.45);
  }
  /* Les champs regroupés dans .module-config-section-group ne sont plus des
     enfants DIRECTS de .module-config-body/.module-config-fields-col (qui
     leur donnait leur espacement vertical via son gap:14px) — ce wrapper
     doit donc fournir le même espacement en interne. */
  .module-config-section-group{ display:flex; flex-direction:column; gap:14px; }
  /* Un champ à la fois premium (f.premiumLocked) ET dépendant d'un toggle
     (f.dependsOn) ne doit JAMAIS cumuler les deux voiles : tant que le
     toggle parent est désactivé, le statut premium est sans objet (rien à
     configurer de toute façon), et l'ancien cumul opacité×grayscale(dependsOn)
     par-dessus grayscale×blur×opacity(premium) rendait le libellé illisible,
     ne laissant plus apparaître que le ruban doré "PREMIUM" en surimpression
     (retour utilisateur, capture à l'appui). Le badge "Fonctionnalité
     désactivée" ci-dessus prend seul le relais tant que is-dependency-off
     est actif ; le voile premium ne redevient visible que si le toggle
     parent repasse actif (syncFieldDependencies retire alors cette classe). */
  .module-config-field-dependent.is-dependency-off .module-lockable-overlay{
    opacity:0 !important;
  }
  .module-config-field-dependent.is-dependency-off .module-lockable-body{
    filter:none !important;
    opacity:1 !important;
  }
  .module-card2-premium-badge{
    position:absolute; top:10px; right:10px; z-index:6;
    display:flex; align-items:center; gap:3px;
    font-family:var(--font-display); font-weight:800; font-size:9px;
    letter-spacing:0.03em; text-transform:uppercase;
    color:#3a2705; padding:3px 7px; border-radius:20px;
    background:linear-gradient(135deg, #caa24a, #f3d27a);
    box-shadow:0 4px 10px -4px rgba(202,162,74,0.6);
    pointer-events:none;
  }

  /* ================= MODULE CONFIG PANEL ================= */
  .module-row{ transition:background 0.15s ease; }
  .module-row.is-active-row{ cursor:pointer; }
  .module-row.is-off-row{ cursor:default; }

  .module-config{ display:none; flex-direction:column; gap:16px; animation:cfgRise 0.3s ease; }
  .module-config.active{ display:flex; }
  @keyframes cfgRise{ from{opacity:0; transform:translateY(6px);} to{opacity:1; transform:translateY(0);} }

  .module-config-head{ display:flex; align-items:center; justify-content:space-between; gap:12px; }
  .module-config-back{
    display:flex; align-items:center; gap:4px;
    font-family:var(--font-body); font-size:12px; font-weight:600; color:var(--accent-deep);
    background:transparent; border:none; cursor:pointer; padding:4px 2px;
  }
  .module-config-back:hover{ text-decoration:underline; }

  /* Regroupe le statut d'auto-save + le bouton "revoir le tutoriel du module"
     dans le même bloc de droite : .module-config-head garde exactement 2
     enfants directs (celui-ci + .module-config-back) pour que son
     justify-content:space-between continue de les répartir aux 2 extrémités,
     au lieu de 3 blocs étalés uniformément si le bouton était posé à plat. */
  .module-config-head-right{ display:flex; align-items:center; gap:10px; }
  .module-config-tour-btn{
    display:flex; align-items:center; justify-content:center;
    width:26px; height:26px; border-radius:50%;
    background:var(--glass-strong); border:1px solid var(--line); color:var(--text-mute);
    font-size:13px; line-height:1; cursor:pointer; padding:0;
    transition:background 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
  }
  .module-config-tour-btn:hover{ background:var(--accent-soft); color:var(--accent-deep); border-color:rgba(90,125,250,0.35); transform:translateY(-1px); }

  .module-config-title{ font-family:var(--font-display); font-weight:800; font-size:15.5px; color:var(--text-hi); }
  /* Le -4px de remontée ne vaut que juste après le bandeau retour (index.html) ;
     utilisé seul (ex: streamhub.html), le titre ne doit pas chevaucher ce qui précède. */
  .module-config-head + .module-config-title,
  .module-config-head + .module-config-readonly-banner + .module-config-title{ margin-top:-4px; }
  /* Même remarque que pour le titre : le -8px ne compense le bandeau retour
     que lorsqu'il précède réellement (index.html). Utilisé seul (streamhub.html),
     le sous-titre ne doit pas remonter sous le titre. */
  .module-config-desc{ font-size:12px; color:var(--text-mute); margin-top:4px; }
  .module-config-head + .module-config-title + .module-config-desc,
  .module-config-head + .module-config-readonly-banner + .module-config-title + .module-config-desc{ margin-top:-8px; }

  /* Mise en page à 2 colonnes : sidebar d'onglets à gauche (liste, comme les
     réglages du module lui-même), contenu de l'onglet actif à droite — avant,
     les onglets s'étalaient en barre horizontale au-dessus du contenu. */
  .module-config-layout{ display:grid; grid-template-columns:220px 1fr; align-items:start; gap:18px; }
  @media (max-width:860px){ .module-config-layout{ grid-template-columns:1fr; } }

  .module-config-body{ display:flex; flex-direction:column; gap:14px; min-width:0; }
  .module-config-tabs{
    display:flex; flex-direction:column; gap:2px; padding:8px;
    background:var(--glass); border:1px solid var(--glass-border); border-radius:16px;
    position:sticky; top:16px;
  }
  .module-config-tab{
    font-family:var(--font-body); text-align:left; color:var(--text-mute);
    background:none; border:1px solid transparent; border-radius:12px; padding:9px 10px; cursor:pointer;
    display:flex; align-items:center; gap:10px;
    transition:color 0.15s ease, background 0.15s ease, border-color 0.15s ease;
  }
  .module-config-tab:hover{ color:var(--text-hi); background:var(--glass-strong); }
  .module-config-tab.active{
    color:var(--accent-deep); background:var(--accent-soft); border-color:rgba(90,125,250,0.35);
  }
  .module-config-tab-icon{
    width:28px; height:28px; flex-shrink:0; border-radius:9px; overflow:hidden;
    display:flex; align-items:center; justify-content:center; font-size:14px; line-height:1;
    background:var(--glass-strong);
  }
  .module-config-tab.active .module-config-tab-icon{ background:var(--accent); }
  .module-config-tab-text{ display:flex; flex-direction:column; min-width:0; gap:1px; }
  .module-config-tab-label{
    font-family:var(--font-display); font-weight:700; font-size:11.5px; color:inherit;
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  }
  .module-config-tab-count{ font-size:10px; color:var(--text-mute); }
  .module-config-tab.is-logs-tab{ margin-top:8px; padding-top:13px; border-top:1px solid var(--line); border-radius:12px 12px 0 0; }
  .module-config-tab.is-logs-tab svg{ width:12px; height:12px; stroke:currentColor; flex-shrink:0; }
  .module-config-logs{ display:flex; flex-direction:column; gap:2px; }
  /* align-items:flex-start (pas center) : une entrée peut désormais tenir sur
     plusieurs lignes (cf. .module-config-log-quote ci-dessous), le centrage
     vertical d'origine n'avait de sens que pour une seule ligne de texte. */
  .module-config-log-row{ display:flex; align-items:flex-start; gap:9px; padding:9px 4px; border-bottom:1px solid var(--glass-border); font-size:11.5px; transition:background-color .25s ease; }
  .module-config-log-row:last-child{ border-bottom:none; }
  .module-config-log-dot{ width:6px; height:6px; margin-top:5px; border-radius:50%; background:var(--accent); flex-shrink:0; }
  .module-config-log-text{ color:var(--text-hi); flex:1 1 auto; line-height:1.5; }
  .module-config-log-text strong{ color:var(--text-hi); font-weight:700; }
  .module-config-log-time{ color:var(--text-mute); font-size:10.5px; flex-shrink:0; padding-top:1px; }
  .module-config-logs-empty{ font-size:11.5px; color:var(--text-mute); padding:10px 4px; }

  /* Barre au-dessus de la liste, ne contient que le bouton "Purger" (cf.
     renderLogsTab, canPurge) — jamais affichée pour la simulation
     buildFakeLogs, seulement pour un module réellement adossé à un flux
     d'activité en base. */
  .module-config-logs-header{ display:flex; justify-content:flex-end; padding:0 4px 8px; }
  .module-config-logs-purge-btn{
    font:inherit;
    font-size:10.5px;
    font-weight:600;
    color:#c0392b;
    background:transparent;
    border:1px solid rgba(192,57,43,0.35);
    border-radius:7px;
    padding:5px 10px;
    cursor:pointer;
    transition:background-color .15s ease, color .15s ease;
  }
  .module-config-logs-purge-btn:hover{ background-color:rgba(192,57,43,0.1); }

  /* Ligne avec détail repliable (cf. .has-details posée par _renderLogRow
     quand l'entrée a au moins un bloc "> ...") : curseur main + léger
     survol, pour signaler que c'est cliquable — une ligne SANS détail
     (la grande majorité) reste, elle, non cliquable et sans ce curseur. */
  .module-config-log-row.has-details{ cursor:pointer; }
  .module-config-log-row.has-details:hover{ background-color:var(--glass); }
  /* Chevron indicateur de repli/dépli, tourne de 90° une fois .expanded
     posé sur la ligne (cf. script.js#renderTab, clic sur .has-details). */
  .module-config-log-chevron{
    flex-shrink:0;
    margin-top:4px;
    color:var(--text-mute);
    transition:transform .18s ease;
  }
  .module-config-log-row.expanded .module-config-log-chevron{ transform:rotate(90deg); color:var(--accent); }

  /* Lignes "> ..." (citation) d'une entrée d'activité — rendu façon champ
     d'embed Discord : liseré coloré à gauche + fond légèrement distinct,
     pour que le détail (ex: rôles ajoutés/retirés) se détache visuellement
     de la ligne de titre au lieu de tout aplatir en une seule phrase.
     Repliée par défaut (max-height:0, overflow caché) : ne s'affiche que
     lorsque la ligne parente porte .expanded (clic dessus, cf. script.js).
     Transition sur max-height (pas display) pour un dépli animé plutôt
     qu'un basculement sec. */
  .module-config-log-quote{
    max-height:0;
    overflow:hidden;
    margin-top:0;
    padding:0 10px;
    border-left:2.5px solid var(--accent);
    background:var(--glass);
    border-radius:0 6px 6px 0;
    color:var(--text-mute);
    font-size:11px;
    line-height:1.6;
    opacity:0;
    transition:max-height .2s ease, opacity .2s ease, padding .2s ease, margin-top .2s ease;
  }
  .module-config-log-row.expanded .module-config-log-quote{
    max-height:300px;
    margin-top:6px;
    padding:7px 10px;
    opacity:1;
  }
  .module-config-log-quote strong{ color:var(--text-hi); font-weight:700; }

  /* Pagination "Activité" (← Précédent / Page N / Suivant →, cf.
     script.js#renderLogsTab) — n'apparaît que si au moins une page voisine
     existe (page > 0 ou hasMore), jamais pour une liste tenant sur une
     seule page. */
  .module-config-logs-pagination{
    display:flex;
    align-items:center;
    justify-content:center;
    gap:14px;
    padding:12px 4px 4px;
  }
  .module-config-logs-page-btn{
    font:inherit;
    font-size:11px;
    font-weight:600;
    color:var(--accent-deep);
    background:var(--glass);
    border:1px solid var(--glass-border);
    border-radius:7px;
    padding:6px 12px;
    cursor:pointer;
    transition:background-color .15s ease, opacity .15s ease;
  }
  .module-config-logs-page-btn:hover:not(:disabled){ background-color:var(--glass-hover, var(--glass)); }
  .module-config-logs-page-btn:disabled{ opacity:.4; cursor:default; }
  .module-config-logs-page-label{ font-size:10.5px; color:var(--text-mute); }

  /* Entrée qui vient d'arriver en temps réel (cf. _subscribeActivity côté
     script.js) : petit flash de fond pour signaler visuellement le nouvel
     élément sans dépendre uniquement de sa position en haut de liste. */
  .module-config-log-row.is-live-new{ background-color:rgba(90,125,250,0.14); }

  /* Onglet "Stats 📊" uniquement (cf. script.js#renderStatsTab) : les
     entrées "Top 5" (classements) sont séparées du reste et affichées dans
     une colonne à droite plutôt qu'à la suite dans la même liste verticale
     — plus lisible dès qu'un module a plusieurs classements (ex.
     systeme-logs : Top 5 activités, sanctions, kicks, bans, raisons...).
     Colonne de droite un peu plus étroite (classements = lignes courtes) et
     visuellement détachée (liseré + fond) pour bien la distinguer du reste
     des stats à gauche. */
  .module-config-stats-grid{ display:grid; grid-template-columns:1.3fr 1fr; align-items:start; gap:18px; }
  .module-config-stats-main{ min-width:0; }
  .module-config-stats-side{
    min-width:0;
    border-left:1px solid var(--glass-border);
    padding-left:18px;
  }
  .module-config-stats-side .module-config-logs{ gap:10px; }
  .module-config-stats-side .module-config-log-row{ border-bottom:none; padding:0; align-items:flex-start; }
  @media (max-width:760px){
    /* Panneau étroit : la colonne de droite passe sous la principale plutôt
       que de compresser les deux jusqu'à l'illisible. */
    .module-config-stats-grid{ grid-template-columns:1fr; gap:6px; }
    .module-config-stats-side{ border-left:none; border-top:1px solid var(--glass-border); padding-left:0; padding-top:10px; margin-top:4px; }
  }

  /* Onglet "Classement 🏆" (cf. script.js#renderLeaderboardTab) — barre
     d'onglets par jeu au-dessus d'un tableau de lignes. Les états
     "Chargement…" / "indisponible" / "personne n'a encore joué" réutilisent
     .module-config-logs-empty (déjà stylée plus haut), seuls le wrapper, la
     barre de jeux et les lignes ont besoin de styles propres ici. */
  .module-config-lb{ display:flex; flex-direction:column; gap:12px; }
  .module-config-lb-games{ display:flex; flex-wrap:wrap; gap:6px; }
  .module-config-lb-game-tab{
    font:inherit; font-family:var(--font-body); font-size:11.5px; font-weight:600;
    color:var(--text-mute); background:var(--glass); border:1px solid var(--glass-border);
    border-radius:9px; padding:7px 12px; cursor:pointer;
    transition:color 0.15s ease, background 0.15s ease, border-color 0.15s ease;
  }
  .module-config-lb-game-tab:hover{ color:var(--text-hi); background:var(--glass-strong); }
  .module-config-lb-game-tab.active{
    color:var(--accent-deep); background:var(--accent-soft); border-color:rgba(90,125,250,0.35);
  }

  .module-config-lb-table{ display:flex; flex-direction:column; gap:2px; }
  .module-config-lb-row{
    display:grid; grid-template-columns:28px 1.4fr 1.2fr auto;
    align-items:center; gap:12px; padding:9px 6px; border-bottom:1px solid var(--glass-border);
    font-size:11.5px;
  }
  .module-config-lb-row:last-child{ border-bottom:none; }
  .module-config-lb-pos{ font-family:var(--font-mono); color:var(--text-mute); font-size:11px; }
  .module-config-lb-row:nth-child(1) .module-config-lb-pos{ color:#ffcf6b; font-weight:700; }
  .module-config-lb-row:nth-child(2) .module-config-lb-pos{ color:#c9d2e3; font-weight:700; }
  .module-config-lb-row:nth-child(3) .module-config-lb-pos{ color:#d68a54; font-weight:700; }
  .module-config-lb-name{ min-width:0; }
  .module-config-lb-name .an-role-name{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .module-config-lb-mid{ min-width:0; display:flex; align-items:center; }
  .module-config-lb-tier{
    display:inline-flex; align-items:baseline; gap:5px; font-size:11px; font-weight:600;
    color:var(--text-hi); background:var(--glass-strong); border-radius:7px; padding:4px 9px;
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  }
  .module-config-lb-tier-pct{ font-size:10px; font-weight:500; color:var(--text-mute); }
  .module-config-lb-tier-unranked{ color:var(--text-mute); background:transparent; padding-left:0; }
  .module-config-lb-end{
    display:flex; flex-direction:column; align-items:flex-end; gap:2px; text-align:right;
  }
  .module-config-lb-end .an-role-count{ font-size:11.5px; white-space:nowrap; }
  .module-config-lb-gains{ font-family:var(--font-mono); color:var(--text-mute); font-size:10.5px; white-space:nowrap; }
  @media (max-width:640px){
    /* Panneau étroit : la colonne "rang" (mid) prend trop de place à côté du
       nom et des gains -> on la masque plutôt que de tout tasser illisible ;
       le rang reste consultable en dépliant la ligne (même resserrement que
       .module-config-stats-grid ci-dessus, pas de dépli dédié ici). */
    .module-config-lb-row{ grid-template-columns:24px 1fr auto; }
    .module-config-lb-mid{ display:none; }
  }

  .module-config-field{ display:flex; flex-direction:column; gap:6px; }
  .module-config-field label{ font-size:11.5px; font-weight:600; color:var(--text-hi); display:flex; align-items:center; gap:6px; }
  .module-config-field .cfg-hint{ font-size:10.5px; color:var(--text-mute); }

  /* Crayon (déverrouille l'édition) + bouton "réinitialiser" à côté du
     label d'un champ (cf. script.js#_fieldControlsHtml). Poussés à droite
     du label via margin-left:auto sur le premier des deux — jamais les
     deux à la fois pour un même champ que si le label est assez large
     (label en display:flex ci-dessus), sinon ils suivent juste le texte. */
  .cfg-field-controls{ display:inline-flex; align-items:center; gap:4px; margin-left:auto; font-weight:400; }
  .cfg-field-edit-btn, .cfg-field-reset-btn{
    display:inline-flex; align-items:center; justify-content:center;
    width:20px; height:20px; padding:0; border-radius:6px;
    background:var(--glass); border:1px solid var(--glass-border);
    color:var(--text-mute); cursor:pointer;
    transition:background-color .15s ease, color .15s ease, border-color .15s ease;
  }
  .cfg-field-edit-btn:hover, .cfg-field-reset-btn:hover{
    background-color:var(--glass-strong); color:var(--accent); border-color:var(--accent);
  }

  /* Champ affiché en lecture seule par défaut (cf. .cfg-field-lockable,
     posé uniquement sur les champs qui ont un f.defaultValue connu — cf.
     renderFieldInner) : .cfg-field-view visible, le vrai contrôle
     (.cfg-field-edit-input) masqué, jusqu'à ce qu'on clique sur le crayon
     (cf. bindFieldEditReset -> .is-editing). L'input reste dans le DOM et
     garde sa valeur/ses listeners tout du long — seule sa VISIBILITÉ change,
     jamais son état — donc rien d'autre à retoucher (auto-save, aperçu live,
     dependsOn... continuent de lire le même élément qu'avant). */
  .cfg-field-view{
    font-size:12.5px; color:var(--text-hi); line-height:1.5;
    background:var(--glass); border:1px solid var(--glass-border); border-radius:10px;
    padding:9px 12px; word-break:break-word;
  }
  .cfg-field-view-empty{ color:var(--text-mute); font-style:italic; }
  .cfg-field-lockable .cfg-field-edit-input{ display:none; }
  .cfg-field-lockable.is-editing .cfg-field-view{ display:none; }
  .cfg-field-lockable.is-editing .cfg-field-edit-input{ display:block; }
  .cfg-field-lockable:not(.is-editing) .cfg-field-edit-btn svg{ pointer-events:none; }
  /* .cfg-input est le champ "canonique" du site : on ne l'exige plus
     imbriqué dans .module-config-field (il ne l'était que par habitude,
     pas par nécessité) pour pouvoir le réutiliser tel quel n'importe où
     ailleurs sur le site, pas seulement dans le panneau de config. */
  input.cfg-input, select.cfg-input, textarea.cfg-input{
    font-family:var(--font-body); font-size:12.5px; color:var(--text-hi);
    background:var(--glass); border:1px solid var(--line); border-radius:10px;
    padding:9px 12px; outline:none; transition:border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
    width:100%; resize:vertical;
  }
  .cfg-input::placeholder{ color:var(--text-mute); opacity:0.75; }
  .cfg-input:hover:not(:disabled){ border-color:rgba(148,163,184,0.5); }
  .cfg-input:focus{ border-color:var(--accent); background:var(--glass-strong); box-shadow:0 0 0 3px rgba(90,125,250,0.15); }
  .cfg-input:disabled{ opacity:0.5; cursor:not-allowed; }
  select.cfg-input{
    appearance:none; -webkit-appearance:none; cursor:pointer;
    background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none'><path d='M5.5 7.5l4.5 4.5 4.5-4.5' stroke='%237c8598' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/></svg>");
    background-repeat:no-repeat; background-position:right 10px center; padding-right:30px;
  }

  /* Titre de sous-bloc au sein d'un onglet (f.section, cf. script.js#renderFieldsWithSections)
     — sépare visuellement plusieurs réglages indépendants regroupés dans le
     même onglet (ex: "Rôles automatiques" / "Rôle temporaire" dans l'onglet
     "Rôles" de bienvenue-depart), pour que l'onglet ne ressemble plus à une
     liste plate de champs sans rapport apparent entre eux. Le filet
     horizontal (border-top) a été retiré : chaque bloc est maintenant sa
     propre carte (.module-config-section-block ci-dessous), qui fournit déjà
     la séparation visuelle — inutile de la doubler ici. */
  .module-config-section-title{
    font-family:var(--font-display); font-weight:800; font-size:11px;
    letter-spacing:0.03em; text-transform:uppercase; color:var(--accent-deep);
  }

  /* Phrase d'explication optionnelle sous le titre de sous-bloc (f.sectionDesc,
     cf. script.js#renderFieldsWithSections) — un peu de contexte pour les
     blocs dont le nom seul ne suffit pas à comprendre ce qu'ils font. */
  .module-config-section-desc{
    font-size:11.5px; color:var(--text-mute); line-height:1.4;
    margin-top:-6px; /* rapproche du titre — l'espacement avec les champs suivants vient du gap du bloc */
  }

  /* Rappel sous UN champ 'role'/'channel' (cf. script.js#renderFieldInner) :
     un rôle/salon fraîchement créé sur Discord n'apparaît pas tout de suite
     dans la liste (cache + polling d'auto-refresh, cf. PICKER_CACHE_TTL_MS
     côté script.js) — cette note évite que la personne pense devoir
     recharger la page. Volontairement plus discret que .module-config-
     section-desc (taille et opacité en dessous) puisqu'il se répète sur
     CHAQUE champ role/channel plutôt qu'une fois par bloc. */
  .module-config-field-hint{
    font-size:10.5px; color:var(--text-mute); opacity:0.75; line-height:1.35;
    margin:4px 0 0;
  }

  /* Encart visuel autour d'un bloc de section entier (titre + description +
     champs) — chaque bloc devient une petite carte à fond légèrement teinté
     plutôt qu'un simple filet horizontal, pour qu'un onglet à plusieurs
     blocs (ex: "Paramètres" de bienvenue-depart : Salons / Journal
     d'activité / Message privé) se scanne d'un coup d'œil. Le gap:14px de
     .module-config-body/.module-config-fields-col (parent flex) fournit déjà
     l'espacement ENTRE les cartes, donc pas de margin ici.
     Look "carte 3D" : léger dégradé + liseré clair en haut (effet de relief,
     comme si la carte était éclairée par le dessus) + double ombre portée
     (une fine et proche pour le bord, une plus large et diffuse pour la
     profondeur) — inspiré de .module-card2 déjà utilisée ailleurs sur le
     dashboard, réutilisé ici pour que TOUTE carte de configuration (bloc de
     section OU ligne de groupe aperçu, cf. .module-config-group-row plus
     bas) partage la même identité visuelle. Léger décollement au survol
     pour renforcer la sensation de profondeur. */
  .module-config-section-block{
    display:flex; flex-direction:column; gap:0;
    position:relative;
    background:linear-gradient(180deg, rgba(255,255,255,0.06), rgba(255,255,255,0.015));
    border:1px solid var(--glass-border, var(--line));
    border-radius:14px;
    padding:0;
    box-shadow:
      0 1px 0 rgba(255,255,255,0.55) inset,
      0 2px 6px -3px rgba(30,40,70,0.14),
      0 12px 24px -18px rgba(30,40,70,0.30);
    transition:transform 0.18s ease, box-shadow 0.18s ease;
  }
  .module-config-section-block:hover{
    transform:translateY(-2px);
    box-shadow:
      0 1px 0 rgba(255,255,255,0.55) inset,
      0 4px 10px -3px rgba(30,40,70,0.18),
      0 18px 30px -18px rgba(30,40,70,0.36);
  }

  /* En-tête cliquable d'une section repliable (cf. script.js#renderSectionedFields
     / bindSectionToggles) — même pattern visuel qu'une ligne de "Activité 🧾"
     (pastille + chevron + titre, cf. .module-config-log-row plus haut) :
     une ligne = un groupe de réglages ("Salons", "Cooldowns", etc.), replié
     par défaut, qui se déplie au clic pour révéler ses champs
     (.module-config-section-panel ci-dessous). */
  .module-config-section-header{
    display:flex; align-items:center; gap:9px;
    width:100%; text-align:left; font:inherit; color:inherit;
    background:transparent; border:none; cursor:pointer;
    padding:13px 16px; border-radius:14px;
    transition:background-color .15s ease;
  }
  .module-config-section-header:hover{ background-color:var(--glass); }
  .module-config-section-dot{ width:6px; height:6px; border-radius:50%; background:var(--accent); flex-shrink:0; }
  .module-config-section-chevron{ flex-shrink:0; color:var(--text-mute); transition:transform .18s ease; }
  .module-config-section-block.is-expanded .module-config-section-chevron{ transform:rotate(90deg); color:var(--accent); }
  .module-config-section-headtext{ display:flex; align-items:baseline; flex-wrap:wrap; gap:8px; flex:1 1 auto; min-width:0; }
  .module-config-section-header .module-config-section-title{ margin:0; }
  .module-config-section-count{ font-size:10.5px; font-weight:600; color:var(--text-mute); }

  /* Corps repliable d'une section : caché par défaut (max-height:0), même
     transition douce que .module-config-field-dependent.is-dependency-off
     plus haut, pour un dépli animé plutôt qu'un basculement sec. */
  .module-config-section-panel{
    display:flex; flex-direction:column; gap:10px;
    max-height:0; overflow:hidden; opacity:0;
    padding:0 16px;
    transition:max-height .3s ease, opacity .22s ease, padding .22s ease;
  }
  .module-config-section-block.is-expanded .module-config-section-panel{
    max-height:4000px; opacity:1;
    padding:2px 16px 16px;
  }

  .module-config-toggle-row{
    display:flex; align-items:center; justify-content:space-between;
    padding:11px 2px; border-bottom:1px solid var(--line); font-size:12.5px; color:var(--text);
  }
  .module-config-toggle-row:last-child{ border-bottom:none; }

  /* ---- Champ 'image' (upload + preview miniature) ---- */
  .cfg-image-row{ display:flex; align-items:center; gap:14px; flex-wrap:wrap; }
  .cfg-image-preview{
    width:64px; height:64px; flex-shrink:0; border-radius:12px; overflow:hidden;
    background:rgba(120,130,150,0.09); border:1.5px dashed var(--glass-border);
    display:flex; align-items:center; justify-content:center;
  }
  .cfg-image-preview img{ width:100%; height:100%; object-fit:cover; display:block; }
  .cfg-image-preview.empty{ color:var(--text-mute); }
  .cfg-image-preview.empty span{ font-size:9px; text-align:center; line-height:1.3; padding:0 4px; }
  .cfg-image-controls{ display:flex; flex-direction:column; gap:6px; align-items:flex-start; }
  .cfg-image-upload-btn{
    font-family:var(--font-body); font-size:11.5px; font-weight:600; color:var(--accent-deep);
    background:var(--accent-soft); border:1px solid transparent; border-radius:10px;
    padding:8px 14px; cursor:pointer; transition:background 0.15s ease;
  }
  .cfg-image-upload-btn:hover{ background:color-mix(in srgb, var(--accent-soft) 70%, var(--accent) 20%); }
  .cfg-image-remove-btn{
    font-family:var(--font-body); font-size:11px; font-weight:600; color:var(--text-mute);
    background:transparent; border:none; cursor:pointer; padding:0; text-decoration:underline;
  }
  .cfg-image-remove-btn:hover{ color:var(--text-hi); }
  .cfg-image-status{ font-size:10.5px; color:var(--text-mute); }

  /* ---- Champ 'library' (bibliothèque à mise à jour en direct — cf.
     script.js#renderFieldInner + bindLibraryFields, core/libraryManager
     côté serveur) : ligne de statut (nb d'entrées, fraîcheur), puis liste
     repliable des entrées réellement actives (mots/domaines/motifs),
     filtrable, avec un bouton "Actualiser" qui force une vérification
     immédiate de la source distante. ---- */
  .cfg-library-status{
    font-size:11.5px; color:var(--text-mute); line-height:1.5;
    background:var(--glass); border:1px solid var(--glass-border); border-radius:10px;
    padding:8px 12px;
  }
  .cfg-library-status b{ color:var(--text-hi); }
  .cfg-library-actions{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
  .cfg-library-toggle-btn, .cfg-library-refresh-btn{
    font-family:var(--font-body); font-size:11.5px; font-weight:600;
    border-radius:10px; padding:8px 14px; cursor:pointer; transition:background 0.15s ease, color 0.15s ease;
  }
  .cfg-library-toggle-btn{ color:var(--accent-deep); background:var(--accent-soft); border:1px solid transparent; }
  .cfg-library-toggle-btn:hover{ background:color-mix(in srgb, var(--accent-soft) 70%, var(--accent) 20%); }
  .cfg-library-refresh-btn{ color:var(--text-mute); background:var(--glass); border:1px solid var(--glass-border); }
  .cfg-library-refresh-btn:hover:not(:disabled){ color:var(--text-hi); border-color:rgba(148,163,184,0.5); }
  .cfg-library-refresh-btn:disabled{ opacity:0.6; cursor:not-allowed; }
  .cfg-library-body{ display:flex; flex-direction:column; gap:8px; }
  .cfg-library-body[hidden]{ display:none; }

  /* ---- Champ 'action' (bouton déclenchant une opération métier côté
     serveur — équivalent dashboard d'une sous-commande slash, cf.
     script.js#renderFieldInner + bindActionFields/openActionModal,
     moduleConfigApi.js POST .../actions/:actionId). ---- */
  .cfg-action-row{ display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap; }
  .cfg-action-label{ font-size:12px; font-weight:600; color:var(--text-hi); }
  .cfg-action-btn{
    font-family:var(--font-body); font-size:11.5px; font-weight:700;
    color:var(--accent-deep); background:var(--accent-soft); border:1px solid transparent;
    border-radius:10px; padding:8px 16px; cursor:pointer; white-space:nowrap;
    transition:background 0.15s ease, opacity 0.15s ease, transform 0.15s ease;
  }
  .cfg-action-btn:hover:not(:disabled){ background:color-mix(in srgb, var(--accent-soft) 70%, var(--accent) 20%); }
  .cfg-action-btn:disabled{ opacity:0.6; cursor:not-allowed; }
  .cfg-action-btn.is-destructive{ color:#dc2626; background:rgba(220,38,38,0.10); }
  .cfg-action-btn.is-destructive:hover:not(:disabled){ background:rgba(220,38,38,0.18); }
  .cfg-action-status{
    font-size:11px; line-height:1.5; border-radius:10px; padding:7px 11px; margin-top:8px;
    background:var(--glass); border:1px solid var(--glass-border); color:var(--text-mute);
  }
  .cfg-action-status[hidden]{ display:none; }
  .cfg-action-status.is-ok{ color:#15803d; background:rgba(34,197,94,0.10); border-color:rgba(34,197,94,0.25); }
  .cfg-action-status.is-error{ color:#dc2626; background:rgba(220,38,38,0.10); border-color:rgba(220,38,38,0.25); }
  .cfg-action-entries{ margin:6px 0 0; padding-left:16px; }
  .cfg-action-entries li{ margin-bottom:2px; }

  /* ---- Champ 'radio-catalog' (module Lecteur Media) : liste en lecture
     seule des webradios du catalogue (jamais de textarea JSON — géré
     uniquement par les actions 'radio_lookup'/'radio_remove'), cf.
     script.js#renderFieldInner + bindRadioCatalogFields. ---- */
  .cfg-radio-catalog-list{ display:flex; flex-direction:column; gap:6px; }
  .cfg-radio-catalog-empty{
    font-size:11.5px; color:var(--text-mute); background:var(--glass); border:1px solid var(--glass-border);
    border-radius:10px; padding:10px 12px;
  }
  .cfg-radio-catalog-row{
    display:flex; align-items:center; gap:10px; min-width:0;
    background:var(--glass); border:1px solid var(--glass-border); border-radius:10px; padding:8px 10px;
    transition:opacity 0.15s ease;
  }
  .cfg-radio-catalog-row.is-removing{ opacity:0.5; }
  .cfg-radio-catalog-name{ font-size:12px; font-weight:600; color:var(--text-hi); white-space:nowrap; }
  .cfg-radio-catalog-url{
    flex:1; min-width:0; font-size:11px; color:var(--text-mute);
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .cfg-radio-catalog-remove{
    flex-shrink:0; width:22px; height:22px; border-radius:8px; border:1px solid transparent;
    color:#dc2626; background:rgba(220,38,38,0.10); cursor:pointer; font-size:12px; line-height:1;
    transition:background 0.15s ease, opacity 0.15s ease;
  }
  .cfg-radio-catalog-remove:hover:not(:disabled){ background:rgba(220,38,38,0.18); }
  .cfg-radio-catalog-remove:disabled{ opacity:0.6; cursor:not-allowed; }

  /* ---- Popup de saisie générique pour un champ 'action' (inputs et/ou
     confirmation destructive) — mêmes proportions/verre dépoli que
     .cfg-jbm-modal ci-dessous pour rester visuellement cohérent. ---- */
  .cfg-action-modal{ position:fixed; inset:0; z-index:98; opacity:0; pointer-events:none; transition:opacity 0.25s ease; }
  .cfg-action-modal.is-open{ opacity:1; pointer-events:auto; }
  .cfg-action-modal-backdrop{ position:absolute; inset:0; background:rgba(15,20,40,0.45); backdrop-filter:blur(3px); }
  .cfg-action-modal-box{
    position:absolute; top:50%; left:50%; width:min(440px, 92vw); max-height:86vh; overflow-y:auto;
    background:var(--glass-strong); border:1px solid var(--glass-border);
    backdrop-filter:blur(26px); -webkit-backdrop-filter:blur(26px);
    border-radius:20px; padding:26px 26px 22px;
    box-shadow:0 30px 70px -20px rgba(20,26,60,0.45), inset 0 1px 0 rgba(255,255,255,0.6);
    transform:translate(-50%,-48%) scale(0.94); transition:transform 0.25s cubic-bezier(.16,.84,.44,1);
  }
  .cfg-action-modal.is-open .cfg-action-modal-box{ transform:translate(-50%,-50%) scale(1); }
  .cfg-action-modal-close{
    position:absolute; top:12px; right:12px; width:28px; height:28px; border-radius:9px;
    border:1px solid var(--line); background:rgba(255,255,255,0.6); color:var(--text-mute);
    font-size:13px; line-height:1; cursor:pointer; display:flex; align-items:center; justify-content:center;
    transition:background 0.15s ease, color 0.15s ease;
  }
  .cfg-action-modal-close:hover{ background:rgba(239,68,68,0.12); color:#dc2626; }
  .cfg-action-modal-title{ font-family:var(--font-display); font-size:16px; font-weight:800; color:var(--text-hi); margin:0 26px 16px 0; }
  .cfg-action-modal-empty{ font-size:11.5px; color:var(--text-mute); font-style:italic; margin:0 0 12px; }
  .cfg-action-modal-field{ display:flex; flex-direction:column; gap:5px; margin-bottom:14px; position:relative; }
  .cfg-action-modal-field label{ font-size:10.5px; font-weight:700; letter-spacing:0.02em; text-transform:uppercase; color:var(--text-mute); display:flex; align-items:center; gap:4px; }
  .cfg-action-modal-req{ color:#dc2626; }
  .cfg-action-modal-input{
    font-family:var(--font-body); font-size:12.5px; color:var(--text-hi);
    background:rgba(255,255,255,0.7); border:1px solid var(--line); border-radius:10px;
    padding:9px 11px; width:100%; box-sizing:border-box; transition:border-color 0.15s ease, background 0.15s ease;
  }
  .cfg-action-modal-input:focus{ border-color:var(--accent); background:var(--glass-strong); outline:none; }
  textarea.cfg-action-modal-input{ resize:vertical; min-height:64px; }
  .cfg-action-modal-file{ font-size:11.5px; }
  .cfg-action-modal-confirm input{ border-color:rgba(220,38,38,0.35); }
  .cfg-action-modal-user-suggestions{
    position:absolute; top:100%; left:0; right:0; z-index:2; margin-top:4px;
    background:var(--glass-strong); border:1px solid var(--glass-border); border-radius:10px;
    box-shadow:0 12px 28px -14px rgba(20,26,60,0.4); max-height:180px; overflow-y:auto;
  }
  .cfg-action-modal-user-suggestions[hidden]{ display:none; }
  .cfg-action-modal-user-suggestion{
    display:block; width:100%; text-align:left; font-family:var(--font-body); font-size:12px;
    color:var(--text-hi); background:none; border:none; padding:8px 11px; cursor:pointer;
  }
  .cfg-action-modal-user-suggestion:hover{ background:var(--accent-soft); }
  .cfg-action-modal-error{ font-size:11.5px; font-weight:600; color:#dc2626; margin:0 0 12px; min-height:14px; }
  .cfg-action-modal-error[hidden]{ display:none; }
  .cfg-action-modal-actions{ display:flex; align-items:center; justify-content:flex-end; gap:10px; margin-top:6px; }
  .cfg-action-modal-cancel, .cfg-action-modal-submit{
    font-family:var(--font-body); font-size:12.5px; font-weight:700; border-radius:11px;
    padding:9px 18px; cursor:pointer; border:none; white-space:nowrap;
    transition:transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease, opacity 0.15s ease;
  }
  .cfg-action-modal-cancel{ color:var(--text-mute); background:rgba(255,255,255,0.55); border:1px solid var(--line); }
  .cfg-action-modal-cancel:hover{ background:rgba(255,255,255,0.8); color:var(--text-hi); }
  .cfg-action-modal-submit{ color:#fff; background:linear-gradient(135deg, var(--accent), var(--accent-deep)); }
  .cfg-action-modal-submit:hover{ transform:translateY(-1px); box-shadow:0 8px 16px -10px rgba(90,125,250,0.5); }
  .cfg-action-modal-submit.is-destructive{ background:linear-gradient(135deg, #ef4444, #b91c1c); }

  @media (max-width:640px){
    .cfg-action-modal-box{ width:94vw; padding:22px 18px 18px; }
  }
  .cfg-library-search{
    font-family:var(--font-body); font-size:12px; color:var(--text-hi);
    background:var(--glass); border:1px solid var(--line); border-radius:10px;
    padding:7px 11px; outline:none;
  }
  .cfg-library-search:focus{ border-color:var(--accent); background:var(--glass-strong); }
  .cfg-library-list{
    max-height:220px; overflow-y:auto;
    background:var(--glass); border:1px solid var(--glass-border); border-radius:10px;
    padding:10px;
  }
  .cfg-library-sublabel{ font-size:10.5px; font-weight:700; text-transform:uppercase; letter-spacing:0.03em; color:var(--text-mute); margin:6px 0 4px; }
  .cfg-library-sublabel:first-child{ margin-top:0; }
  .cfg-library-chips{ display:flex; flex-wrap:wrap; gap:6px; }
  .cfg-library-chip{
    display:inline-block; font-size:11px; color:var(--text-hi);
    background:var(--glass-strong); border:1px solid var(--glass-border); border-radius:999px;
    padding:4px 10px;
  }
  .cfg-library-chip-pattern{ cursor:help; }
  .cfg-library-empty{ font-size:11.5px; color:var(--text-mute); font-style:italic; }

  /* ---- Champ 'verified-list' (cf. script.js#renderFieldInner + type
     'verified-list' déclaré par un module, ex: streamhub#twitch_streamers) :
     liste de badges (pseudo réel, avatar, statut live) + ligne d'ajout qui
     ouvre le popup de vérification (.cfg-vlist-modal, structure partagée
     avec la modale JSON builder .cfg-jbm-* — cf. plus bas dans ce fichier —
     seul le CONTENU du corps change). Même "recette visuelle" que
     .cfg-library-chips ci-dessus pour rester cohérent, en plus riche
     (avatar, indicateur live, suppression directe). ---- */
  .cfg-vlist-chips{
    display:flex; flex-wrap:wrap; gap:6px;
    background:var(--glass); border:1px solid var(--glass-border); border-radius:10px;
    padding:10px; min-height:20px;
  }
  .cfg-vlist-empty, .cfg-vlist-loading{ font-size:11.5px; color:var(--text-mute); font-style:italic; }
  .cfg-vlist-chip{
    display:inline-flex; align-items:center; gap:6px; font-size:11.5px; font-weight:600; color:var(--text-hi);
    background:var(--glass-strong); border:1px solid var(--glass-border); border-radius:999px;
    padding:4px 6px 4px 4px;
  }
  .cfg-vlist-chip.is-live{ border-color:rgba(239,68,68,0.5); background:rgba(239,68,68,0.08); }
  .cfg-vlist-chip.is-unknown{ border-color:rgba(234,179,8,0.5); background:rgba(234,179,8,0.08); color:var(--text-mute); }
  .cfg-vlist-chip-avatar{ width:20px; height:20px; border-radius:50%; flex-shrink:0; background:rgba(120,130,150,0.2); }
  .cfg-vlist-chip-name{ white-space:nowrap; }
  .cfg-vlist-chip-live{ font-size:9.5px; font-weight:800; letter-spacing:0.02em; color:#dc2626; }
  .cfg-vlist-chip-remove{
    display:flex; align-items:center; justify-content:center; width:16px; height:16px;
    font-size:10px; line-height:1; color:var(--text-mute); background:rgba(148,163,184,0.15);
    border:none; border-radius:50%; cursor:pointer; padding:0; transition:background 0.12s ease, color 0.12s ease;
  }
  .cfg-vlist-chip-remove:hover{ background:rgba(239,68,68,0.16); color:#dc2626; }
  /* Pastille "gérable" (liste Jeux suivis de GameCore) : son corps est un
     bouton qui ouvre le panneau par jeu (.cfg-gspace-modal plus bas), le ✕
     restant le seul geste de retrait — d'où l'engrenage, qui rend le clic
     découvrable sans texte supplémentaire. */
  .cfg-vlist-chip-main{
    display:inline-flex; align-items:center; gap:6px;
    font:inherit; color:inherit; background:none; border:none; padding:0; margin:0; cursor:pointer;
  }
  .cfg-vlist-chip-gear{ font-size:9.5px; opacity:0.55; transition:opacity 0.12s ease; }
  .cfg-vlist-chip.is-manageable{ transition:border-color 0.12s ease, background 0.12s ease; }
  .cfg-vlist-chip.is-manageable:hover{ border-color:var(--accent); background:rgba(90,125,250,0.1); }
  .cfg-vlist-chip.is-manageable:hover .cfg-vlist-chip-gear{ opacity:1; }
  .cfg-vlist-chip-main:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; border-radius:999px; }

  /* ---- Panneau "espace de jeu" (GameCore) : ouvert au clic sur une
     pastille de la liste Jeux suivis, il remplace les anciennes commandes
     /gamecore jeu salons|auto. Structure de modale partagée (.cfg-jbm-*),
     seul le CONTENU du corps est spécifique. ---- */
  .cfg-gspace-head{ display:flex; align-items:center; gap:12px; margin-bottom:14px; }
  .cfg-gspace-art{ width:52px; height:70px; object-fit:cover; border-radius:8px; flex-shrink:0; background:rgba(120,130,150,0.2); }
  .cfg-gspace-name{ font-size:15px; font-weight:800; color:var(--text-hi); }
  .cfg-gspace-sub{ font-size:11.5px; color:var(--text-mute); margin-top:3px; }
  .cfg-gspace-warn{
    font-size:11.5px; color:var(--text-mute); background:rgba(234,179,8,0.08);
    border:1px solid rgba(234,179,8,0.35); border-radius:10px; padding:9px 11px; margin:0 0 14px;
  }
  .cfg-gspace-block{
    background:var(--glass); border:1px solid var(--glass-border); border-radius:12px;
    padding:12px 13px; margin-bottom:12px;
  }
  .cfg-gspace-block--danger{ border-color:rgba(239,68,68,0.35); background:rgba(239,68,68,0.05); }
  .cfg-gspace-block-title{ font-size:12.5px; font-weight:800; color:var(--text-hi); margin-bottom:5px; }
  .cfg-gspace-block-desc{ font-size:11.5px; color:var(--text-mute); margin:0 0 10px; line-height:1.5; }
  .cfg-gspace-rows{ display:flex; flex-direction:column; gap:8px; }
  .cfg-gspace-row{ display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1.3fr); align-items:center; gap:10px; }
  .cfg-gspace-row.is-locked{ opacity:0.5; }
  .cfg-gspace-row-label{ font-size:11.5px; font-weight:600; color:var(--text-hi); }
  .cfg-gspace-auto-tag{
    font-size:9.5px; font-weight:700; color:var(--accent); background:rgba(90,125,250,0.12);
    border-radius:999px; padding:1px 7px; margin-left:4px; vertical-align:middle;
  }
  .cfg-gspace-select{ width:100%; }
  .cfg-gspace-text{ width:100%; }
  .cfg-gspace-btn{
    font-size:11.5px; font-weight:700; padding:7px 13px; border-radius:9px; cursor:pointer;
    border:1px solid var(--glass-border); background:var(--glass-strong); color:var(--text-hi);
    transition:background 0.12s ease, border-color 0.12s ease, opacity 0.12s ease;
  }
  .cfg-gspace-btn:disabled{ opacity:0.5; cursor:not-allowed; }
  .cfg-gspace-publish-row{ display:flex; flex-wrap:wrap; gap:8px; }
  .cfg-gspace-btn--primary{ border-color:transparent; background:var(--accent); color:#fff; }
  .cfg-gspace-btn--danger{ border-color:rgba(239,68,68,0.45); color:#dc2626; background:rgba(239,68,68,0.08); }
  .cfg-gspace-status{ font-size:11.5px; color:var(--text-mute); min-height:16px; }
  .cfg-gspace-status.is-ok{ color:#16a34a; }
  .cfg-gspace-status.is-error{ color:#dc2626; }
  @media (max-width:560px){
    .cfg-gspace-row{ grid-template-columns:1fr; gap:4px; }
  }
  .cfg-vlist-chip-spinner{
    width:11px; height:11px; border-radius:50%; flex-shrink:0;
    border:2px solid rgba(90,125,250,0.25); border-top-color:var(--accent);
    animation:spin 0.7s linear infinite;
  }
  .cfg-vlist-add-row{ display:flex; gap:8px; margin-top:8px; }
  .cfg-vlist-add-input{
    flex:1; font-family:var(--font-body); font-size:12.5px; color:var(--text-hi);
    background:rgba(255,255,255,0.65); border:1px solid var(--line); border-radius:10px;
    padding:9px 12px; outline:none; transition:border-color 0.15s ease, background 0.15s ease;
    min-width:0;
  }
  .cfg-vlist-add-input:focus{ border-color:var(--accent); background:rgba(255,255,255,0.85); }
  .cfg-vlist-add-btn{
    font-family:var(--font-body); font-size:11.5px; font-weight:700; color:#fff; white-space:nowrap;
    background:var(--accent); border:none; border-radius:10px; padding:9px 16px; cursor:pointer;
    transition:transform 0.12s ease, box-shadow 0.12s ease;
  }
  .cfg-vlist-add-btn:hover{ transform:translateY(-1px); box-shadow:0 8px 16px -10px rgba(90,125,250,0.5); }

  /* ---- Contenu du popup de vérification (.cfg-vlist-modal, structure
     .cfg-jbm-* partagée — cf. bloc "MODALE JSON BUILDER" plus bas pour
     overlay/head/foot/boutons) : état "vérification en cours", puis résultat
     (avatar + pseudo réel + followers + statut live) ou message d'erreur. ---- */
  .cfg-vlist-modal-checking{
    display:flex; flex-direction:column; align-items:center; gap:14px;
    padding:26px 10px 10px; text-align:center;
  }
  .cfg-vlist-modal-checking .cfg-vlist-chip-spinner{ width:30px; height:30px; border-width:3px; }
  .cfg-vlist-modal-checking p{ font-size:12.5px; color:var(--text-mute); margin:0; }
  .cfg-vlist-modal-result{ display:flex; align-items:flex-start; gap:14px; }
  .cfg-vlist-modal-avatar{ width:56px; height:56px; border-radius:50%; flex-shrink:0; background:rgba(120,130,150,0.2); }
  .cfg-vlist-modal-info{ display:flex; flex-direction:column; gap:5px; min-width:0; }
  .cfg-vlist-modal-name{ font-family:var(--font-display); font-weight:800; font-size:16px; color:var(--text-hi); }
  .cfg-vlist-modal-sub{ font-size:12px; color:var(--text-mute); }
  .cfg-vlist-modal-live{ font-size:12px; font-weight:700; border-radius:8px; padding:5px 10px; display:inline-block; margin-top:2px; }
  .cfg-vlist-modal-live.is-live{ color:#dc2626; background:rgba(239,68,68,0.10); }
  .cfg-vlist-modal-live.is-offline{ color:var(--text-mute); background:var(--glass); }

  /* ---- Choix parmi plusieurs chaînes (phase 'multiple', cf. script.js
     #vlistRenderModalBody) : plusieurs chaînes YouTube peuvent partager un
     même pseudo tapé sans '@' — l'utilisateur choisit la bonne dans une
     liste plutôt que d'en voir une ajoutée à sa place sans l'avoir vue. ---- */
  .cfg-vlist-modal-multi-hint{ font-size:12.5px; color:var(--text-mute); margin:0 0 12px; }
  .cfg-vlist-modal-candidates{ display:flex; flex-direction:column; gap:6px; max-height:280px; overflow-y:auto; }
  .cfg-vlist-modal-candidate{
    display:flex; align-items:center; gap:12px; width:100%; text-align:left;
    padding:8px 10px; border-radius:10px; border:1px solid rgba(120,130,150,0.18);
    background:rgba(255,255,255,0.02); cursor:pointer; font:inherit; color:var(--text-hi);
    transition:border-color 0.12s ease, background 0.12s ease;
  }
  .cfg-vlist-modal-candidate:hover{ border-color:rgba(90,125,250,0.5); background:rgba(90,125,250,0.08); }
  .cfg-vlist-modal-candidate-avatar{ width:36px; height:36px; border-radius:50%; flex-shrink:0; background:rgba(120,130,150,0.2); }
  .cfg-vlist-modal-candidate-name{ font-size:13.5px; font-weight:700; }

  /* ---- Champ 'bgcard' (image de fond arrivée/départ + aperçu recadrable) ----
     Deux champs 'bgcard' consécutifs (arrivée/départ) sont regroupés côte à
     côte par renderSectionedFields#flushDepGroup dans un wrapper
     .module-config-bgcard-row → grille 2 colonnes ici. Chaque champ garde sa
     propre carte .module-config-bgcard (label + aperçu + contrôles), donc le
     style individuel marche aussi bien seul (1 colonne) qu'en paire. */
  .module-config-bgcard-row{
    display:grid; grid-template-columns:1fr 1fr; gap:16px; align-items:start;
  }
  @media (max-width:640px){
    .module-config-bgcard-row{ grid-template-columns:1fr; }
  }

  /* ---- Sections en colonnes (f.column/f.columnTitle) ----
     Ex: onglet "Pièces & XP" du module économie, section "Gains" — gains en
     pièces à gauche, gains en XP à droite (cf. renderSectionedFields#hasColumns,
     script.js). Une colonne = .module-config-column, avec un petit titre
     optionnel (f.columnTitle, posé sur un seul champ par colonne) puis ses
     champs empilés normalement (dependsOn/bgcard fonctionnent pareil à
     l'intérieur, via renderFieldRun). Même repli 1 colonne sur mobile que
     .module-config-bgcard-row ci-dessus. */
  .module-config-columns-row{
    display:grid; grid-template-columns:1fr 1fr; gap:20px; align-items:start;
  }
  @media (max-width:640px){
    .module-config-columns-row{ grid-template-columns:1fr; gap:14px; }
  }
  .module-config-column{
    display:flex; flex-direction:column; gap:10px;
    padding:12px; border-radius:12px; background:var(--glass-soft, rgba(255,255,255,0.03));
    border:1px solid var(--border-soft, rgba(255,255,255,0.06));
  }
  .module-config-column-title{
    font-size:11.5px; font-weight:700; color:var(--text-hi); letter-spacing:0.01em;
    padding-bottom:2px; margin-bottom:2px; border-bottom:1px solid var(--border-soft, rgba(255,255,255,0.08));
  }
  /* ---- Onglet coupé en 2 (f.side) ----
     Ex: onglet "Pièces & XP" du module économie — TOUT l'onglet séparé en
     un bloc pièces à gauche et un bloc XP à droite (cf.
     renderFieldsWithOptionalSideSplit, script.js), chaque bloc gardant ses
     propres cartes .module-config-section-block empilées normalement (pas
     de fond/carte supplémentaire ici, contrairement à .module-config-column
     ci-dessus — les sections à l'intérieur ont déjà leur propre carte).
     Même repli 1 colonne sur mobile que les autres grilles à 2 côtés. */
  .module-config-side-split{
    display:grid; grid-template-columns:1fr 1fr; gap:20px; align-items:start;
  }
  @media (max-width:640px){
    .module-config-side-split{ grid-template-columns:1fr; gap:14px; }
  }
  .module-config-side-col{ display:flex; flex-direction:column; gap:14px; min-width:0; }
  .module-config-side-title{
    font-size:13px; font-weight:700; color:var(--text-hi); letter-spacing:0.01em;
    padding-bottom:6px; margin-bottom:2px; border-bottom:1px solid var(--border-soft, rgba(255,255,255,0.08));
  }
  .module-config-bgcard{ display:flex; flex-direction:column; gap:8px; }
  .module-config-bgcard label{ font-size:11.5px; font-weight:600; color:var(--text-hi); }

  /* Carte d'aperçu : même ratio que la bannière générée côté bot (≈2.6:1).
     Fond dégradé par défaut (is-empty) tant qu'aucune image n'est choisie,
     sinon l'image de fond réelle (posée en inline style par script.js). */
  .cfg-bgcard-preview{
    position:relative; width:100%; aspect-ratio:2.6/1; border-radius:14px;
    overflow:hidden; background-color:#1a1b26; background-size:cover; background-position:50% 50%;
    background-repeat:no-repeat;
    border:1.5px solid var(--glass-border); cursor:grab; user-select:none; touch-action:none;
    box-shadow:0 2px 10px -4px rgba(20,25,45,0.35);
  }
  .module-config-bgcard.is-empty .cfg-bgcard-preview{
    background-image:linear-gradient(135deg, #2b3350, #1a1b26) !important; cursor:default;
  }
  .cfg-bgcard-preview.is-dragging{ cursor:grabbing; }

  /* Voile dégradé bas (lisibilité) — reproduit approximativement le rendu
     réel généré par le bot (_generateCanvas), juste pour donner une idée. */
  .cfg-bgcard-tint{
    position:absolute; inset:0;
    background:linear-gradient(180deg, rgba(10,12,22,0) 35%, rgba(10,12,22,0.72) 100%);
    pointer-events:none;
  }
  .module-config-bgcard.is-empty .cfg-bgcard-tint{ display:none; }

  /* Avatar placeholder (rond) — positionné à gauche pour la carte d'arrivée,
     à droite pour celle de départ (f.avatarSide, cf. renderFieldInner). */
  .cfg-bgcard-avatar{
    position:absolute; bottom:10px; width:15%; aspect-ratio:1/1; border-radius:50%;
    background:rgba(255,255,255,0.16); border:2px solid rgba(255,255,255,0.55);
    pointer-events:none;
  }
  .cfg-bgcard-avatar--left{ left:10px; }
  .cfg-bgcard-avatar--right{ right:10px; }
  .module-config-bgcard.is-empty .cfg-bgcard-avatar{ display:none; }

  /* Logo N&R (petit badge coin supérieur) */
  .cfg-bgcard-logo{
    position:absolute; top:8px; right:10px; width:22px; height:22px; border-radius:6px;
    background:rgba(255,255,255,0.14); border:1px solid rgba(255,255,255,0.35);
    pointer-events:none;
  }
  .module-config-bgcard.is-empty .cfg-bgcard-logo{ display:none; }

  .cfg-bgcard-empty-txt{
    position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
    font-size:10.5px; color:var(--text-mute); text-align:center; padding:0 12px; pointer-events:none;
  }
  .module-config-bgcard:not(.is-empty) .cfg-bgcard-empty-txt{ display:none; }

  /* Indice de recadrage — visible seulement au survol, pour ne pas polluer
     l'aperçu en permanence. */
  .cfg-bgcard-hint{
    position:absolute; top:8px; left:10px; font-size:9.5px; font-weight:600; color:#fff;
    background:rgba(10,12,22,0.55); border-radius:6px; padding:3px 7px; opacity:0;
    transition:opacity 0.15s ease; pointer-events:none;
  }
  .module-config-bgcard:not(.is-empty) .cfg-bgcard-preview:hover .cfg-bgcard-hint{ opacity:1; }

  /* Flèches de recadrage (up/down/left/right) — petit pavé directionnel en
     bas à droite, jamais visible sans image (rien à recadrer). */
  .cfg-bgcard-nudges{
    position:absolute; bottom:8px; right:8px; z-index:2;
    display:grid; grid-template-columns:repeat(3, 22px); grid-template-rows:repeat(2, 22px);
    gap:2px; opacity:0; transition:opacity 0.15s ease;
  }
  .module-config-bgcard:not(.is-empty) .cfg-bgcard-preview:hover .cfg-bgcard-nudges,
  .module-config-bgcard:not(.is-empty) .cfg-bgcard-nudges:focus-within{ opacity:1; }
  .cfg-bgcard-nudge{
    display:flex; align-items:center; justify-content:center;
    font-size:10px; line-height:1; color:#fff; background:rgba(10,12,22,0.55);
    border:1px solid rgba(255,255,255,0.25); border-radius:5px; cursor:pointer;
    transition:background 0.12s ease;
  }
  .cfg-bgcard-nudge:hover{ background:rgba(90,125,250,0.75); }
  .cfg-bgcard-nudge--up{ grid-column:2; grid-row:1; }
  .cfg-bgcard-nudge--left{ grid-column:1; grid-row:2; }
  .cfg-bgcard-nudge--right{ grid-column:3; grid-row:2; }
  .cfg-bgcard-nudge--down{ grid-column:2; grid-row:2; }

  .cfg-bgcard-center-btn{
    font-family:var(--font-body); font-size:11px; font-weight:600; color:var(--text-mute);
    background:transparent; border:none; cursor:pointer; padding:0; text-decoration:underline;
  }
  .cfg-bgcard-center-btn:hover{ color:var(--text-hi); }
  .module-config-bgcard.is-empty .cfg-image-controls .cfg-bgcard-center-btn{ display:none; }

  /* ---- Champ 'role'/'channel' (select peuplé dynamiquement) : le petit
     temps de chargement réseau (fetchGuildRoles/fetchGuildChannels, cf.
     bindPickerFields) reste discret plutôt que de laisser le select figé
     sans indication, entre le rendu initial et l'arrivée des vraies options. */
  select.cfg-input.cfg-picker-select.is-loading{ opacity:0.6; cursor:wait; }

  /* ---- Champ 'user' (recherche live par pseudo, cf. bindUserFields) : la
     valeur réelle (l'ID Discord) vit dans un <input type="hidden"> — seul le
     champ de recherche visible (.cfg-user-search) est stylé ici, avec le
     même look que .cfg-input pour rester cohérent avec le reste du panneau. */
  .cfg-user-picker{ position:relative; }
  .cfg-user-search{
    font-family:var(--font-body); font-size:12.5px; color:var(--text-hi);
    background:rgba(255,255,255,0.65); border:1px solid var(--line); border-radius:10px;
    padding:9px 12px; outline:none; transition:border-color 0.15s ease, background 0.15s ease;
    width:100%; box-sizing:border-box;
  }
  .cfg-user-search:focus{ border-color:var(--accent); background:rgba(255,255,255,0.85); }
  .cfg-user-suggestions{
    position:absolute; left:0; right:0; top:calc(100% + 4px); z-index:20;
    max-height:220px; overflow-y:auto;
    background:var(--panel, #fff); border:1px solid var(--glass-border, var(--line)); border-radius:10px;
    box-shadow:0 12px 24px -12px rgba(30,40,70,0.30);
    display:flex; flex-direction:column; padding:4px;
  }
  .cfg-user-suggestions[hidden]{ display:none; }
  .cfg-user-suggestion{
    display:flex; align-items:center; gap:8px; width:100%;
    font-family:var(--font-body); font-size:12px; color:var(--text-hi); text-align:left;
    background:transparent; border:none; border-radius:8px; padding:6px 8px; cursor:pointer;
  }
  .cfg-user-suggestion:hover{ background:var(--accent-soft); }
  .cfg-user-avatar{ width:22px; height:22px; border-radius:50%; flex-shrink:0; background:rgba(120,130,150,0.2); }

  /* ---- Champ 'color' (palette prédéfinie + sélecteur personnalisé) ---- */
  .cfg-color-row{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
  .cfg-color-swatches{ display:flex; flex-wrap:wrap; gap:6px; }
  .cfg-color-swatch{
    width:22px; height:22px; flex-shrink:0; border-radius:7px; padding:0;
    border:1.5px solid rgba(255,255,255,0.65); box-shadow:0 0 0 1px var(--glass-border);
    cursor:pointer; position:relative; transition:transform 0.12s ease, box-shadow 0.12s ease;
  }
  .cfg-color-swatch:hover{ transform:scale(1.12); }
  .cfg-color-swatch.is-active{ box-shadow:0 0 0 2px var(--accent); transform:scale(1.08); }
  .cfg-color-swatch.is-active::after{
    content:'✓'; position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
    font-size:11px; color:#fff; text-shadow:0 1px 2px rgba(0,0,0,0.55);
  }
  /* Puce "personnalisée" : dégradé arc-en-ciel comme indice visuel, avec un
     vrai <input type="color"> natif superposé (opacity:0) — cliquer n'importe
     où sur la puce ouvre le sélecteur système, sans JS custom pour ça. */
  .cfg-color-custom-trigger{ background:conic-gradient(from 180deg, #ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000); overflow:hidden; }
  .cfg-color-native{ position:absolute; inset:0; width:100%; height:100%; border:none; padding:0; cursor:pointer; opacity:0; }
  .cfg-color-hex{ width:110px; flex:0 0 auto; font-family:var(--font-mono, ui-monospace, monospace); text-transform:uppercase; }

  /* ---- Panneau : une ligne par groupe (champs + son propre aperçu Discord) ----
     Volontairement PAS une colonne "tous les champs" + une colonne "tous les
     aperçus" empilés séparément : dans un onglet à 2 groupes (ex: "Extras"
     avec arrivée ET départ, ou "Arrivée & Départ" avec join ET leave), chaque
     aperçu doit rester sur la même ligne (ou dans la même carte, cf.
     .has-paired-groups ci-dessous) que SES champs, jamais désaligné du
     groupe qu'il représente. */
  .module-config-body.has-preview{ display:flex; flex-direction:column; gap:22px; }
  .module-config-fields-col{ display:flex; flex-direction:column; gap:14px; min-width:0; }
  .module-config-ungrouped{ padding-bottom:4px; border-bottom:1px solid var(--line); }

  /* Chaque groupe (champs + aperçu) devient lui aussi une carte "3D",
     cohérente avec .module-config-section-block ci-dessus — même dégradé,
     même double ombre, même léger décollement au survol — pour que
     "Arrivée" et "Départ" (ou les 2 blocs Extras) se lisent clairement comme
     2 blocs distincts plutôt qu'une simple liste de champs qui s'enchaîne. */
  .module-config-group-row{
    display:grid; grid-template-columns:minmax(0,1fr) 300px; gap:22px; align-items:start;
    position:relative;
    background:linear-gradient(180deg, rgba(255,255,255,0.06), rgba(255,255,255,0.015));
    border:1px solid var(--glass-border, var(--line));
    border-radius:16px;
    padding:18px 18px 16px;
    box-shadow:
      0 1px 0 rgba(255,255,255,0.55) inset,
      0 2px 6px -3px rgba(30,40,70,0.14),
      0 12px 24px -18px rgba(30,40,70,0.30);
    transition:transform 0.18s ease, box-shadow 0.18s ease;
  }
  .module-config-group-row:hover{
    transform:translateY(-2px);
    box-shadow:
      0 1px 0 rgba(255,255,255,0.55) inset,
      0 4px 10px -3px rgba(30,40,70,0.18),
      0 18px 30px -18px rgba(30,40,70,0.36);
  }
  .module-config-group-fields{ display:flex; flex-direction:column; gap:14px; min-width:0; }
  .module-config-group-title{
    font-family:var(--font-display); font-weight:800; font-size:12.5px; color:var(--accent-deep);
    display:flex; align-items:center; gap:7px;
  }
  /* Petit repère visuel (pastille) devant "Arrivée"/"Départ" — vert pour
     l'un, rouge pour l'autre (mêmes teintes que les couleurs d'embed par
     défaut, cf. PREVIEW_DEFAULT_COLOR côté script.js) : quand les 2 cartes
     sont côte à côte, ça aide à repérer laquelle est laquelle d'un coup
     d'œil, sans avoir à lire le titre. */
  .module-config-group-title::before{
    content:''; width:7px; height:7px; border-radius:50%; flex-shrink:0;
    background:var(--accent);
  }
  .module-config-group-row[data-group-prefix^="leave"] .module-config-group-title::before,
  .module-config-group-row[data-group-prefix="extra_leave"] .module-config-group-title::before{
    background:#f87171;
  }
  .module-config-group-row[data-group-prefix="join"] .module-config-group-title::before,
  .module-config-group-row[data-group-prefix="extra_join"] .module-config-group-title::before{
    background:#57F287;
  }

  /* ---- Sélecteur "1 aperçu à la fois" (cf. tab.groupsAsSelector, onglet
     Avertissements du module Sécurité avancée) : le layout par défaut
     (.module-config-body.has-preview en colonne) suffit déjà, seul ce menu
     déroulant a besoin d'un style dédié, posé juste au-dessus de l'unique
     .module-config-group-row rendue. */
  .module-config-group-selector{ max-width:420px; }
  .module-config-group-selector label{
    display:block; font-family:var(--font-display); font-weight:800; font-size:12.5px;
    color:var(--accent-deep); margin-bottom:6px;
  }
  .module-config-group-selector-select{ font-weight:600; }

  /* ---- Groupes CÔTE À CÔTE (Arrivée & Départ, Extras) ----
     Posée par script.js#renderTab quand l'onglet détecte EXACTEMENT 2
     groupes aperçu (au-delà, cf. .has-many-groups plus bas, mise en page
     dédiée — les deux sont mutuellement exclusives, d'où le
     ":not(.has-many-groups)" en garde-fou). `auto-fit`/`minmax` place 2
     cartes par ligne sur un écran assez large et repasse automatiquement à
     1 carte par ligne sur un écran étroit, sans media query dédiée. Les
     champs "sans groupe" éventuels (ex: rien aujourd'hui pour ces onglets,
     mais générique) s'étendent sur toute la largeur (grid-column:1/-1) pour
     rester au-dessus des 2 cartes, jamais coincés dans l'une des colonnes.
     À l'intérieur de chaque carte appairée, les champs restent au-dessus de
     l'aperçu (empilé, 1 colonne) plutôt que côte à côte comme en
     plein-largeur — sinon, une fois la carte réduite à ~340-450px, le bloc
     "champs | aperçu 300px fixe" d'origine serait bien trop à l'étroit. */
  .module-config-body.has-preview.has-paired-groups:not(.has-many-groups){
    display:grid;
    grid-template-columns:repeat(auto-fit, minmax(340px, 1fr));
    gap:22px;
    align-items:start;
  }
  .module-config-body.has-preview.has-paired-groups:not(.has-many-groups) .module-config-ungrouped{
    grid-column:1 / -1;
  }
  .module-config-body.has-preview.has-paired-groups:not(.has-many-groups) .module-config-group-row{
    grid-template-columns:1fr;
  }
  .module-config-body.has-preview.has-paired-groups:not(.has-many-groups) .discord-preview{
    max-width:480px;
  }

  /* ---- 3 groupes ou plus (ex: onglet "Arrivée" : join + dm + extra_join) ----
     auto-fit seul donnait 3 cartes de largeur égale alors que "join"
     concentre bien plus de champs que "dm"/"extra_join" réunis : une
     colonne surchargée à côté de deux colonnes quasi vides, illisible.
     À partir de 3 groupes, on repasse sur une grille fixe à 2 colonnes :
     le groupe le plus fourni (posé --primary côté JS, cf. renderTab)
     occupe la colonne large sur toute la hauteur, les autres s'empilent
     dans la colonne étroite — même esprit "carte par bloc" que Départ,
     mais qui reste lisible quand les blocs n'ont pas la même taille. */
  .module-config-body.has-preview.has-many-groups .module-config-ungrouped{
    margin-bottom:22px;
  }
  /* .module-config-many-groups-body : conteneur FLEX (pas grid) dédié au cas
     3 groupes ou plus — cf. script.js#renderTab. Flexbox garantit que l'ordre
     visuel suit TOUJOURS l'ordre du DOM (donc l'ordre des champs *_message du
     configSchema) : contrairement à une grille CSS en "grid-auto-flow: row
     dense" combinée à un item "grid-row: 1 / -1", où le placement automatique
     peut faire dériver l'ordre affiché de l'ordre déclaré (ex: un bloc de
     configuration qui remonte au-dessus d'un autre alors qu'il est placé
     après lui dans le schéma) — bug corrigé ici. */
  .module-config-many-groups-body{
    display:flex;
    align-items:flex-start;
    gap:22px;
  }
  .module-config-many-groups-body > .module-config-group-row--primary{
    flex:1.7 1 0%;
    min-width:0;
    grid-template-columns:1fr;
  }
  /* Sidebar : les groupes secondaires empilés dans l'ordre du DOM, sans
     mécanisme de placement automatique qui pourrait les réordonner. */
  .module-config-group-sidebar{
    flex:1 1 0%;
    min-width:280px;
    display:flex;
    flex-direction:column;
    gap:22px;
  }
  .module-config-group-sidebar .module-config-group-row{
    grid-template-columns:1fr;
  }
  .module-config-many-groups-body .discord-preview{
    max-width:none;
  }
  @media (max-width:900px){
    .module-config-many-groups-body{ flex-direction:column; }
    .module-config-group-sidebar{ min-width:0; width:100%; }
  }

  .cfg-chip-row{ display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin-top:-4px; }
  .cfg-chip-row-label{ font-size:10px; font-weight:600; color:var(--text-mute); margin-right:2px; }
  .cfg-chip{
    font-family:var(--font-mono); font-size:10.5px; font-weight:600; color:var(--accent-deep);
    background:var(--accent-soft); border:1px solid transparent; border-radius:7px;
    padding:4px 9px; cursor:pointer; transition:background 0.15s ease, border-color 0.15s ease;
  }
  .cfg-chip:hover{ background:color-mix(in srgb, var(--accent-soft) 65%, var(--accent) 22%); }
  .cfg-chip:disabled{ opacity:0.4; cursor:not-allowed; }
  .cfg-template-row .cfg-chip{ font-family:var(--font-body); }

  /* Rappel markdown : mêmes puces visuellement, mais purement informatives
     (pas de clic) — fond neutre au lieu de la couleur accent des puces
     interactives (variables/modèles), pour que l'œil comprenne tout de
     suite qu'elles ne font rien au clic. */
  .cfg-markdown-row{ margin-top:2px; }
  .cfg-markdown-chip{
    font-family:var(--font-mono); font-size:10.5px; font-weight:600; color:var(--text-mute);
    background:var(--panel-2, rgba(255,255,255,0.06)); border:1px solid transparent; border-radius:7px;
    padding:4px 9px; cursor:default;
  }
  .cfg-markdown-hint{ font-size:10px; color:var(--text-mute); font-style:italic; }

  @media (max-width:980px){
    .module-config-group-row{ grid-template-columns:1fr; }
  }


  .discord-preview{ display:flex; flex-direction:column; gap:8px; }
  .discord-preview-label{
    font-size:10px; font-weight:700; letter-spacing:0.08em; text-transform:uppercase; color:var(--text-mute);
    display:flex; align-items:center; gap:8px; flex-wrap:wrap;
  }
  .discord-msg{
    display:flex; gap:11px; padding:14px; border-radius:14px;
    background:#313338; border:1px solid rgba(0,0,0,0.2);
  }
  .discord-avatar{ width:36px; height:36px; border-radius:50%; overflow:hidden; flex-shrink:0; background:var(--accent); }
  .discord-avatar img{ width:100%; height:100%; object-fit:cover; display:block; }
  .discord-msg-body{ min-width:0; flex:1 1 auto; }
  .discord-msg-head{ display:flex; align-items:baseline; gap:7px; margin-bottom:3px; flex-wrap:wrap; }
  .discord-bot-name{ font-family:var(--font-display); font-weight:700; font-size:13px; color:#f2f3f5; }
  .discord-bot-tag{
    font-size:9px; font-weight:700; color:#fff; background:var(--accent); border-radius:3px;
    padding:1px 4px; letter-spacing:0.02em; line-height:1.4;
  }
  .discord-msg-time{ font-size:10.5px; color:#949ba4; }
  .discord-msg-text, .discord-embed-desc{ font-size:12.5px; line-height:1.5; color:#dbdee1; word-break:break-word; }
  .discord-msg-text b, .discord-embed-desc b{ color:#fff; font-weight:700; }
  .discord-msg-text i, .discord-embed-desc i{ font-style:italic; }
  .discord-msg-text u, .discord-embed-desc u{ text-decoration:underline; }
  .discord-msg-text s, .discord-embed-desc s{ text-decoration:line-through; color:#949ba4; }
  .discord-msg-text code, .discord-embed-desc code{
    font-family:var(--font-mono, monospace); font-size:11.5px; background:#1e1f22;
    border-radius:4px; padding:1px 4px;
  }
  .discord-embed{
    margin-top:6px; padding:10px 12px; border-radius:6px;
    background:#2b2d31; border-left:4px solid var(--accent); max-width:100%;
  }
  /* Corps de l'embed (titre + description) à gauche, vignette du bot à
     droite — reflète setThumbnail() côté backend (cf.
     src/utils/embeds.js#baseEmbed : "obligatoire sur tout embed du bot"),
     posée automatiquement sur CHAQUE embed envoyé, donc affichée ici sur
     CHAQUE embed de l'aperçu, sans dépendre d'un réglage du modèle. */
  .discord-embed-row{ display:flex; align-items:flex-start; justify-content:space-between; gap:10px; }
  .discord-embed-body{ min-width:0; flex:1 1 auto; }
  .discord-embed-thumb{ flex:0 0 auto; width:56px; height:56px; border-radius:6px; overflow:hidden; }
  .discord-embed-thumb img{ display:block; width:100%; height:100%; object-fit:cover; }
  .discord-embed-title{ font-family:var(--font-display); font-weight:700; font-size:13px; color:#f2f3f5; margin-bottom:4px; }
  .discord-embed-img{ margin-top:10px; border-radius:5px; overflow:hidden; max-width:100%; }
  .discord-embed-img img{ display:block; width:100%; max-height:180px; object-fit:cover; }

  /* Champs name/value d'un embed (ex: aperçu par catégorie de
     administrations/systeme-logs, cf. script.js#renderCategoryPreviewBody)
     — grille qui replie les champs `inline` par 2, comme le fait réellement
     Discord, tandis qu'un champ non-inline occupe toute la largeur. */
  .discord-embed-fields{
    display:grid; grid-template-columns:repeat(2, minmax(0, 1fr));
    gap:8px 12px; margin-top:8px;
  }
  .discord-embed-field{ min-width:0; }
  .discord-embed-field--block{ grid-column:1 / -1; }
  .discord-embed-field-name{ font-family:var(--font-display); font-weight:700; font-size:11.5px; color:#f2f3f5; margin-bottom:2px; }
  .discord-embed-field-value{ font-size:12px; line-height:1.45; color:#dbdee1; word-break:break-word; }

  /* Vignette "avatar de l'utilisateur concerné" (cfg.log_show_avatar) —
     remplace la vignette par défaut du bot (.discord-embed-thumb img) dans
     l'aperçu quand ce réglage est actif, cf. administrations/systeme-logs
     (embed.setThumbnail(avatarURL) plutôt que le thumbnail du bot posé par
     baseEmbed). Pas de vrai avatar disponible dans un aperçu fictif —
     placeholder générique plutôt qu'une fausse photo. */
  .discord-embed-thumb--user{
    display:flex; align-items:center; justify-content:center;
    background:linear-gradient(160deg, var(--accent), color-mix(in srgb, var(--accent) 60%, #1e1f22 40%));
    font-size:20px;
  }

  /* Ligne compacte (log_detailed_<categorie> désactivé) — même bulle
     .discord-msg que le mode détaillé, mais sans embed : juste une ligne de
     texte, cf. buildCategoryPreview#mode:'compact' côté module. */
  .discord-log-compact-line{ font-size:12.5px; line-height:1.5; color:#dbdee1; word-break:break-word; }
  .discord-log-compact-line b{ color:#fff; font-weight:700; }

  /* Salon effectif visé par CETTE catégorie (salon dédié si renseigné,
     sinon repli sur le salon général de logs) — au-dessus de la bulle
     Discord simulée, même esprit que .discord-preview-label mais avec sa
     propre ligne pour ne jamais se confondre avec le libellé "Aperçu". */
  .module-config-category-preview-channel{
    font-size:11px; color:var(--text-mute);
  }
  .module-config-category-preview-channel b{ color:var(--text-hi); font-weight:600; }

  /* État "en chargement" / "erreur" du contenu de l'aperçu (le temps de la
     réponse de POST .../modules/:moduleId/preview, cf. script.js#
     refreshCategoryPreviews) — squelette discret plutôt qu'un embed vide
     qui donnerait l'impression d'un bug. */
  .module-config-category-preview[data-preview-state="loading"] .discord-msg-content{ opacity:0.55; }
  .module-config-category-preview-error{
    font-size:11.5px; color:#e05252; line-height:1.4;
  }

  /* Bloc de section (cf. script.js#renderSectionedFields) qui porte un
     champ `preview: true` (ex: le toggle d'activation d'une catégorie de
     logs) : passe en 2 colonnes — réglages à gauche, faux embed Discord
     représentatif à droite — plutôt que la simple pile verticale par
     défaut de .module-config-section-block, pour que la personne qui
     configure voie IMMÉDIATEMENT le rendu de ce qu'elle règle, sans avoir
     à activer la catégorie pour de vrai et attendre un événement réel. */
  .module-config-section-block--with-preview{
    display:flex; flex-direction:row; flex-wrap:wrap; align-items:flex-start; gap:16px;
  }
  .module-config-section-block--with-preview .module-config-section-fields{
    flex:1 1 260px; min-width:0;
    display:flex; flex-direction:column; gap:10px;
  }
  .module-config-category-preview{
    flex:1 1 260px; min-width:240px; max-width:340px;
    display:flex; flex-direction:column; gap:6px;
  }
  @media (max-width:700px){
    .module-config-section-block--with-preview{ flex-direction:column; }
    .module-config-category-preview{ max-width:none; }
  }

  /* Aperçu de LISTE (cf. script.js#renderListPreviewShell, f.listPreview) —
     variante de .module-config-category-preview pour un catalogue qui n'est
     PAS un message Discord (bourse, immobilier, métiers...) : même gabarit
     2 colonnes, mais un simple récapitulatif icône/titre/sous-titre plutôt
     qu'une bulle Discord simulée, recalculé localement à chaque frappe. */
  .module-config-list-preview{
    flex:1 1 260px; min-width:240px; max-width:340px;
    display:flex; flex-direction:column; gap:6px;
  }
  .module-config-list-preview-body{
    display:flex; flex-direction:column; gap:4px;
    max-height:340px; overflow-y:auto;
    background:rgba(0,0,0,0.16);
    border:1px solid var(--glass-border, var(--line));
    border-radius:10px;
    padding:6px;
  }
  .module-config-list-preview-row{
    display:flex; align-items:flex-start; gap:8px;
    padding:6px 7px; border-radius:7px;
    background:rgba(255,255,255,0.03);
  }
  .module-config-list-preview-icon{ font-size:14px; line-height:1.3; flex:0 0 auto; }
  .module-config-list-preview-text{ display:flex; flex-direction:column; gap:1px; min-width:0; }
  .module-config-list-preview-title{ font-size:12px; font-weight:600; color:var(--text-hi); word-break:break-word; }
  .module-config-list-preview-sub{ font-size:11px; color:var(--text-mute); word-break:break-word; }
  .module-config-list-preview-more{ font-size:11px; color:var(--text-mute); text-align:center; padding:4px 0 2px; }
  .module-config-list-preview-empty{ font-size:11.5px; color:var(--text-mute); padding:8px 4px; }
  @media (max-width:700px){
    .module-config-list-preview{ max-width:none; }
  }

  /* Avertissement "Message aléatoire (PRO)" (cf. renderRandomNotice dans
     script.js) — au-dessus de la bulle Discord simulée, dans le même bloc
     .discord-preview : prévient que le message réglé à gauche est ignoré en
     prod et liste ce qui sera réellement tiré au hasard. Vide (display:none
     via :empty) tant que le toggle correspondant n'est pas actif. */
  .discord-preview-random-slot:empty{ display:none; }
  .discord-preview-notice--random{
    padding:10px 12px; border-radius:10px; font-size:11.5px; line-height:1.5;
    background:rgba(249,115,22,0.10); border:1px solid rgba(249,115,22,0.28);
  }
  .discord-preview-notice-head{ font-weight:700; color:#c2410c; margin-bottom:3px; }
  html.theme-dark .discord-preview-notice-head{ color:#fdba74; }
  .discord-preview-notice-body{ color:var(--text-mute); }
  .discord-preview-notice-list{ margin:6px 0 0; padding-left:16px; color:var(--text); }
  .discord-preview-notice-list li{ margin-top:3px; }
  .discord-preview-notice-list b{ color:var(--text-hi); }

  /* Boutons sous le message d'arrivée public (join_buttons_enabled, PRO) —
     miroir visuel des ActionRow réellement envoyées (cf. _buildJoinButtons
     côté backend et renderButtonsPreview côté script.js), affichés SOUS le
     texte/embed dans la même bulle de message. `disabled` volontaire : c'est
     un aperçu, pas de vraie interaction possible ici. */
  .discord-preview-buttons-row{ display:flex; flex-wrap:wrap; gap:7px; margin-top:9px; }
  .discord-preview-btn{
    font-family:var(--font-body); font-size:11.5px; font-weight:600; color:#f2f3f5;
    border-radius:5px; padding:6px 11px; border:1px solid rgba(0,0,0,0.25); cursor:default;
  }
  .discord-preview-btn--link{ background:#4e5058; }
  .discord-preview-btn--primary{ background:#5865f2; }
  /* Styles complémentaires (Secondary/Success/Danger) — réutilisés par
     l'aperçu de panneau du builder Rôles & Réactions (cf. .cfg-rr-* plus
     bas) en plus des 2 variantes ci-dessus (--link sert de Secondary,
     couleurs alignées sur les vraies teintes de ButtonStyle Discord.js). */
  .discord-preview-btn--secondary{ background:#4e5058; }
  .discord-preview-btn--success{ background:#248046; }
  .discord-preview-btn--danger{ background:#da373c; }

  /* Remplace l'ancien couple Annuler/Sauvegarder : chaque frappe/toggle
     déclenche un enregistrement auto-debounced (cf. script.js#scheduleAutoSave),
     ce badge en tête de panneau reflète juste où en est CE cycle-là. */
  .module-config-autosave-status{
    font-family:var(--font-body); font-size:11.5px; font-weight:600;
    color:var(--text-mute); display:flex; align-items:center; gap:5px;
    transition:color 0.2s ease;
  }
  .module-config-autosave-status::before{
    content:''; width:6px; height:6px; border-radius:50%; background:currentColor; flex-shrink:0;
  }
  .module-config-autosave-status.is-pending{ color:var(--text-mute); }
  .module-config-autosave-status.is-saving{ color:var(--accent-deep); }
  .module-config-autosave-status.is-saving::before{ animation:cfgAutosavePulse 0.9s ease infinite; }
  .module-config-autosave-status.is-saved{ color:var(--mint); }
  .module-config-autosave-status.is-error{ color:#dc2626; }
  @keyframes cfgAutosavePulse{ 0%,100%{opacity:1;} 50%{opacity:0.25;} }

  /* Bandeau "Lecture seule" (rôle modérateur, cf. script.js#openModuleConfigPanel
     opts.readOnly) — en tête de panneau, avant le titre du module. */
  .module-config-readonly-banner{
    font-family:var(--font-body); font-size:12.5px; font-weight:600;
    color:#b45309; background:rgba(217,119,6,0.12); border:1px solid rgba(217,119,6,0.28);
    border-radius:9px; padding:8px 12px; margin:10px 0 0;
  }
  /* Tous les champs du panneau sont posés `disabled` en JS quand
     readOnly — ce voile visuel confirme l'état au coup d'œil sans avoir à
     lire chaque champ individuellement. */
  .module-config.is-readonly .module-config-body{ opacity:0.82; cursor:not-allowed; }
  .module-config.is-readonly input:disabled,
  .module-config.is-readonly select:disabled,
  .module-config.is-readonly textarea:disabled,
  .module-config.is-readonly button:disabled{ cursor:not-allowed; }

  /* Toggle module ON/OFF grisé pour un rôle sans droit d'écriture (cf.
     script.js#renderCategoryPage canWrite) — reste cliquable (affiche un
     toast explicatif) plutôt que réellement `disabled`, pour ne pas
     bloquer le focus clavier sur toute la carte. */
  .toggle.is-readonly{ opacity:0.45; cursor:not-allowed; }

  /* Bouton "Tester" d'un groupe aperçu (arrivée/départ/extras) — envoie un
     vrai message dans le salon configuré du module, via le bot, avec les
     valeurs LIVE du panneau (même non encore confirmées par l'auto-save).
     Posé dans l'en-tête de l'aperçu Discord, à côté du nom du groupe. */
  .module-config-group-test-btn{
    font-family:var(--font-body); font-size:11px; font-weight:700; color:var(--accent-deep);
    background:rgba(90,125,250,0.10); border:1px solid rgba(90,125,250,0.28); border-radius:10px;
    padding:5px 11px; cursor:pointer; transition:background 0.15s ease, transform 0.15s ease;
    display:inline-flex; align-items:center; gap:5px;
    text-transform:none; letter-spacing:normal;
  }
  .module-config-group-test-btn:hover{ background:rgba(90,125,250,0.18); transform:translateY(-1px); }
  .module-config-group-test-btn:active{ transform:translateY(0) scale(0.97); }
  .module-config-group-test-btn:disabled{ opacity:0.55; cursor:default; transform:none; }
  .module-config-group-test-status{
    font-size:10.5px; font-weight:600; color:var(--text-mute); margin-left:6px;
    text-transform:none; letter-spacing:normal;
  }
  .module-config-group-test-status.is-error{ color:#dc2626; }
  .module-config-group-test-status.is-ok{ color:var(--mint); }

  /* ================= PAGES (Vue d'ensemble / Analytiques / Commandes) ================= */
  .page-area{ flex:1 1 auto; min-height:0; overflow-y:auto; overflow-x:hidden; display:flex; flex-direction:column; }
  .page{ display:none; }
  .page.active{ display:flex; flex-direction:column; gap:16px; min-height:0; flex:1 1 auto; }
  #page-overview.active{ gap:10px; }

  .side-link.disabled{ opacity:0.45; cursor:not-allowed; }
  .side-link.disabled:hover{ background:transparent; color:inherit; }
  .badge-soon{ font-size:9px; font-weight:600; padding:1px 6px; border-radius:6px; background:rgba(135,144,168,0.18); color:var(--text-mute); margin-left:auto; }

  /* ---- Analytiques ---- */
  .an-grid{ display:grid; grid-template-columns:1.4fr 1fr; gap:16px; }
  .side-status-dot{ width:7px; height:7px; border-radius:50%; background:var(--mint); display:inline-block; margin-left:6px; box-shadow:0 0 0 3px rgba(34,184,146,0.18); }

  .status-gauge-track{ margin-top:2px; }
  .status-gauge-fill.status-gauge-ok{ background:linear-gradient(90deg, var(--mint), #57d3ac); }
  .status-gauge-fill.status-gauge-warn{ background:linear-gradient(90deg, #e0a520, #ffcf6b); }
  .status-gauge-fill.status-gauge-danger{ background:linear-gradient(90deg, #c9503f, var(--coral)); }
  .status-gauge-sub{ font-size:11px; color:var(--text-mute); margin-top:8px; }

  .incident-list{ display:flex; flex-direction:column; gap:4px; }
  .incident-row{
    display:flex; align-items:center; gap:12px; padding:11px 4px;
    border-bottom:1px solid var(--line);
  }
  .incident-row:last-child{ border-bottom:none; }
  .incident-dot{ width:8px; height:8px; border-radius:50%; background:var(--text-mute); flex-shrink:0; }
  .incident-row.incident-active .incident-dot{ background:var(--coral); box-shadow:0 0 0 3px rgba(239,125,107,0.18); }
  .incident-row.incident-resolved .incident-dot{ background:var(--mint); }
  .incident-body{ flex:1; min-width:0; }
  .incident-title{ font-size:13px; font-weight:600; color:var(--text-hi); }
  .incident-meta{ font-size:11px; color:var(--text-mute); margin-top:2px; }
  .incident-status-tag{
    font-size:10.5px; font-weight:700; padding:3px 9px; border-radius:7px; flex-shrink:0;
    background:rgba(135,144,168,0.16); color:var(--text-mute);
  }
  .incident-row.incident-active .incident-status-tag{ background:rgba(239,125,107,0.16); color:var(--coral); }
  .incident-row.incident-resolved .incident-status-tag{ background:rgba(34,184,146,0.14); color:var(--mint); }

  .incident-severity-group{ display:flex; gap:8px; margin-bottom:12px; }
  .incident-severity-chip{
    font-family:var(--font-body); font-size:12px; font-weight:600; color:var(--text-mute);
    padding:6px 14px; border-radius:20px; border:1px solid var(--line); background:transparent;
    cursor:pointer; transition:all 0.15s ease;
  }
  .incident-severity-chip:hover{ color:var(--text-hi); }
  .incident-severity-chip.active{ background:var(--accent-soft); border-color:transparent; color:var(--accent-deep); }
  .incident-severity-chip[data-severity="critique"].active{ background:rgba(239,125,107,0.16); color:var(--coral); }
  .incident-severity-chip[data-severity="majeur"].active{ background:rgba(255,207,107,0.2); color:#a8720a; }

  .status-textarea{
    width:100%; resize:vertical; min-height:76px;
    font-family:var(--font-body); font-size:13px; color:var(--text-hi);
    padding:11px 13px; border-radius:10px; border:1px solid var(--line);
    background:var(--glass); outline:none; transition:border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
  }
  .status-textarea:hover:not(:disabled){ border-color:rgba(148,163,184,0.5); }
  .status-textarea:focus{ border-color:var(--accent); background:var(--glass-strong); box-shadow:0 0 0 3px rgba(90,125,250,0.15); }
  .status-textarea::placeholder{ color:var(--text-mute); opacity:0.75; }

  .an-bar-list{ display:flex; flex-direction:column; gap:12px; }
  .an-bar-row{ display:flex; flex-direction:column; gap:5px; }
  .an-bar-top{ display:flex; align-items:center; justify-content:space-between; font-size:12px; color:var(--text); }
  .an-bar-top b{ color:var(--text-hi); font-family:var(--font-mono); font-weight:500; font-size:11.5px; }
  .an-bar-track{ height:7px; border-radius:6px; background:rgba(148,163,184,0.18); overflow:hidden; }
  .an-bar-fill{ height:100%; border-radius:6px; background:linear-gradient(90deg, var(--accent), #8fa5ff); }
  .an-role-list{ display:flex; flex-direction:column; }
  .an-role-row{ display:flex; align-items:center; justify-content:space-between; padding:9px 4px; border-bottom:1px solid var(--line); font-size:12.5px; }
  .an-role-row:last-child{ border-bottom:none; }
  .an-role-name{ display:flex; align-items:center; gap:9px; color:var(--text); }
  .an-role-dot{ width:8px; height:8px; border-radius:50%; flex-shrink:0; }
  .an-role-avatar{ width:20px; height:20px; border-radius:50%; object-fit:cover; flex-shrink:0; background:var(--line); }
  .an-role-avatar-fallback{ width:20px; height:20px; border-radius:50%; display:flex; align-items:center; justify-content:center; font-size:9.5px; font-weight:700; color:#fff; flex-shrink:0; }
  .an-role-count{ font-family:var(--font-mono); color:var(--text-hi); font-size:12px; }

  /* ---- Vue d'ensemble : carte "Top 5 XP" coupée en deux avec "Top 5 Coins" ---- */
  .card-split{ display:flex; gap:20px; }
  .card-split-col{ flex:1 1 0; min-width:0; }
  .card-split-col + .card-split-col{ border-left:1px solid var(--line); padding-left:20px; }
  @media (max-width:640px){
    .card-split{ flex-direction:column; gap:16px; }
    .card-split-col + .card-split-col{ border-left:none; padding-left:0; border-top:1px solid var(--line); padding-top:16px; }
  }

  /* ---- Pagination générique (5 entrées/page) des blocs de la page
     Analytiques : "Détail par salon", "Liste des membres", etc. ---- */
  .an-pagination{ display:flex; align-items:center; justify-content:center; gap:12px; padding-top:10px; margin-top:4px; }
  .an-pagination[hidden]{ display:none; }
  .an-pagination-btn{ display:inline-flex; align-items:center; justify-content:center; width:26px; height:26px; border-radius:7px; border:1px solid var(--line); background:var(--glass-strong); color:var(--text); cursor:pointer; font-size:13px; line-height:1; transition:background .15s ease, opacity .15s ease; }
  .an-pagination-btn:hover:not(:disabled){ background:rgba(148,163,184,0.16); }
  .an-pagination-btn:disabled{ opacity:.35; cursor:default; }
  .an-pagination-info{ font-size:11.5px; color:var(--text-mute); font-family:var(--font-mono); }

  /* ---- Vue d'ensemble : cartes "Annonces" / "Patchnotes" ---- */
  .board-list{ display:flex; flex-direction:column; max-height:340px; overflow-y:auto; }
  .board-row{ display:flex; align-items:flex-start; gap:12px; padding:11px 4px; border-bottom:1px solid var(--line); }
  .board-row:last-child{ border-bottom:none; }
  .board-row-tag{
    flex-shrink:0; margin-top:1px; font-size:10px; font-weight:700; text-transform:uppercase; letter-spacing:0.05em;
    padding:3px 8px; border-radius:7px; background:rgba(90,125,250,0.16); color:var(--accent-deep);
  }
  .board-row-tag.type-patch{ background:rgba(34,184,146,0.18); color:#0f7a5c; }
  .board-row-tag.type-maintenance{ background:rgba(245,166,35,0.2); color:#a5670f; }
  .board-row-tag.type-warning{ background:rgba(239,68,68,0.18); color:#b53434; }
  .board-row-body{ flex:1; min-width:0; }
  .board-row-title{ font-size:12.5px; font-weight:700; color:var(--text-hi); }
  .board-row-msg{ font-size:11.5px; color:var(--text-mute); margin-top:2px; line-height:1.45; }
  .board-row-meta{ font-size:10.5px; color:var(--text-mute); margin-top:4px; }
  .an-section-title{ font-family:var(--font-display); font-weight:700; font-size:13.5px; color:var(--text-hi); display:flex; align-items:center; gap:8px; margin-top:4px; }
  .an-section-title::after{ content:""; flex:1; height:1px; background:var(--line); }
  .an-emoji-list{ display:flex; flex-direction:column; }
  .an-emoji-row{ display:flex; align-items:center; gap:10px; padding:8px 4px; border-bottom:1px solid var(--line); }
  .an-emoji-row:last-child{ border-bottom:none; }
  .an-emoji-glyph{ font-size:18px; width:26px; text-align:center; flex-shrink:0; }
  .an-emoji-body{ flex:1; min-width:0; }
  .an-emoji-top{ display:flex; align-items:center; justify-content:space-between; font-size:12px; color:var(--text); margin-bottom:4px; }
  .an-emoji-top b{ color:var(--text-hi); font-family:var(--font-mono); font-weight:500; font-size:11.5px; }
  .mod-log-list{ display:flex; flex-direction:column; }
  .mod-log-row{ display:flex; align-items:center; gap:10px; padding:9px 4px; border-bottom:1px solid var(--line); font-size:12.5px; }
  .mod-log-row:last-child{ border-bottom:none; }
  .mod-log-tag{ font-size:10px; font-weight:700; padding:3px 8px; border-radius:7px; flex-shrink:0; text-transform:uppercase; letter-spacing:0.02em; }
  .mod-log-tag.kick{ background:rgba(239,125,107,0.14); color:var(--coral); }
  .mod-log-tag.timeout{ background:rgba(255,167,38,0.16); color:#b6690a; }
  .mod-log-tag.ban{ background:rgba(180,40,40,0.14); color:#a12f2f; }
  .mod-log-tag.warn{ background:rgba(90,125,250,0.12); color:var(--accent-deep); }
  .mod-log-tag.open{ background:rgba(34,184,146,0.14); color:var(--mint); }
  .mod-log-tag.claimed{ background:rgba(255,167,38,0.16); color:#b6690a; }
  .mod-log-tag.closed{ background:rgba(148,163,184,0.18); color:var(--text-mute); }

  /* ================= FACTURES (settings > Premium) ================= */
  .invoice-list{ display:flex; flex-direction:column; margin-top:6px; }
  .invoice-row{ display:flex; align-items:center; gap:12px; padding:11px 4px; border-bottom:1px solid var(--line); font-size:12.5px; }
  .invoice-row:last-child{ border-bottom:none; }
  .invoice-row .invoice-main{ flex:1; min-width:0; }
  .invoice-row .invoice-number{ font-family:var(--font-mono); font-weight:600; color:var(--text-hi); display:block; }
  .invoice-row .invoice-sub{ color:var(--text-mute); font-size:11.5px; }
  .invoice-row .invoice-amount{ font-weight:700; color:var(--text-hi); flex-shrink:0; }
  .invoice-tag{ font-size:10px; font-weight:700; padding:3px 8px; border-radius:7px; flex-shrink:0; text-transform:uppercase; letter-spacing:0.02em; }
  .invoice-tag.paid{ background:rgba(34,184,146,0.14); color:var(--mint); }
  .invoice-tag.refused, .invoice-tag.recurring_failed{ background:rgba(239,125,107,0.14); color:var(--coral); }
  .invoice-tag.cancelled{ background:rgba(148,163,184,0.18); color:var(--text-mute); }
  .invoice-dl{
    flex-shrink:0; display:inline-flex; align-items:center; justify-content:center;
    width:30px; height:30px; border-radius:9px; border:1px solid var(--line);
    color:var(--text); background:var(--glass); cursor:pointer; text-decoration:none;
  }
  .invoice-dl:hover{ background:var(--accent-soft); color:var(--accent-deep); border-color:var(--accent); }
  .mod-log-body{ flex:1; min-width:0; color:var(--text); }
  .mod-log-body b{ color:var(--text-hi); }
  .mod-log-time{ font-size:10.5px; color:var(--text-mute); flex-shrink:0; white-space:nowrap; }
  .an-full{ grid-column:1 / -1; }
  .member-list{ display:flex; flex-direction:column; max-height:320px; overflow-y:auto; }
  .member-row{ display:flex; align-items:center; gap:11px; padding:9px 4px; border-bottom:1px solid var(--line); font-size:12.5px; }
  .member-row:last-child{ border-bottom:none; }
  .member-avatar{ width:28px; height:28px; border-radius:50%; display:flex; align-items:center; justify-content:center; font-size:10px; font-weight:700; color:#fff; flex-shrink:0; }
  .member-avatar-img{ width:28px; height:28px; border-radius:50%; object-fit:cover; flex-shrink:0; background:var(--line); }
  .member-body{ flex:1; min-width:0; display:flex; flex-direction:column; }
  .member-name{ color:var(--text-hi); font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .member-sub{ font-size:10.5px; color:var(--text-mute); }
  .member-val{ font-family:var(--font-mono); color:var(--accent-deep); font-size:12px; font-weight:500; flex-shrink:0; text-align:right; }
  .chan-list{ display:flex; flex-direction:column; }
  .chan-row{ display:flex; align-items:center; gap:11px; padding:10px 4px; border-bottom:1px solid var(--line); font-size:12.5px; }
  .chan-row:last-child{ border-bottom:none; }
  .chan-icon{ width:26px; height:26px; border-radius:8px; background:var(--accent-soft); color:var(--accent-deep); display:flex; align-items:center; justify-content:center; font-size:12px; flex-shrink:0; }
  .chan-body{ flex:1; min-width:0; display:flex; flex-direction:column; }
  .chan-name{ color:var(--text-hi); font-weight:600; }
  .chan-sub{ font-size:10.5px; color:var(--text-mute); }
  .chan-val{ font-family:var(--font-mono); color:var(--text-hi); font-size:12px; text-align:right; flex-shrink:0; }

  /* ---- Toast de sauvegarde automatique ---- */
  .toast-container{
    position:fixed; bottom:22px; right:22px; z-index:9999;
    display:flex; flex-direction:column; align-items:flex-end; gap:10px;
    pointer-events:none;
  }
  .toast{
    display:flex; align-items:center; gap:10px;
    background:var(--glass-strong); border:1px solid var(--glass-border);
    backdrop-filter:blur(24px); -webkit-backdrop-filter:blur(24px);
    border-radius:14px; padding:12px 16px 12px 12px;
    box-shadow:0 16px 38px -14px rgba(30,41,59,0.35);
    font-size:12.5px; font-weight:600; color:var(--text-hi);
    max-width:320px; cursor:pointer; pointer-events:auto;
    transform:translateY(22px) scale(0.98); opacity:0;
    transition:transform 0.45s cubic-bezier(.2,.8,.2,1), opacity 0.4s ease;
  }
  .toast.show{ transform:translateY(0) scale(1); opacity:1; }
  .toast.hide{ transform:translateY(10px) scale(0.98); opacity:0; }
  .toast-icon{
    width:22px; height:22px; border-radius:50%; flex-shrink:0;
    background:rgba(34,184,146,0.16); color:var(--mint);
    display:flex; align-items:center; justify-content:center;
  }
  .toast-icon svg{ width:12px; height:12px; }
  .toast-text b{ color:var(--accent-deep); }

  /* ---- Bandeau d'avertissement avant déconnexion pour inactivité ---- */
  .idle-warning-banner{
    position:fixed; top:18px; left:50%; transform:translateX(-50%);
    z-index:10000;
    display:flex; align-items:center; gap:14px;
    background:var(--glass-strong); border:1px solid rgba(245,158,11,0.45);
    backdrop-filter:blur(24px); -webkit-backdrop-filter:blur(24px);
    border-radius:14px; padding:12px 14px 12px 16px;
    box-shadow:0 16px 38px -14px rgba(30,41,59,0.35);
    font-size:12.5px; font-weight:600; color:var(--text-hi);
    max-width:min(420px, calc(100vw - 28px));
    animation:idleWarningIn 0.35s cubic-bezier(.2,.8,.2,1);
  }
  @keyframes idleWarningIn{
    from{ transform:translateX(-50%) translateY(-14px); opacity:0; }
    to{ transform:translateX(-50%) translateY(0); opacity:1; }
  }
  .idle-warning-stay{
    flex-shrink:0; border:none; border-radius:10px; padding:8px 14px;
    background:#f59e0b; color:#1a1200; font-weight:700; font-size:12px;
    cursor:pointer; transition:filter 0.15s ease;
  }
  .idle-warning-stay:hover{ filter:brightness(1.08); }
  @media (max-width:640px){
    .idle-warning-banner{ left:14px; right:14px; transform:none; max-width:none; }
    @keyframes idleWarningIn{ from{ transform:translateY(-14px); opacity:0; } to{ transform:translateY(0); opacity:1; } }
  }

  .top-updated.saving{ color:var(--accent-deep); }
  .top-updated.saving::before{ content:''; display:inline-block; width:6px; height:6px; border-radius:50%; background:var(--accent); margin-right:5px; animation:pulseSave 0.8s ease-in-out infinite; }
  @keyframes pulseSave{ 0%,100%{ opacity:0.35; } 50%{ opacity:1; } }

  /* ---- Bandeau "redémarrage du bot" (centré en haut de l'écran) ---- */
  .restart-banner-container{
    position:fixed; top:18px; left:50%; z-index:10000;
    transform:translateX(-50%) translateY(-14px); opacity:0; pointer-events:none;
    transition:transform 0.4s cubic-bezier(.2,.8,.2,1), opacity 0.35s ease;
    width:100%; display:flex; justify-content:center; padding:0 16px; box-sizing:border-box;
  }
  .restart-banner-container.show{ transform:translateX(-50%) translateY(0); opacity:1; pointer-events:auto; }
  .restart-banner{
    display:flex; align-items:center; gap:10px;
    background:var(--glass-strong); border:1px solid rgba(90,125,250,0.35);
    backdrop-filter:blur(24px); -webkit-backdrop-filter:blur(24px);
    border-radius:14px; padding:10px 18px 10px 12px;
    box-shadow:0 16px 38px -14px rgba(30,41,59,0.4);
    max-width:440px;
  }
  .restart-banner-icon{
    width:26px; height:26px; border-radius:50%; flex-shrink:0;
    background:rgba(90,125,250,0.16); color:var(--accent-deep);
    display:flex; align-items:center; justify-content:center;
  }
  .restart-banner-icon svg{ width:14px; height:14px; animation:restartSpin 1s linear infinite; }
  @keyframes restartSpin{ from{ transform:rotate(0deg); } to{ transform:rotate(360deg); } }
  .restart-banner-text{ font-size:12.5px; font-weight:700; color:var(--text-hi); line-height:1.3; }
  .restart-banner-sub{ font-size:11px; font-weight:500; color:var(--text-mute); margin-top:1px; }

  @media (max-width: 980px){
    .restart-banner{ max-width:none; }
  }

  @media (max-width: 980px){
    .toast-container{ right:14px; bottom:14px; left:14px; align-items:stretch; }
    .toast{ max-width:none; }
  }

  /* ---- Commandes ---- */
  .cmd-layout{ display:grid; grid-template-columns:300px 1fr; gap:16px; flex:1 1 auto; min-height:0; }
  .cmd-list-panel{
    background:var(--glass); border:1px solid var(--glass-border);
    backdrop-filter:blur(24px); -webkit-backdrop-filter:blur(24px);
    border-radius:20px; padding:14px; overflow-y:auto; min-height:0;
    display:flex; flex-direction:column; gap:2px;
  }
  .cmd-search-box{
    display:flex; align-items:center; gap:8px; background:var(--glass);
    border:1px solid var(--line); border-radius:10px; padding:9px 12px;
    font-size:12.5px; color:var(--text-mute); margin-bottom:10px;
    transition:border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
  }
  .cmd-search-box svg{ width:14px; height:14px; stroke:var(--text-mute); flex-shrink:0; }
  .cmd-search-box input{ flex:1 1 auto; border:none; background:transparent; outline:none; font-size:12.5px; color:var(--text-hi); font-family:inherit; }
  .cmd-search-box input::placeholder{ color:var(--text-mute); }
  .cmd-group-label{ font-size:10.5px; font-weight:700; letter-spacing:0.06em; text-transform:uppercase; color:var(--text-mute); padding:10px 8px 4px; }
  .cmd-item{
    display:flex; flex-direction:column; gap:2px; padding:9px 10px; border-radius:12px;
    cursor:pointer; transition:background 0.15s ease, color 0.15s ease;
  }
  .cmd-item:hover{ background:rgba(255,255,255,0.65); }
  .cmd-item.active{ background:var(--accent-soft); }
  .cmd-item .cmd-name{ font-family:var(--font-mono); font-size:12.5px; font-weight:600; color:var(--text-hi); }
  .cmd-item.active .cmd-name{ color:var(--accent-deep); }
  .cmd-item .cmd-desc{ font-size:11px; color:var(--text-mute); }

  .cmd-detail-panel{
    background:var(--glass); border:1px solid var(--glass-border);
    backdrop-filter:blur(24px); -webkit-backdrop-filter:blur(24px);
    border-radius:20px; padding:26px 28px; overflow-y:auto; min-height:0;
  }
  .cmd-detail-empty{
    height:100%; display:flex; flex-direction:column; align-items:center; justify-content:center;
    text-align:center; color:var(--text-mute); font-size:13px; gap:8px;
  }
  .cmd-detail-empty svg{ width:34px; height:34px; stroke:var(--text-mute); opacity:0.6; }
  .cmd-detail-head{ display:flex; align-items:center; gap:10px; margin-bottom:6px; }
  .cmd-detail-name{ font-family:var(--font-mono); font-size:19px; font-weight:600; color:var(--text-hi); }
  .cmd-detail-cat{ font-size:10.5px; font-weight:600; padding:3px 9px; border-radius:8px; background:var(--accent-soft); color:var(--accent-deep); }
  .cmd-detail-usage{
    font-family:var(--font-mono); font-size:13px; color:var(--accent-deep);
    background:rgba(90,125,250,0.08); border:1px solid rgba(90,125,250,0.18);
    border-radius:10px; padding:10px 14px; margin:14px 0 18px; display:inline-block;
  }
  .cmd-detail-desc{ font-size:13.5px; line-height:1.65; color:var(--text); margin-bottom:20px; }
  .cmd-detail-meta{ display:grid; grid-template-columns:repeat(3,1fr); gap:12px; margin-bottom:20px; }
  .cmd-meta-box{ background:rgba(255,255,255,0.5); border:1px solid var(--line); border-radius:12px; padding:10px 14px; }
  .cmd-meta-lbl{ font-size:10px; color:var(--text-mute); text-transform:uppercase; letter-spacing:0.06em; margin-bottom:3px; }
  .cmd-meta-val{ font-size:12.5px; color:var(--text-hi); font-weight:600; }
  .cmd-detail-example-lbl{ font-size:11px; font-weight:600; color:var(--text-mute); text-transform:uppercase; letter-spacing:0.06em; margin-bottom:8px; }
  .cmd-detail-example{ font-family:var(--font-mono); font-size:12.5px; color:var(--text); background:rgba(148,163,184,0.12); border-radius:10px; padding:12px 14px; }

  @media (max-width: 980px){
    .page-area{ overflow:visible; }
    .an-grid{ grid-template-columns:1fr; }
    .cmd-layout{ grid-template-columns:1fr; }
    .cmd-list-panel{ max-height:340px; }
  }

  /* ================= DASHBOARD CLARITY UPGRADES ================= */

  /* -- sidebar: icons + affordances -- */
  .side-search{ display:flex; align-items:center; gap:8px; cursor:pointer; transition:border-color 0.15s ease, background 0.15s ease; }
  .side-search:hover{ border-color:rgba(90,125,250,0.4); background:rgba(255,255,255,0.75); }
  .side-search svg{ width:14px; height:14px; stroke:var(--text-mute); flex-shrink:0; }
  .side-kbd{ margin-left:auto; font-family:var(--font-mono); font-size:9.5px; color:var(--text-mute); background:rgba(255,255,255,0.7); border:1px solid var(--line); border-radius:5px; padding:1px 5px; }

  .side-link{ gap:10px; }
  .side-link svg{ width:15px; height:15px; stroke:var(--text-mute); flex-shrink:0; transition:stroke 0.15s ease; }
  .side-link.active svg{ stroke:var(--accent-deep); }
  .side-link:hover svg{ stroke:var(--text-hi); }
  .side-link .lbl{ flex:1; display:flex; align-items:center; gap:6px; }

  /* -- topbar: freshness + clearer status -- */
  .top-meta{ display:flex; align-items:center; gap:14px; }
  .top-updated{ font-size:11px; color:var(--text-mute); }

  /* -- hero pill: true gold vs status green, no ambiguity -- */
  .pill.gold{ background:linear-gradient(135deg, rgba(255,207,107,0.28), rgba(255,157,92,0.22)); color:#8a5a12; }

  /* -- KPI cards: trend context so numbers are precise, not just raw -- */
  .kpi{ display:flex; flex-direction:column; gap:6px; }
  .kpi-top{ display:flex; align-items:flex-end; justify-content:space-between; gap:8px; }
  .kpi-trend{
    display:inline-flex; align-items:center; gap:3px; font-size:10.5px; font-weight:700;
    padding:2px 6px; border-radius:7px; font-family:var(--font-mono);
  }
  .kpi-trend.up{ color:var(--mint); background:rgba(34,184,146,0.14); }
  .kpi-trend.down{ color:var(--coral); background:rgba(239,125,107,0.14); }
  .kpi-trend.flat{ color:var(--text-mute); background:rgba(135,144,168,0.14); }
  .kpi-sub{ font-size:10.5px; color:var(--text-mute); }

  /* -- activity chart: legend + axis so the line is legible at a glance -- */
  .chart-wrap{ position:relative; }
  .chart-legend{ display:flex; align-items:center; gap:8px; font-size:11px; color:var(--text-mute); margin-bottom:2px; }
  .chart-legend .dot{ width:7px; height:7px; border-radius:50%; background:var(--accent); }
  .chart-axis{ display:flex; justify-content:space-between; margin-top:4px; padding:0 2px; }
  .chart-axis span{ font-size:10px; color:var(--text-mute); font-family:var(--font-mono); }
  .chart-tag{ font-family:var(--font-mono); font-size:10px; font-weight:700; fill:var(--text-hi); paint-order:stroke; stroke:var(--bg); stroke-width:3px; stroke-linejoin:round; }
  .chart-point{ fill:var(--accent); stroke:var(--bg, transparent); stroke-width:1.5; }
  .chart-tooltip{
    position:absolute; z-index:5; pointer-events:none; top:0; left:0;
    background:var(--glass-strong); border:1px solid var(--glass-border);
    backdrop-filter:blur(24px); -webkit-backdrop-filter:blur(24px);
    border-radius:10px; padding:6px 10px; font-size:11px; color:var(--text-hi);
    box-shadow:0 14px 30px -10px rgba(20,26,60,0.45); white-space:nowrap;
    opacity:0; transform:translate(-50%, -100%); transition:opacity 0.12s ease;
  }
  .chart-tooltip.visible{ opacity:1; }
  .chart-tooltip .ct-date{ color:var(--text-mute); font-size:10px; margin-bottom:2px; }
  .chart-tooltip .ct-value{ font-weight:700; font-family:var(--font-mono); }
  .chart-tooltip .ct-value b{ color:var(--accent-deep); }

  /* -- top XP list: avatars + relative bars make rank comparison instant -- */
  .top-list li{ gap:10px; }
  .top-list .name{ flex:1; min-width:0; }
  .top-list .who{ display:flex; flex-direction:column; gap:3px; min-width:0; flex:1; }
  .top-list .uname{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .top-avatar{
    width:24px; height:24px; border-radius:50%; flex-shrink:0;
    display:flex; align-items:center; justify-content:center;
    font-size:9.5px; font-weight:700; color:#fff;
    background:linear-gradient(135deg, var(--accent), #8fa5ff);
  }
  .top-list li:nth-child(1) .top-avatar{ background:linear-gradient(135deg, #ffcf6b, #ff9d5c); }
  .top-list li:nth-child(2) .top-avatar{ background:linear-gradient(135deg, #b9c3d6, #8b96ac); }
  .top-list li:nth-child(3) .top-avatar{ background:linear-gradient(135deg, #d7a06a, #b97b46); }
  .xp-bar-wrap{ height:4px; border-radius:3px; background:rgba(90,125,250,0.12); overflow:hidden; }
  .xp-bar{ height:100%; border-radius:3px; background:linear-gradient(90deg, var(--accent), var(--accent-deep)); }

  /* -- module list: real toggle affordance instead of an inert dot -- */
  .module-row{ gap:12px; cursor:pointer; border-radius:10px; padding:9px 6px; transition:background 0.15s ease; }
  .module-row:hover{ background:rgba(255,255,255,0.55); }
  .m-name{ flex:1; min-width:0; }
  .m-desc{ font-size:10.5px; color:var(--text-mute); margin-top:1px; }
  .m-name-col{ display:flex; flex-direction:column; align-items:flex-start; }
  .toggle{ position:relative; width:34px; height:19px; flex-shrink:0; border-radius:20px; background:rgba(135,144,168,0.3); transition:background 0.2s ease; }
  .toggle::after{ content:''; position:absolute; top:2px; left:2px; width:15px; height:15px; border-radius:50%; background:#fff; box-shadow:0 1px 3px rgba(0,0,0,0.25); transition:transform 0.2s ease; }
  .toggle.on{ background:var(--mint); }
  .toggle.on::after{ transform:translateX(15px); }

  /* -- quick actions: icon anchors each action for faster scanning -- */
  .qa-btn{ display:flex; align-items:flex-start; gap:10px; }
  .qa-icon{
    width:28px; height:28px; border-radius:9px; flex-shrink:0;
    display:flex; align-items:center; justify-content:center;
    background:var(--accent-soft); color:var(--accent-deep);
  }
  .qa-icon svg{ width:14px; height:14px; stroke:currentColor; fill:none; }
  .qa-txt{ min-width:0; }

  .card-link{ cursor:pointer; transition:color 0.15s ease; }
  .card-link:hover{ color:var(--accent-deep); }
  .card-link .tab{ padding:2px 6px; border-radius:6px; transition:background 0.15s ease, color 0.15s ease; }
  .card-link .tab.active{ background:var(--accent-soft); color:var(--accent-deep); font-weight:600; }

  /* ================= NO-SCROLL FIT-TO-VIEWPORT LAYOUT ================= */
  html, body{ height:100%; overflow:hidden; }

  .dash-layout{ height:100vh; min-height:0; }
  .sidebar{ height:100vh; overflow-y:auto; padding:12px 12px; gap:8px; }

  /* tighter internal spacing so the whole nav column fits without scrolling,
     even on shorter laptop screens */
  .sidebar .side-server-card{ padding:7px 10px 5px; }
  .sidebar .side-bot-logo-header{ padding:0 0 6px; }
  .sidebar .side-bot-logo{ height:48px; }
  .sidebar .side-server-banner{ height:40px; margin:-7px -10px 0 -10px; }
  .sidebar .side-server-top-row{ margin-top:-18px; }
  .sidebar .side-server-avatar{ width:40px; height:40px; font-size:11px; }
  .sidebar .side-server-divider{ margin:6px 0 4px; }
  .sidebar .side-premium-badge{ padding:5px 8px; }
  .sidebar .side-search{ padding:7px 10px; font-size:12px; }
  .sidebar .side-group-label{ padding:0 6px 2px; }
  .sidebar .side-nav{ gap:1px; }
  .sidebar .side-link{ padding:6px 10px; font-size:12.5px; }
  .sidebar .side-subdivider{ margin:4px 8px; }
  .sidebar .side-foot{ padding:8px; gap:8px; margin-top:auto; height:46px; box-sizing:border-box; }
  .sidebar .side-foot .avatar{ width:26px; height:26px; font-size:10px; }

  .main{
    height:100vh; min-height:0; overflow:hidden;
    display:flex; flex-direction:column;
    gap:10px;
    padding:16px 30px 12px;
  }
  .topbar, .kpi-row, .dash-footer{ margin:0; flex:0 0 auto; }

  .kpi-row{ gap:12px; }
  .kpi{ padding:12px 16px; gap:4px; }
  .kpi-num{ font-size:20px; }

  .grid-2{ margin:0; min-height:0; overflow:hidden; gap:14px; flex:1 1 0; }

  .grid-2 .card{
    min-height:0; overflow:hidden;
    display:flex; flex-direction:column;
    padding:13px 18px;
  }
  .grid-2 .card-head{ flex:0 0 auto; margin-bottom:8px; }
  .grid-2 .mini-stats{ flex:0 0 auto; margin-bottom:6px; }
  .grid-2 .chart-legend{ flex:0 0 auto; margin-bottom:0; }
  .grid-2 .chart-wrap{ flex:1 1 auto; min-height:0; height:auto; margin-top:2px; }
  .grid-2 .chart-axis{ flex:0 0 auto; margin-top:2px; }

  .grid-2 .top-list{ flex:1 1 auto; min-height:0; overflow-y:auto; justify-content:space-evenly; }
  .grid-2 .top-list li{ padding:6px 0; }

  .grid-2 .module-list{ flex:1 1 auto; min-height:0; overflow-y:auto; justify-content:space-evenly; }
  .grid-2 .module-row{ padding:7px 6px; }

  .grid-2 .quick-actions{ flex:1 1 auto; align-content:center; }

  .dash-footer{
    /* min-height (pas height fixe) : la notice de reboot peut apparaître
       et faire grandir le contenu du footer. Avant, height:92px +
       overflow:hidden coupait/écrasait cette notice au lieu de lui faire
       de la place — elle semblait "flotter" hors de sa boîte plutôt que
       s'afficher proprement dans le footer. Ici .dash-footer garde
       flex:0 0 auto (cf. règle .main plus haut) donc en grandissant il
       prend juste un peu plus de place et .grid-2 (flex:1 1 0) rétrécit
       d'autant — toujours pas de scroll sur la page.
    */
    padding-top:8px; min-height:92px; box-sizing:border-box;
    display:flex; flex-direction:column; justify-content:center;
  }
  .dash-footer .banner{ margin-bottom:0; padding:9px 16px; }
  .banner-divider{ margin:6px 0; }
  .banner-reboot-notice{ flex-direction:column; align-items:flex-start; }
  .banner-reboot-btn{ width:100%; text-align:center; }
  .banner-announcement{ flex-wrap:nowrap; }
  .banner-announcement-text{ flex-direction:column; align-items:flex-start; gap:2px; }
  .banner-announcement-message{ font-size:11.5px; }
  .dash-footer .dash-copyright{ padding-bottom:0; font-size:9.5px; }

  /* Restore normal scrolling flow on small screens, where the sidebar
     already collapses and everything stacks in a single column. */
  @media (max-width: 980px){
    html, body{ height:auto; overflow-y:auto; overflow-x:hidden; }
    .dash-layout{ height:auto; min-height:100vh; }
    .sidebar{ height:auto; }
    .main{
      display:block; height:auto; overflow:visible;
      padding:20px;
    }
    .topbar{ margin-bottom:20px; }
    .hero-card{ margin-bottom:18px; }
    .kpi-row{ margin-bottom:18px; }
    .grid-2{ display:grid; overflow:visible; margin-bottom:16px; flex:none; min-height:0; }
    .grid-2 .card{ overflow:visible; }
    .grid-2 .chart-wrap{ height:120px; flex:none; }
    .grid-2 .top-list, .grid-2 .module-list{ overflow:visible; flex:none; }
    .dash-footer{ margin-top:24px; padding-top:20px; }
  }

  /* ================= DIDACTICIEL (onboarding) ================= */
  .tour-help-btn{
    display:inline-flex; align-items:center; gap:6px;
    background:var(--glass-strong); border:1px solid var(--line); border-radius:12px;
    padding:8px 14px; font-size:12px; font-weight:600; color:var(--text);
    cursor:pointer; transition:background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
  }
  .tour-help-btn:hover{ background:var(--accent-soft); color:var(--accent-deep); border-color:rgba(90,125,250,0.35); }
  .tour-help-btn svg{ flex-shrink:0; }
  .tour-help-btn .foot-chevron{ width:11px; height:11px; margin-left:-2px; transition:transform 0.2s ease; }
  .tour-help-btn[aria-expanded="true"] .foot-chevron{ transform:rotate(180deg); }

  /* ================= MENU AIDE (déroulant) ================= */
  .help-menu-overlay{
    position:fixed; inset:0; z-index:195; background:transparent;
    opacity:0; pointer-events:none; transition:opacity 0.25s ease;
  }
  .help-menu-overlay.open{ opacity:1; pointer-events:auto; }

  .help-menu-panel{
    position:fixed; z-index:197; width:240px;
    background:var(--glass-strong); border:1px solid var(--glass-border);
    backdrop-filter:blur(22px); -webkit-backdrop-filter:blur(22px);
    border-radius:16px; padding:8px;
    box-shadow:0 22px 50px -18px rgba(31,41,88,0.4), inset 0 1px 0 rgba(255,255,255,0.6);
    opacity:0; pointer-events:none; transform-origin:top left;
    transform:translateY(-10px) scale(0.97);
    transition:opacity 0.3s cubic-bezier(.16,.84,.44,1), transform 0.3s cubic-bezier(.16,.84,.44,1);
  }
  .help-menu-panel.open{ opacity:1; pointer-events:auto; transform:translateY(0) scale(1); }
  .help-menu-panel > *{ opacity:0; transform:translateY(-4px); transition:opacity 0.25s ease, transform 0.25s ease; }
  .help-menu-panel.open > *{ opacity:1; transform:translateY(0); }

  .help-menu-item{
    display:flex; align-items:center; gap:10px; padding:9px 10px; border-radius:10px;
    font-size:12.5px; font-weight:600; color:var(--text-hi); cursor:pointer; text-decoration:none;
    transition:background 0.15s ease, color 0.15s ease;
  }
  .help-menu-item svg{ width:15px; height:15px; stroke:currentColor; flex-shrink:0; opacity:0.75; }
  .help-menu-item:hover, .help-menu-item:focus-visible{ background:var(--accent-soft); color:var(--accent-deep); outline:none; }
  .help-menu-item .sub{ display:block; font-size:9.5px; font-weight:600; color:var(--text-mute); margin-top:1px; }
  .help-menu-item:hover .sub, .help-menu-item:focus-visible .sub{ color:var(--accent-deep); opacity:0.75; }
  .help-menu-divider{ height:1px; background:var(--line); margin:5px 6px; opacity:0.8; }
  .help-menu-label{
    font-size:9.5px; font-weight:700; letter-spacing:0.08em; text-transform:uppercase;
    color:var(--text-mute); padding:6px 10px 3px;
  }

  /* ================= CHAT ASSISTANT N&R ================= */
  .nrchat-overlay{
    position:fixed; inset:0; z-index:220;
    background:rgba(20,26,41,0.4); backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px);
    opacity:0; pointer-events:none; transition:opacity 0.3s ease;
  }
  .nrchat-overlay.open{ opacity:1; pointer-events:auto; }

  .nrchat-modal{
    position:fixed; z-index:221; right:26px; bottom:26px;
    width:min(370px, calc(100vw - 32px)); height:min(540px, calc(100vh - 60px));
    background:var(--glass-strong); border:1px solid var(--glass-border);
    backdrop-filter:blur(24px); -webkit-backdrop-filter:blur(24px);
    border-radius:22px; box-shadow:0 30px 70px -20px rgba(31,41,88,0.45), inset 0 1px 0 rgba(255,255,255,0.6);
    display:flex; flex-direction:column; overflow:hidden;
    opacity:0; pointer-events:none; transform:translateY(18px) scale(0.97);
    transition:opacity 0.32s cubic-bezier(.16,.84,.44,1), transform 0.32s cubic-bezier(.16,.84,.44,1);
  }
  .nrchat-modal.open{ opacity:1; pointer-events:auto; transform:translateY(0) scale(1); }

  .nrchat-head{
    display:flex; align-items:center; gap:10px; padding:14px 14px 12px; flex-shrink:0;
    border-bottom:1px solid var(--line);
  }
  .nrchat-head .avatar{
    width:34px; height:34px; border-radius:12px; flex-shrink:0;
    background:#fff; border:1px solid var(--line);
    display:flex; align-items:center; justify-content:center; color:#fff;
    padding:3px;
  }
  .nrchat-head .avatar img{ width:100%; height:100%; object-fit:contain; }
  .nrchat-head .who{ font-size:13px; font-weight:800; color:var(--text-hi); }
  .nrchat-head .sub{ font-size:10.5px; color:#22b892; font-weight:600; display:flex; align-items:center; gap:4px; }
  .nrchat-head .sub::before{ content:''; width:6px; height:6px; border-radius:50%; background:#22b892; box-shadow:0 0 0 2px rgba(34,184,146,0.25); }
  .nrchat-close{
    margin-left:6px; width:28px; height:28px; border-radius:9px; border:1px solid var(--line);
    background:var(--glass); color:var(--text-mute); cursor:pointer; font-size:13px; line-height:1;
    display:flex; align-items:center; justify-content:center; transition:background 0.15s ease, color 0.15s ease;
  }
  .nrchat-close:hover{ background:var(--accent-soft); color:var(--accent-deep); }

  /* Bouton "appel entrant" dans l'en-tête du widget : n'apparaît que quand
     le staff propose réellement un appel (call:offer), jamais avant — le
     visiteur ne peut pas initier d'appel lui-même. Icône téléphone toujours
     visible ; icône caméra ajoutée seulement pour un appel micro+vidéo. Un
     clic ici équivaut à "Accepter" sur le message d'appel dans la
     conversation — pratique si ce message a défilé plus haut. */
  .nrchat-head-call{
    margin-left:auto; display:flex; align-items:center; gap:5px; position:relative;
    padding:6px 9px; border-radius:10px; border:1px solid rgba(34,184,146,0.4);
    background:rgba(34,184,146,0.14); color:#1a9d76; cursor:pointer; font:inherit;
    animation:nrchatHeadCallPulse 1.6s infinite ease-in-out;
  }
  .nrchat-head-call:hover{ background:rgba(34,184,146,0.24); }
  .nrchat-head-call svg{ display:block; }
  .nrchat-head-call-dot{
    position:absolute; top:-3px; right:-3px; width:8px; height:8px; border-radius:50%;
    background:#ef7d6b; border:1.5px solid #fff;
  }
  @keyframes nrchatHeadCallPulse{
    0%, 100%{ box-shadow:0 0 0 0 rgba(34,184,146,0.5); }
    50%{ box-shadow:0 0 0 5px rgba(34,184,146,0); }
  }

  .nrchat-body{ flex:1; overflow-y:auto; padding:14px; display:flex; flex-direction:column; gap:10px; }
  .nrchat-msg{
    max-width:82%; font-size:12.5px; line-height:1.45; padding:9px 12px; border-radius:14px;
    animation:nrchatIn 0.25s ease;
  }
  @keyframes nrchatIn{ from{ opacity:0; transform:translateY(6px); } to{ opacity:1; transform:translateY(0); } }
  .nrchat-msg.bot{
    background:var(--glass); border:1px solid var(--line); color:var(--text-hi);
    border-bottom-left-radius:4px;
  }
  .nrchat-msg.me{
    background:linear-gradient(135deg, var(--accent), var(--accent-deep)); color:#fff;
    border-bottom-right-radius:4px;
  }
  .nrchat-msg.typing{ display:flex; align-items:center; gap:4px; padding:11px 14px; }
  .nrchat-msg.typing span{
    width:6px; height:6px; border-radius:50%; background:var(--text-mute); opacity:0.6;
    animation:nrchatDot 1s infinite ease-in-out;
  }
  .nrchat-msg.typing span:nth-child(2){ animation-delay:0.15s; }
  .nrchat-msg.typing span:nth-child(3){ animation-delay:0.3s; }
  @keyframes nrchatDot{ 0%,60%,100%{ transform:translateY(0); opacity:0.5; } 30%{ transform:translateY(-3px); opacity:1; } }

  .nrchat-status-bar{
    flex-shrink:0; display:flex; align-items:center; gap:7px; padding:7px 14px;
    border-top:1px solid var(--line); background:rgba(148,163,184,0.06);
    font-size:10.5px; font-weight:600; color:var(--text-mute); letter-spacing:0.01em;
  }
  .nrchat-status-dot{
    width:7px; height:7px; border-radius:50%; background:#22b892; flex-shrink:0;
    box-shadow:0 0 0 0 rgba(34,184,146,0.55); animation:nrchatPulse 2.2s infinite ease-out;
  }
  @keyframes nrchatPulse{
    0%{ box-shadow:0 0 0 0 rgba(34,184,146,0.55); }
    70%{ box-shadow:0 0 0 6px rgba(34,184,146,0); }
    100%{ box-shadow:0 0 0 0 rgba(34,184,146,0); }
  }

  .nrchat-staff-note{
    font-size:11px; color:var(--text-mute); background:var(--glass); border:1px dashed var(--line);
    border-radius:10px; padding:8px 10px; align-self:flex-start; max-width:88%;
  }
  .nrchat-msg.staff-sent{
    align-self:center; background:rgba(34,184,146,0.12); border:1px solid rgba(34,184,146,0.3);
    color:#1a9d76; font-weight:700; text-align:center; border-radius:12px;
  }
  /* Avertissement système (ex. enregistrement de la conversation) : couleur
     ambre distincte de l'accusé de réception (vert) et des bulles
     bot/visiteur, pour qu'il ne soit jamais confondu avec un vrai message. */
  .nrchat-msg.notice{
    align-self:center; background:rgba(245,158,11,0.14); border:1px solid rgba(245,158,11,0.35);
    color:#b45309; font-weight:600; text-align:center; border-radius:12px;
  }
  .nrchat-msg .ts{ display:block; font-size:9.5px; opacity:0.6; margin-top:3px; font-weight:400; }
  /* Accusés de réception façon WhatsApp, sur nos propres messages ('me')
     uniquement : ✓ envoyé, ✓✓ distribué, ✓✓ bleu = lu. Le survol (title)
     donne le libellé exact — voir applyReceiptStatus() dans script.js. */
  .nrchat-msg .ts .msg-status{
    margin-left:4px; font-weight:700; letter-spacing:-1px; display:inline-block;
  }
  .nrchat-msg .ts .msg-status[data-status="read"]{ color:#53bdeb; }

  /* ---- écran d'appel entrant (plein cadre du widget) ----
     Affiché dès que le staff propose un appel (call:offer), tant que le
     visiteur n'a pas répondu : même principe que l'overlay staff-call-panel
     côté console (le visiteur doit voir d'un coup d'œil qu'on l'appelle),
     avec en plus l'anneau de sonnerie animé façon appel entrant mobile.
     position:absolute + inset:0 à l'intérieur de .nrchat-modal (qui a déjà
     overflow:hidden + le bon border-radius) : pas besoin de le redéfinir ici. */
  .nrchat-incoming-call{
    position:absolute; inset:0; z-index:30;
    display:flex; align-items:center; justify-content:center;
    background:rgba(15,18,32,0.6);
    backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
    animation:nrchatIncomingCallIn 0.28s cubic-bezier(.16,.84,.44,1);
  }
  @keyframes nrchatIncomingCallIn{ from{ opacity:0; } to{ opacity:1; } }
  .nrchat-incoming-call-card{
    display:flex; flex-direction:column; align-items:center; gap:10px;
    padding:10px 20px 4px; max-width:88%; text-align:center;
  }
  .nrchat-incoming-call-avatar{
    position:relative; width:76px; height:76px; border-radius:50%; margin-bottom:6px;
    display:flex; align-items:center; justify-content:center;
    background:linear-gradient(135deg, var(--accent), var(--accent-deep));
  }
  .nrchat-incoming-call-icon{ font-size:28px; line-height:1; filter:drop-shadow(0 1px 1px rgba(0,0,0,0.25)); }
  .nrchat-incoming-call-ring{
    position:absolute; inset:0; border-radius:50%; border:2px solid rgba(90,125,250,0.55);
    animation:nrchatIncomingCallRing 1.8s infinite ease-out;
  }
  .nrchat-incoming-call-ring.delay{ animation-delay:0.6s; }
  @keyframes nrchatIncomingCallRing{
    0%{ transform:scale(1); opacity:0.8; }
    100%{ transform:scale(1.9); opacity:0; }
  }
  .nrchat-incoming-call-title{ font-size:15px; font-weight:800; color:#fff; }
  .nrchat-incoming-call-sub{ font-size:12px; font-weight:600; color:rgba(255,255,255,0.75); margin-top:-4px; }
  .nrchat-incoming-call-actions{ display:flex; gap:18px; margin-top:12px; }
  .nrchat-incoming-call-btn{
    display:flex; flex-direction:column; align-items:center; gap:6px;
    background:none; border:none; cursor:pointer; font:inherit; color:#fff; padding:4px;
  }
  .nrchat-incoming-call-btn svg{
    width:44px; height:44px; border-radius:50%; padding:12px; box-sizing:border-box;
    transition:filter 0.15s ease, transform 0.15s ease;
  }
  .nrchat-incoming-call-btn:hover svg{ transform:translateY(-1px); filter:brightness(1.08); }
  .nrchat-incoming-call-btn.accept svg{ background:#22b892; color:#fff; }
  .nrchat-incoming-call-btn.decline svg{ background:#ef4444; color:#fff; }
  .nrchat-incoming-call-btn span{ font-size:10.5px; font-weight:700; }

  /* ---- appel micro / micro+vidéo (proposé par le staff, accepté par le visiteur) ---- */
  .nrchat-msg.call-offer{
    background:rgba(90,125,250,0.12); border:1px solid rgba(90,125,250,0.3);
    color:var(--text-hi); border-bottom-left-radius:4px; text-align:left; font-weight:400;
  }
  .nrchat-call-panel{
    flex-shrink:0; display:flex; align-items:center; gap:10px; padding:10px 14px;
    border-top:1px solid var(--line); background:rgba(90,125,250,0.08);
  }
  .nrchat-call-status{ flex:1; font-size:11.5px; font-weight:700; color:var(--accent-deep); }
  .nrchat-call-media{ display:flex; gap:6px; }
  .nrchat-call-video{
    width:64px; height:48px; border-radius:8px; background:#000; object-fit:cover; border:1px solid var(--line);
  }
  /* Ne jamais display:none ces balises, même en appel audio seul : le flux
     distant (y compris le son) transite par cette <video>, et display:none
     suspend la lecture (donc le son) sur pas mal de navigateurs, surtout
     mobile. On masque visuellement sans arrêter la lecture. */
  .nrchat-call-panel.audio-mode .nrchat-call-video{
    position:absolute; width:1px; height:1px; padding:0; margin:-1px;
    overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0;
  }
  .nrchat-call-hangup{
    font-size:11px; font-weight:700; padding:7px 11px; border-radius:9px; border:1px solid rgba(239,68,68,0.4);
    background:rgba(239,68,68,0.12); color:#dc2626; cursor:pointer; flex-shrink:0;
  }
  .nrchat-call-hangup:hover{ background:rgba(239,68,68,0.2); }
  .nrchat-call-toggle{
    font-size:13px; padding:7px 9px; border-radius:9px; border:1px solid var(--line);
    background:var(--glass); cursor:pointer; flex-shrink:0; line-height:1;
  }
  .nrchat-call-toggle:hover{ background:var(--glass-strong); }
  .nrchat-call-toggle.active{
    border-color:rgba(239,68,68,0.4); background:rgba(239,68,68,0.12); color:#dc2626;
  }
  /* Pas de caméra à couper en mode audio seul (pas de piste vidéo capturée). */
  .nrchat-call-panel.audio-mode #nrchatCallCam{ display:none; }

  /* ---- ligne de message générique : avatar + pseudo + bulle ----
     Utilisée pour les messages du bot (logo N&R), du visiteur ('me',
     avatar généré) et des réponses d'un vrai membre du staff. */
  .nrchat-msg-row{
    display:flex; align-items:flex-end; gap:8px; max-width:88%;
    animation:nrchatIn 0.25s ease;
  }
  .nrchat-msg-row.row-bot{ align-self:flex-start; }
  .nrchat-msg-row.row-me{ align-self:flex-end; flex-direction:row-reverse; }
  .nrchat-avatar{
    width:26px; height:26px; border-radius:50%; flex-shrink:0; object-fit:cover;
    border:1px solid var(--line); background:var(--glass);
  }
  .nrchat-avatar-logo{ object-fit:contain; padding:2px; background:#fff; }
  .nrchat-msg-col{ display:flex; flex-direction:column; gap:3px; min-width:0; }
  .nrchat-msg-row.row-me .nrchat-msg-col{ align-items:flex-end; }
  .nrchat-msg-row .nrchat-msg{ max-width:100%; }
  .nrchat-msg-name{ font-size:10.5px; font-weight:700; color:#1a9d76; padding:0 2px; }
  .nrchat-msg-row.row-me .nrchat-msg-name{ color:var(--accent-deep); }
  .nrchat-msg.staff-reply{
    background:rgba(34,184,146,0.12); border:1px solid rgba(34,184,146,0.3);
    color:var(--text-hi); border-bottom-left-radius:4px; text-align:left; font-weight:400;
  }

  .nrchat-foot{ flex-shrink:0; padding:12px; border-top:1px solid var(--line); display:flex; gap:8px; }
  .nrchat-input{
    flex:1; border:1px solid var(--line); background:var(--glass); border-radius:10px;
    padding:9px 12px; font-size:12.5px; font-family:inherit; color:var(--text-hi); resize:none;
    outline:none; transition:border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
  }
  .nrchat-input:hover:not(:disabled){ border-color:rgba(148,163,184,0.5); }
  .nrchat-input:focus{ border-color:var(--accent); background:var(--glass-strong); box-shadow:0 0 0 3px rgba(90,125,250,0.15); }
  .nrchat-input::placeholder{ color:var(--text-mute); opacity:0.75; }
  .nrchat-send{
    width:38px; height:38px; border-radius:12px; border:none; flex-shrink:0;
    background:linear-gradient(135deg, var(--accent), var(--accent-deep)); color:#fff;
    display:flex; align-items:center; justify-content:center; cursor:pointer;
    transition:filter 0.15s ease, transform 0.15s ease;
  }
  .nrchat-send:hover{ filter:brightness(1.08); transform:translateY(-1px); }
  .nrchat-send:disabled{ opacity:0.5; cursor:default; transform:none; }

  .nrchat-card{
    background:var(--glass); border:1px solid var(--line); border-radius:12px;
    padding:10px 12px; max-width:88%; align-self:flex-start;
  }
  .nrchat-card-title{
    display:flex; align-items:center; gap:8px; font-family:var(--font-mono, monospace);
    font-size:12.5px; font-weight:700; color:var(--text-hi); margin-bottom:4px;
  }
  .nrchat-card-tag{
    font-family:inherit; font-size:9.5px; font-weight:700; text-transform:uppercase; letter-spacing:0.04em;
    color:var(--accent-deep); background:var(--accent-soft); border-radius:6px; padding:2px 6px;
  }
  .nrchat-card-tag.ok{ color:#1a9d76; background:rgba(34,184,146,0.14); }
  .nrchat-card-tag.soon{ color:var(--text-mute); background:rgba(148,163,184,0.18); }
  .nrchat-card-usage{
    font-family:var(--font-mono, monospace); font-size:11.5px; color:var(--accent-deep);
    background:var(--accent-soft); border-radius:8px; padding:5px 8px; margin-bottom:6px; display:inline-block;
  }
  .nrchat-card-desc{ font-size:12px; line-height:1.45; color:var(--text-hi); margin-bottom:6px; }
  .nrchat-card-meta{ font-size:10.5px; color:var(--text-mute); font-weight:600; }

  .nrchat-actions{ display:flex; flex-wrap:wrap; gap:6px; margin-top:8px; align-self:flex-start; }
  .nrchat-action-btn{
    font-size:11.5px; font-weight:700; color:#fff; text-decoration:none;
    background:linear-gradient(135deg, var(--accent), var(--accent-deep)); border:none; border-radius:9px;
    padding:7px 11px; cursor:pointer; display:inline-flex; align-items:center;
    transition:filter 0.15s ease;
  }
  .nrchat-action-btn:hover{ filter:brightness(1.08); }

  /* Statut affiché à la place des boutons Accepter/Refuser une fois qu'on
     y a répondu (ou que l'appel est terminé) : texte simple, non cliquable,
     pour ne jamais laisser une action déjà traitée avoir l'air toujours en
     attente dans l'historique de la conversation. */
  .nrchat-call-offer-status{
    font-size:11.5px; font-weight:600; color:var(--text-mute);
    background:rgba(135,144,168,0.12); border-radius:9px; padding:6px 10px;
    display:inline-flex; align-items:center;
  }

  .nrchat-chips{ display:flex; flex-wrap:wrap; gap:6px; align-self:flex-start; max-width:100%; }
  .nrchat-chip{
    font-size:11.5px; font-weight:600; color:var(--text-hi);
    background:var(--glass); border:1px solid var(--line); border-radius:20px;
    padding:6px 11px; cursor:pointer; transition:background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
  }
  .nrchat-chip:hover{ background:var(--accent-soft); color:var(--accent-deep); border-color:rgba(90,125,250,0.35); }

  @media (max-width: 560px){
    .nrchat-modal{ right:10px; left:10px; bottom:10px; width:auto; }
  }

  .tour-welcome-overlay{
    position:fixed; inset:0; z-index:190;
    background:rgba(20,26,41,0.4); backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px);
    opacity:0; pointer-events:none; transition:opacity 0.3s ease;
  }
  .tour-welcome-overlay.open{ opacity:1; pointer-events:auto; }
  .tour-welcome-modal{
    position:fixed; z-index:191; top:50%; left:50%;
    width:min(420px, 90vw);
    background:var(--glass-strong); border:1px solid var(--glass-border);
    backdrop-filter:blur(26px); -webkit-backdrop-filter:blur(26px);
    border-radius:26px; padding:38px 32px 30px; text-align:center;
    box-shadow:0 30px 70px -20px rgba(20,26,60,0.45), inset 0 1px 0 rgba(255,255,255,0.6);
    opacity:0; pointer-events:none;
    transform:translate(-50%,-48%) scale(0.94);
    transition:opacity 0.36s cubic-bezier(.16,.84,.44,1), transform 0.36s cubic-bezier(.16,.84,.44,1);
  }
  .tour-welcome-modal.open{ opacity:1; pointer-events:auto; transform:translate(-50%,-50%) scale(1); }
  .tour-welcome-badge{
    width:56px; height:56px; margin:0 auto 18px; border-radius:18px;
    background:linear-gradient(135deg, var(--accent), #8fa5ff);
    display:flex; align-items:center; justify-content:center;
    box-shadow:0 10px 24px -8px rgba(90,125,250,0.55); font-size:24px;
  }
  .tour-welcome-modal h3{ font-family:var(--font-display); font-weight:800; font-size:21px; color:var(--text-hi); letter-spacing:-0.01em; margin-bottom:8px; }
  .tour-welcome-modal p{ font-size:13px; color:var(--text-mute); line-height:1.65; margin-bottom:24px; }
  .tour-welcome-actions{ display:flex; flex-direction:column; gap:10px; }
  .tour-welcome-actions .cta{ margin-top:0; width:100%; }
  .tour-welcome-skip{
    background:none; border:none; font-size:12.5px; color:var(--text-mute);
    cursor:pointer; padding:8px; text-decoration:underline;
  }
  .tour-welcome-skip:hover{ color:var(--text-hi); }

  .tour-highlight{
    position:fixed; z-index:201; border-radius:14px;
    box-shadow:0 0 0 9999px rgba(15,20,35,0.58);
    border:2px solid rgba(90,125,250,0.85);
    pointer-events:none;
    transition:top 0.35s cubic-bezier(.16,.84,.44,1), left 0.35s cubic-bezier(.16,.84,.44,1),
               width 0.35s cubic-bezier(.16,.84,.44,1), height 0.35s cubic-bezier(.16,.84,.44,1);
  }
  .tour-tooltip{
    position:fixed; z-index:202; width:min(300px, 86vw);
    background:var(--glass-strong); border:1px solid var(--glass-border);
    backdrop-filter:blur(24px); -webkit-backdrop-filter:blur(24px);
    border-radius:18px; padding:18px 20px;
    box-shadow:0 24px 55px -15px rgba(20,26,60,0.45);
    transition:top 0.35s cubic-bezier(.16,.84,.44,1), left 0.35s cubic-bezier(.16,.84,.44,1);
  }
  .tour-step-count{ font-size:10.5px; font-weight:700; letter-spacing:0.06em; text-transform:uppercase; color:var(--accent-deep); margin-bottom:6px; }
  .tour-tooltip h4{ font-family:var(--font-display); font-weight:800; font-size:14.5px; color:var(--text-hi); margin-bottom:6px; }
  .tour-tooltip p{ font-size:12px; line-height:1.55; color:var(--text); margin-bottom:14px; }
  .tour-tooltip-actions{ display:flex; align-items:center; justify-content:space-between; gap:8px; }
  .tour-btn{ font-size:12px; font-weight:700; padding:8px 14px; border-radius:10px; border:none; cursor:pointer; transition:transform 0.15s ease, box-shadow 0.15s ease; }
  .tour-btn.primary{ background:linear-gradient(135deg, var(--accent), var(--accent-deep)); color:#fff; box-shadow:0 10px 20px -8px rgba(90,125,250,0.55); }
  .tour-btn.primary:hover{ transform:translateY(-1px); }
  .tour-btn.ghost{ background:transparent; color:var(--text-mute); padding:8px 6px; }
  .tour-btn.ghost:hover{ color:var(--text-hi); }
  .tour-skip-link{ background:none; border:none; font-size:11px; color:var(--text-mute); text-decoration:underline; cursor:pointer; margin-top:10px; display:block; text-align:center; width:100%; }
  .tour-skip-link:hover{ color:var(--text-hi); }

  /* ================= PARAMÈTRES (Compte / Apparence / Notifications) ================= */
  .settings-tabs{
    display:flex; gap:6px; margin-bottom:20px; border-bottom:1px solid var(--line); padding-bottom:0;
  }
  .settings-tab{
    display:flex; align-items:center; gap:8px;
    background:none; border:none; cursor:pointer;
    font-family:var(--font-body); font-size:13px; font-weight:600; color:var(--text-mute);
    padding:10px 16px; border-bottom:2px solid transparent; margin-bottom:-1px;
    transition:color 0.15s ease, border-color 0.15s ease;
  }
  .settings-tab svg{ width:15px; height:15px; stroke:currentColor; flex-shrink:0; }
  .settings-tab:hover{ color:var(--text-hi); }
  .settings-tab.active{ color:var(--accent-deep); border-bottom-color:var(--accent); }

  .settings-panel{ display:none; flex-direction:column; gap:18px; }
  .settings-panel.active{ display:flex; }

  .settings-card{
    background:var(--glass); border:1px solid var(--glass-border);
    backdrop-filter:blur(18px); -webkit-backdrop-filter:blur(18px);
    border-radius:20px; padding:24px 26px;
  }
  .settings-card-head{ margin-bottom:18px; }
  .settings-card-head-row{ display:flex; align-items:flex-start; justify-content:space-between; gap:16px; }
  .settings-card-title{ font-family:var(--font-display); font-weight:800; font-size:16px; color:var(--text-hi); }
  .settings-card-sub{ font-size:12.5px; color:var(--text-mute); margin-top:4px; line-height:1.6; max-width:560px; }

  /* --- Compte --- */
  .discord-account-row{ display:flex; align-items:center; gap:16px; flex-wrap:wrap; }
  .discord-avatar .avatar{ width:56px; height:56px; font-size:16px; }
  .discord-account-info{ flex:1; min-width:180px; }
  .discord-account-name{ font-family:var(--font-display); font-weight:800; font-size:16px; color:var(--text-hi); display:flex; align-items:center; gap:6px; }
  .discord-verified{ color:var(--mint); display:inline-flex; }
  .discord-account-id{ font-size:12px; color:var(--text-mute); margin-top:3px; display:flex; align-items:center; gap:6px; }
  .discord-account-id code{ font-family:var(--font-mono); background:rgba(148,163,184,0.14); padding:2px 6px; border-radius:6px; }
  .mini-copy-btn{
    background:none; border:none; cursor:pointer; color:var(--text-mute); padding:2px;
    display:inline-flex; align-items:center; transition:color 0.15s ease;
  }
  .mini-copy-btn:hover{ color:var(--accent-deep); }
  .discord-account-badge{
    display:flex; align-items:center; gap:7px; font-size:12px; font-weight:600; color:var(--accent-deep);
    background:var(--accent-soft); padding:8px 14px; border-radius:999px; white-space:nowrap;
  }
  .discord-account-grid{
    display:grid; grid-template-columns:repeat(auto-fit, minmax(180px, 1fr)); gap:14px;
    margin-top:20px; padding-top:20px; border-top:1px solid var(--line);
  }
  .daf-lbl{ font-size:10.5px; font-weight:700; letter-spacing:0.06em; text-transform:uppercase; color:var(--text-mute); margin-bottom:4px; }
  .daf-val{ font-size:13.5px; font-weight:600; color:var(--text-hi); }
  .settings-card-actions{ display:flex; gap:10px; flex-wrap:wrap; margin-top:22px; }
  .btn-secondary{
    display:flex; align-items:center; gap:7px; font-size:12.5px; font-weight:700;
    background:var(--accent-soft); color:var(--accent-deep); border:none; border-radius:11px;
    padding:10px 16px; cursor:pointer; transition:transform 0.15s ease;
  }
  .btn-secondary:hover{ transform:translateY(-1px); }
  .btn-danger-ghost{
    font-size:12.5px; font-weight:700; background:none; color:var(--coral);
    border:1px solid rgba(239,125,107,0.4); border-radius:11px; padding:10px 16px; cursor:pointer;
    transition:background 0.15s ease;
  }
  .btn-danger-ghost:hover{ background:rgba(239,125,107,0.08); }

  /* --- Apparence : mode clair / sombre --- */
  .mode-grid{ display:grid; grid-template-columns:repeat(auto-fill, minmax(128px, 1fr)); gap:14px; }
  .mode-swatch{
    position:relative; cursor:pointer; border-radius:16px; padding:3px;
    border:2px solid transparent; background:var(--glass-strong);
    transition:border-color 0.15s ease, transform 0.15s ease;
  }
  .mode-swatch:hover{ transform:translateY(-2px); }
  .mode-swatch.active{ border-color:var(--accent); }
  .mode-swatch-preview{
    height:56px; border-radius:12px; overflow:hidden; padding:8px; display:flex; flex-direction:column; gap:5px;
  }
  .mode-swatch-preview.is-light{ background:#eef1f7; }
  .mode-swatch-preview.is-dark{ background:#11151f; }
  .mode-swatch-preview-bar{ height:8px; width:60%; border-radius:4px; }
  .mode-swatch-preview.is-light .mode-swatch-preview-bar{ background:#c7cede; }
  .mode-swatch-preview.is-dark .mode-swatch-preview-bar{ background:#333c52; }
  .mode-swatch-preview-line{ height:6px; width:85%; border-radius:3px; }
  .mode-swatch-preview.is-light .mode-swatch-preview-line{ background:#dbe0ec; }
  .mode-swatch-preview.is-dark .mode-swatch-preview-line{ background:#242c3f; }
  .mode-swatch-name{
    font-size:11.5px; font-weight:700; color:var(--text-hi); text-align:center; padding:8px 4px 5px;
  }
  .mode-swatch-check{
    position:absolute; top:8px; right:8px; width:18px; height:18px; border-radius:50%;
    background:var(--accent); color:#fff; display:none; align-items:center; justify-content:center;
    box-shadow:0 4px 10px -3px rgba(0,0,0,0.3);
  }
  .mode-swatch-check svg{ width:11px; height:11px; }
  .mode-swatch.active .mode-swatch-check{ display:flex; }

  /* --- Apparence : thèmes --- */
  .theme-grid{ display:grid; grid-template-columns:repeat(auto-fill, minmax(128px, 1fr)); gap:14px; }
  .theme-swatch{
    position:relative; cursor:pointer; border-radius:16px; padding:3px;
    border:2px solid transparent; background:var(--glass-strong);
    transition:border-color 0.15s ease, transform 0.15s ease;
  }
  .theme-swatch:hover{ transform:translateY(-2px); }
  .theme-swatch.active{ border-color:var(--accent); }
  .theme-swatch-preview{
    height:56px; border-radius:12px; display:flex; overflow:hidden;
  }
  .theme-swatch-preview span{ flex:1; }
  .theme-swatch-name{
    font-size:11.5px; font-weight:700; color:var(--text-hi); text-align:center; padding:8px 4px 5px;
  }
  .theme-swatch-check{
    position:absolute; top:8px; right:8px; width:18px; height:18px; border-radius:50%;
    background:var(--accent); color:#fff; display:none; align-items:center; justify-content:center;
    box-shadow:0 4px 10px -3px rgba(0,0,0,0.3);
  }
  .theme-swatch-check svg{ width:11px; height:11px; }
  .theme-swatch.active .theme-swatch-check{ display:flex; }

  /* --- Apparence : thème personnalisé --- */
  .theme-swatch-custom .theme-swatch-preview{
    position:relative; display:flex; align-items:center; justify-content:center;
    background:repeating-linear-gradient(45deg, rgba(148,163,184,0.16) 0 8px, rgba(148,163,184,0.06) 8px 16px);
  }
  .theme-pencil-btn{
    position:absolute; bottom:6px; right:6px; width:24px; height:24px; border-radius:50%;
    background:var(--glass-strong); border:1px solid var(--glass-border); color:var(--text-hi);
    display:flex; align-items:center; justify-content:center; cursor:pointer; z-index:2;
    transition:background 0.15s ease, transform 0.15s ease;
  }
  .theme-pencil-btn:hover{ background:var(--accent-soft); color:var(--accent-deep); transform:scale(1.08); }
  .theme-pencil-btn svg{ width:12px; height:12px; }
  .theme-swatch-custom .theme-swatch-preview-dot{ width:14px; height:14px; border-radius:50%; margin:0 3px; box-shadow:0 0 0 2px rgba(255,255,255,0.5); }

  .custom-theme-panel{
    margin-top:16px; padding:18px; border-radius:16px;
    background:var(--glass-strong); border:1px solid var(--glass-border);
    display:none; flex-direction:column; gap:16px;
  }
  .custom-theme-panel.open{ display:flex; }
  .custom-theme-panel-title{ font-family:var(--font-display); font-weight:800; font-size:14px; color:var(--text-hi); }
  .custom-color-grid{ display:grid; grid-template-columns:repeat(auto-fill, minmax(120px, 1fr)); gap:14px; }
  .custom-color-field{ display:flex; flex-direction:column; align-items:center; gap:8px; cursor:pointer; }
  .custom-color-field input[type="color"]{
    -webkit-appearance:none; appearance:none; width:48px; height:48px; border-radius:50%;
    border:2px solid var(--glass-border); padding:0; cursor:pointer; background:none;
  }
  .custom-color-field input[type="color"]::-webkit-color-swatch-wrapper{ padding:0; border-radius:50%; }
  .custom-color-field input[type="color"]::-webkit-color-swatch{ border:none; border-radius:50%; }
  .custom-color-field span{ font-size:11px; font-weight:600; color:var(--text-mute); text-align:center; }
  .custom-theme-panel-actions{ display:flex; gap:10px; flex-wrap:wrap; justify-content:flex-end; }
  .btn-primary-sm{
    display:flex; align-items:center; gap:7px; font-size:12.5px; font-weight:700; color:#fff;
    background:linear-gradient(135deg, var(--accent), var(--accent-deep)); border:none; border-radius:11px;
    padding:10px 16px; cursor:pointer; transition:transform 0.15s ease;
  }
  .btn-primary-sm:hover{ transform:translateY(-1px); }

  /* --- Apparence : polices --- */
  .font-grid{ display:grid; grid-template-columns:repeat(auto-fill, minmax(200px, 1fr)); gap:12px; }
  .font-option{
    position:relative; cursor:pointer; border-radius:14px; padding:14px 16px;
    border:2px solid var(--line); background:var(--glass-strong);
    transition:border-color 0.15s ease, transform 0.15s ease;
  }
  .font-option:hover{ transform:translateY(-1px); }
  .font-option.active{ border-color:var(--accent); background:var(--accent-soft); }
  .font-option-title{ font-weight:800; font-size:16px; color:var(--text-hi); margin-bottom:3px; }
  .font-option-sample{ font-size:12px; color:var(--text-mute); }
  .font-option-check{
    position:absolute; top:10px; right:10px; width:16px; height:16px; border-radius:50%;
    background:var(--accent); color:#fff; display:none; align-items:center; justify-content:center;
  }
  .font-option-check svg{ width:10px; height:10px; }
  .font-option.active .font-option-check{ display:flex; }

  /* --- Switches (toggle) --- */
  .switch{ position:relative; display:inline-block; width:40px; height:23px; flex-shrink:0; cursor:pointer; }
  .switch input{ position:absolute; opacity:0; width:0; height:0; }
  .switch-track{
    position:absolute; inset:0; background:rgba(148,163,184,0.35); border-radius:999px;
    transition:background 0.18s ease;
  }
  .switch-thumb{
    position:absolute; top:2.5px; left:2.5px; width:18px; height:18px; border-radius:50%;
    background:#fff; box-shadow:0 2px 5px rgba(0,0,0,0.25); transition:transform 0.18s ease;
  }
  .switch input:checked + .switch-track{ background:linear-gradient(135deg, var(--accent), var(--accent-deep)); }
  .switch input:checked + .switch-track .switch-thumb{ transform:translateX(17px); }
  .switch input:disabled + .switch-track{ opacity:0.4; cursor:not-allowed; }
  .switch-lg{ width:46px; height:26px; }
  .switch-lg .switch-thumb{ width:21px; height:21px; }
  .switch-lg input:checked + .switch-track .switch-thumb{ transform:translateX(20px); }

  /* --- Notifications : matrice --- */
  #notifDetailCard{ transition:opacity 0.2s ease; }
  #notifDetailCard.notif-disabled{ opacity:0.45; pointer-events:none; }
  .notif-matrix-head{
    display:grid; grid-template-columns:1fr 100px 120px; gap:10px; align-items:center;
    padding:0 14px 10px; font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:0.05em;
    color:var(--text-mute);
  }
  .nm-col-toggle{ text-align:center; }
  .notif-matrix-body{ display:flex; flex-direction:column; gap:2px; }
  .notif-row{
    display:grid; grid-template-columns:1fr 100px 120px; gap:10px; align-items:center;
    padding:12px 14px; border-radius:12px; transition:background 0.15s ease;
  }
  .notif-row:hover{ background:rgba(148,163,184,0.08); }
  .notif-row-title{ font-size:13px; font-weight:700; color:var(--text-hi); }
  .notif-row-desc{ font-size:11.5px; color:var(--text-mute); margin-top:2px; }
  .notif-row-toggle{ display:flex; justify-content:center; }

  @media (max-width:640px){
    .notif-matrix-head, .notif-row{ grid-template-columns:1fr 70px 90px; }
    .notif-row-desc{ display:none; }
  }

  /* --------------------------------------------------------------------
     Fix : bug de rendu Safari iOS avec les cartes en verre dépoli.
     Sur mobile, de nombreuses cartes (.card, .kpi, .server-card,
     .cat-hero, .settings-card, .hero-card) empilent chacune un
     backdrop-filter:blur(). iOS Safari a un bug de compositing connu
     qui, avec beaucoup de calques flous actifs en même temps sur une
     page qui scrolle, fait "fuiter" le contenu d'une carte déjà
     scrollée par-dessus une carte suivante (effet fantôme/transparence).
     On désactive le flou sur ces cartes empilées en dessous de 768px
     et on les rend opaques à la place : le rendu reste net (le fond
     de la page est déjà uni sur mobile) et le bug disparaît. Les
     panneaux qui s'affichent seuls par-dessus le reste (modales,
     menus, tooltips) gardent leur flou, ils ne sont jamais empilés
     entre eux donc ne déclenchent pas le bug.
  -------------------------------------------------------------------- */
  @media (max-width:768px){
    .card,
    .kpi,
    .server-card,
    .cat-hero,
    .settings-card,
    .hero-card{
      background:var(--glass-solid) !important;
      backdrop-filter:none !important;
      -webkit-backdrop-filter:none !important;
      isolation:isolate;
    }
  }

  /* ====================================================================
     Champ 'onboarding-builder' (parcours d'onboarding en fil privé) —
     modèles prêts à l'emploi + liste d'étapes éditable, cf. script.js#
     renderOnboardingStepCard / bindOnboardingBuilder. Réutilise le
     vocabulaire visuel des champs de config existants (var(--text-hi),
     var(--text-mute), var(--line), var(--accent)...) plutôt que d'inventer
     une palette à part.
     -------------------------------------------------------------------- */
  .module-config-onboarding-field{ display:flex; flex-direction:column; gap:8px; }
  .cfg-ob-root{ display:flex; flex-direction:column; gap:14px; }
  .cfg-ob-loading{ font-size:11.5px; color:var(--text-mute); padding:8px 0; }

  /* ---- Champs du builder : simple alias de .cfg-input (cf. plus haut) ----
     Avant, .cfg-ob-input dupliquait sa propre recette (fond/rayon/focus
     légèrement différents de .cfg-input) — deux champs "texte" du même
     dashboard ne se ressemblaient pas tout à fait. On lui donne maintenant
     exactement le même sélecteur/déclarations qu'à .cfg-input : un seul
     vocabulaire visuel pour les champs texte de TOUT le site (cf. bloc
     générique en tête de fichier pour les champs sans classe dédiée), avec
     juste la hauteur mini du textarea adaptée aux petites cartes d'étape. */
  input.cfg-ob-input, select.cfg-ob-input, textarea.cfg-ob-input{
    font-family:var(--font-body); font-size:12.5px; color:var(--text-hi);
    background:var(--glass); border:1px solid var(--line); border-radius:10px;
    padding:9px 12px; outline:none; width:100%; box-sizing:border-box; resize:vertical;
    transition:border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
  }
  .cfg-ob-input::placeholder{ color:var(--text-mute); opacity:0.75; }
  .cfg-ob-input:hover:not(:disabled){ border-color:rgba(148,163,184,0.5); }
  .cfg-ob-input:focus{ border-color:var(--accent); background:var(--glass-strong); box-shadow:0 0 0 3px rgba(90,125,250,0.15); }
  .cfg-ob-input:disabled{ opacity:0.5; cursor:not-allowed; }
  select.cfg-ob-input{
    appearance:none; -webkit-appearance:none; cursor:pointer;
    background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none'><path d='M5.5 7.5l4.5 4.5 4.5-4.5' stroke='%237c8598' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/></svg>");
    background-repeat:no-repeat; background-position:right 10px center; padding-right:30px;
  }
  textarea.cfg-ob-input{ min-height:52px; line-height:1.45; }

  /* ---- Modèles prêts à l'emploi ---- */
  .cfg-ob-templates{
    display:grid; grid-template-columns:repeat(auto-fit, minmax(150px, 1fr)); gap:8px;
  }
  .cfg-ob-template-btn{
    display:flex; flex-direction:column; gap:4px; text-align:left; cursor:pointer;
    background:rgba(255,255,255,0.55); border:1px solid var(--line); border-radius:12px;
    padding:10px 12px; transition:border-color 0.15s ease, background 0.15s ease, transform 0.15s ease;
    font-family:var(--font-body);
  }
  .cfg-ob-template-btn:hover{ border-color:var(--accent); background:rgba(255,255,255,0.8); transform:translateY(-1px); }
  .cfg-ob-template-label{ font-size:12px; font-weight:700; color:var(--accent-deep); }
  .cfg-ob-template-desc{ font-size:10.5px; color:var(--text-mute); line-height:1.35; }

  /* ---- Liste d'étapes ---- */
  .cfg-ob-steps-list{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:10px; }
  .cfg-ob-empty{ font-size:11.5px; color:var(--text-mute); padding:6px 0; }

  .cfg-ob-step-card{
    display:flex; flex-direction:column; gap:10px;
    background:linear-gradient(180deg, rgba(255,255,255,0.06), rgba(255,255,255,0.015));
    border:1px solid var(--glass-border, var(--line)); border-radius:14px; padding:14px;
    box-shadow:0 1px 0 rgba(255,255,255,0.05) inset, 0 8px 18px -14px rgba(0,0,0,0.5);
    transition:border-color 0.15s ease, box-shadow 0.15s ease;
  }
  .cfg-ob-step-card:hover{ border-color:rgba(255,255,255,0.18); }
  .cfg-ob-step-head{ display:flex; align-items:center; gap:8px; }
  .cfg-ob-step-num{
    font-family:var(--font-display); font-weight:800; font-size:11px; color:var(--accent-deep);
    background:var(--accent-soft); width:22px; height:22px; border-radius:7px;
    display:flex; align-items:center; justify-content:center; flex-shrink:0;
  }
  .cfg-ob-step-type{ flex:1; font-weight:600; }
  .cfg-ob-step-actions{ display:flex; gap:4px; flex-shrink:0; }
  .cfg-ob-icon-btn{
    width:24px; height:24px; border-radius:7px; border:1px solid var(--line);
    background:rgba(255,255,255,0.06); color:var(--text-mute); cursor:pointer;
    display:flex; align-items:center; justify-content:center; font-size:10px;
    transition:background 0.15s ease, color 0.15s ease;
  }
  .cfg-ob-icon-btn:hover:not(:disabled){ background:var(--accent-soft); color:var(--accent-deep); }
  .cfg-ob-icon-btn:disabled{ opacity:0.35; cursor:not-allowed; }
  .cfg-ob-icon-btn--danger:hover:not(:disabled){ background:rgba(220,38,38,0.12); color:#dc2626; }

  /* Titre = accroche de la carte (plus visible) ; description = texte
     secondaire plus discret, pour que l'œil distingue les deux au premier
     coup d'œil au lieu d'une pile de champs identiques. */
  .cfg-ob-title-input{ font-weight:700; font-size:13px; }
  .cfg-ob-desc-input{ resize:vertical; min-height:44px; color:var(--text); }
  .cfg-ob-desc-counter{
    display:block; align-self:flex-end; margin-top:-6px;
    font-size:10px; color:var(--text-mute); opacity:0.75;
  }
  .cfg-ob-desc-counter.is-over{ color:#dc2626; opacity:1; font-weight:600; }

  /* Sous-champs (emoji, salon, rôles…) légèrement encaissés dans un liseré
     supérieur, pour les détacher visuellement du couple titre/description
     plutôt que de les laisser à plat dans la même colonne. */
  .cfg-ob-subfield{
    display:flex; flex-direction:column; gap:5px; margin-top:2px;
    padding-top:10px; border-top:1px dashed var(--line);
  }
  .cfg-ob-subfield label{ font-size:10.5px; font-weight:700; letter-spacing:0.02em; text-transform:uppercase; color:var(--text-mute); }
  .cfg-ob-subfield--inline{ max-width:160px; }
  .cfg-ob-hint{ font-size:10px; color:var(--text-mute); opacity:0.8; line-height:1.35; margin:0; }
  .cfg-ob-emoji-input{ text-align:center; font-size:15px; max-width:80px; }

  .cfg-ob-role-chips{ display:flex; flex-wrap:wrap; gap:6px; }
  .cfg-ob-role-chip{
    display:inline-flex; align-items:center; gap:5px; font-size:11px; color:var(--text);
    background:rgba(255,255,255,0.55); border:1px solid var(--line); border-radius:999px;
    padding:5px 10px 5px 8px; cursor:pointer; transition:border-color 0.15s ease, background 0.15s ease;
  }
  .cfg-ob-role-chip input{ margin:0; accent-color:var(--ob-role-color, var(--accent)); }
  .cfg-ob-role-chip.is-checked{ border-color:var(--ob-role-color, var(--accent)); background:var(--accent-soft); }
  .cfg-ob-role-chip.is-disabled{ opacity:0.4; cursor:not-allowed; }

  /* Bouton "Créer automatiquement le rôle Vérifié" (roles_on_accept) —
     même famille que .cfg-ob-add-btn (action positive discrète), mais
     pleine largeur et marge au-dessus des puces de rôles qu'il complète. */
  .cfg-ob-create-role-btn{
    margin-top:2px; align-self:flex-start;
    font-family:var(--font-body); font-size:11.5px; font-weight:600; color:var(--accent-deep);
    background:var(--accent-soft); border:1px solid transparent; border-radius:9px;
    padding:6px 12px; cursor:pointer; transition:background 0.15s ease, opacity 0.15s ease;
  }
  .cfg-ob-create-role-btn:hover:not(:disabled){ background:color-mix(in srgb, var(--accent-soft) 65%, var(--accent) 22%); }
  .cfg-ob-create-role-btn:disabled{ opacity:0.6; cursor:default; }

  /* Bouton "Publier / Mettre à jour dans le salon" (étape 'accept', sous
     le sélecteur "Récupérer le règlement depuis un salon") — même famille
     visuelle que .cfg-ob-create-role-btn (action positive discrète), avec
     son statut inline juste à côté plutôt qu'en dessous, pour rester
     compact sous un select déjà accompagné de son .cfg-ob-hint. */
  .cfg-ob-publish-row{ display:flex; align-items:center; gap:10px; margin-top:6px; flex-wrap:wrap; }
  .cfg-ob-publish-rule-btn{
    font-family:var(--font-body); font-size:11.5px; font-weight:600; color:var(--accent-deep);
    background:var(--accent-soft); border:1px solid transparent; border-radius:9px;
    padding:6px 12px; cursor:pointer; transition:background 0.15s ease, opacity 0.15s ease, transform 0.15s ease;
  }
  .cfg-ob-publish-rule-btn:hover:not(:disabled){ background:color-mix(in srgb, var(--accent-soft) 65%, var(--accent) 22%); transform:translateY(-1px); }
  .cfg-ob-publish-rule-btn:active:not(:disabled){ transform:translateY(0) scale(0.97); }
  .cfg-ob-publish-rule-btn:disabled{ opacity:0.6; cursor:default; transform:none; }
  .cfg-ob-publish-status{ font-family:var(--font-body); font-size:11px; font-weight:600; color:var(--text-mute); }
  .cfg-ob-publish-status.is-ok{ color:var(--mint); }
  .cfg-ob-publish-status.is-error{ color:#dc2626; }

  /* Bouton "Créer automatiquement" générique sous un champ 'role' quelconque
     (cf. renderFieldInner/bindRoleCreateButtons dans script.js) — même
     famille visuelle que .cfg-ob-create-role-btn, posé juste après le
     <select> du champ plutôt que sous des puces de rôles, avec un champ
     texte à côté pour laisser le staff choisir le nom du rôle avant de le
     créer (pré-rempli avec le nom par défaut du schéma). */
  .cfg-role-create-row{ display:flex; align-items:center; gap:8px; margin-top:6px; flex-wrap:wrap; }
  .cfg-role-create-name{
    flex:1 1 160px; min-width:120px;
    font-family:var(--font-body); font-size:12.5px; color:var(--text);
    background:rgba(255,255,255,0.7); border:1px solid var(--line); border-radius:9px;
    padding:6px 10px;
  }
  .cfg-role-create-name:focus{ outline:none; border-color:var(--accent); }
  .cfg-role-create-btn{
    display:inline-block; flex:0 0 auto;
    font-family:var(--font-body); font-size:11.5px; font-weight:600; color:var(--accent-deep);
    background:var(--accent-soft); border:1px solid transparent; border-radius:9px;
    padding:6px 12px; cursor:pointer; transition:background 0.15s ease, opacity 0.15s ease;
  }
  .cfg-role-create-btn:hover:not(:disabled){ background:color-mix(in srgb, var(--accent-soft) 65%, var(--accent) 22%); }
  .cfg-role-create-btn:disabled{ opacity:0.6; cursor:default; }
  .cfg-role-create-status{ display:block; margin-top:4px; font-family:var(--font-body); font-size:11px; font-weight:600; color:var(--text-mute); }
  .cfg-role-create-status.is-success{ color:var(--mint); }
  .cfg-role-create-status.is-error{ color:#dc2626; }

  /* Modèles de règlement (étape 'accept') : mêmes cartes que
     .cfg-ob-template-btn mais colonne plus étroite possible (texte de
     règlement plus long à décrire que les modèles de parcours). */
  .cfg-ob-rule-templates{ grid-template-columns:repeat(auto-fit, minmax(130px, 1fr)); }

  /* ---- Ajout d'étape ---- */
  .cfg-ob-add-row{ display:flex; gap:8px; align-items:center; }
  .cfg-ob-add-row .cfg-ob-add-type{
    font-family:var(--font-body); font-size:12px; color:var(--text-hi);
    background:rgba(255,255,255,0.65); border:1px solid var(--line); border-radius:10px;
    padding:8px 10px; flex:1;
  }
  .cfg-ob-add-btn{
    font-family:var(--font-body); font-size:11.5px; font-weight:700; color:#fff;
    background:linear-gradient(135deg, var(--accent), var(--accent-deep));
    border:none; border-radius:10px; padding:8px 14px; cursor:pointer; white-space:nowrap;
    transition:transform 0.15s ease, box-shadow 0.15s ease;
  }
  .cfg-ob-add-btn:hover{ transform:translateY(-1px); box-shadow:0 8px 16px -10px rgba(90,125,250,0.5); }

  /* ---- Statut de sauvegarde dédié (même vocabulaire que .module-config-
     autosave-status, mais propre à ce champ : route de sauvegarde séparée,
     cf. bindOnboardingBuilder) ---- */
  .cfg-ob-status{
    font-family:var(--font-body); font-size:11px; font-weight:600; color:var(--text-mute);
    display:flex; align-items:center; gap:5px; min-height:14px;
  }
  .cfg-ob-status:not(:empty)::before{
    content:''; width:6px; height:6px; border-radius:50%; background:currentColor; flex-shrink:0;
  }
  .cfg-ob-status.is-pending{ color:var(--text-mute); }
  .cfg-ob-status.is-saving{ color:var(--accent-deep); }
  .cfg-ob-status.is-saved{ color:var(--mint); }
  .cfg-ob-status.is-error{ color:#dc2626; }

  /* ---- Bouton "Tester l'onboarding sur moi" — ouvre un vrai fil privé de
     test sur le serveur (cf. bindOnboardingBuilder / _test kind:'onboarding'
     côté bot). Même vocabulaire visuel que .module-config-group-test-btn
     (autre mécanisme de test, cf. plus haut) pour rester cohérent. ---- */
  .cfg-ob-test-row{
    display:flex; align-items:center; gap:8px; margin-top:10px; flex-wrap:wrap;
  }
  .cfg-ob-test-btn{
    font-family:var(--font-body); font-size:12px; font-weight:700; color:var(--accent-deep);
    background:rgba(90,125,250,0.10); border:1px solid rgba(90,125,250,0.28); border-radius:10px;
    padding:7px 14px; cursor:pointer; transition:background 0.15s ease, transform 0.15s ease;
    display:inline-flex; align-items:center; gap:6px;
  }
  .cfg-ob-test-btn:hover{ background:rgba(90,125,250,0.18); transform:translateY(-1px); }
  .cfg-ob-test-btn:active{ transform:translateY(0) scale(0.97); }
  .cfg-ob-test-btn:disabled{ opacity:0.5; cursor:default; transform:none; }
  .cfg-ob-test-status{
    font-family:var(--font-body); font-size:11px; font-weight:600; color:var(--text-mute);
  }
  .cfg-ob-test-status.is-saving{ color:var(--accent-deep); }
  .cfg-ob-test-status.is-ok{ color:var(--mint); }
  .cfg-ob-test-status.is-error{ color:#dc2626; }

  /* ════════════════════════════════════════════════════════════════════
     BUILDER RÔLES & RÉACTIONS (.cfg-rr-*) — cf. script.js#renderFieldInner
     "f.type === 'rr-panel-builder'" + bindRolesReactionsBuilder(). Champ
     purement AFFICHAGE côté configSchema (comme .cfg-ob-* juste au-dessus,
     dont il reprend le vocabulaire visuel — input/select/icon-btn/status),
     mais persiste via SES PROPRES routes dédiées (/api/roles-reactions/...)
     plutôt que la route générique .../config : la liste de panneaux vit en
     base dans rr_panels/rr_panel_roles, pas dans le JSON de config du
     module. Disposition en 2 colonnes : liste des panneaux à gauche,
     bloc de création/édition ("réactions" = rôle+emoji+label+style) à
     droite, avec aperçu live de l'embed en bas de ce bloc droit.
     ════════════════════════════════════════════════════════════════════ */
  .module-config-rr-field{ display:flex; flex-direction:column; gap:8px; }
  .cfg-rr-root{ display:flex; flex-direction:column; gap:12px; }

  .cfg-rr-toolbar{ display:flex; align-items:center; justify-content:space-between; gap:10px; flex-wrap:wrap; }
  .cfg-rr-toolbar-hint{ font-size:11px; color:var(--text-mute); line-height:1.4; max-width:60ch; }

  .cfg-rr-layout{ display:grid; grid-template-columns:minmax(200px, 260px) 1fr; gap:16px; align-items:start; }
  @media (max-width: 860px){ .cfg-rr-layout{ grid-template-columns:1fr; } }

  /* Variant à 3 zones (déclencheurs mot/phrase/emoji, demande du 07/09) :
     liste de ce qui est déjà créé/validé, puis config, puis aperçu — les
     3 séparées et visibles ensemble sur grand écran, au lieu d'empiler
     l'aperçu sous le formulaire de config comme dans le variant à 2 zones
     ci-dessus (rôles & réactions). Se replie progressivement : d'abord
     l'aperçu passe sous la config (tablette), puis tout s'empile (mobile). */
  .cfg-rr-layout--3col{ grid-template-columns:minmax(200px, 240px) minmax(260px, 1fr) minmax(230px, 300px); }
  @media (max-width: 1180px){
    .cfg-rr-layout--3col{ grid-template-columns:minmax(200px, 240px) 1fr; }
    .cfg-rr-layout--3col .cfg-rr-col-preview{ grid-column:2; }
  }
  @media (max-width: 860px){
    .cfg-rr-layout--3col{ grid-template-columns:1fr; }
    .cfg-rr-layout--3col .cfg-rr-col-preview{ grid-column:auto; }
  }

  /* ---- Colonne de gauche : liste des panneaux déjà créés ---- */
  .cfg-rr-col-left{ display:flex; flex-direction:column; gap:8px; }
  .cfg-rr-panel-list{ display:flex; flex-direction:column; gap:7px; max-height:520px; overflow-y:auto; padding-right:2px; }
  .cfg-rr-panel-card{
    display:flex; flex-direction:column; gap:3px; text-align:left; cursor:pointer;
    background:var(--glass); border:1px solid rgba(255,255,255,0.08); border-radius:10px;
    padding:9px 11px; transition:border-color .15s ease, background .15s ease;
  }
  .cfg-rr-panel-card:hover{ border-color:rgba(255,255,255,0.18); }
  .cfg-rr-panel-card.is-active{ border-color:var(--accent); background:var(--accent-soft); }
  .cfg-rr-panel-card-title{ font-weight:700; font-size:12.5px; color:var(--text-hi); }
  .cfg-rr-panel-card-meta{ font-size:10.5px; color:var(--text-mute); display:flex; align-items:center; gap:6px; flex-wrap:wrap; }
  .cfg-rr-badge{
    display:inline-flex; align-items:center; gap:3px; font-size:9.5px; font-weight:700;
    text-transform:uppercase; letter-spacing:0.02em; padding:1px 6px; border-radius:999px;
    background:rgba(148,163,184,0.16); color:var(--text-mute);
  }
  .cfg-rr-badge--live{ background:rgba(36,128,70,0.18); color:#4ade80; }
  .cfg-rr-new-btn{
    display:flex; align-items:center; justify-content:center; gap:6px; width:100%;
    font-family:var(--font-body); font-size:12px; font-weight:700; color:#fff;
    background:linear-gradient(135deg, var(--accent), var(--accent-deep)); border:none;
    border-radius:10px; padding:9px 12px; cursor:pointer;
  }
  .cfg-rr-new-btn:hover{ transform:translateY(-1px); box-shadow:0 8px 16px -10px rgba(90,125,250,0.5); }
  .cfg-rr-empty-list{ font-size:11px; color:var(--text-mute); padding:10px 2px; text-align:center; }

  /* ---- Suggestions prédéfinies (onglet "Réactions", déclencheurs) ---- */
  .cfg-rrx-presets{ display:flex; align-items:center; gap:7px; flex-wrap:wrap; margin:2px 0 4px; }
  .cfg-rrx-presets-label{ font-size:10.5px; font-weight:700; color:var(--text-mute); text-transform:uppercase; letter-spacing:0.02em; margin-right:2px; }
  .cfg-rrx-preset-chip{
    font-family:var(--font-body); font-size:11.5px; font-weight:600; color:var(--text-hi);
    background:var(--glass); border:1px solid rgba(255,255,255,0.12); border-radius:999px;
    padding:5px 12px; cursor:pointer; transition:border-color .15s ease, background .15s ease, transform .15s ease;
  }
  .cfg-rrx-preset-chip:hover:not(:disabled){ border-color:var(--accent); background:var(--accent-soft); transform:translateY(-1px); }
  .cfg-rrx-preset-chip:disabled{ opacity:0.4; cursor:not-allowed; }

  /* ---- Carte "déclencheur" (onglet Réactions, mot/phrase/emoji) ----
     Remplace l'ancienne ligne unique surchargée (type+valeur+2 actions+
     actif+compteur+suppr tous alignés à l'horizontale, illisible sur les
     écrans moyens, cf. capture du 07/09) par une carte à deux étages :
     identité en haut, les deux actions clairement séparées en dessous. */
  .cfg-rrx-trigger-card{
    display:flex; flex-direction:column; gap:10px; background:rgba(255,255,255,0.03);
    border:1px solid rgba(255,255,255,0.1); border-radius:11px; padding:11px 13px;
  }
  .cfg-rrx-trigger-top{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
  .cfg-rrx-trigger-type{ flex:0 0 auto; width:auto; min-width:96px; }
  .cfg-rrx-trigger-value{ flex:1 1 180px; min-width:140px; font-weight:600; }
  .cfg-rrx-hitcount{ font-size:10.5px; color:var(--text-mute); flex-shrink:0; white-space:nowrap; }
  .cfg-rrx-active-toggle{
    display:flex; align-items:center; gap:5px; font-size:11px; font-weight:600; color:var(--text-mute);
    flex-shrink:0; white-space:nowrap; cursor:pointer;
  }
  .cfg-rrx-active-toggle input{ accent-color:var(--accent); width:14px; height:14px; cursor:pointer; }

  .cfg-rrx-trigger-actions{ display:grid; grid-template-columns:1fr 1fr; gap:10px; }
  @media (max-width: 640px){ .cfg-rrx-trigger-actions{ grid-template-columns:1fr; } }
  .cfg-rrx-action-block{
    display:flex; flex-direction:column; gap:6px; background:rgba(255,255,255,0.02);
    border:1px dashed rgba(255,255,255,0.1); border-radius:9px; padding:8px 10px;
    transition:border-color .15s ease, background .15s ease;
  }
  .cfg-rrx-action-block.is-on{ border-style:solid; border-color:var(--accent); background:var(--accent-soft); }
  .cfg-rrx-action-toggle{
    display:flex; align-items:center; gap:6px; font-size:12px; font-weight:700; color:var(--text-hi); cursor:pointer;
  }
  .cfg-rrx-action-toggle input{ accent-color:var(--accent); width:14px; height:14px; cursor:pointer; }
  .cfg-rrx-emoji-input{ width:100%; text-align:center; }
  .cfg-rrx-response-input{ width:100%; }

  /* ---- Liste de messages de réponse (demande du 07/09, "plein de messages
     sur une même réaction, tiré au hasard") : une ligne par variante, un
     bouton "+ Ajouter" en dessous, et l'indice "tiré au hasard" affiché
     uniquement s'il y a effectivement plusieurs variantes à tirer. ---- */
  .cfg-rrx-response-list{ display:flex; flex-direction:column; gap:6px; }
  .cfg-rrx-response-row{ display:flex; align-items:center; gap:6px; }
  .cfg-rrx-response-row .cfg-rrx-response-input{ flex:1 1 auto; min-width:0; }
  .cfg-rrx-msg-add{
    align-self:flex-start; font-family:var(--font-body); font-size:11px; font-weight:700; color:var(--accent);
    background:transparent; border:1px dashed rgba(255,255,255,0.18); border-radius:8px;
    padding:5px 10px; cursor:pointer; margin-top:6px; transition:border-color .15s ease, background .15s ease;
  }
  .cfg-rrx-msg-add:hover:not(:disabled){ border-color:var(--accent); background:var(--accent-soft); }
  .cfg-rrx-msg-add:disabled{ opacity:0.4; cursor:not-allowed; }
  .cfg-rrx-msg-hint{ font-size:10.5px; color:var(--text-mute); margin:4px 0 0; }
  /* Même note "tiré au hasard", affichée cette fois dans l'aperçu Discord
     sous le message du bot (cf. renderPreview côté script.js). */
  .cfg-rrx-preview-random-note{ font-size:10px; color:rgba(255,255,255,0.45); margin-top:4px; }

  /* ---- Aperçu animé du déclencheur (demande du 07/09) : le message du
     membre apparaît, PUIS la réaction s'installe dessous, PUIS le bot tape
     avant de révéler sa réponse — au lieu d'un rendu figé d'un coup. Rejoué
     en boucle par schedulePreviewReplay() (script.js) via un re-render
     périodique, chaque re-render remettant ces animations à zéro. ---- */
  .cfg-rrx-preview-msg{ display:flex; gap:10px; align-items:flex-start; }
  .cfg-rrx-preview-avatar{
    width:36px; height:36px; border-radius:50%; flex-shrink:0; display:flex; align-items:center; justify-content:center;
    font-size:16px; background:rgba(255,255,255,0.08);
    animation: cfgRrxFadeIn .25s ease both;
  }
  @keyframes cfgRrxFadeIn{ from{ opacity:0; transform:translateY(3px); } to{ opacity:1; transform:translateY(0); } }

  .cfg-rrx-preview-reactions{ margin-top:5px; }
  .cfg-rrx-preview-reaction-pill{
    display:inline-flex; align-items:center; gap:5px; font-size:11.5px; font-weight:600; color:#dbdee1;
    background:rgba(88,101,242,0.16); border:1px solid rgba(88,101,242,0.5); border-radius:8px; padding:2px 7px;
    opacity:0; transform:scale(0.4);
    animation: cfgRrxReactionPop .4s cubic-bezier(.34,1.56,.64,1) forwards;
    animation-delay: .55s;
  }
  .cfg-rrx-preview-reaction-emoji{ font-size:13px; line-height:1; }
  @keyframes cfgRrxReactionPop{
    0%{ opacity:0; transform:scale(0.4); }
    65%{ opacity:1; transform:scale(1.18); }
    100%{ opacity:1; transform:scale(1); }
  }

  /* Bulle bot : la zone de contenu superpose les points "en train d'écrire"
     et le texte final (même espace, l'un fondu vers l'autre) pour ne pas
     faire sauter la mise en page quand le texte apparaît. */
  .cfg-rrx-preview-bot-content{ position:relative; min-height:1.3em; }
  .cfg-rrx-preview-bot-text{
    opacity:0; transform:translateY(3px);
    animation: cfgRrxBotTextIn .3s ease forwards;
    animation-delay: 1.75s;
  }
  @keyframes cfgRrxBotTextIn{ to{ opacity:1; transform:translateY(0); } }

  .cfg-rrx-preview-typing{
    position:absolute; top:2px; left:0; display:inline-flex; align-items:center; gap:3px;
    padding:5px 9px; border-radius:10px; background:rgba(255,255,255,0.06);
    opacity:0;
    animation: cfgRrxTypingFade 1.75s ease forwards;
  }
  @keyframes cfgRrxTypingFade{
    0%{ opacity:0; }
    14%{ opacity:1; }
    80%{ opacity:1; }
    100%{ opacity:0; }
  }
  .cfg-rrx-typing-dot{
    width:5px; height:5px; border-radius:50%; background:rgba(255,255,255,0.55);
    animation: cfgRrxDotBounce .9s ease-in-out infinite;
  }
  .cfg-rrx-typing-dot:nth-child(2){ animation-delay:.15s; }
  .cfg-rrx-typing-dot:nth-child(3){ animation-delay:.3s; }
  @keyframes cfgRrxDotBounce{
    0%, 60%, 100%{ transform:translateY(0); opacity:.55; }
    30%{ transform:translateY(-3px); opacity:1; }
  }

  .cfg-rrx-preview-bot{
    opacity:0;
    animation: cfgRrxFadeIn .3s ease forwards;
    animation-delay: .5s;
  }

  @media (prefers-reduced-motion: reduce){
    .cfg-rrx-preview-avatar, .cfg-rrx-preview-reaction-pill, .cfg-rrx-preview-bot-text,
    .cfg-rrx-preview-typing, .cfg-rrx-typing-dot, .cfg-rrx-preview-bot{
      animation:none !important; opacity:1 !important; transform:none !important;
    }
    .cfg-rrx-preview-typing{ display:none; }
  }
  /* Ligne de puces "Variables" sous le champ réponse (cf. renderRrxVariablesRow
     dans script.js) — même look que .cfg-chip-row/.cfg-var-row utilisés pour
     les champs message classiques (welcome/leave/etc.), juste resserrée pour
     tenir dans le bloc d'action compact du déclencheur. */
  .cfg-rrx-var-row{ margin-top:2px; }

  /* ---- Colonne de droite : le "bloc" de création/édition demandé ---- */
  .cfg-rr-col-right{
    display:flex; flex-direction:column; gap:14px; background:var(--glass); border:1px solid rgba(255,255,255,0.08);
    border-radius:12px; padding:14px 16px;
  }
  .cfg-rr-section-title{ font-family:var(--font-display); font-weight:700; font-size:12.5px; color:var(--text-hi); }
  .cfg-rr-panel-head{ display:flex; align-items:center; justify-content:space-between; gap:10px; }
  .cfg-rr-section{ display:flex; flex-direction:column; gap:10px; padding-top:14px; border-top:1px solid rgba(255,255,255,0.08); }
  .cfg-rr-status-wrap{ min-height:16px; margin-top:-6px; } /* évite que le formulaire saute quand le statut apparaît */

  /* Champs du formulaire de panneau : libellé au-dessus, même recette que le reste du dashboard */
  .cfg-rr-field{ display:flex; flex-direction:column; gap:5px; min-width:0; }
  .cfg-rr-field > label{ font-size:10.5px; font-weight:700; letter-spacing:0.02em; text-transform:uppercase; color:var(--text-mute); }
  .cfg-rr-color{
    width:100%; height:38px; padding:3px; box-sizing:border-box; cursor:pointer;
    background:var(--glass); border:1px solid var(--line); border-radius:10px;
  }
  .cfg-rr-color::-webkit-color-swatch-wrapper{ padding:0; }
  .cfg-rr-color::-webkit-color-swatch{ border:none; border-radius:7px; }
  .cfg-rr-color::-moz-color-swatch{ border:none; border-radius:7px; }
  .cfg-rr-check{
    display:flex; align-items:center; gap:8px; align-self:end; min-height:38px;
    font-size:12px; color:var(--text-hi); cursor:pointer; user-select:none;
  }
  .cfg-rr-check input{ width:16px; height:16px; accent-color:var(--accent); cursor:pointer; flex-shrink:0; margin:0; }

  /* Bouton de suppression du panneau : action destructrice, visuellement distincte mais discrète */
  .cfg-rr-danger-btn{
    display:inline-flex; align-items:center; gap:6px; flex-shrink:0; cursor:pointer;
    font-family:var(--font-body); font-size:11.5px; font-weight:700; color:#f87171;
    background:rgba(220,38,38,0.10); border:1px solid rgba(220,38,38,0.35); border-radius:9px;
    padding:6px 11px; transition:background .15s ease, border-color .15s ease, color .15s ease;
  }
  .cfg-rr-danger-btn:hover{ background:rgba(220,38,38,0.20); border-color:rgba(220,38,38,0.6); color:#fca5a5; }

  /* ---- Colonne de droite (variant 3 zones) : aperçu Discord, à part de
     la config qu'elle reflète — cf. .cfg-rr-layout--3col plus haut. Même
     habillage carte que .cfg-rr-col-right pour que les deux se répondent
     visuellement, mais "sticky" pour rester visible en scrollant la liste
     de gauche sur les longs formulaires. ---- */
  .cfg-rr-col-preview{
    display:flex; flex-direction:column; gap:10px; background:var(--glass); border:1px solid rgba(255,255,255,0.08);
    border-radius:12px; padding:14px 16px; position:sticky; top:12px;
  }
  @media (max-width: 860px){ .cfg-rr-col-preview{ position:static; } }
  .cfg-rr-grid-2{ display:grid; grid-template-columns:1fr 1fr; gap:10px; }
  @media (max-width: 560px){ .cfg-rr-grid-2{ grid-template-columns:1fr; } }

  /* ---- Une "réaction" déjà ajoutée au panneau (rôle + emoji + label + style) ---- */
  .cfg-rr-reactions-list{ display:flex; flex-direction:column; gap:8px; }
  /* Grille à 4 colonnes : emoji | label (prend la place restante) | couleur du bouton | actions.
     Les actions ont leur propre colonne "auto" : elles ne peuvent plus être poussées hors de la
     ligne par le <select> (qui hérite de width:100% via select.cfg-ob-input, d'où le bug où
     le ✕ « Retirer » n'était plus cliquable). */
  .cfg-rr-reaction-row{
    display:grid; grid-template-columns:28px minmax(0,1fr) 96px auto; align-items:center; gap:8px;
    background:rgba(255,255,255,0.03); border:1px solid rgba(255,255,255,0.08);
    border-radius:10px; padding:7px 9px;
  }
  @media (max-width: 560px){
    .cfg-rr-reaction-row{ grid-template-columns:28px minmax(0,1fr) auto; }
    .cfg-rr-reaction-row .cfg-rr-reaction-style-select{ grid-column:2; }
    .cfg-rr-reaction-row .cfg-rr-reaction-actions{ grid-column:3; grid-row:1 / span 2; }
  }
  .cfg-rr-reaction-emoji{ font-size:17px; text-align:center; }
  .cfg-rr-reaction-row select.cfg-ob-input,
  .cfg-rr-reaction-row input.cfg-ob-input{ width:100%; min-width:0; padding:7px 10px; }
  .cfg-rr-reaction-row select.cfg-ob-input{ padding-right:28px; }
  .cfg-rr-reaction-actions{ display:flex; align-items:center; gap:4px; }
  .cfg-rr-reaction-actions .cfg-ob-icon-btn{ width:28px; height:28px; font-size:11px; flex-shrink:0; }

  /* ---- Formulaire "+ Ajouter une réaction" (rôle/emoji/label/style) ---- */
  .cfg-rr-add-reaction{
    display:grid; grid-template-columns:1fr 60px 1fr 120px auto; gap:8px; align-items:end;
    background:rgba(255,255,255,0.02); border:1px solid rgba(255,255,255,0.08); border-radius:9px; padding:10px;
  }
  @media (max-width: 700px){ .cfg-rr-add-reaction{ grid-template-columns:1fr 1fr; } }
  .cfg-rr-add-reaction .cfg-rr-new-btn{ white-space:nowrap; height:36px; padding:0 14px; }
  .cfg-rr-add-reaction label{ font-size:9.5px; font-weight:700; letter-spacing:0.02em; text-transform:uppercase; color:var(--text-mute); display:block; margin-bottom:3px; }

  .cfg-rr-preview-box{ background:#313338; border-radius:10px; padding:14px; display:flex; flex-direction:column; gap:10px; }
  .cfg-rr-embed{
    background:#2b2d31; border-left:4px solid #5865F2; border-radius:4px;
    padding:10px 14px; max-width:100%; box-sizing:border-box;
  }
  .cfg-rr-embed-title{ font-weight:700; color:#f2f3f5; font-size:14px; line-height:1.3; overflow-wrap:anywhere; }
  .cfg-rr-embed-desc{ color:#dbdee1; font-size:12.5px; line-height:1.4; margin-top:6px; white-space:pre-wrap; overflow-wrap:anywhere; }
  .cfg-rr-embed-buttons{ display:flex; flex-wrap:wrap; gap:7px; }
  .cfg-rr-embed-select{
    display:flex; align-items:center; justify-content:space-between; gap:8px; max-width:340px;
    background:#1e1f22; border:1px solid #1e1f22; border-radius:4px; padding:9px 12px;
    color:#b5bac1; font-size:12.5px;
  }
  .cfg-rr-preview-empty{ font-size:11px; color:rgba(255,255,255,0.5); text-align:center; padding:8px 0; }

  .cfg-rr-publish-row{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
  .cfg-rr-publish-row .cfg-ob-input{ max-width:220px; }

  /* ════════════════════════════════════════════════════════════════════
     MODULE TICKETS (.cfg-tk-*) — onglets Catégories/Blacklist/Statistiques
     (cf. script.js#bindTicketsCategoriesBuilder/bindTicketsBlacklistBuilder/
     bindTicketsStatsView). Réutilise volontairement .cfg-rr-layout/
     .cfg-rr-col-left/.cfg-rr-col-right/.cfg-rr-new-btn/.cfg-rr-empty-list/
     .cfg-rr-toolbar* (roles-reactions, juste au-dessus) pour la structure
     générale — seuls les éléments propres à Tickets (liste de catégories,
     formulaire, blacklist, cartes stats) ont leur propre style ici.
     ════════════════════════════════════════════════════════════════════ */
  .module-config-tk-field{ display:flex; flex-direction:column; gap:8px; }
  .cfg-tk-root{ display:flex; flex-direction:column; gap:12px; }

  /* ---- Liste de catégories (colonne de gauche) ---- */
  .cfg-tk-list-row{ display:flex; align-items:center; gap:6px; width:100%; }
  .cfg-tk-list-move{ display:flex; flex-direction:column; gap:2px; flex-shrink:0; }
  .cfg-tk-list-move .cfg-ob-icon-btn{ width:20px; height:16px; padding:0; font-size:9px; line-height:1; }
  .cfg-tk-list-item{
    display:flex; align-items:center; gap:8px; text-align:left; width:100%; cursor:pointer;
    background:var(--glass); border:1px solid rgba(255,255,255,0.08); border-radius:10px;
    padding:9px 11px; font-family:var(--font-body); font-size:12.5px; font-weight:600; color:var(--text-hi);
    transition:border-color .15s ease, background .15s ease;
  }
  .cfg-tk-list-item:hover{ border-color:rgba(255,255,255,0.18); }
  .cfg-tk-list-item.is-active{ border-color:var(--accent); background:var(--accent-soft); }
  .cfg-tk-list-item em{ font-style:normal; color:var(--text-mute); font-weight:500; margin-left:4px; }
  .cfg-tk-dot{ width:10px; height:10px; border-radius:50%; flex-shrink:0; box-shadow:0 0 0 2px rgba(255,255,255,0.08) inset; }

  /* ---- Formulaire catégorie (colonne de droite) ---- */
  .cfg-tk-form{
    display:flex; flex-direction:column; gap:12px; background:var(--glass); border:1px solid rgba(255,255,255,0.08);
    border-radius:12px; padding:14px 16px;
  }
  .cfg-tk-form-row{ display:flex; flex-direction:column; gap:5px; }
  .cfg-tk-form-row label{ font-size:9.5px; font-weight:700; letter-spacing:0.02em; text-transform:uppercase; color:var(--text-mute); }
  .cfg-tk-form-row--split{ display:grid; grid-template-columns:1fr 1fr; gap:10px; }
  @media (max-width: 560px){ .cfg-tk-form-row--split{ grid-template-columns:1fr; } }
  .cfg-tk-color-input{ padding:2px; height:34px; cursor:pointer; }
  .cfg-tk-toggle-label{ display:flex; align-items:center; gap:6px; font-size:12px; font-weight:600; color:var(--text-hi); cursor:pointer; margin-top:16px; }
  .cfg-tk-toggle-label input{ accent-color:var(--accent); width:14px; height:14px; cursor:pointer; }

  /* ---- Questionnaire pré-ticket (jusqu'à 5 questions) ---- */
  .cfg-tk-questions{ display:flex; flex-direction:column; gap:6px; margin-bottom:6px; }
  .cfg-tk-question-row{ display:flex; align-items:center; gap:6px; }
  .cfg-tk-question-row .cfg-ob-input{ flex:1 1 auto; min-width:0; }
  .cfg-tk-q-required{ display:flex; align-items:center; gap:4px; font-size:10.5px; font-weight:600; color:var(--text-mute); white-space:nowrap; cursor:pointer; flex-shrink:0; }
  .cfg-tk-q-required input{ accent-color:var(--accent); width:13px; height:13px; cursor:pointer; }

  .cfg-tk-form-actions{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-top:4px; }

  /* Modèles de catégorie (chips, création uniquement) */
  .cfg-tk-templates{ display:flex; flex-wrap:wrap; gap:6px; }
  .cfg-tk-template-chip{
    padding:6px 12px; border-radius:999px; border:1px solid rgba(255,255,255,0.14);
    background:rgba(255,255,255,0.04); color:var(--text-hi); font-size:11.5px; font-weight:600;
    cursor:pointer; transition:border-color .15s ease, background .15s ease;
  }
  .cfg-tk-template-chip:hover{ border-color:var(--accent); background:var(--accent-soft); }

  /* Sélecteur de jours (disponibilité par horaires) */
  .cfg-tk-day-picker{ display:flex; flex-wrap:wrap; gap:6px; }
  .cfg-tk-day-btn{
    min-width:42px; padding:6px 0; border-radius:8px; border:1px solid rgba(255,255,255,0.14);
    background:rgba(255,255,255,0.04); color:var(--text-mute); font-size:11px; font-weight:700;
    text-transform:uppercase; letter-spacing:.02em; cursor:pointer; transition:border-color .15s ease, background .15s ease, color .15s ease;
  }
  .cfg-tk-day-btn:hover{ border-color:rgba(255,255,255,0.28); }
  .cfg-tk-day-btn.is-active{ border-color:var(--accent); background:var(--accent-soft); color:var(--text-hi); }
  .cfg-tk-schedule-row{ gap:8px; }
  .cfg-tk-schedule-row[hidden]{ display:none; }
  .cfg-tk-schedule-times{ margin-top:4px; }

  /* ---- Blacklist ---- */
  .cfg-tk-bl-list{ display:flex; flex-direction:column; gap:6px; }
  .cfg-tk-bl-row{
    display:flex; align-items:center; gap:10px; background:rgba(255,255,255,0.03);
    border:1px dashed rgba(255,255,255,0.12); border-radius:9px; padding:7px 10px;
  }
  .cfg-tk-bl-id{ font-family:var(--font-mono, monospace); font-size:11.5px; font-weight:700; color:var(--text-hi); flex-shrink:0; }
  .cfg-tk-bl-reason{ font-size:11.5px; color:var(--text-mute); flex:1 1 auto; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .cfg-tk-bl-form{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-top:4px; }
  .cfg-tk-bl-form input.cfg-ob-input{ flex:1 1 180px; min-width:140px; }

  /* ---- Statistiques (lecture seule) ---- */
  .cfg-tk-stats-grid{ display:grid; grid-template-columns:repeat(auto-fit, minmax(120px, 1fr)); gap:10px; }
  .cfg-tk-stat-card{
    display:flex; flex-direction:column; gap:4px; background:var(--glass); border:1px solid rgba(255,255,255,0.08);
    border-radius:11px; padding:11px 13px;
  }
  .cfg-tk-stat-card span{ font-size:9.5px; font-weight:700; letter-spacing:0.02em; text-transform:uppercase; color:var(--text-mute); }
  .cfg-tk-stat-card strong{ font-family:var(--font-display); font-size:18px; color:var(--text-hi); }
  .cfg-tk-stats-cols{ display:grid; grid-template-columns:1fr 1fr; gap:16px; margin-top:6px; }
  @media (max-width: 640px){ .cfg-tk-stats-cols{ grid-template-columns:1fr; } }
  .cfg-tk-stats-cols h4{ font-family:var(--font-display); font-size:11.5px; font-weight:700; color:var(--text-hi); margin:0 0 8px; }
  .cfg-tk-stat-row{
    display:flex; align-items:center; justify-content:space-between; gap:8px; font-size:11.5px; color:var(--text-mute);
    padding:5px 0; border-bottom:1px solid rgba(255,255,255,0.06);
  }
  .cfg-tk-stat-row strong{ color:var(--text-hi); font-weight:700; }

  /* ════════════════════════════════════════════════════════════════════
     JSON BUILDER (.cfg-jb-*) — remplace un textarea JSON brut par des
     cartes/formulaire (cf. script.js#renderFieldInner "f.builder" +
     bindJsonBuilders). Même vocabulaire visuel que le builder d'onboarding
     (.cfg-ob-*) juste au-dessus — cartes en dégradé léger, sous-champs
     séparés par un liseré pointillé — pour que les deux "constructeurs"
     du site se ressentent comme UNE seule famille de composants, pas deux
     designs concurrents.
     ════════════════════════════════════════════════════════════════════ */
  .module-config-jb-field{ display:flex; flex-direction:column; gap:8px; }
  .cfg-jb-root{ display:flex; flex-direction:column; gap:10px; }
  .cfg-jb-empty{ font-size:11.5px; color:var(--text-mute); padding:6px 0; }

  /* ---- Champs internes : même recette que .cfg-input/.cfg-ob-input, pour
     qu'un champ "Prix" dans une carte boutique ne jure pas à côté d'un
     champ "Prix" classique ailleurs dans le même panneau. ---- */
  input.cfg-jb-input, select.cfg-jb-input, textarea.cfg-jb-input{
    font-family:var(--font-body); font-size:12.5px; color:var(--text-hi);
    background:var(--glass); border:1px solid var(--line); border-radius:10px;
    padding:9px 12px; outline:none; width:100%; box-sizing:border-box; resize:vertical;
    transition:border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
  }
  .cfg-jb-input::placeholder{ color:var(--text-mute); opacity:0.75; }
  .cfg-jb-input:hover:not(:disabled){ border-color:rgba(148,163,184,0.5); }
  .cfg-jb-input:focus{ border-color:var(--accent); background:var(--glass-strong); box-shadow:0 0 0 3px rgba(90,125,250,0.15); }
  select.cfg-jb-input{
    appearance:none; -webkit-appearance:none; cursor:pointer;
    background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none'><path d='M5.5 7.5l4.5 4.5 4.5-4.5' stroke='%237c8598' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/></svg>");
    background-repeat:no-repeat; background-position:right 10px center; padding-right:30px;
  }
  textarea.cfg-jb-input{ min-height:52px; line-height:1.4; font-family:var(--font-mono, monospace); font-size:11.5px; }
  /* Sous-champ JSON imbriqué (ex: "rewards" d'un coffre) resté volontairement
     brut (structure trop profonde pour une carte de plus) — bordure rouge
     douce le temps que la personne finit de corriger une syntaxe invalide,
     jamais bloquant : la dernière version valide reste celle envoyée. */
  textarea.cfg-jb-input.is-invalid{ border-color:#dc2626; box-shadow:0 0 0 3px rgba(220,38,38,0.12); }

  /* ---- Cartes (kind:'list') ---- */
  .cfg-jb-list{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:10px; }
  .cfg-jb-card{
    display:flex; flex-direction:column; gap:10px;
    background:linear-gradient(180deg, rgba(255,255,255,0.06), rgba(255,255,255,0.015));
    border:1px solid var(--glass-border, var(--line)); border-radius:14px; padding:14px;
    box-shadow:0 1px 0 rgba(255,255,255,0.05) inset, 0 8px 18px -14px rgba(0,0,0,0.5);
    transition:border-color 0.15s ease;
  }
  .cfg-jb-card:hover{ border-color:rgba(255,255,255,0.18); }
  .cfg-jb-card-head{ display:flex; align-items:center; justify-content:space-between; gap:8px; }
  .cfg-jb-card-title{ font-family:var(--font-display); font-weight:700; font-size:13px; color:var(--text-hi); }
  .cfg-jb-remove-btn{
    width:24px; height:24px; border-radius:7px; border:1px solid var(--line); flex-shrink:0;
    background:rgba(255,255,255,0.06); color:var(--text-mute); cursor:pointer;
    display:flex; align-items:center; justify-content:center; font-size:10px;
    transition:background 0.15s ease, color 0.15s ease;
  }
  .cfg-jb-remove-btn:hover{ background:rgba(220,38,38,0.12); color:#dc2626; }

  /* Grille de sous-champs : 2 colonnes dès que la place le permet, colonnes
     "xs" (emoji) capées courtes pour ne pas gâcher la largeur d'une carte
     entière sur un champ de 2-3 caractères. */
  .cfg-jb-card-grid{ display:grid; grid-template-columns:repeat(auto-fit, minmax(150px, 1fr)); gap:10px 12px; }
  .cfg-jb-subfield{ display:flex; flex-direction:column; gap:5px; }
  .cfg-jb-subfield label{ font-size:10.5px; font-weight:700; letter-spacing:0.02em; text-transform:uppercase; color:var(--text-mute); }
  .cfg-jb-optional{ text-transform:none; font-weight:500; opacity:0.75; }
  .cfg-jb-subfield--json{ grid-column:1 / -1; }
  .cfg-jb-hint{ font-size:10px; color:var(--text-mute); opacity:0.8; line-height:1.35; margin:0; }
  .cfg-jb-col-xs{ max-width:90px; text-align:center; font-size:15px; }

  /* ---- Sous-liste imbriquée (type:'sublist', dans la grille de la modale)
     — remplace un champ type:'json' brut par de petites cartes répétables
     (ex: récompenses d'un coffre, objets requis d'une recette) : mêmes
     familles visuelles que .cfg-jb-add-btn/.cfg-jb-remove-btn ci-dessus,
     un ton plus discret (encadré, fond légèrement distinct) pour marquer
     l'imbrication à l'intérieur de la carte du champ parent. ---- */
  .cfg-jb-sublist{ display:flex; flex-direction:column; gap:10px; }
  .cfg-jb-subrows{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:8px; }
  .cfg-jb-subrow{
    display:flex; align-items:flex-start; gap:8px;
    border:1px solid var(--line); border-radius:10px; padding:10px;
    background:rgba(255,255,255,0.03);
  }
  .cfg-jb-subrow-grid{ flex:1; display:grid; grid-template-columns:repeat(auto-fit, minmax(120px, 1fr)); gap:8px 10px; }
  .cfg-jb-sub-field{ display:flex; flex-direction:column; gap:4px; }
  .cfg-jb-sub-field label{ font-size:10px; font-weight:700; letter-spacing:0.02em; text-transform:uppercase; color:var(--text-mute); }
  .cfg-jb-sub-remove-btn{
    width:22px; height:22px; border-radius:6px; border:1px solid var(--line); flex-shrink:0; margin-top:2px;
    background:rgba(255,255,255,0.06); color:var(--text-mute); cursor:pointer;
    display:flex; align-items:center; justify-content:center; font-size:9px;
    transition:background 0.15s ease, color 0.15s ease;
  }
  .cfg-jb-sub-remove-btn:hover{ background:rgba(220,38,38,0.12); color:#dc2626; }
  .cfg-jb-sub-add-btn{
    align-self:flex-start;
    font-family:var(--font-body); font-size:11px; font-weight:700; color:var(--text-hi);
    background:rgba(255,255,255,0.06); border:1px dashed var(--line); border-radius:9px;
    padding:7px 12px; cursor:pointer; white-space:nowrap;
    transition:background 0.15s ease, border-color 0.15s ease;
  }
  .cfg-jb-sub-add-btn:hover{ background:rgba(255,255,255,0.12); border-color:var(--accent); }

  /* ---- Paires clé/valeur (kind:'map') ---- */
  .cfg-jb-map-head{
    display:grid; grid-template-columns:1fr 1fr 26px; gap:8px;
    font-size:10.5px; font-weight:700; letter-spacing:0.02em; text-transform:uppercase; color:var(--text-mute);
    padding:0 2px;
  }
  .cfg-jb-map-rows{ display:flex; flex-direction:column; gap:6px; }
  .cfg-jb-map-row{ display:grid; grid-template-columns:1fr 1fr 26px; gap:8px; align-items:center; }

  /* ---- Bouton "+ Ajouter" — même famille que .cfg-ob-add-btn ---- */
  .cfg-jb-color{ width:56px; height:36px; padding:2px; cursor:pointer; border-radius:8px; }
  .cfg-jb-add-btn{
    align-self:flex-start;
    font-family:var(--font-body); font-size:11.5px; font-weight:700; color:#fff;
    background:linear-gradient(135deg, var(--accent), var(--accent-deep));
    border:none; border-radius:10px; padding:8px 14px; cursor:pointer; white-space:nowrap;
    transition:transform 0.15s ease, box-shadow 0.15s ease;
  }
  .cfg-jb-add-btn:hover{ transform:translateY(-1px); box-shadow:0 8px 16px -10px rgba(90,125,250,0.5); }

  /* ---- Résumé dans la page (kind:'list'/'map') — remplace les anciennes
     cartes complètes .cfg-jb-card/.cfg-jb-map-row : une ligne cliquable par
     objet, l'édition détaillée vivant désormais dans la modale (.cfg-jbm-*
     ci-dessous). ---- */
  .cfg-jb-rows{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:6px; }
  .cfg-jb-row{ display:flex; align-items:stretch; gap:6px; }
  .cfg-jb-row-main{
    flex:1; display:flex; flex-direction:column; gap:2px; text-align:left; cursor:pointer;
    background:rgba(255,255,255,0.55); border:1px solid var(--line); border-radius:12px;
    padding:9px 14px; font-family:var(--font-body);
    transition:border-color 0.15s ease, background 0.15s ease, transform 0.15s ease;
  }
  .cfg-jb-row-main:hover{ border-color:var(--accent); background:rgba(255,255,255,0.8); transform:translateY(-1px); }
  .cfg-jb-row-title{ font-weight:700; font-size:12.5px; color:var(--text-hi); }
  .cfg-jb-row-sub{ font-size:10.5px; color:var(--text-mute); }

  /* ════════════════════════════════════════════════════════════════════
     MODALE JSON BUILDER (.cfg-jbm-*) — même recette visuelle que la popup
     abonnement (.plans-overlay/.plans-modal, cf. plus haut) pour que
     "créer un objet" ressente comme une action de PREMIER RANG du site,
     pas un popup improvisé. Réutilise directement les keyframes globales
     plansFade / successPop / successRing / successDraw déjà définies plus
     haut plutôt que d'en redéclarer des équivalentes.
     ════════════════════════════════════════════════════════════════════ */
  .cfg-jbm-overlay{
    position:fixed; inset:0; z-index:95;
    background:rgba(20,26,41,0.38); backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px);
    opacity:0; pointer-events:none; transition:opacity 0.3s ease;
  }
  .cfg-jbm-overlay.open{ opacity:1; pointer-events:auto; }
  .cfg-jbm-modal{
    position:fixed; z-index:97; top:50%; left:50%;
    width:min(640px, 92vw); max-height:86vh; overflow-y:auto;
    background:var(--glass-strong); border:1px solid var(--glass-border);
    backdrop-filter:blur(26px); -webkit-backdrop-filter:blur(26px);
    border-radius:24px; padding:28px 30px 24px;
    box-shadow:0 30px 70px -20px rgba(20,26,60,0.45), inset 0 1px 0 rgba(255,255,255,0.6);
    opacity:0; pointer-events:none;
    transform:translate(-50%,-48%) scale(0.94);
    transition:opacity 0.36s cubic-bezier(.16,.84,.44,1), transform 0.36s cubic-bezier(.16,.84,.44,1);
  }
  .cfg-jbm-modal.open{ opacity:1; pointer-events:auto; transform:translate(-50%,-50%) scale(1); }
  .cfg-jbm-close{
    position:absolute; top:14px; right:14px; width:30px; height:30px; border-radius:9px;
    border:1px solid var(--line); background:rgba(255,255,255,0.6); color:var(--text-mute);
    font-size:14px; line-height:1; cursor:pointer; display:flex; align-items:center; justify-content:center;
    transition:background 0.15s ease, color 0.15s ease;
  }
  .cfg-jbm-close:hover{ background:rgba(239,68,68,0.12); color:#dc2626; }

  .cfg-jbm-head{ margin-bottom:18px; padding-right:26px; }
  .cfg-jbm-eyebrow{
    display:block; font-size:10.5px; font-weight:700; letter-spacing:0.04em; text-transform:uppercase;
    color:var(--accent-deep); margin-bottom:4px;
  }
  .cfg-jbm-title{ font-family:var(--font-display); font-size:19px; font-weight:800; color:var(--text-hi); margin:0; }

  .cfg-jbm-step{ animation:plansFade 0.35s ease; }

  /* ---- Étape 1 : cartes de type ---- */
  .cfg-jbm-type-grid{ display:grid; grid-template-columns:repeat(auto-fit, minmax(160px, 1fr)); gap:10px; }
  .cfg-jbm-type-card{
    display:flex; flex-direction:column; align-items:flex-start; gap:4px; text-align:left; cursor:pointer;
    background:rgba(255,255,255,0.55); border:1.5px solid var(--line); border-radius:14px;
    padding:14px 14px 12px; font-family:var(--font-body);
    transition:border-color 0.15s ease, background 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
  }
  .cfg-jbm-type-card:hover{ border-color:var(--accent); background:rgba(255,255,255,0.85); transform:translateY(-2px); box-shadow:0 10px 22px -14px rgba(90,125,250,0.45); }
  .cfg-jbm-type-card.is-selected{ border-color:var(--accent); background:var(--accent-soft); }
  .cfg-jbm-type-emoji{ font-size:24px; line-height:1; }
  .cfg-jbm-type-label{ font-weight:700; font-size:13px; color:var(--text-hi); }
  .cfg-jbm-type-desc{ font-size:10.5px; color:var(--text-mute); line-height:1.35; }

  /* ---- Étape 2 : pill "type choisi" + grille de champs ---- */
  .cfg-jbm-type-pill{
    display:inline-flex; align-items:center; gap:10px; margin-bottom:16px;
    background:var(--accent-soft); border-radius:999px; padding:6px 8px 6px 14px;
    font-size:12px; font-weight:700; color:var(--accent-deep);
  }
  .cfg-jbm-type-pill-change{
    font-family:var(--font-body); font-size:10.5px; font-weight:700; color:#fff;
    background:var(--accent-deep); border:none; border-radius:999px; padding:5px 11px; cursor:pointer;
    transition:opacity 0.15s ease;
  }
  .cfg-jbm-type-pill-change:hover{ opacity:0.85; }
  .cfg-jbm-grid{ display:grid; grid-template-columns:repeat(auto-fit, minmax(180px, 1fr)); gap:14px 16px; }
  .cfg-jbm-field{ display:flex; flex-direction:column; gap:5px; }
  .cfg-jbm-field label{ font-size:10.5px; font-weight:700; letter-spacing:0.02em; text-transform:uppercase; color:var(--text-mute); }
  .cfg-jbm-field--json{ grid-column:1 / -1; }
  .cfg-jbm-error{ font-size:11.5px; font-weight:600; color:#dc2626; margin:12px 0 0; min-height:14px; }

  /* ---- Pied de modale ---- */
  .cfg-jbm-foot{ display:flex; align-items:center; gap:10px; margin-top:24px; }
  .cfg-jbm-foot-spacer{ flex:1; }
  .cfg-jbm-btn{
    font-family:var(--font-body); font-size:12.5px; font-weight:700; border-radius:11px;
    padding:9px 18px; cursor:pointer; border:none; white-space:nowrap;
    transition:transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease, opacity 0.15s ease;
  }
  .cfg-jbm-btn--primary{
    color:#fff; background:linear-gradient(135deg, var(--accent), var(--accent-deep));
  }
  .cfg-jbm-btn--primary:hover{ transform:translateY(-1px); box-shadow:0 8px 16px -10px rgba(90,125,250,0.5); }
  .cfg-jbm-btn--ghost{ color:var(--text-mute); background:rgba(255,255,255,0.55); border:1px solid var(--line); }
  .cfg-jbm-btn--ghost:hover{ background:rgba(255,255,255,0.8); color:var(--text-hi); }
  .cfg-jbm-btn--danger{ color:#dc2626; background:rgba(220,38,38,0.10); }
  .cfg-jbm-btn--danger:hover{ background:rgba(220,38,38,0.18); }

  /* ---- Confirmation de succès — réutilise .success-check tel quel ---- */
  .cfg-jbm-success{
    display:flex; flex-direction:column; align-items:center; gap:12px;
    padding:26px 10px 10px; text-align:center; animation:successStepIn 0.45s cubic-bezier(.16,.84,.44,1);
  }
  .cfg-jbm-success p{ font-family:var(--font-display); font-weight:700; font-size:14px; color:var(--text-hi); margin:0; }

  @media (max-width:640px){
    .cfg-jbm-modal{ width:94vw; padding:22px 18px 18px; }
    .cfg-jbm-type-grid{ grid-template-columns:repeat(auto-fit, minmax(130px, 1fr)); }
  }

  /* ====================================================================
     BLOCS DE JEU (onglet "Jeux 🎰", ex: Route de l'infini) — 1 tuile
     cliquable par jeu (cf. gameBlocks du CONFIG_SCHEMA côté index.js et
     renderGameBlockTile/renderGameBlockPopup/bindGameBlocks côté
     script.js). La tuile ouvre une popup en grand qui répartit ses champs
     en zones : config + messages à gauche, récompenses / aperçu /
     cooldowns & gages à droite. Réutilise le vocabulaire visuel commun
     (var(--glass)/var(--line)/var(--accent)) et le même patron de popup
     que .plans-overlay/.plans-modal plus haut, pour rester cohérent avec
     le reste du dashboard.
     ==================================================================== */
  .module-config-gameblock-grid{
    display:grid; grid-template-columns:repeat(auto-fill, minmax(220px, 1fr));
    gap:14px; margin-bottom:18px;
  }
  .module-config-gameblock-tile{
    display:flex; flex-direction:column; gap:8px; text-align:left; cursor:pointer;
    background:linear-gradient(165deg, rgba(255,255,255,0.9), rgba(237,242,255,0.55));
    border:1.5px solid var(--glass-border); border-radius:18px; padding:16px 18px;
    transition:transform 0.2s cubic-bezier(.2,.8,.2,1), box-shadow 0.2s ease, border-color 0.2s ease;
  }
  html.theme-dark .module-config-gameblock-tile{
    background:linear-gradient(165deg, rgba(255,255,255,0.06), rgba(255,255,255,0.03));
  }
  .module-config-gameblock-tile:hover, .module-config-gameblock-tile:focus-visible{
    transform:translateY(-3px); box-shadow:0 16px 32px -18px rgba(31,41,88,0.35); border-color:var(--accent);
    outline:none;
  }
  .module-config-gameblock-tile-top{ display:flex; align-items:center; justify-content:space-between; gap:8px; }
  .module-config-gameblock-tile-icon{ font-size:26px; line-height:1; }
  .module-config-gameblock-tile-title{ font-family:var(--font-display); font-weight:800; font-size:14.5px; color:var(--text-hi); }
  .module-config-gameblock-tile-subtitle{ font-size:11.5px; color:var(--text-mute); }
  .module-config-gameblock-tile-cta{
    margin-top:2px; font-size:11.5px; font-weight:700; color:var(--accent-deep);
  }

  .module-config-gameblock-modal{
    position:fixed; inset:0; z-index:210;
    opacity:0; pointer-events:none; transition:opacity 0.25s ease;
  }
  .module-config-gameblock-modal.is-open{ opacity:1; pointer-events:auto; }
  .module-config-gameblock-modal-backdrop{
    position:absolute; inset:0; background:rgba(20,26,41,0.38);
    backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px);
  }
  .module-config-gameblock-modal-box{
    position:absolute; z-index:1; top:50%; left:50%; transform:translate(-50%,-48%) scale(0.96);
    width:min(920px, 94vw); max-height:88vh; overflow-y:auto;
    background:var(--glass-strong); border:1px solid var(--glass-border);
    backdrop-filter:blur(26px); -webkit-backdrop-filter:blur(26px);
    border-radius:24px; padding:26px 30px 30px;
    box-shadow:0 30px 70px -20px rgba(20,26,60,0.45), inset 0 1px 0 rgba(255,255,255,0.6);
    transition:transform 0.28s cubic-bezier(.16,.84,.44,1);
  }
  .module-config-gameblock-modal.is-open .module-config-gameblock-modal-box{ transform:translate(-50%,-50%) scale(1); }
  .module-config-gameblock-modal-head{
    display:flex; align-items:center; gap:10px; margin-bottom:18px; padding-right:34px;
  }
  .module-config-gameblock-modal-icon{ font-size:22px; line-height:1; }
  .module-config-gameblock-modal-title{ font-family:var(--font-display); font-weight:800; font-size:17px; color:var(--text-hi); }
  .module-config-gameblock-modal-close{
    position:absolute; top:20px; right:22px; width:32px; height:32px; border-radius:10px;
    border:1px solid var(--line); background:rgba(255,255,255,0.6); color:var(--text-mute);
    font-size:16px; line-height:1; cursor:pointer; display:flex; align-items:center; justify-content:center;
    transition:background 0.15s ease, color 0.15s ease;
  }
  .module-config-gameblock-modal-close:hover{ background:rgba(239,68,68,0.12); color:#dc2626; }
  .module-config-gameblock-modal-body{
    display:grid; grid-template-columns:1.1fr 1fr; gap:22px; align-items:start;
  }
  @media (max-width:760px){
    .module-config-gameblock-modal-body{ grid-template-columns:1fr; }
  }
  .module-config-gameblock-col{ display:flex; flex-direction:column; gap:14px; min-width:0; }
  .module-config-gameblock-zone-label{
    font-family:var(--font-display); font-weight:700; font-size:11.5px; letter-spacing:0.02em;
    text-transform:uppercase; color:var(--text-mute); margin-bottom:-4px;
  }
  .module-config-gameblock-preview{
    background:rgba(255,255,255,0.5); border:1px solid var(--line); border-radius:14px; padding:12px 14px;
  }
  html.theme-dark .module-config-gameblock-preview{ background:rgba(255,255,255,0.04); }
  .module-config-gameblock-preview-select{
    font-size:11px; border-radius:8px; border:1px solid var(--line); background:var(--glass);
    color:var(--text); padding:3px 8px;
  }

