:root{
  --void:#0A0C0E;
  --panel:#131619;
  --panel-raised:#191D21;
  --hair:#23282D;
  --hair-strong:#31373D;
  --text-1:#ECEFF2;
  --text-2:#8A9198;
  --text-3:#565C62;
  --signal:#FF8B3D;
  --signal-dim:#3D2A1A;
  --ok:#3ED9A0;
  --ok-dim:#132B23;
  --warn:#FFC94D;
  --warn-dim:#2E2610;
  --danger:#FF6459;
  --danger-dim:#2E1613;
  --info:#5B9DFF;
  --info-dim:#152238;
}
*{box-sizing:border-box; margin:0; padding:0;}
html,body{height:100%; overflow:hidden;}
body{
  background:var(--void);
  color:var(--text-1);
  font-family:'Inter', sans-serif;
  -webkit-font-smoothing:antialiased;
  min-height:100vh;
}
::selection{background:var(--signal); color:var(--void);}
a{color:inherit; text-decoration:none;}
.mono{font-family:'JetBrains Mono', monospace;}
.display{font-family:'Space Grotesk', sans-serif;}
:focus-visible{outline:2px solid var(--signal); outline-offset:2px;}
button, input, select{font-family:inherit;}

.shell{display:flex; height:100vh;}

/* ---- SIDEBAR ---- */
.side{
  width:220px; flex-shrink:0;
  background:var(--panel);
  border-right:1px solid var(--hair);
  display:flex; flex-direction:column;
  padding:24px 16px;
  position:sticky; top:0; height:100vh; overflow-y:auto;
}
.brand{display:flex; align-items:center; gap:10px; padding:0 8px 28px;}
.brand-mark{
  width:26px; height:26px; border-radius:6px;
  background:var(--signal);
  display:flex; align-items:center; justify-content:center;
  font-family:'Space Grotesk', sans-serif; font-weight:700; font-size:14px;
  color:var(--void);
}
.brand-name{font-family:'Space Grotesk', sans-serif; font-weight:600; font-size:15px; letter-spacing:0.2px;}
nav{display:flex; flex-direction:column; gap:2px;}
.nav-item{
  display:flex; align-items:center; gap:11px;
  padding:9px 10px; border-radius:7px;
  font-size:13.5px; color:var(--text-2);
  transition:background 0.15s ease, color 0.15s ease;
}
.nav-item i{font-size:17px; width:17px; text-align:center;}
.nav-item:hover{background:var(--panel-raised); color:var(--text-1);}
.nav-item.active{background:var(--signal-dim); color:var(--signal);}
.side-foot{
  margin-top:auto; padding:12px 10px;
  border-top:1px solid var(--hair);
  display:flex; align-items:center; gap:8px;
  font-size:12px; color:var(--text-3);
}
.dot-live{
  width:6px; height:6px; border-radius:50%; flex-shrink:0;
  background:var(--ok);
  animation:pulse 2.2s infinite;
}
@keyframes pulse{
  0%{box-shadow:0 0 0 0 rgba(62,217,160,0.45);}
  70%{box-shadow:0 0 0 6px rgba(62,217,160,0);}
  100%{box-shadow:0 0 0 0 rgba(62,217,160,0);}
}

/* ---- MAIN ---- */
main{flex:1; min-width:0; padding:32px 40px; height:100vh; overflow-y:auto;}
.top{
  display:flex; align-items:flex-end; justify-content:space-between;
  margin-bottom:28px; flex-wrap:wrap; gap:12px;
}
h1{font-family:'Space Grotesk', sans-serif; font-weight:600; font-size:22px; letter-spacing:-0.2px;}
.sub{color:var(--text-2); font-size:13px; margin-top:4px;}
.badge-live{
  display:flex; align-items:center; gap:7px;
  background:var(--panel); border:1px solid var(--hair);
  padding:7px 13px; border-radius:99px;
  font-family:'JetBrains Mono', monospace; font-size:12px; color:var(--text-2);
}

/* metric cards */
.metrics{
  display:grid; grid-template-columns:repeat(4, 1fr);
  gap:1px; background:var(--hair);
  border:1px solid var(--hair); border-radius:10px;
  overflow:hidden; margin-bottom:28px;
}
.metric{background:var(--panel); padding:18px 20px;}
.metric-label{font-size:12px; color:var(--text-2); margin-bottom:8px;}
.metric-value{font-family:'JetBrains Mono', monospace; font-weight:600; font-size:26px;}
.metric-value.ok{color:var(--ok);}
.metric-value.warn{color:var(--warn);}
.metric-value.danger{color:var(--danger);}

/* generic panel */
.panel{
  background:var(--panel); border:1px solid var(--hair); border-radius:10px;
  padding:20px 24px; margin-bottom:28px;
}
.panel-head{
  display:flex; align-items:center; justify-content:space-between;
  margin-bottom:18px; flex-wrap:wrap; gap:8px;
}
.panel-title{font-family:'Space Grotesk', sans-serif; font-weight:500; font-size:14.5px;}
.panel-title .mono{color:var(--text-2); font-size:12.5px; margin-left:8px; font-weight:400;}
.panel-desc{color:var(--text-2); font-size:12.5px; margin-top:4px;}

/* batch lights */
.lights{display:flex; gap:8px; margin-bottom:14px;}
.light-cell{flex:1; min-width:0;}
.light-bar{
  height:34px; border-radius:6px;
  display:flex; align-items:center; justify-content:center;
  font-family:'JetBrains Mono', monospace; font-size:11px; font-weight:600;
  border:1px solid var(--hair-strong);
}
.light-bar.done{background:var(--ok-dim); color:var(--ok); border-color:rgba(62,217,160,0.3);}
.light-bar.active{background:var(--signal-dim); color:var(--signal); border-color:rgba(255,139,61,0.4); animation:flicker 1.4s infinite;}
.light-bar.warn{background:var(--warn-dim); color:var(--warn); border-color:rgba(255,201,77,0.35);}
.light-bar.danger{background:var(--danger-dim); color:var(--danger); border-color:rgba(255,100,89,0.35);}
.light-bar.idle{background:transparent; color:var(--text-3);}
@keyframes flicker{0%,100%{opacity:1;} 50%{opacity:0.55;}}
.light-label{text-align:center; font-size:10px; color:var(--text-3); margin-top:6px; font-family:'JetBrains Mono', monospace; line-height:1.5; word-break:break-word; padding:0 2px;}

/* log / list rows */
.rows{display:flex; flex-direction:column;}
.row{
  display:flex; align-items:center; gap:14px;
  padding:11px 24px; border-bottom:1px solid var(--hair);
  font-size:13px;
}
.panel > .rows{margin:0 -24px -20px; }
.panel > .panel-head + .rows{margin-top:0;}
.row:last-child{border-bottom:none;}
.row:hover{background:var(--panel-raised);}
.row-time{font-family:'JetBrains Mono', monospace; font-size:11.5px; color:var(--text-3); width:64px; flex-shrink:0;}
.row-icon{width:15px; flex-shrink:0; font-size:15px;}
.row-icon.ok{color:var(--ok);}
.row-icon.warn{color:var(--warn);}
.row-icon.danger{color:var(--danger);}
.row-icon.info{color:var(--info);}
.row-main{flex:1; min-width:0; color:var(--text-1);}
.row-sub{color:var(--text-3); font-size:11.5px; margin-top:1px;}
.tag{
  font-family:'JetBrains Mono', monospace; font-size:10.5px;
  color:var(--text-2); background:var(--panel-raised);
  border:1px solid var(--hair); padding:2px 8px; border-radius:5px;
  flex-shrink:0; white-space:nowrap;
}
.tag.ok{color:var(--ok); border-color:rgba(62,217,160,0.3);}
.tag.warn{color:var(--warn); border-color:rgba(255,201,77,0.3);}
.tag.danger{color:var(--danger); border-color:rgba(255,100,89,0.3);}
.tag.info{color:var(--info); border-color:rgba(91,157,255,0.3);}

/* tables */
table{width:100%; border-collapse:collapse; font-size:13px;}
th{
  text-align:left; font-size:11px; text-transform:uppercase; letter-spacing:0.4px;
  color:var(--text-3); font-weight:500; padding:0 24px 10px;
  font-family:'JetBrains Mono', monospace;
}
td{padding:12px 24px; border-top:1px solid var(--hair); vertical-align:middle;}
tr:hover td{background:var(--panel-raised);}
/* Tableau large: le defilement horizontal reste DANS le cadre.
   `table{width:100%}` ne protege de rien: la largeur minimale du contenu
   l'emporte, et avec `td{padding:12px 24px}` six colonnes depassent
   largement 390 px. Sans conteneur qui defile, c'est la page entiere qui
   s'elargit et toute la mise en page casse.

   `.scroll-area` fait deja ce travail pour les tableaux qu'elle enveloppe
   (profils, proxies, sms). Cette classe couvre les tableaux qui n'ont pas
   besoin, eux, d'une hauteur maximale ni d'un en-tete fige. */
.table-scroll{overflow-x:auto; -webkit-overflow-scrolling:touch;}

.panel-table{padding:20px 0 4px;}
.panel-table .panel-head{padding:0 24px; margin-bottom:16px;}
.cell-mono{font-family:'JetBrains Mono', monospace; font-size:12.5px; color:var(--text-2);}
.cell-mask{font-family:'JetBrains Mono', monospace; font-size:12.5px; color:var(--text-3); letter-spacing:1px;}

/* status pill */
.pill{
  display:inline-flex; align-items:center; gap:6px;
  font-size:11.5px; font-family:'JetBrains Mono', monospace;
  padding:4px 10px; border-radius:99px; border:1px solid var(--hair-strong);
}
.pill.ok{color:var(--ok); background:var(--ok-dim); border-color:rgba(62,217,160,0.3);}
.pill.warn{color:var(--warn); background:var(--warn-dim); border-color:rgba(255,201,77,0.3);}
.pill.danger{color:var(--danger); background:var(--danger-dim); border-color:rgba(255,100,89,0.3);}
.pill.idle{color:var(--text-3); background:var(--panel-raised);}
.pill.info{color:var(--info); background:var(--info-dim); border-color:rgba(91,157,255,0.3);}
.pill-dot{width:5px; height:5px; border-radius:50%; background:currentColor;}

/* buttons */
.btn{
  display:inline-flex; align-items:center; gap:7px;
  font-family:'Space Grotesk', sans-serif; font-weight:500; font-size:13px;
  padding:9px 16px; border-radius:7px; border:1px solid var(--hair-strong);
  background:var(--panel-raised); color:var(--text-1);
  cursor:pointer; transition:border-color 0.15s ease, background 0.15s ease;
}
.btn:hover{border-color:var(--text-3);}
.btn.primary{background:var(--signal); color:var(--void); border-color:var(--signal);}
.btn.primary:hover{opacity:0.9;}
.btn i{font-size:16px;}
.btn-row{display:flex; gap:10px; flex-wrap:wrap;}

/* form controls */
.field{display:flex; flex-direction:column; gap:6px; margin-bottom:16px;}
.field label{font-size:12px; color:var(--text-2);}
.field input, .field select{
  background:var(--void); border:1px solid var(--hair-strong); border-radius:7px;
  padding:9px 12px; color:var(--text-1); font-size:13px;
}
.field input:focus, .field select:focus{border-color:var(--signal);}
.field-row{display:flex; gap:16px; flex-wrap:wrap;}
.field-row .field{flex:1; min-width:160px;}

/* segmented toggle */
.segmented{
  display:inline-flex; background:var(--void); border:1px solid var(--hair-strong);
  border-radius:7px; padding:2px; gap:2px;
}
.segmented button{
  border:none; background:transparent; color:var(--text-2);
  font-size:12.5px; padding:6px 14px; border-radius:5px; cursor:pointer;
  font-family:'Space Grotesk', sans-serif; font-weight:500;
}
.segmented button.active{background:var(--signal-dim); color:var(--signal);}

/* progress bar */
.bar-track{height:6px; background:var(--void); border-radius:4px; overflow:hidden; border:1px solid var(--hair);}
.bar-fill{height:100%; background:var(--signal);}
.bar-fill.ok{background:var(--ok);}

/* ---- ZONES DÉFILANTES INTERNES ----
   Un tableau ou un journal long défile dans son propre cadre au lieu de
   pousser toute la page: la sidebar, les autres panneaux et l'en-tête du
   tableau restent visibles pendant qu'on parcourt les 100 profils. */
.scroll-area{
  overflow-y:auto;
  overflow-x:auto;
  max-height:56vh;
  scrollbar-width:thin;
  scrollbar-color:var(--hair-strong) transparent;
  overscroll-behavior:contain;
}
.scroll-area.tall{max-height:68vh;}
.scroll-area.short{max-height:34vh;}
.scroll-area::-webkit-scrollbar{width:10px; height:10px;}
.scroll-area::-webkit-scrollbar-track{background:transparent;}
.scroll-area::-webkit-scrollbar-thumb{
  background:var(--hair-strong);
  border-radius:99px;
  border:3px solid var(--panel);
}
.scroll-area::-webkit-scrollbar-thumb:hover{background:var(--text-3);}

/* En-tête de tableau figé pendant le défilement interne. Fond opaque
   obligatoire, sinon les lignes défilent visiblement derrière. */
.scroll-area > table thead th{
  position:sticky; top:0; z-index:2;
  background:var(--panel);
  padding-top:14px;
  box-shadow:inset 0 -1px 0 var(--hair);
}
/* Le conteneur défilant ne doit pas rogner les marges négatives des rows. */
.panel > .rows.scroll-area{margin:0 -24px -20px;}
.panel > .panel-head + .rows.scroll-area{margin-top:0;}

@media (max-height:800px){
  .scroll-area{max-height:46vh;}
  .scroll-area.tall{max-height:56vh;}
  .scroll-area.short{max-height:28vh;}
}

/* grid helpers */
.grid-2{display:grid; grid-template-columns:1fr 1fr; gap:20px;}
.grid-3{display:grid; grid-template-columns:repeat(3, 1fr); gap:20px;}

@media (max-width:900px){
  .grid-2, .grid-3{grid-template-columns:1fr;}
}
@media (max-width:760px){
  .side{display:none;}
  main{padding:20px;}
  .metrics{grid-template-columns:repeat(2, 1fr);}
  .lights{flex-wrap:wrap;}
}


/* ===== NAVIGATION MOBILE =====
   Point de bascule aligne sur `.side{display:none}` ci-dessus (760px) : la
   barre du bas doit apparaitre exactement quand la barre laterale disparait,
   sinon la page se retrouve sans navigation dans l'intervalle. */
@media (max-width:760px){
  .mobile-topbar{
    display:flex; align-items:center; justify-content:space-between;
    padding:14px 16px; background:var(--panel); border-bottom:1px solid var(--hair);
    position:sticky; top:0; z-index:15;
  }
  .mobile-topbar .brand{padding:0; gap:9px;}

  /* ---- Hauteur utile et compensation de la barre du bas ----
     Deux defauts se cumulaient ici, et le premier rendait le second
     invisible au diagnostic.

     1. `body{padding-bottom:64px}` ne servait a RIEN. Le body ne defile pas
        — `html,body{overflow:hidden}` plus haut — c'est `main` qui porte
        `overflow-y:auto`. Reserver de la place en bas du body ne repousse
        donc aucun contenu scrollable.

     2. `.shell{height:100vh}` est pose SOUS `.mobile-topbar`, qui occupe sa
        propre hauteur dans le flux (~54 px). La colonne mesurait donc
        100vh + 54 px dans un body en `overflow:hidden`: les 54 derniers
        pixels de `main` tombaient hors de l'ecran, hors d'atteinte.

     Le body devient une colonne flex de la hauteur exacte du viewport: la
     topbar prend sa hauteur naturelle, `.shell` occupe le reste. Aucune
     valeur en dur ne decrit la topbar — elle peut changer sans rien casser
     ici. */
  body{
    display:flex; flex-direction:column;
    height:100%;
    height:100dvh;   /* ignore par les navigateurs sans dvh, qui gardent 100% */
    min-height:0;    /* annule le `min-height:100vh` global: sur mobile 100vh
                        depasse la zone visible quand la barre d'URL est
                        affichee, et rallongeait le body d'autant */
    padding-bottom:0;
  }
  .shell{flex:1; min-height:0; height:auto;}

  /* `login.html` et `setup.html` n'ont pas de `.shell`: leur unique enfant
     est `.login-wrap{min-height:100vh}`. Dans un body devenu colonne flex de
     100dvh, ce 100vh depasse le conteneur des que la barre d'URL est
     affichee, et la carte se retrouve coupee en bas dans un body en
     `overflow:hidden`. `flex:1` lui fait occuper la hauteur reelle, ce qui
     preserve son centrage. */
  .login-wrap{flex:1; min-height:0;}

  /* `.bottom-nav` est `position:fixed`: elle recouvre le bas de `main`, qui
     doit donc reserver sa hauteur. Celle-ci est calculee depuis ses propres
     declarations: 8 (padding haut) + 6 (padding item) + ~23 (icone 19px)
     + 3 (gap) + ~12 (libelle 9.5px) + 6 + 8 = 66 px. Valeur DERIVEE, pas
     mesuree dans un navigateur: si la barre change de taille, c'est ici
     qu'il faut le reporter.

     `env(safe-area-inset-bottom)` est indispensable et etait le plus gros
     manque: la barre l'ajoute deja a son propre padding, donc sur un iPhone
     a indicateur d'accueil elle mesure ~100 px quand la compensation en
     valait 24. Les 16 px restants evitent que le dernier element touche la
     barre. */
  main{
    height:100%;
    padding-bottom:calc(66px + 16px + env(safe-area-inset-bottom, 0px));
  }

  .bottom-nav{
    display:flex; position:fixed; left:0; right:0; bottom:0; z-index:40;
    border-top:1px solid var(--hair); background:var(--panel);
    padding:8px 4px calc(8px + env(safe-area-inset-bottom, 0px));
  }
  .bottom-nav-item{
    flex:1; display:flex; flex-direction:column; align-items:center; gap:3px;
    padding:6px 2px; color:var(--text-3); font-size:9.5px; font-family:'Space Grotesk', sans-serif;
    border-radius:8px; background:transparent; border:none; text-decoration:none; cursor:pointer;
  }
  .bottom-nav-item i{font-size:19px;}
  .bottom-nav-item.active{color:var(--signal);}

  .more-sheet{
    display:none; position:fixed; inset:0; background:rgba(10,12,14,0.7); z-index:50;
    align-items:flex-end;
  }
  .more-sheet.open{display:flex;}
  .more-sheet-panel{
    background:var(--panel); border-top:1px solid var(--hair); border-radius:16px 16px 0 0;
    width:100%; padding:18px 16px 24px;
  }
  .more-sheet-panel nav{display:flex; flex-direction:column; gap:2px; margin-top:12px;}
  .more-sheet-panel .nav-item{font-size:14px !important;}
  .more-sheet-panel .nav-item i{font-size:17px !important; margin-right:0;}
  .sheet-handle{width:36px; height:4px; background:var(--hair-strong); border-radius:99px; margin:0 auto;}
}
@media (min-width:761px){
  .mobile-topbar, .bottom-nav, .more-sheet{display:none !important;}
}
