/* =====================================================================
   RSKTV — thème unifié du panel
   ---------------------------------------------------------------------
   Aligne admin.html, reseller.html, login.html et activate.html sur la
   charte du site rsktv.com. Chargée APRÈS la feuille interne de chaque
   page : à spécificité égale, la dernière règle l'emporte.

   Principe : on ne touche à AUCUNE ligne des interfaces. Tout passe par
   ce fichier, donc le retour arrière consiste à retirer une balise <link>.

   Avant : trois chartes qui s'ignoraient — admin sombre rouge/ambre,
   revendeur CLAIR ambre, activation noire et or. Aucune ne correspondait
   au site.
   ===================================================================== */

/* ── 1. Jetons du site, copiés à l'identique de website/index.html ───── */
:root{
  color-scheme: dark;

  --ground:#06080B;
  --panel:#0D1219;
  --panel-2:#111823;
  --line:#1E2731;
  --line-soft:#161E27;
  --ink:#E9EEF3;
  --ink-2:#8E9BA8;
  --ink-3:#7C8A97;

  --tally:#FF2233;
  --tally-hi:#FF5563;
  --tally-glow:rgba(255,34,51,.42);
  /* Encre posée SUR un aplat rouge. Le blanc n'y tient pas : sur #FF2233
     il plafonne à 3,80:1, sous le seuil AA de 4,5. Cette encre sombre
     donne 5,07:1 sur l'aplat et 6,19:1 sur l'état de survol. */
  --tally-ink:#0B0F14;

  /* Couleurs sémantiques : un tableau de bord a besoin de distinguer
     succès / attente / erreur. Elles sont refroidies et désaturées pour
     cohabiter avec le rouge de marque sans lui disputer l'attention. */
  --ok:#4FB58B;      --ok-ink:#7FD6B4;      --ok-bg:rgba(79,181,139,.14);
  --info:#5AA9E6;    --info-ink:#8FC7F0;    --info-bg:rgba(90,169,230,.14);
  --warn:#E8A33D;    --warn-ink:#F0C889;    --warn-bg:rgba(232,163,61,.14);
  --danger:#FF2233;  --danger-ink:#FF8A96;  --danger-bg:rgba(255,34,51,.14);
  --neutral-bg:rgba(255,255,255,.06);

  --f-display:"Bahnschrift","DIN Alternate","DIN Condensed","Avenir Next Condensed","Helvetica Neue",system-ui,sans-serif;
  --f-text:"Segoe UI Variable Text","Segoe UI",-apple-system,BlinkMacSystemFont,"SF Pro Text",Roboto,"Helvetica Neue",Arial,sans-serif;
  --f-mono:ui-monospace,"Cascadia Mono","SF Mono","Segoe UI Mono",Menlo,Consolas,monospace;

  --ease:cubic-bezier(.2,.7,.2,1);

  /* ── 2. Remappage des variables de admin.html / login.html ───────── */
  --bg:#06080B;   --bg2:#0D1219;  --bg3:#111823;
  --glass:rgba(13,18,25,.95);     --glass2:rgba(255,255,255,.03);
  --border:#161E27;               --border2:#1E2731;
  --acc:#FF2233;                  --acc2:#C4121F;
  --amber:#E8A33D;                --amber2:#C9862B;
  --brand-red:#FF2233;            --brand-red-deep:#C4121F;
  --brand-amber:#E8A33D;          --brand-amber-deep:#C9862B;
  --bg-abyss:#06080B;             --bg-base:#0D1219;
  --bg-card:#111823;              --bg-elevated:#151E29;
  --bg-input:#0F1620;
  --stroke-1:#161E27;             --stroke-2:#1E2731;
  --red-glow:rgba(255,34,51,.28); --amber-glow:rgba(232,163,61,.20);

  /* ── 3. Remappage des variables de reseller.html ─────────────────── */
  /* Son accent primaire était l'ambre ; il devient le rouge de marque —
     c'est le cœur de la mise en cohérence avec le site. */
  --red:#FF2233;   --red2:#C4121F;
  --card:#0D1219;
  --t1:#E9EEF3;    --t2:#8E9BA8;   --t3:#7C8A97;
  --grad-brand:linear-gradient(135deg,#FF2233 0%,#FF5563 100%);
  --shadow-brand:0 8px 32px rgba(255,34,51,.24);

  /* ── 4. Remappage des variables de activate.html ─────────────────── */
  /* L'or était une quatrième identité. Il rejoint le rouge de marque. */
  --gold:#FF2233;  --gold-hi:#FF5563;
  --text:#E9EEF3;  --muted:#8E9BA8;
}

/* ── 5. Typographie commune ─────────────────────────────────────────── */
body{
  font-family:var(--f-text);
  background:var(--ground);
  color:var(--ink);
  -webkit-font-smoothing:antialiased;
}
h1,h2,h3,h4,.brand,.u-name,.page-title,.card-title{
  font-family:var(--f-display);
  letter-spacing:-.01em;
}
code,pre,kbd,samp,.mono,input[type="text"].mono{font-family:var(--f-mono)}

/* ── 6. Le focus est visible et c'est le rouge de marque ────────────── */
:focus-visible{outline:2px solid var(--tally);outline-offset:2px}

/* ── 6b. Fonds de page ───────────────────────────────────────────────
   Les écrans de connexion portaient deux halos, un rouge et un AMBRE, qui
   donnaient au fond une teinte brune. `#login-page` est un sélecteur
   d'identifiant : une règle sur `body` ne peut pas l'emporter, il faut le
   viser nommément. Le second halo passe du rouge froid, sans ambre. */
#login-page,
body.login,
.login-page{
  background:
    radial-gradient(circle at 18% 0%,  rgba(255,34,51,.15) 0%, transparent 52%),
    radial-gradient(circle at 82% 100%, rgba(255,34,51,.07) 0%, transparent 52%),
    linear-gradient(135deg,#06080B 0%,#0B1017 100%) !important;
}

/* ── 6c. Géométrie ───────────────────────────────────────────────────
   Le site est angulaire : rayons de 2 à 3 px. Le panel arrondissait à
   14 px, ce qui lit « application grand public » là où le site lit
   « outil ». On resserre, en laissant les pastilles rondes. */
.login-card,.modal,.card,.pkg-card,.pm-card,
.login-input,.form-control,select,textarea,
.login-btn,.btn,.btn-login,.btn-primary,.btn-dark,.btn-danger,.act-btn{border-radius:3px}
.badge,.pill,.credits-pill,[class^="s-"],[class^="p-"],[class^="cr-status"]{border-radius:999px}

/* ── 6d. Halo du signe ───────────────────────────────────────────────
   Aligné sur --tally-glow du site plutôt que sur l'ancien #FF1744. */
.login-logo img{filter:drop-shadow(0 4px 16px rgba(255,34,51,.30))}

/* ── 6e. Mode clair de l'administration ──────────────────────────────
   admin.html propose une bascule clair/sombre (localStorage data-theme).
   Ses variables sont déclarées sous [data-theme="light"], de spécificité
   supérieure à :root — sans ce bloc, le mode clair reprendrait l'ancienne
   charte. On le conserve donc, mais dans la palette du site. */
[data-theme="light"]{
  /* `:root` declare `color-scheme: dark`, et ce bloc ne le remettait jamais :
     TOUS les controles natifs du panel rendaient en sombre alors que la page
     est claire. Les cases a cocher s'affichaient en carres noirs — l'element
     le plus lourd de chaque rangee etant celui qui compte le moins — et les
     menus deroulants comme les barres de defilement suivaient. Une ligne. */
  color-scheme: light;

  --ground:#F7F9FB;  --panel:#FFFFFF;  --panel-2:#F1F5F8;
  --line:#DCE3EA;    --line-soft:#E8EDF2;
  --ink:#0B0F14;     --ink-2:#4A5A68;  --ink-3:#6B7A88;

  --bg:#F7F9FB;      --bg2:#FFFFFF;    --bg3:#F1F5F8;
  --glass:rgba(255,255,255,.95);       --glass2:rgba(0,0,0,.03);
  --border:#E8EDF2;  --border2:#DCE3EA;
  --card:#FFFFFF;
  --t1:#0B0F14;      --t2:#4A5A68;     --t3:#6B7A88;

  /* Le rouge et son encre ne changent PAS d'un mode à l'autre : c'est la
     marque, et l'encre sombre sur l'aplat reste la seule qui tienne le
     seuil AA. */
  --acc:#FF2233;     --acc2:#C4121F;
  --tally:#FF2233;   --tally-ink:#0B0F14;
  --neutral-bg:rgba(0,0,0,.05);
  --ok-bg:rgba(79,181,139,.16);   --ok-ink:#1E7A5A;
  --info-bg:rgba(90,169,230,.16); --info-ink:#1E6BA8;
  --warn-bg:rgba(232,163,61,.18); --warn-ink:#8A5D12;
  --danger-bg:rgba(255,34,51,.12);--danger-ink:#B3121F;
}

/* =====================================================================
   7. reseller.html — conversion du thème CLAIR
   ---------------------------------------------------------------------
   48 % seulement de ses couleurs passaient par une variable : les
   surfaces blanches et les encres sombres sont écrites en dur. On les
   reprend ici, sélecteur par sélecteur, plutôt que par un remplacement
   aveugle qui aurait transformé « texte blanc sur aplat rouge » en
   « texte blanc sur fond blanc ».
   ===================================================================== */

/* Surfaces */
.login-card,
.modal,
.card,
.pkg-card,
.pm-card{background:var(--panel);border-color:var(--line)}
.login-card{box-shadow:0 25px 60px rgba(0,0,0,.55)}
.modal{box-shadow:0 30px 80px rgba(0,0,0,.6)}
.sidebar,
.toast-item,
#rk-burger,
.store-preview img{background:var(--panel-2)}
.sidebar{box-shadow:4px 0 24px rgba(0,0,0,.5);border-right:1px solid var(--line-soft)}

/* Champs de saisie : le fond clair devient un creux sombre */
.login-input,
.form-control,
.form-control[readonly],
select,
textarea{background:var(--panel-2);color:var(--ink);border-color:var(--line)}
.login-input:focus,
.form-control:focus{background:var(--panel-2);border-color:var(--tally);box-shadow:0 0 0 3px rgba(255,34,51,.18)}
.form-control[readonly]{color:var(--ink-2)}
.login-input::placeholder,
.form-control::placeholder{color:var(--ink-3);opacity:1}

/* Tableaux */
thead th{background:var(--panel-2);color:var(--ink-3);border-bottom:1px solid var(--line)}
tbody td{color:var(--ink-2)}
tbody tr{border-bottom:1px solid var(--line-soft)}
tbody tr:hover{background:var(--panel-2)}

/* Encres du panneau latéral et de la navigation */
.login-logo-text .name,
.sidebar-logo .brand,
.u-name,
.nav-item:hover{color:var(--ink)}
.u-role,
.nav-item,
.credits-hero .ch-lbl,
.store-preview .sp-msg{color:var(--ink-2)}
.nav-section{color:var(--ink-3)}
.nav-item:hover{background:rgba(255,255,255,.05)}
.nav-item.active{background:rgba(255,34,51,.12);color:var(--ink)}
.sidebar-logo,.sidebar-user{border-bottom:1px solid var(--line-soft)}
.sidebar-footer{border-top:1px solid var(--line-soft)}
.logout-btn{color:var(--danger-ink)}
.logout-btn:hover{color:var(--tally)}

/* Texte posé sur un aplat coloré : encre sombre, jamais blanc.
   C'est la règle qui a été établie sur le site — sur #FF2233 le blanc
   ne tient pas le seuil AA. */
.login-btn,
.btn-primary,
.btn-danger,
.pkg-card .pkg-badge,
.ftab.all.active,
.ftab.soon.active,
.ftab.expired.active,
.act-btn.renew:hover,
.act-btn.del:hover,
.act-btn:hover{color:var(--tally-ink)}
.login-btn:hover{box-shadow:0 12px 36px rgba(255,34,51,.40)}

/* Ces aplats-là restent sombres : l'encre claire y est correcte */
.btn-dark,
.toast-item,
#rk-burger,
.sidebar-logo .credits-pill,
.u-avatar{color:var(--ink)}
.btn-dark:hover{background:var(--panel)}

/* Onglets de filtre */
.ftab{border-color:var(--line);color:var(--ink-2)}
.ftab.all{background:var(--neutral-bg)}
.ftab.soon{background:var(--warn-bg);color:var(--warn-ink);border-color:transparent}
.ftab.soon.active{background:var(--warn);border-color:var(--warn)}
.ftab.expired{background:var(--danger-bg);color:var(--danger-ink);border-color:transparent}
.ftab.expired.active{background:var(--tally);border-color:var(--tally)}
.ftab .badge{background:rgba(255,255,255,.16)}

/* Pastilles d'état d'abonnement */
.s-active{background:var(--ok-bg);color:var(--ok-ink)}
.s-trial{background:var(--info-bg);color:var(--info-ink)}
.s-expired{background:var(--danger-bg);color:var(--danger-ink)}
.s-blocked{background:var(--warn-bg);color:var(--warn-ink)}
.s-lifetime{background:linear-gradient(90deg,#FF2233,#C4121F);color:var(--tally-ink)}

/* Pastilles de plateforme : une seule teinte neutre, la plateforme n'est
   pas une information à colorer différemment sept fois. */
.p-android,.p-tizen,.p-tvos,.p-ios,.p-windows,.p-default{
  background:var(--neutral-bg);color:var(--ink-2)
}

/* Compte à rebours */
.days-ok{color:var(--ok-ink)}
.days-warn{color:var(--warn-ink)}
.days-danger{color:var(--danger-ink)}

/* Boutons d'action de ligne */
.act-btn{border-color:var(--line);color:var(--ink-2)}
.act-btn.renew{background:var(--warn-bg);color:var(--warn-ink);border-color:transparent}
.act-btn.renew:hover{background:var(--warn)}
.act-btn.del{background:var(--danger-bg);color:var(--danger-ink);border-color:transparent}
.act-btn.del:hover{background:var(--tally)}

/* Encadrés d'information */
.alert-warning{background:var(--warn-bg);color:var(--warn-ink);border:1px solid rgba(232,163,61,.30)}
.alert-info{background:var(--info-bg);color:var(--info-ink);border:1px solid rgba(90,169,230,.30)}
.alert-success{background:var(--ok-bg);color:var(--ok-ink);border:1px solid rgba(79,181,139,.30)}
.alert-danger{background:var(--danger-bg);color:var(--danger-ink);border:1px solid rgba(255,34,51,.30)}

/* Sélections */
.radio-opt.selected,
.pkg-card.selected,
.pm-card.selected{background:rgba(255,34,51,.07);border-color:var(--tally)}
.pkg-card:hover{box-shadow:0 8px 24px rgba(0,0,0,.35)}

/* Bandeau de crédits */
.credits-hero{background:linear-gradient(135deg,var(--panel-2),var(--panel));border:1px solid var(--line)}

/* Statuts de demande de crédits */
.cr-status.pending{background:var(--warn-bg);color:var(--warn-ink)}
.cr-status.approved{background:var(--ok-bg);color:var(--ok-ink)}
.cr-status.rejected{background:var(--danger-bg);color:var(--danger-ink)}
.cr-status.cancelled{background:var(--neutral-bg);color:var(--ink-3)}

/* Voiles de modale */
#rk-overlay.show{background:rgba(0,0,0,.62)}

/* =====================================================================
   8. admin.html — 78 % passait déjà par des variables, il ne reste que
   les quelques littéraux de la charte précédente.
   ===================================================================== */
/* Le bouton de connexion portait la classe utilitaire `text-white`, donc du
   blanc sur l'aplat rouge : 3,80:1, sous le seuil AA de 4,5. On vise la
   combinaison des deux classes — spécificité 2, elle bat `.text-white` seule,
   sans avoir besoin de !important et sans toucher aux autres usages légitimes
   de `text-white` (encre claire sur fond sombre). */
.btn-login,
.btn-login.text-white,
.btn-primary.text-white,
.btn-acc.text-white{color:var(--tally-ink)}
.btn-login:hover{box-shadow:0 4px 20px var(--red-glow)}

/* Le badge de rôle était ambre — une couleur que le site n'emploie pas. Son
   style est EN LIGNE dans le HTML, seul !important peut le reprendre sans
   modifier admin.html. Il rejoint le rouge de marque, comme « ESPACE
   REVENDEUR » côté revendeur. */
#login-role-badge{color:var(--tally)!important}

.badge-ok,.st-active{background:var(--ok-bg);color:var(--ok-ink)}
.badge-warn,.st-trial{background:var(--warn-bg);color:var(--warn-ink)}
.badge-err,.st-expired{background:var(--danger-bg);color:var(--danger-ink)}
.btn-primary,.btn.primary,.btn-acc{color:var(--tally-ink)}

/* WhatsApp garde sa couleur : c'est l'identité d'un service tiers, pas
   la nôtre. On la désature juste assez pour qu'elle ne crie pas. */
.wa,.whatsapp,[class*="whatsapp"]{--wa:#3FA96B}

/* =====================================================================
   10. Parcours d'ajout / activation (panel-parcours.js)
   ===================================================================== */
/* Choix de durée, avec le coût annoncé sur le bouton lui-même */
.pk-durees{display:flex;gap:8px}
.pk-duree{
  flex:1;padding:11px 12px;border-radius:3px;cursor:pointer;text-align:left;
  background:transparent;border:1px solid var(--line);color:var(--ink-2);
  font-size:.95rem;font-weight:600;
}
.pk-duree span{display:block;font-family:var(--f-mono);font-size:10.5px;
  letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3);margin-top:3px}
.pk-duree.on{border-color:var(--tally);background:rgba(255,34,51,.08);color:var(--ink)}
.pk-duree.on span{color:var(--tally)}

/* Saisie de la playlist */
.pk-opt{font-weight:400;color:var(--ink-3);font-size:.82rem}
.pk-onglets{display:flex;border-bottom:1px solid var(--line);margin-bottom:10px}
.pk-onglet{
  padding:8px 14px;background:transparent;border:0;border-bottom:2px solid transparent;
  margin-bottom:-1px;cursor:pointer;color:var(--ink-3);
  font-family:var(--f-mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;
}
.pk-onglet.on{color:var(--ink);border-bottom-color:var(--tally)}
.pk-pane{display:none}
.pk-pane.on{display:block}
.pk-pane .form-control{margin-bottom:8px}
.pk-row{display:flex;gap:8px}
.pk-row .form-control{flex:1;min-width:0}

/* Confirmation du débit */
#pk-voile{
  position:fixed;inset:0;z-index:9500;display:flex;align-items:center;justify-content:center;
  background:rgba(0,0,0,.66);padding:24px;
}
.pk-carte{
  width:100%;max-width:400px;background:var(--panel);border:1px solid var(--line);
  border-radius:3px;box-shadow:0 30px 80px rgba(0,0,0,.6);padding:22px;
}
.pk-titre{font-family:var(--f-display);font-weight:700;font-size:1.12rem;color:var(--ink)}
/* L'adresse en gros : c'est elle qu'on vérifie avant de payer. */
.pk-mac{
  font-family:var(--f-mono);font-size:1.05rem;letter-spacing:.10em;color:var(--tally);
  margin:8px 0 16px;
}
.pk-avert{
  background:var(--warn-bg);color:var(--warn-ink);padding:10px 12px;border-radius:2px;
  font-size:.86rem;line-height:1.5;margin-bottom:14px;
}
.pk-lignes{border-top:1px solid var(--line-soft)}
.pk-lignes > div{
  display:flex;justify-content:space-between;gap:16px;padding:9px 0;
  border-bottom:1px solid var(--line-soft);font-size:.92rem;
}
.pk-lignes span{color:var(--ink-3)}
.pk-lignes b{color:var(--ink)}
.pk-err{margin-top:12px;color:var(--danger-ink);font-size:.88rem}
.pk-boutons{display:flex;gap:8px;margin-top:18px}
.pk-btn{
  flex:1;padding:11px 12px;border-radius:3px;cursor:pointer;
  background:transparent;border:1px solid var(--line);color:var(--ink-2);
  font-family:var(--f-mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;
}
.pk-btn:hover{border-color:var(--ink-3);color:var(--ink)}
.pk-btn.oui{background:var(--tally);border-color:var(--tally);color:var(--tally-ink);font-weight:700}
.pk-btn.oui:hover{background:var(--tally-hi);border-color:var(--tally-hi)}
.pk-btn[disabled]{opacity:.45;cursor:default}

/* Séparateur entre les actions courantes et les actions destructrices */
.pk-sep{
  display:inline-block;width:1px;align-self:stretch;min-height:22px;
  background:var(--line);margin:0 5px;
}

/* =====================================================================
   9. Fenêtre de diagnostic (panel-diag.js)
   ===================================================================== */
#diag-voile{
  position:fixed;inset:0;z-index:9000;display:flex;align-items:center;justify-content:center;
  background:rgba(0,0,0,.62);padding:24px;
}
.diag-carte{
  width:100%;max-width:440px;background:var(--panel);border:1px solid var(--line);
  border-radius:3px;box-shadow:0 30px 80px rgba(0,0,0,.6);overflow:hidden;
}
.diag-tete{
  display:flex;align-items:flex-start;justify-content:space-between;gap:16px;
  padding:18px 20px 14px;border-bottom:1px solid var(--line-soft);
}
.diag-titre{font-family:var(--f-display);font-weight:700;font-size:1.1rem;color:var(--ink)}
.diag-mac{font-family:var(--f-mono);font-size:11.5px;letter-spacing:.08em;color:var(--ink-3);margin-top:3px}
.diag-x{
  background:transparent;border:0;color:var(--ink-3);font-size:24px;line-height:1;
  cursor:pointer;padding:0 4px;
}
.diag-x:hover{color:var(--ink)}
.diag-corps{padding:18px 20px}

/* L'état ouvert est la seule chose qui porte le rouge : c'est lui qui compte. */
.diag-etat{
  font-family:var(--f-mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  padding:8px 11px;border-radius:2px;margin-bottom:14px;
}
.diag-etat.ferme{background:var(--neutral-bg);color:var(--ink-3)}
.diag-etat.ouvert{background:var(--danger-bg);color:var(--danger-ink)}

.diag-item{border-left:2px solid var(--tally);padding:10px 14px;background:var(--panel-2)}
.diag-lbl{
  font-family:var(--f-mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink-3);
}
.diag-val{font-size:1.02rem;font-weight:600;color:var(--ink);margin-top:5px;word-break:break-word}
.diag-frais{font-size:.82rem;color:var(--ink-3);margin-top:5px}

.diag-attente{
  padding:12px 14px;background:var(--panel-2);border-left:2px solid var(--line);
  color:var(--ink-2);font-size:.9rem;line-height:1.55;
}
.diag-err{color:var(--danger-ink);font-size:.9rem}

.diag-boutons{display:flex;gap:8px;flex-wrap:wrap;margin-top:16px}
.diag-btn{
  flex:1 1 auto;padding:10px 12px;border-radius:3px;cursor:pointer;
  background:transparent;border:1px solid var(--line);color:var(--ink-2);
  font-family:var(--f-mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;
}
.diag-btn:hover{border-color:var(--ink-3);color:var(--ink)}
.diag-btn.danger{background:var(--tally);border-color:var(--tally);color:var(--tally-ink);font-weight:700}
.diag-btn.danger:hover{background:var(--tally-hi);border-color:var(--tally-hi)}
.diag-btn[disabled]{opacity:.5;cursor:default}

.diag-note{
  padding:12px 20px 16px;border-top:1px solid var(--line-soft);
  color:var(--ink-3);font-size:.79rem;line-height:1.5;
}

/* =====================================================================
   11. RÉVISION DU 2026-07-30 — cinq corrections de conception
   ---------------------------------------------------------------------
   Ce bloc corrige des choix faits plus haut dans ce même fichier. Il est
   placé en fin de feuille pour l'emporter, et laissé séparé pour que la
   raison de chaque correction reste lisible.
   ===================================================================== */

/* ── 1. Les états ne dépendent plus de la seule teinte ────────────────
   Mesure du 30/07 : les quatre fonds teintés à 14 % avaient des
   luminances séparées de 1,00 à 1,13 — en niveaux de gris, c'était le
   même badge. Pour une deutéranopie ou une protanopie (~8 % des hommes),
   « actif » et « expiré » devenaient indiscernables sur une liste de 74
   appareils. On ajoute donc DEUX canaux non colorés : un liseré gauche
   plein, et un glyphe de tête. La couleur devient un renfort, plus le
   seul porteur de l'information. */
.s-active,.s-trial,.s-expired,.s-blocked,
.cr-status.pending,.cr-status.approved,.cr-status.rejected,.cr-status.cancelled{
  border-radius:2px;border-left:3px solid currentColor;padding-left:9px;
}
.s-active{background:rgba(79,181,139,.22)}
.s-trial{background:rgba(90,169,230,.16)}
.s-expired{background:rgba(255,34,51,.20)}
.s-blocked{background:rgba(232,163,61,.26)}

.s-active::before  {content:"\2713\00a0"}   /* ✓ */
.s-trial::before   {content:"\25F4\00a0"}   /* ◴ en cours */
.s-expired::before {content:"\2715\00a0"}   /* ✕ */
.s-blocked::before {content:"\2298\00a0"}   /* ⊘ */
.cr-status.approved::before {content:"\2713\00a0"}
.cr-status.pending::before  {content:"\25F4\00a0"}
.cr-status.rejected::before {content:"\2715\00a0"}
.cr-status.cancelled::before{content:"\2014\00a0"}

.alert-success,.alert-info,.alert-warning,.alert-danger{border-left-width:3px}

/* ── 2. Le rouge redevient un signal ──────────────────────────────────
   Il portait quatorze rôles : action principale, état actif, sélection,
   danger, marque. Quand tout est rouge, plus rien ne l'est. On le réserve
   à l'ACTION PRINCIPALE, au DANGER et au FOCUS. La sélection et l'état
   actif passent au neutre, marqués par un trait, pas par une couleur. */
.pk-duree.on{
  border-color:var(--ink-3);background:rgba(255,255,255,.06);color:var(--ink);
  box-shadow:inset 3px 0 0 var(--ink-2);
}
.pk-duree.on span{color:var(--ink-2)}
.pk-onglet.on{color:var(--ink);border-bottom-color:var(--ink-2)}
.pl-tab.on{color:var(--ink);border-bottom-color:var(--ink-2)}
.ftab.expired.active{background:var(--ink-3);border-color:var(--ink-3);color:var(--ground)}
.radio-opt.selected,.pkg-card.selected,.pm-card.selected{
  background:rgba(255,255,255,.05);border-color:var(--ink-3);
}
.nav-item.active{background:rgba(255,255,255,.07);box-shadow:inset 3px 0 0 var(--ink-2)}
/* L'encadré de diagnostic n'est pas une alerte : trait neutre. */
.diag-item{border-left-color:var(--ink-3)}

/* ── 3. Confirmer et détruire ne se ressemblent plus ──────────────────
   « Confirmer le débit » et « Supprimer » portaient le même rouge plein.
   Désormais : APLAT rouge = l'action principale, une seule par écran ;
   CONTOUR rouge = l'action destructrice. Le geste qui engage et le geste
   qui détruit ne se confondent plus. */
.btn-icon.danger,.act-btn.del,.btn-danger{
  background:transparent;border:1px solid var(--tally);color:var(--tally-hi);
}
.btn-icon.danger:hover,.act-btn.del:hover,.btn-danger:hover{
  background:rgba(255,34,51,.12);color:var(--tally-hi);
}
/* « Fermer la fenêtre » du diagnostic n'est pas destructeur : il l'était
   visuellement par erreur. Il redevient neutre. */
.diag-btn.danger{
  background:transparent;border-color:var(--line);color:var(--ink-2);font-weight:600;
}
.diag-btn.danger:hover{background:transparent;border-color:var(--ink-3);color:var(--ink)}

/* Hiérarchie : l'option neutre n'occupe plus la moitié de la surface
   devant une action irréversible et payante. */
.pk-boutons #pk-non{flex:0 0 34%}
.pk-boutons #pk-oui{flex:1 1 auto}

/* ── 4. Les actions destructrices portent un libellé ──────────────────
   Le libellé est ajouté par panel-parcours.js ; il ne s'affiche que sur
   ces boutons-là, pour ne pas alourdir la ligne entière. */
.btn-icon.danger{width:auto;padding:0 10px;gap:6px;display:inline-flex;align-items:center}
.pk-lbl{font-size:11px;font-weight:600;letter-spacing:.02em}

/* ── 5. Les capitales sont réservées aux libellés très courts ─────────
   Six règles les imposaient, dont sur les boutons et les onglets. Les
   capitales effacent la silhouette des mots et l'interlettrage les
   éloigne : coût de lecture permanent, pour un outil utilisé toute la
   journée. On les garde sur les étiquettes de champ et les pastilles —
   deux ou trois mots — et on les retire des commandes. */
.pk-btn,.diag-btn,.pk-onglet,.pl-tab,.ftab,.btn,.login-btn,.btn-login,
.btn-primary,.btn-dark,.btn-danger,.act-btn{
  text-transform:none;letter-spacing:.01em;font-family:var(--f-text);font-size:.92rem;
}
.pk-btn.oui,.btn-primary,.login-btn,.btn-login{font-weight:700}

/* Le coût ne doit pas se couper : « 2 CRÉDITS » passait à la ligne et
   désalignait les deux boutons de durée. */
.pk-duree span{white-space:nowrap}
.pk-duree{min-width:0}

/* =====================================================================
   12. Confirmation des actions sensibles (panel-actions.js)
   ---------------------------------------------------------------------
   Remplace les boîtes natives du navigateur — vingt-deux confirm/prompt/
   alert — sur les gestes qui touchent un vrai client : supprimer, bloquer,
   changer l'hôte de tout le parc.

   Trois principes tenus ici :
   · Le rouge reste le signal du destructif, jamais une décoration. Dans la
     fenêtre, un seul aplat rouge : le bouton qui détruit.
   · L'annulation est neutre mais pas effacée — elle reçoit le focus à
     l'ouverture, donc la touche Entrée ne détruit rien.
   · La MAC est en chasse fixe et en corps large : c'est l'information qu'on
     relit avant de valider, elle ne doit pas se lire comme du texte courant.
   ===================================================================== */

.rk-ask-fond{
  position:fixed;inset:0;z-index:9999;
  display:flex;align-items:center;justify-content:center;padding:24px;
  background:rgba(3,5,8,.72);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
  opacity:0;transition:opacity .16s var(--ease);
}
.rk-ask-fond.rk-ouvert{opacity:1}

.rk-ask{
  width:100%;max-width:470px;max-height:88vh;overflow:auto;
  background:var(--panel);border:1px solid var(--line);border-radius:14px;
  box-shadow:0 24px 60px rgba(0,0,0,.55);
  transform:translateY(8px) scale(.985);
  transition:transform .18s var(--ease);
}
.rk-ask-large{max-width:560px}
.rk-ask-fond.rk-ouvert .rk-ask{transform:none}

.rk-ask-tete{
  display:flex;align-items:center;gap:12px;
  padding:18px 22px 14px;border-bottom:1px solid var(--line-soft);
}
.rk-ask-tete h3{
  margin:0;font-family:var(--f-display);font-weight:700;
  font-size:1.06rem;line-height:1.25;color:var(--ink);
}
.rk-ask-sceau{
  flex:0 0 34px;height:34px;border-radius:9px;
  display:flex;align-items:center;justify-content:center;font-size:16px;
}
.rk-ask-danger .rk-ask-sceau{background:var(--danger-bg);color:var(--danger-ink)}
.rk-ask-warn   .rk-ask-sceau{background:var(--warn-bg);  color:var(--warn-ink)}

.rk-ask-corps{padding:16px 22px 4px}
.rk-ask-intro{margin:0 0 14px;font-size:.92rem;line-height:1.5;color:var(--ink-2)}

/* L'objet de l'action : lu d'un coup d'œil, sans confusion possible. */
.rk-ask-cible{
  background:var(--panel-2);border:1px solid var(--line-soft);
  border-radius:10px;padding:12px 14px;margin-bottom:14px;text-align:center;
}
.rk-ask-mac{
  font-family:var(--f-mono);font-size:1.02rem;font-weight:600;
  letter-spacing:.09em;color:var(--ink);
}
.rk-ask-mac-neuf{color:var(--ok-ink)}
.rk-ask-vers{color:var(--ink-3);font-size:13px;margin:5px 0}
.rk-ask-sous{margin-top:5px;font-size:.8rem;color:var(--ink-3)}
.rk-ask-compte{font-family:var(--f-display);font-size:1.9rem;font-weight:700;color:var(--ink);line-height:1}

/* Conséquences énoncées : on ne fait pas deviner ce qu'on casse. */
.rk-ask-conseq{margin:0 0 14px;padding:0;list-style:none}
.rk-ask-conseq li{
  position:relative;padding:3px 0 3px 18px;
  font-size:.87rem;line-height:1.45;color:var(--ink-2);
}
.rk-ask-conseq li::before{
  content:"";position:absolute;left:3px;top:11px;
  width:4px;height:4px;border-radius:50%;background:var(--ink-3);
}

/* Garde-fou de saisie : proportionné au risque, seulement sur l'irréversible. */
.rk-ask-garde{display:block;font-size:.83rem;color:var(--ink-2);margin-bottom:6px}
.rk-ask-garde b{color:var(--ink);font-family:var(--f-mono);letter-spacing:.06em}
.rk-ask-saisie{
  width:100%;padding:10px 12px;
  background:var(--ground);border:1px solid var(--line);border-radius:8px;
  color:var(--ink);font-family:var(--f-mono);font-size:.95rem;letter-spacing:.06em;
}
.rk-ask-saisie:focus{outline:none;border-color:var(--tally);box-shadow:0 0 0 3px var(--tally-glow)}
.rk-ask-garde-note{margin:6px 0 0;font-size:.76rem;color:var(--ink-3)}

.rk-ask-retour{
  margin:14px 0 0;padding:9px 12px;border-radius:8px;
  background:var(--neutral-bg);font-size:.81rem;line-height:1.45;color:var(--ink-2);
}
.rk-ask-retour i{margin-right:6px;color:var(--ink-3)}

.rk-ask-pied{
  display:flex;gap:10px;justify-content:flex-end;
  padding:16px 22px 18px;margin-top:14px;border-top:1px solid var(--line-soft);
}
.rk-ask-btn{
  padding:9px 18px;border-radius:8px;cursor:pointer;
  font-family:var(--f-text);font-size:.92rem;font-weight:600;
  border:1px solid transparent;transition:background .14s var(--ease),border-color .14s var(--ease);
}
.rk-ask-btn:focus-visible{outline:none;box-shadow:0 0 0 3px var(--tally-glow)}
.rk-ask-neutre{background:transparent;border-color:var(--line);color:var(--ink-2)}
.rk-ask-neutre:hover{border-color:var(--ink-3);color:var(--ink)}
.rk-ask-neutre-fort{background:var(--panel-2);border-color:var(--line2,var(--line));color:var(--ink)}
.rk-ask-neutre-fort:hover{border-color:var(--ink-3)}
/* Seul aplat rouge de la fenêtre. L'encre sombre y tient le contraste AA. */
.rk-ask-danger-btn{background:var(--tally);border-color:var(--tally);color:var(--tally-ink);font-weight:700}
.rk-ask-danger-btn:hover:not([disabled]){background:var(--tally-hi);border-color:var(--tally-hi)}
.rk-ask-warn-btn{background:var(--warn);border-color:var(--warn);color:#0B0F14;font-weight:700}
.rk-ask-warn-btn:hover:not([disabled]){filter:brightness(1.08)}
.rk-ask-btn[disabled]{opacity:.42;cursor:not-allowed}

/* Changement d'hôte : saisie, puis prévisualisation nominative. */
.rk-champ{margin-bottom:10px}
.rk-champ label{display:block;font-size:.8rem;color:var(--ink-2);margin-bottom:5px}
.rk-champ input{
  width:100%;padding:10px 12px;
  background:var(--ground);border:1px solid var(--line);border-radius:8px;
  color:var(--ink);font-family:var(--f-mono);font-size:.9rem;
}
.rk-champ input:focus{outline:none;border-color:var(--tally);box-shadow:0 0 0 3px var(--tally-glow)}
.rk-fleche{text-align:center;color:var(--ink-3);font-size:14px;margin:2px 0 8px}

.rk-apercu{margin-top:14px;border-radius:10px;padding:12px 14px;font-size:.86rem;line-height:1.45}
.rk-apercu-vide{background:var(--neutral-bg);color:var(--ink-2)}
.rk-apercu-vide i{color:var(--warn-ink);margin-right:6px}
.rk-apercu-plein{background:var(--panel-2);border:1px solid var(--line-soft)}
.rk-apercu-tete{color:var(--ink);margin-bottom:8px}
.rk-apercu-tete b{font-family:var(--f-display);font-size:1.1rem}
.rk-apercu-liste{margin:0;padding:0;list-style:none;max-height:190px;overflow:auto}
.rk-apercu-liste li{
  display:flex;align-items:baseline;gap:10px;
  padding:5px 0;border-top:1px solid var(--line-soft);
}
.rk-apercu-liste li:first-child{border-top:0}
.rk-apercu-mac{font-family:var(--f-mono);font-size:.82rem;letter-spacing:.05em;color:var(--ink)}
.rk-apercu-nom{font-size:.8rem;color:var(--ink-3)}

@media (max-width:520px){
  .rk-ask-pied{flex-wrap:wrap}
  .rk-ask-pied .rk-ask-btn{flex:1 1 auto}
}
@media (prefers-reduced-motion:reduce){
  .rk-ask-fond,.rk-ask{transition:none}
}

/* Ton « restaurateur » : rendre l'accès n'est ni un avertissement ni une
   destruction. Sans lui, débloquer un client portait le même rouge que
   supprimer son appareil — le signal perdait tout son sens. */
.rk-ask-ok .rk-ask-sceau{background:var(--ok-bg);color:var(--ok-ink)}
.rk-ask-ok-btn{background:var(--ok);border-color:var(--ok);color:#06080B;font-weight:700}
.rk-ask-ok-btn:hover:not([disabled]){filter:brightness(1.08)}

/* =====================================================================
   13. Liste des appareils — colonne d'actions (panel-appareils.js)
   ---------------------------------------------------------------------
   Neuf commandes en `flex-wrap` retombaient sur trois lignes : la hauteur
   de chaque rangee dependait du nombre de boutons de l'appareil, et le
   tableau ondulait. Le rail ci-dessous a une largeur FIXE et quatre
   emplacements, identiques sur toutes les rangees.

   Les commandes sont volontairement discretes : dans un tableau, ce qu'on
   lit d'abord doit etre la DONNEE — statut, expiration, derniere activite —
   pas la rangee de boutons qui se repete a l'identique cinquante fois.
   Elles se revelent au survol et au clavier, sans jamais disparaitre
   completement : une commande invisible est une commande introuvable.
   ===================================================================== */

.rk-rail{
  display:flex;align-items:center;justify-content:flex-end;
  gap:2px;white-space:nowrap;
}

/* Toutes les commandes du rail ont EXACTEMENT la meme empreinte : c'est
   cette regularite qui fait tenir l'alignement d'une rangee a l'autre. */
.rk-rail .rk-act{
  width:30px;height:30px;padding:0;flex:0 0 30px;
  display:inline-flex;align-items:center;justify-content:center;
  background:transparent;border:1px solid transparent;border-radius:7px;
  color:var(--ink-3);font-size:13px;line-height:1;cursor:pointer;
  transition:background .12s var(--ease),color .12s var(--ease),border-color .12s var(--ease);
}
.rk-rail .rk-act:hover{background:var(--panel-2);border-color:var(--line);color:var(--ink)}
.rk-rail .rk-act:focus-visible{
  outline:none;border-color:var(--tally);box-shadow:0 0 0 3px var(--tally-glow);color:var(--ink);
}
/* Le contour permanent des commandes s'efface : il dessinait une grille de
   boutons par-dessus la grille du tableau. */
.rk-rail .rk-act.btn-icon{background:transparent;border-color:transparent}
.rk-rail .rk-act.btn-icon:hover{background:var(--panel-2);border-color:var(--line);color:var(--ink)}
.rk-rail .rk-act.danger,
.rk-rail .rk-act.ok,
.rk-rail .rk-act.info,
.rk-rail .rk-act.warn{border-color:transparent;color:var(--ink-3)}

/* Les commandes s'estompent hors survol de la rangee. Le contraste reste
   suffisant pour rester reperable ; il ne s'agit pas de les cacher. */
/* L'opacite etait une mauvaise idee : elle depend du fond, donc du theme.
   En clair, des traits de 13 px a 80 % disparaissaient purement et
   simplement. On pose une ENCRE — secondaire au repos, pleine au survol —
   qui tient ses ~7:1 dans les deux themes sans calcul. */
#devices-body tr .rk-rail .rk-act,
#devices-tbody tr .rk-rail .rk-act{opacity:1;color:var(--ink-2)}
#devices-body tr:hover .rk-rail .rk-act,
#devices-tbody tr:hover .rk-rail .rk-act,
#devices-body tr:focus-within .rk-rail .rk-act{color:var(--ink)}
#devices-body tr:hover .rk-rail .rk-act,
#devices-body tr:focus-within .rk-rail .rk-act{opacity:1}

.rk-plus{font-size:15px}
.rk-plus-actif{background:var(--panel-2)!important;border-color:var(--line)!important;color:var(--ink)!important;opacity:1!important}

/* ── Menu des autres actions ─────────────────────────────────────────────
   `position:fixed` : la derniere rangee d'un tableau defilant verrait sinon
   son menu rogne par le conteneur. */
.rk-menu{
  position:fixed;z-index:9998;min-width:212px;
  background:var(--panel);border:1px solid var(--line);border-radius:10px;
  box-shadow:0 16px 40px rgba(0,0,0,.5);
  padding:5px;display:flex;flex-direction:column;gap:1px;
  text-align:left;white-space:nowrap;
}
.rk-menu[hidden]{display:none}
.rk-menu .rk-menu-item{
  display:flex;align-items:center;gap:9px;width:100%;
  padding:7px 10px;border:0;border-radius:7px;
  background:transparent;color:var(--ink-2);
  font-family:var(--f-text);font-size:.86rem;font-weight:500;
  text-align:left;cursor:pointer;transition:background .12s var(--ease),color .12s var(--ease);
}
.rk-menu .rk-menu-item i{font-size:13px;width:15px;text-align:center;flex:0 0 15px}
.rk-menu .rk-menu-item:hover{background:var(--panel-2);color:var(--ink)}
.rk-menu .rk-menu-item:focus-visible{
  outline:none;background:var(--panel-2);color:var(--ink);
  box-shadow:inset 0 0 0 1px var(--tally);
}
/* Le seul rouge de la liste, et il n'apparait qu'ici — au moment ou l'on
   s'appprete a detruire. Separe du reste : on ne tombe pas dessus par
   glissement du pointeur. */
.rk-menu .rk-menu-item-danger{color:var(--danger-ink)}
.rk-menu .rk-menu-item-danger:hover{background:var(--danger-bg);color:var(--danger-ink)}
.rk-menu .rk-menu-item-danger:first-of-type{
  margin-top:5px;padding-top:11px;border-top:1px solid var(--line-soft);border-radius:0 0 7px 7px;
}

/* ── Pays : pastille lisible ─────────────────────────────────────────────
   Le drapeau emoji ne s'affiche pas sous Windows — la police systeme n'en
   contient aucun glyphe et rend les deux lettres brutes du code, deja
   repete juste en dessous. Chaque rangee affichait donc « MA » puis « MA ».
   Une seule pastille, en chasse fixe, suffit et se lit a toutes tailles. */
.rk-pays{
  display:inline-block;margin-top:4px;padding:1px 6px;border-radius:5px;
  background:var(--neutral-bg);border:1px solid var(--line-soft);
  color:var(--ink-2);font-family:var(--f-mono);font-size:10px;
  font-weight:600;letter-spacing:.06em;line-height:1.5;
}

.rk-mac-absente{
  font-family:var(--f-text);font-size:11.5px;font-style:italic;color:var(--ink-3);
}

/* Les chiffres qui se lisent en colonne doivent s'aligner en colonne :
   dates d'expiration, jours restants, derniere activite. */
#devices-body td{font-variant-numeric:tabular-nums}

@media (prefers-reduced-motion:reduce){
  .rk-rail .rk-act,.rk-menu .rk-menu-item{transition:none}
}

/* ── Identite de l'appareil : deux lignes, toujours ──────────────────────
   La cellule empilait de une a quatre lignes selon ce que l'appareil avait
   renseigne. Composition fixe desormais : l'identite lisible au-dessus, les
   identifiants techniques en dessous — meme nature, meme chasse fixe. */
.rk-ident{display:flex;flex-direction:column;gap:2px;min-width:0}
.rk-ident-l1{display:flex;align-items:baseline;gap:6px;min-width:0}
.rk-ident-l2{display:flex;align-items:baseline;gap:5px;min-width:0}

/* Seconde interface reseau. Elle enonce un FAIT, pas une valeur : deux
   adresses cote a cote demandent 215 px quand la colonne en fait 198, et
   tronquer un identifiant ferait recopier une adresse fausse. La valeur
   complete est au survol, et un clic la copie. */
.rk-mac2{
  flex:0 0 auto;padding:0 6px;border-radius:5px;
  background:var(--neutral-bg);border:1px dashed var(--line-soft);
  color:var(--ink-3);font-size:9.5px;font-weight:700;line-height:1.7;
  white-space:nowrap;cursor:pointer;letter-spacing:.02em;
}
.rk-mac2:hover{border-color:var(--ink-3);color:var(--ink-2)}

/* ── Champ de saisie de la seconde adresse (fiche appareil) ───────────────
   Pose A COTE de `#mac-field`, que la modale masque en edition. L'adresse
   principale est rappelee au-dessus : sans elle, on saisit « la seconde » de
   quoi ? En edition la fiche n'en montrait plus aucune.

   Le bloc est AUTONOME : il portait la classe `fld`, qui n'est definie que
   dans la feuille de l'admin. Cote revendeur elle ne designait rien, etiquette
   et champ restaient sur la meme ligne, et la boite de saisie recouvrait le
   mot « facultatif ». Un composant ajoute ne doit rien emprunter a la page qui
   l'accueille : les deux pages n'ont pas les memes regles, et rien dans la
   feuille ne permet de le savoir. */
.rk-mac2-fld{display:block;margin:0 0 16px}
.rk-mac2-fld > label{
  display:block;margin:0 0 6px;
  font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--ink-2);
}
.rk-mac2-fld > input{
  display:block;width:100%;box-sizing:border-box;
  padding:10px 12px;border-radius:8px;
  /* `--panel-2` et non `--bg-input` : ce dernier vaut #0F1620 dans LES DEUX
     themes — un champ noir sur fond blanc. Le repli n'a jamais joué, le
     jeton existant simplement. */
  background:var(--panel-2);
  border:1px solid var(--line);color:var(--ink);
  font-family:var(--f-mono);font-size:14px;letter-spacing:1px;
  /* La chasse fixe a une boite de ligne plus haute que la police du panel :
     sans cette valeur le champ depassait de 3 px ses voisins natifs, et un
     alignement approximatif se lit plus mal qu'un alignement absent. */
  line-height:1.2;
}
.rk-mac2-fld > input:focus{
  outline:none;border-color:var(--tally);box-shadow:0 0 0 3px var(--tally-glow);
}
.rk-mac2-fac{
  font-size:10px;font-weight:600;text-transform:lowercase;
  color:var(--ink-3);opacity:.75;margin-left:4px;
}
.rk-mac2-ref{
  font-size:11.5px;color:var(--ink-3);margin:-2px 0 6px;
}
.rk-mac2-ref b{
  font-family:var(--f-mono);color:var(--ink-2);font-weight:700;letter-spacing:.04em;
}
/* 52 caracteres par ligne : au-dela, l'oeil perd le debut de la suivante. */
.rk-mac2-aide{
  font-size:11.5px;line-height:1.5;color:var(--ink-3);margin-top:6px;max-width:52ch;
}
.rk-mac2:focus-visible{outline:none;border-color:var(--tally);box-shadow:0 0 0 3px var(--tally-glow)}

/* Cote revendeur, la pastille est sur la LIGNE 1, qui n'avait pas de hauteur
   bornee : elle passait de 13,3 a 17,6 px et la rangee concernee faisait 80 px
   contre 78 pour les autres. Une rangee plus haute que ses voisines empeche de
   suivre une ligne du regard jusqu'a sa colonne d'actions — c'est le defaut
   qu'on avait corrige en composant l'identite en lignes fixes.

   On borne donc la ligne pour TOUTES les rangees, pas seulement celles qui
   portent une pastille : c'est l'egalite entre rangees qui compte, pas la
   hauteur elle-meme. `center` et non `baseline` : le meme piege que le drapeau,
   deja paye une fois. */
#devices-tbody .rk-ident-l1{height:18px;align-items:center;overflow:hidden}

.rk-nom{
  font-size:12.5px;font-weight:700;color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:190px;
}
.rk-nom-vide{font-weight:500;font-style:italic;color:var(--ink-3)}

.rk-mac{
  font-family:var(--f-mono);font-size:11.5px;font-weight:600;
  letter-spacing:.055em;color:var(--info-ink);white-space:nowrap;
}
.rk-mac-absente{font-size:11.5px;font-style:italic;color:var(--ink-3);white-space:nowrap}
.rk-ip{
  font-family:var(--f-mono);font-size:11px;color:var(--ink-3);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.rk-sep-point{color:var(--line);font-size:11px;flex:0 0 auto}

/* ── Derniere connexion, en ligne (espace revendeur) ──────────────────────
   Il n'a pas de colonne dediee : l'information rejoint la ligne des
   renseignements secondaires, au meme poids que « ajoute le ». */
.rk-vu-inline{flex:0 0 auto;font-size:11px;color:var(--ink-3);cursor:help;white-space:nowrap}

/* La date d'expiration au-dessus du nombre de jours : le nombre dit
   l'urgence, la date dit l'echeance. Meme disposition que cote admin. */
.rk-exp-date{font-size:11.5px;font-weight:600;color:var(--ink-2);line-height:1.35;cursor:help}

/* Mentions secondaires : une pastille tient sur la ligne du nom au lieu de
   fabriquer une rangee plus haute que les autres. */
.rk-tag{
  flex:0 0 auto;padding:1px 6px;border-radius:5px;
  background:var(--neutral-bg);border:1px solid var(--line-soft);
  color:var(--ink-3);font-size:10px;font-weight:600;line-height:1.6;
  white-space:nowrap;
}
.rk-tag-note{
  background:var(--warn-bg);border-color:transparent;color:var(--warn-ink);
  font-weight:500;font-style:italic;
  max-width:150px;overflow:hidden;text-overflow:ellipsis;
}

/* Version de l'application : un numero lisible, l'identifiant de build
   complet au survol. La chaine entiere passait a la ligne et faisait grandir
   la rangee — pour une information qu'on ne lit jamais en entier. */
.rk-version{
  display:inline-block;padding:1px 7px;border-radius:5px;
  background:var(--neutral-bg);border:1px solid var(--line-soft);
  color:var(--ink-2);font-family:var(--f-mono);font-size:10.5px;
  font-weight:600;letter-spacing:.03em;line-height:1.6;white-space:nowrap;
}

/* ── Build sans version produit ───────────────────────────────────────────
   Le bord tirete est la convention du provisoire : il annonce « identifiant
   interne, pas numero de version » a la lecture, sans qu'il faille survoler.
   La boite reste identique — sur une colonne alignee, un changement de
   gabarit se lirait comme un desordre, pas comme une information. */
.rk-version--build{
  border-style:dashed;
  cursor:help;
}

/* ── Aucune version annoncee ──────────────────────────────────────────────
   Sans cadre ni fond : une absence doit se lire comme une absence, jamais
   comme une valeur. Assez visible pour qu'on la remarque en balayant la
   colonne — c'est aujourd'hui le cas de 25 appareils Android sur 33, et
   c'est exactement ce qu'il faut voir. */
.rk-version--muet{
  background:transparent;border-color:transparent;
  color:var(--ink-2);opacity:.5;font-weight:500;
  padding-left:2px;padding-right:2px;
  cursor:help;
}

/* Rythme vertical unique. Les rangees oscillaient entre 56 et 94 px selon ce
   que l'appareil avait renseigne ; une fois les cellules recomposees il ne
   restait que quelques pixels d'ecart, dus a la premiere colonne selon
   qu'elle porte une pastille pays ou un simple point de statut. On fixe la
   hauteur : dans un tableau qu'on parcourt, la regularite de la trame est ce
   qui permet de suivre une ligne du regard jusqu'a ses commandes. */
#devices-body tr{height:64px}
#devices-body td{vertical-align:middle}

/* ── Espace revendeur : meme grammaire que l'espace admin ────────────────
   Les commandes y sont declarees en <div class="act-btn"> et non en
   <button> : sans role ni tabindex, aucune n'etait atteignable au clavier.
   panel-appareils.js les rend focusables ; il reste a leur donner la meme
   empreinte visuelle que les commandes de l'espace admin. */
.rk-rail .rk-act.act-btn{
  width:30px;height:30px;padding:0;margin:0;flex:0 0 30px;
  background:transparent;border:1px solid transparent;border-radius:7px;
  color:var(--ink-3);
}
.rk-rail .rk-act.act-btn:hover{background:var(--panel-2);border-color:var(--line);color:var(--ink)}
/* La corbeille rouge disparait de la rangee : elle vit desormais dans le
   menu, ou elle est nommee. Meme regle que cote admin. */
.rk-rail .rk-act.act-btn.del,
.rk-rail .rk-act.act-btn.renew{border-color:transparent;color:var(--ink-3);background:transparent}
.rk-menu .rk-menu-item.act-btn{
  width:auto;height:auto;flex:none;
  justify-content:flex-start;border:0;border-radius:7px;
}

.rk-pays-nom{font-size:11px;color:var(--ink-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* Meme rythme vertical que l'espace admin. */
#devices-tbody tr{height:64px}
#devices-tbody td{vertical-align:middle;font-variant-numeric:tabular-nums}

/* Date d'ajout. La liste est triee dessus cote serveur depuis toujours
   (ORDER BY created_at DESC), mais l'ecran n'affichait que la derniere
   activite : impossible de verifier l'ordre, ni de savoir depuis quand un
   client est la. Discrete — c'est un repere, pas une donnee qu'on lit en
   premier ; la date complete vient au survol. */
.rk-ajout{
  font-size:10.5px;color:var(--ink-3);white-space:nowrap;
  margin-top:2px;font-variant-numeric:tabular-nums;
}
.rk-ajout-inline{margin-top:0}

/* =====================================================================
   14. Pagination de la liste des appareils (panel-appareils.js)
   ---------------------------------------------------------------------
   Le tableau rendait toutes les rangees d'un coup : a 74 appareils la page
   faisait plusieurs ecrans, l'en-tete des colonnes disparaissait des la
   dixieme ligne, et chaque frappe dans la recherche repeignait l'ensemble.

   La barre se lit de gauche a droite dans l'ordre ou l'on s'interroge :
   OU suis-je (« 1-25 sur 41 »), puis COMMENT je change de vue. Le decompte
   est l'information ; les commandes ne sont que le moyen, et restent donc
   plus discretes que lui.
   ===================================================================== */

.rk-pager{
  display:flex;align-items:center;justify-content:space-between;gap:16px;
  flex-wrap:wrap;
  margin-top:2px;padding:12px 14px;
  background:var(--panel);border:1px solid var(--line-soft);
  border-top:0;border-radius:0 0 12px 12px;
}
.rk-pg-compte{font-size:.84rem;color:var(--ink-3);font-variant-numeric:tabular-nums}
.rk-pg-compte b{color:var(--ink);font-weight:700}

.rk-pg-droite{display:flex;align-items:center;gap:18px;flex-wrap:wrap}

.rk-pg-taille{
  display:inline-flex;align-items:center;gap:8px;
  font-size:.8rem;color:var(--ink-3);white-space:nowrap;
}
.rk-pg-select{
  background:var(--panel-2);border:1px solid var(--line);border-radius:7px;
  color:var(--ink);font-family:var(--f-text);font-size:.82rem;
  padding:5px 8px;cursor:pointer;
}
.rk-pg-select:focus-visible{outline:none;border-color:var(--tally);box-shadow:0 0 0 3px var(--tally-glow)}

.rk-pg-nav{display:inline-flex;align-items:center;gap:4px}
.rk-pg-pos{
  font-size:.82rem;color:var(--ink-3);white-space:nowrap;
  padding:0 8px;font-variant-numeric:tabular-nums;
}
.rk-pg-pos b{color:var(--ink);font-weight:700}
.rk-pg-btn{
  width:30px;height:30px;padding:0;
  display:inline-flex;align-items:center;justify-content:center;
  background:transparent;border:1px solid var(--line);border-radius:7px;
  color:var(--ink-2);font-size:13px;cursor:pointer;
  transition:background .12s var(--ease),color .12s var(--ease),border-color .12s var(--ease);
}
.rk-pg-btn:hover:not([disabled]){background:var(--panel-2);border-color:var(--ink-3);color:var(--ink)}
.rk-pg-btn:focus-visible{outline:none;border-color:var(--tally);box-shadow:0 0 0 3px var(--tally-glow)}
/* Bout de liste : le bouton reste lisible, il ne disparait pas a moitie —
   sinon on doute d'avoir bien vu qu'il existe. */
.rk-pg-btn[disabled]{opacity:.55;cursor:default;border-color:var(--line-soft)}

@media (max-width:640px){
  .rk-pager{justify-content:center;text-align:center}
  .rk-pg-droite{width:100%;justify-content:space-between}
}
@media (prefers-reduced-motion:reduce){
  .rk-pg-btn{transition:none}
}

/* =====================================================================
   15. Le tableau tient dans la page (panel-appareils.js)
   ---------------------------------------------------------------------
   Mesure a 1366 px : le tableau reclamait 1269 px pour un conteneur de
   1067. Il fallait donc faire defiler horizontalement pour atteindre la
   colonne d'actions — celle dont on a le plus besoin.

   Deux postes dominaient : la cellule d'identite, sans borne, prenait
   411 px a elle seule ; et « Version » occupait une colonne entiere pour
   trois caracteres.
   ===================================================================== */

/* L'identite est bornee. L'adresse MAC ne se tronque JAMAIS — c'est
   l'identifiant, on le recopie. L'adresse IP, elle, peut ceder : elle est
   indicative et reste entiere au survol. */
.rk-ident{max-width:250px}
.rk-nom{max-width:250px}
.rk-ip{min-width:0}
.rk-mac,.rk-mac-absente{flex:0 0 auto}

/* La version rejoint la plateforme ; sa colonne disparait. */
.rk-plateforme{display:flex;align-items:center;gap:7px;flex-wrap:nowrap}

/* ── Pastille de plateforme ───────────────────────────────────────────────
   Le constructeur se lit dans la couleur, l'OS dans le texte. La table du
   panel ne connaissait pas les prefixes constructeur (« SAMSUNG_TIZEN »,
   « APPLE_IOS ») que les applications envoient : la majorite du parc tombait
   dans un rendu gris sans icone. */
.rk-plat{
  display:inline-flex;align-items:center;gap:5px;
  padding:2px 8px;border-radius:5px;
  background:var(--neutral-bg);border:1px solid var(--line-soft);
  font-size:10.5px;font-weight:700;white-space:nowrap;
  color:var(--ink-2);
}
.rk-plat i{font-size:11px;line-height:1}

/* ── Teintes constructeur — DEUX valeurs par marque ───────────────────────
   Le bleu Samsung d'origine (#1428a0) depasse 9:1 sur blanc mais tombe sous
   2:1 sur le panneau sombre : illisible. Les valeurs claires sont elles aussi
   ajustees — le gris Apple officiel plafonnait a 2,9:1 sur blanc, le vert
   Android a 3,4:1. Une couleur de marque n'est pas une couleur de texte : on
   garde la teinte, pas la valeur exacte. */
.rk-plat-tizen   { color:#7a95ff }
.rk-plat-webos   { color:#ff7d99 }
.rk-plat-apple   { color:#bcc3ca }
.rk-plat-android { color:#5ad395 }
.rk-plat-windows { color:#5cbdf0 }
.rk-plat-linux   { color:#ff9166 }

[data-theme="light"] .rk-plat-tizen   { color:#1428a0 }
[data-theme="light"] .rk-plat-webos   { color:#a50034 }
[data-theme="light"] .rk-plat-apple   { color:#5c646b }
[data-theme="light"] .rk-plat-android { color:#1f7a47 }
[data-theme="light"] .rk-plat-windows { color:#0a6ea3 }
[data-theme="light"] .rk-plat-linux   { color:#b8401a }

/* Aucune plateforme declaree : une absence, pas une valeur. */
.rk-plat-vide{
  background:transparent;border-color:transparent;
  color:var(--ink-2);opacity:.5;font-weight:500;padding-left:2px;padding-right:2px;
  cursor:help;
}
/* Inconnue : affichee TELLE QUELLE. La masquer empecherait de voir arriver
   une plateforme nouvelle — ou une valeur corrompue. */
/* Mesure : `--ink-3` plafonnait a 3,95:1 en theme clair — sous le seuil de
   lisibilite. Or une plateforme non reconnue est un signal de diagnostic :
   c'est la derniere chose qui doive etre effacee. */
.rk-plat-inconnue{color:var(--ink-2);cursor:help}
/* Libelle ecrase par un appel de prechargement : le bord tirete dit que la
   valeur est provisoire, comme pour un build sans version produit. */
.rk-plat-suspect{border-style:dashed;cursor:help}

/* =====================================================================
   20. Sections autres que « Appareils » (panel-sections.js)
   ===================================================================== */

/* ── Journal d'audit : la couleur dit la GRAVITE, rien d'autre ────────────
   Toutes les actions etaient de la meme teinte — un echec de connexion
   s'affichait comme une connexion reussie. On ouvre un journal d'audit pour
   reperer l'anormal : c'est la seule chose que la couleur doit encoder. */
.rk-act{
  display:inline-flex;align-items:center;
  padding:2px 8px;border-radius:5px;
  font-size:10.5px;font-weight:700;white-space:nowrap;
  background:var(--neutral-bg);border:1px solid var(--line-soft);
  color:var(--ink-2);cursor:help;
}
.rk-act-danger   {background:var(--danger-bg);border-color:transparent;color:var(--danger-ink)}
.rk-act-attention{background:var(--warn-bg);  border-color:transparent;color:var(--warn-ink)}
.rk-act-info     {color:var(--ink-2)}
.rk-act-neutre   {background:transparent;border-color:transparent;color:var(--ink-3);font-weight:600}

/* La rangee entiere se signale : dans une liste longue, une pastille seule
   se rate au balayage. Un liseré, pas un aplat — l'aplat de la page reste
   celui de l'action principale. */
.rk-log-alerte > td:first-child{box-shadow:inset 3px 0 0 var(--danger)}

/* En-tete de page dont le titre repete a ete retire : on rattrape l'espace
   qu'occupait le h2, sans quoi le sous-titre flotte. */
.rk-hdr-degage{padding-top:2px}

/* ── Colonne « Max » masquee quand elle ne varie pas ──────────────────────
   Elle affichait 100 sur chaque ligne : une colonne constante coute de la
   largeur sans rien apprendre. Elle revient d'elle-meme des que des plafonds
   distincts sont fixes. */
.rk-sans-max thead th:nth-child(5),
.rk-sans-max tbody td:nth-child(5){display:none}

/* ── Delai depuis la derniere connexion ──────────────────────────────────
   « il y a 7 semaines » se lit ; « 14/06/26 08:32 » se calcule. La date
   exacte reste au survol — c'est elle qu'on cite, pas le delai. */
.rk-delai{cursor:help}
.rk-delai-loin{color:var(--warn-ink);font-weight:600}

/* ── Action reversible ────────────────────────────────────────────────────
   « Desactiver » se rattrape, « Supprimer » non. Les peindre du meme rouge
   revenait a n'en signaler aucune : un seul rouge, celui qui ne se rattrape
   pas. */
.rk-reversible{color:var(--ink-2)!important;border-color:var(--line)!important}
.rk-reversible:hover{color:var(--warn-ink)!important;border-color:var(--warn-ink)!important}

/* Administrateur ou systeme : la colonne TYPE dit deja qui agit, l'identifiant
   interne n'ajoute rien. Il reste au survol pour qui doit le citer. */
.rk-user-vide{color:var(--ink-2);opacity:.45;cursor:help}

/* ── Barre « chercher + filtrer » ─────────────────────────────────────────
   Meme gabarit que celle des appareils : deux barres qui font la meme chose
   doivent se ressembler, sinon on reapprend a chaque page. */
.rk-barre{
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  margin:0 0 12px;
}
.rk-rech{
  display:flex;align-items:center;gap:8px;
  flex:1 1 240px;min-width:200px;height:36px;
  padding:0 12px;border-radius:8px;
  /* `--panel-2` et non `--bg-input` : ce dernier vaut #0F1620 dans LES DEUX
     themes — un champ noir sur fond blanc. Le repli n'a jamais joué, le
     jeton existant simplement. */
  background:var(--panel-2);border:1px solid var(--line);
}
.rk-rech i{color:var(--ink-3);font-size:13px;flex:0 0 auto}
.rk-rech input{
  flex:1 1 auto;min-width:0;height:100%;
  background:transparent;border:0;outline:none;
  color:var(--ink);font-size:13px;
}
.rk-rech:focus-within{border-color:var(--tally);box-shadow:0 0 0 3px var(--tally-glow)}

/* Le compteur de chaque filtre : discret, mais il dit combien on trouvera
   AVANT de cliquer. */
.rk-ftab-n{
  background:var(--neutral-bg);border-radius:10px;padding:1px 6px;
  font-size:10px;font-weight:700;color:inherit;
}
.rk-ftab-actif .rk-ftab-n{background:var(--ink-2);color:var(--panel)}

/* ── Totaux ───────────────────────────────────────────────────────────────
   Poses AU-DESSUS du tableau : c'est la reponse a la question qu'on se pose
   en arrivant — « combien ai-je vendu ? » — elle ne doit pas attendre qu'on
   ait fait defiler. Ils se recalculent sur les lignes VISIBLES : un total
   calcule sur autre chose que ce qu'on voit est un mensonge. */
.rk-totaux{
  display:flex;flex-wrap:wrap;gap:10px;margin:0 0 14px;
}
.rk-total{
  display:flex;flex-direction:column;gap:2px;
  min-width:110px;padding:9px 14px;border-radius:9px;
  background:var(--neutral-bg);border:1px solid var(--line-soft);
}
/* Le chiffre domine, l'intitule s'efface : l'inverse ferait une legende avec
   un chiffre en note de bas de page. */
.rk-total-l{
  font-size:9.5px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;
  color:var(--ink-3);
}
.rk-total-v{
  font-family:var(--f-mono);font-size:16px;font-weight:700;
  color:var(--ink);letter-spacing:-.01em;line-height:1.2;
}
.rk-total-plus { color:var(--ok) }
.rk-total-moins{ color:var(--danger) }

/* ── Liste filtree a zero ─────────────────────────────────────────────────
   Une liste vide doit le DIRE. Rester blanche laisse croire a un
   chargement qui n'aboutit pas. */
/* ── Tableau de bord : sept cartes au lieu de six ─────────────────────────
   Six appareils n'etaient comptes nulle part — dont trois abonnements a vie.
   La carte LIFETIME rejoint la rangee ; une regle de largeur suffit, on ne
   touche pas au balisage. */
@media (min-width:1200px){
  .rk-sept-cartes > [class*="col-"]{
    flex:0 0 14.2857%;max-width:14.2857%;
  }
}
/* Lifetime : la teinte du statut correspondant dans la liste des appareils —
   un meme etat ne doit pas changer de couleur d'un ecran a l'autre. */
.stat-card.c-lifetime{border-bottom-color:#7c3aed}
.stat-card.c-lifetime .stat-icon{color:#7c3aed}
/* Le total decompose ses parts au survol : sept cartes ne suffisent pas a
   montrer six statuts sans encombrer. */
.rk-total-detail{cursor:help}

/* Une absence, pas un pays : elle se lit en retrait du reste de la liste. */
.rk-pays-inconnu-ligne{
  display:flex;align-items:center;gap:12px;
  padding:9px 4px;font-size:13px;
  color:var(--ink-3);font-style:italic;cursor:help;
}

/* ── Bouton « afficher le secret » ────────────────────────────────────────
   Meme gabarit que les boutons voisins (regenerer, copier) : trois commandes
   alignees sur un champ doivent avoir la meme taille, sinon l'ajout se
   remarque comme une piece rapportee. */
.rk-oeil{flex:0 0 auto}

/* La mention sous la cle d'application. L'avertissement est en deux temps :
   ce a quoi la cle doit correspondre, puis ce qu'il en coute de la changer —
   juste a cote du bouton qui le permet. */
.rk-mention-cle{line-height:1.55}
.rk-mention-cle strong{color:var(--warn-ink)}

.rk-vide{
  padding:28px 16px!important;text-align:center;
  color:var(--ink-3);font-size:13px;
}
.rk-sans-colonne-version thead th:nth-child(4),
.rk-sans-colonne-version tbody td:nth-child(4){display:none}

/* « Playlist » rejoint l'identite : une colonne entiere pour un seul mot. */
.rk-tag-source{
  background:var(--info-bg);border-color:transparent;color:var(--info-ink);
  font-weight:600;letter-spacing:.02em;
}
.rk-sans-colonne-source thead th:nth-child(5),
.rk-sans-colonne-source tbody td:nth-child(5){display:none}

/* L'identite se resserre : c'est le poste le plus lourd du tableau, et le
   nom d'un client tient dans 220 px. Le reste est au survol. */
.rk-ident,.rk-nom{max-width:220px}
.rk-plateforme{gap:6px}

/* Gouttieres : 14 px de chaque cote sur huit colonnes faisaient 224 px de
   rembourrage pur, soit un cinquieme de la largeur utile. A 10 px la lecture
   reste aeree et le tableau gagne la marge qui lui manquait pour tenir dans
   la page sans defilement lateral. */
#devices-body td,
#devices-tbody td{padding-left:10px;padding-right:10px}
table:has(#devices-body) thead th,
table:has(#devices-tbody) thead th{padding-left:10px;padding-right:10px}

/* ── Source de l'appareil, sous l'adresse MAC ────────────────────────────
   Le couple qu'on lit en diagnostic : quel appareil, vers quel serveur.
   On affiche l'ORIGINE seule — une URL M3U porte `username=` et `password=`
   en clair, qui n'ont rien a faire dans une liste qu'on parcourt a plusieurs
   devant un ecran. L'adresse complete reste au survol. */
/* `center` et non `baseline` : cette ligne melange une image (le drapeau) et
   du texte, et un element flex sans texte a pour ligne de base son bord
   INFERIEUR. Le drapeau reclamait donc 16 px au-dessus de la ligne de base la
   ou le texte n'en demande que 9 — la ligne de base descendait d'autant, et
   tout le contenu passait sous la borne basse. */
.rk-ident-l3{display:flex;align-items:center;gap:6px;min-width:0}
.rk-source{
  font-family:var(--f-mono);font-size:10.5px;color:var(--ink-3);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;
}
.rk-source-vide{font-family:var(--f-text);font-style:italic}

/* La fiche et ce que recoit le client ne concordent pas. C'est l'ecart qui
   est passe inapercu sur onze appareils : il se voit desormais. */
.rk-tag-alerte{
  flex:0 0 auto;background:var(--warn-bg);border-color:transparent;
  color:var(--warn-ink);font-weight:700;cursor:help;
}

/* Trois lignes au lieu de deux : la rangee grandit, mais reste IDENTIQUE
   partout — c'est l'uniformite qui fait tenir la lecture, pas la hauteur. */
#devices-body tr,#devices-tbody tr{height:78px}

/* La pastille « ecart » a une boite plus haute que le texte de la source :
   les trois rangees concernees depassaient de 5 px et cassaient l'uniformite
   qu'on venait d'obtenir. La ligne est donc bornee, et la pastille se cale
   dessus au lieu de l'ecarter. */
/* 18 px, mesure : c'est la hauteur du plus grand element de la ligne (la
   pastille d'etat, 16,5 px avec sa bordure). A 16 px, 5,2 px etaient coupes
   des lors qu'un drapeau etait present — c'est-a-dire sur chaque rangee.
   La hauteur reste FIGEE : c'est elle qui garantit des rangees de meme taille,
   raison d'etre de cette borne. Elle est juste, pas relachee. */
.rk-ident-l3{height:18px;overflow:hidden}
.rk-tag-alerte{padding:0 6px;font-size:9.5px;line-height:1.6}

/* =====================================================================
   16. Copier, filtrer, alerter (panel-appareils.js)
   ---------------------------------------------------------------------
   Trois gestes qui manquaient a la liste : recopier une adresse sans la
   saisir a la main, demander « tous les appareils sur cet hote », et voir
   qu'un catalogue n'a pas charge avant que le client n'appelle.

   Les affordances n'apparaissent qu'au survol de la rangee : la ligne doit
   rester une ligne de donnees, pas une barre d'outils.
   ===================================================================== */

/* Adresse MAC : cliquer copie. */
.rk-copiable{cursor:pointer;border-radius:4px;padding:0 2px;margin-left:-2px;
  transition:background .12s var(--ease),color .12s var(--ease)}
.rk-copiable:hover{background:var(--neutral-bg);color:var(--ink)}
.rk-copiable:focus-visible{outline:none;box-shadow:0 0 0 2px var(--tally-glow)}
.rk-copie{background:var(--ok-bg)!important;color:var(--ok-ink)!important}
.rk-copie-ko{background:var(--danger-bg)!important;color:var(--danger-ink)!important}

/* Hote : cliquer filtre. Le souligne pointille dit « ceci agit » sans
   ajouter un bouton de plus sur une ligne deja dense. */
.rk-source-filtrable{
  cursor:pointer;border-bottom:1px dotted transparent;
  transition:color .12s var(--ease),border-color .12s var(--ease);
}
#devices-body tr:hover .rk-source-filtrable,
#devices-tbody tr:hover .rk-source-filtrable{border-bottom-color:var(--line)}
.rk-source-filtrable:hover{color:var(--ink);border-bottom-color:var(--ink-3)}
.rk-source-filtrable:focus-visible{outline:none;color:var(--ink);box-shadow:0 0 0 2px var(--tally-glow);border-radius:3px}

/* Copie de l'adresse complete : discrete, revelee au survol de la rangee. */
.rk-copie-url{
  flex:0 0 auto;width:18px;height:16px;padding:0;
  display:inline-flex;align-items:center;justify-content:center;
  background:transparent;border:0;border-radius:4px;
  color:var(--ink-3);font-size:10px;cursor:pointer;
  opacity:0;transition:opacity .12s var(--ease),background .12s var(--ease),color .12s var(--ease);
}
#devices-body tr:hover .rk-copie-url,
#devices-tbody tr:hover .rk-copie-url,
.rk-copie-url:focus-visible{opacity:1}
.rk-copie-url:hover{background:var(--neutral-bg);color:var(--ink)}
.rk-copie-url:focus-visible{outline:none;box-shadow:0 0 0 2px var(--tally-glow)}

/* Etat du catalogue : on ne montre que l'anormal. Un bandeau « tout va
   bien » sur chaque ligne ne se lit plus au bout de trois rangees. */
.rk-tag-cat{flex:0 0 auto;padding:0 6px;font-size:9.5px;line-height:1.6;font-weight:700;cursor:help}

/* ── Colonne « Etat playlist » ────────────────────────────────────────────
   Une colonne de nombres se lit en la balayant verticalement, ce qui suppose
   que tous les chiffres tombent au meme endroit : d'ou la chasse fixe et la
   largeur constante, independante de la valeur.

   Elle occupe une colonne deja presente dans le balisage — « Playlist » cote
   admin, « Version » cote revendeur — dont le contenu avait ete deplace
   ailleurs. Pas un pixel de plus qu'avant. */
.rk-col-pl{text-align:center;white-space:nowrap;width:96px}
.rk-pl-nb{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:28px;height:24px;padding:0 7px;border-radius:7px;
  background:var(--neutral-bg);border:1px solid var(--line-soft);
  color:var(--ink-2);font-family:var(--f-mono);font-size:12.5px;font-weight:700;
  cursor:help;
}
/* Zero : quatre appareils actifs du parc n'ont aucune playlist. Le chiffre
   seul se serait noye au milieu des autres — il prend la teinte d'alerte,
   celle des statuts en danger. */
.rk-pl-nb-zero{background:var(--danger-bg);border-color:transparent;color:var(--danger-ink)}
.rk-tag-cat-ko{background:var(--danger-bg);border-color:transparent;color:var(--danger-ink)}
.rk-tag-cat-attente{background:var(--warn-bg);border-color:transparent;color:var(--warn-ink)}

/* Filtre actif : visible et retirable d'un geste — un tableau filtre sans
   indication se lit comme un tableau vide. */
.rk-pg-filtre{
  display:inline-flex;align-items:center;gap:7px;
  padding:4px 10px;border-radius:7px;
  background:var(--info-bg);border:1px solid transparent;
  color:var(--info-ink);font-family:var(--f-mono);font-size:.78rem;font-weight:600;
  cursor:pointer;transition:background .12s var(--ease);
}
.rk-pg-filtre:hover{background:var(--panel-2);color:var(--ink)}
.rk-pg-filtre:focus-visible{outline:none;box-shadow:0 0 0 3px var(--tally-glow)}
.rk-pg-filtre-x{font-size:9px;opacity:.7}

@media (prefers-reduced-motion:reduce){
  .rk-copiable,.rk-source-filtrable,.rk-copie-url,.rk-pg-filtre{transition:none}
}

/* ── Correction : l'adresse IP sous l'adresse MAC ────────────────────────
   L'IP etait posee A COTE de la MAC, separee d'un point, et une troisieme
   ligne montrait l'URL de la playlist — qui n'avait pas ete demandee.
   L'identite se lit maintenant de haut en bas : qui, quelle machine, quelle
   adresse. L'hote n'a plus de ligne : il est porte par la pastille de
   source, qui reste cliquable pour filtrer. */
.rk-ip{
  font-family:var(--f-mono);font-size:11px;color:var(--ink-3);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;
}
.rk-ip-vide{font-family:var(--f-text);font-style:italic}

/* La pastille de source devient une commande : meme discretion, mais elle
   repond au survol et au clavier. */
.rk-tag-source.rk-source-filtrable{cursor:pointer;transition:background .12s var(--ease),color .12s var(--ease)}
.rk-tag-source.rk-source-filtrable:hover{background:var(--info-bg);color:var(--ink)}
.rk-tag-source.rk-source-filtrable:focus-visible{outline:none;box-shadow:0 0 0 2px var(--tally-glow)}

/* ── Drapeaux (table de correspondance /flags/) ──────────────────────────
   Un drapeau clair sur fond sombre a besoin d'un contour : sans lui, le
   blanc du drapeau francais ou canadien se decoupe dans le vide et la forme
   se perd. Le liseré est net, pas une ombre floue — la liste se repeint a
   chaque frappe dans la recherche. */
.rk-drapeau{
  display:block;width:20px;height:15px;margin:4px auto 0;
  border-radius:2px;border:1px solid rgba(255,255,255,.14);
  object-fit:cover;background:var(--panel-2);
}
/* Dans l'identite revendeur, le drapeau se pose sur la ligne, pas au-dessus. */
.rk-ident-l2 .rk-drapeau{display:inline-block;margin:0;vertical-align:-2px}

/* =====================================================================
   17. Bascule de langue (panel-langue.js)
   ---------------------------------------------------------------------
   Deux lettres, la langue active en clair et l'autre en retrait : on lit
   d'un coup d'oeil ou l'on est ET ce que le clic va faire. Un drapeau
   aurait ete pire — un drapeau designe un pays, pas une langue.
   ===================================================================== */
.rk-langue-btn{
  display:inline-flex;align-items:center;gap:1px;
  height:32px;padding:0 9px;margin-right:6px;
  background:transparent;border:1px solid var(--line);border-radius:8px;
  color:var(--ink-2);font-family:var(--f-mono);font-size:11px;font-weight:700;
  letter-spacing:.06em;cursor:pointer;
  transition:background .12s var(--ease),border-color .12s var(--ease),color .12s var(--ease);
}
.rk-langue-btn:hover{background:var(--panel-2);border-color:var(--ink-3);color:var(--ink)}
.rk-langue-btn:focus-visible{outline:none;border-color:var(--tally);box-shadow:0 0 0 3px var(--tally-glow)}
.rk-langue-actif{color:var(--ink)}
.rk-langue-autre{color:var(--ink-3);opacity:.55}
.rk-langue-autre::before{content:'/';margin:0 2px;opacity:.5}

/* =====================================================================
   18. Statuts, en-tete collant, et corrections vues a l'ecran
   ---------------------------------------------------------------------
   Constate en THEME CLAIR, qui est celui reellement utilise — toutes les
   mesures precedentes portaient sur le sombre. C'etait l'angle mort.
   ===================================================================== */

/* ── Une seule grammaire de couleur pour les statuts ──────────────────────
   Le rendu d'origine peignait « actif » en AMBRE : sur quarante-quatre
   appareils, trente-quatre — les clients sains — portaient la couleur qui
   signifie « attention » partout ailleurs. Le liseré de rangee aussi. */
:root{
  --rk-statut-ok:var(--ok);
  --rk-statut-info:var(--info);
  --rk-statut-warn:var(--warn);
  --rk-statut-danger:var(--danger);
  --rk-statut-neutre:var(--ink-3);
}
.rk-statut{
  display:inline-block;padding:3px 11px;border-radius:20px;
  font-family:var(--f-text);font-size:11px;font-weight:700;
  letter-spacing:.015em;white-space:nowrap;line-height:1.5;
}
.rk-statut-ok{background:var(--ok-bg);color:var(--ok-ink)}
.rk-statut-info{background:var(--info-bg);color:var(--info-ink)}
.rk-statut-warn{background:var(--warn-bg);color:var(--warn-ink)}
.rk-statut-danger{background:var(--danger-bg);color:var(--danger-ink)}
/* --ink-3 sur le gris neutre donnait 3,94:1, sous le seuil AA de 4,5.
   L'encre secondaire passe largement et reste discrete. */
.rk-statut-neutre{background:var(--neutral-bg);color:var(--ink-2)}

/* Le liseré de rangee : un rappel, pas une barre. 3 px d'aplat vif sur
   chaque ligne saturait la colonne de gauche. */
#devices-body tr{border-left-width:3px;border-left-style:solid}

.rk-sans-date{color:var(--ink-3)}

/* ── En-tete de colonnes collant ──────────────────────────────────────────
   Seule la barre du haut l'etait. Sur une page de vingt-cinq rangees, on
   perdait les intitules des la dixieme ligne — et on lisait une adresse IP
   sans savoir de quelle colonne elle venait. */
/* `position:sticky` colle au plus proche ancetre qui defile. Le conteneur du
   tableau porte `overflow-x:auto`, ce qui force `overflow-y` a `auto` : c'est
   donc LUI le contexte de defilement, et l'en-tete collait a un conteneur qui
   s'en allait avec la page. On borne sa hauteur : les rangees defilent a
   l'interieur, l'en-tete tient, et la barre d'outils comme la pagination
   restent a l'ecran. */
/* PREMIERE TENTATIVE, ECARTEE : borner la hauteur du conteneur pour qu'il
   devienne la zone de defilement. A l'ecran, le tableau se retrouvait coupe
   au milieu d'une rangee, avec du vide en dessous et la pagination hors de
   vue. Une correction qui abime plus qu'elle ne repare n'en est pas une.

   RETENU : `overflow-x:clip` ne cree PAS de contexte de defilement, la ou
   `auto` en cree un sur les deux axes. La page reprend donc son defilement
   naturel, et l'en-tete colle sous la barre du haut. En dessous de 1200 px,
   le tableau a besoin de defiler lateralement : on rend `auto` et on renonce
   a l'en-tete collant, plutot que de rendre des colonnes inatteignables. */
@media (min-width:1200px){
  div:has(> table > #devices-body),
  div:has(> table > #devices-tbody){
    overflow-x:clip;overflow-y:visible;max-height:none;
  }
  table:has(#devices-body) thead th,
  table:has(#devices-tbody) thead th{
    position:sticky;top:52px;z-index:20;      /* 52 px = hauteur de .topbar */
    background:var(--panel);
    box-shadow:inset 0 -1px 0 var(--line);
  }
}
@media (max-width:1199px){
  div:has(> table > #devices-body),
  div:has(> table > #devices-tbody){overflow-x:auto}
}

/* ── Commandes de rangee : lisibles en clair aussi ────────────────────────
   `--ink-3` a 80 % donne 3,96:1 sur fond sombre, mais des traits de 13 px
   sur du blanc n'y survivent pas : a l'ecran, les commandes disparaissaient.
   En clair, on ne les estompe plus — on les pose en encre secondaire. */
/* (surcharge en clair retiree : la regle est desormais commune aux deux themes) */

/* ── Drapeau : a cote de l'adresse IP ─────────────────────────────────────
   Empile sous la case a cocher, il formait une bande rouge verticale sur le
   bord gauche — quatre drapeaux marocains l'un sous l'autre, juste a cote du
   liseré de statut : deux signaux colores cote a cote qui ne disent pas la
   meme chose. Et il n'etait pas a sa place : le pays est DEDUIT de l'adresse
   IP par geolocalisation. Il la precede desormais, et la premiere colonne
   retrouve son seul role — selectionner. */
#devices-body td:first-child{white-space:nowrap;text-align:center}
#devices-body td:first-child > input[type="checkbox"]{display:inline-block;margin:0}
/* Pas de `vertical-align` ici : c'est un element flex, la propriete y est
   sans effet. Je l'y avais mise en croyant regler l'alignement — elle n'a
   jamais rien fait, et masquait le vrai probleme, qui etait `align-items`. */
.rk-drapeau-inline{
  width:21px;height:16px;margin:0 5px 0 0;display:inline-block;flex:0 0 auto;
}

/* =====================================================================
   19. Barre d'outils : une hierarchie, et un seul rouge
   ---------------------------------------------------------------------
   Huit commandes au meme poids visuel : la barre passait a la ligne,
   « Transfert MAC » et l'actualisation restaient orphelines en dessous, et
   le champ de recherche etait tronque. Les trois outils rares rejoignent un
   menu ; la barre se lit en trois temps — chercher, filtrer, agir.
   ===================================================================== */

/* Tout ce bloc est porte par `#page-devices`, qui n'existe QUE dans
   admin.html. Les deux interfaces ont une `.toolbar`, mais leur balisage n'a
   rien de commun — sans cette frontiere, `.toolbar > *{flex:0 0 auto}`
   annulait le `.search-box{flex:1}` du revendeur, et sa recherche cessait de
   s'etirer. */
#page-devices .toolbar{flex-wrap:nowrap!important;align-items:center}

/* Une hauteur unique. Sept hauteurs se cotoyaient sur la meme ligne, et un
   alignement approximatif se remarque plus qu'un alignement absent : l'oeil
   lit un ecart de 2 px comme un defaut, la ou il accepte une grille franche. */
#page-devices .toolbar > *,
#page-devices .toolbar > div > button{flex:0 0 auto}
#page-devices .toolbar button,
#page-devices .toolbar .sel,
#page-devices .toolbar .search-wrap{
  height:36px;
  display:inline-flex;align-items:center;
  padding-top:0;padding-bottom:0;
  white-space:nowrap;                 /* aucun libelle ne se replie */
}
#page-devices .toolbar .search-wrap{display:flex;flex:1 1 220px;min-width:180px}
#page-devices .toolbar .search-wrap input{height:100%;padding-top:0;padding-bottom:0}
#page-devices .toolbar .sel{padding-right:28px}

/* Le groupe des filtres rapides : sans largeur plancher il se comprimait sous
   sa taille utile et ses boutons debordaient par-dessus la recherche. */
.rk-ftabs{display:flex;gap:6px;align-items:center;flex:0 0 auto}

.rk-outils{position:relative;flex:0 0 auto;margin-left:auto}
.rk-outils-btn{display:inline-flex;align-items:center;gap:6px;white-space:nowrap}
.rk-outils .rk-menu{min-width:230px}

/* Filtre actif : un ETAT, pas une action.
   Il portait l'aplat rouge de « + Ajouter ». Deux rouges se disputaient
   l'attention alors que la regle du panel en veut un seul : celui de
   l'action principale. Un etat se signale par le contraste et le poids. */
.rk-ftab{
  font-size:12px;padding:0 12px;white-space:nowrap;
  height:36px;display:inline-flex;align-items:center;gap:6px;
  background:transparent;border:1px solid var(--line);color:var(--ink-2);
  border-radius:8px;cursor:pointer;
  transition:background .12s var(--ease),border-color .12s var(--ease),color .12s var(--ease);
}
.rk-ftab:hover{border-color:var(--ink-3);color:var(--ink)}
.rk-ftab-actif{
  background:var(--panel-2);border-color:var(--ink-3);color:var(--ink);font-weight:700;
  box-shadow:inset 0 -2px 0 var(--tally);   /* un trait, pas un aplat */
}
.rk-ftab:focus-visible{outline:none;border-color:var(--tally);box-shadow:0 0 0 3px var(--tally-glow)}
.rk-ftab span{background:var(--neutral-bg)!important;color:inherit;border-radius:10px;padding:1px 6px;font-size:10px}
/* Le compteur restait un aplat rouge : cela refaisait DEUX rouges a l'ecran
   alors que le trait sous l'onglet suffit a dire « actif ». Un seul aplat
   rouge dans cette page, et c'est « + Ajouter ». */
.rk-ftab-actif span{background:var(--ink-2)!important;color:var(--panel)}

@media (max-width:1100px){
  #page-devices .toolbar{flex-wrap:wrap!important}
  .rk-outils{margin-left:0}
}

/* ── Pays inconnu ────────────────────────────────────────────────────────
   Le rendu d'origine posait la un POINT DE STATUT, avec l'ancienne palette :
   sur la meme rangee, la pastille disait « Actif » en vert et le point disait
   ambre. Deux couleurs pour un seul etat — et une information deja portee par
   sa propre colonne. Le marqueur dit maintenant ce qu'il doit dire : on ne
   sait pas d'ou vient cet appareil. */
.rk-pays-inconnu{
  display:inline-block;width:27px;height:20px;vertical-align:middle;
  border:1px dashed var(--line);border-radius:2px;background:transparent;
}

/* ── Cases a cocher ──────────────────────────────────────────────────────
   Le controle natif rendait un carre noir plein : l'element le plus lourd de
   la rangee etait celui qui compte le moins. Il prend la couleur de marque
   quand il est coche, et se fait discret sinon. */
#devices-body input[type="checkbox"],
#devices-tbody input[type="checkbox"],
table:has(#devices-body) thead input[type="checkbox"]{
  width:15px;height:15px;cursor:pointer;
  accent-color:var(--tally);
}

/* Le titre repete retire, la ligne d'en-tete se resserre : le compteur reste
   a gauche, l'action principale a droite. On recupere la hauteur d'un titre
   qui ne disait rien que la barre du haut ne disait deja. */
.rk-hdr-degage{align-items:center;padding-bottom:4px}
.rk-hdr-degage > div > p{margin:0;font-size:13px;color:var(--ink-2)}
