/* ═══════════════ LE CHOIX DES BALLES À L'ORDINATEUR (#chars, hors téléphone) ═══════════════
   Js', 03/10 : « l'UI du choix des balles sur PC on va le refaire en s'inspirant de l'UI du menu de base où on choisit le
   mode de jeu ». Le même monde que l'entrée (css/hub.css) : sa nuit et son décor. À gauche, la fiche de ta balle comme une
   carte du lobby (sa scène à ses couleurs, la balle en grand, « Valider » en or) ; à droite, un grand panneau à la couleur
   de la catégorie choisie, comme le contenu d'un onglet du menu : ses onglets biseautés (Toutes, ★ Favoris, puis les
   catégories), la recherche, « Au hasard » et la grille. Tout est mesuré en --u, comme l'entrée (10 px à 1 920 × 1 080).
   Rien ne change au fonctionnement : un clic sur une balle la choisit tout de suite (et prévient le groupe), « Valider »
   ferme. Au téléphone, rien ne change non plus (css/balles.css) : toutes ces règles sont en html:not(.tel), sauf le dé (tout
   en bas), le même partout. css/revanche.css, chargé après, garde la main sur « Confirmer » et « Prêt ✓ » : aucune règle
   d'ici sur #charsOk ne doit dépasser sa force, (2,2,0). */

/* ─── les mesures de l'entrée (elles n'existent que sur .bd-hub : on les redonne ici, comme le coffre et le profil) ─── */
html:not(.tel) #chars {
  --u: clamp(6px, min(0.521vw, 0.926vh), 15px);
  --out: 2px 2px 0 var(--ink), -1.5px -1.5px 0 var(--ink), 1.5px -1.5px 0 var(--ink), -1.5px 1.5px 0 var(--ink), 0 2px 0 var(--ink);
  --out3: 3px 3px 0 var(--ink), -2px -2px 0 var(--ink), 2px -2px 0 var(--ink), -2px 2px 0 var(--ink), 0 3px 0 var(--ink), 3px 0 0 var(--ink);
}
@media (max-height: 520px) { html:not(.tel) #chars { --u: 4px; } }
/* LA COULEUR DE CHAQUE CATÉGORIE (Js' : Toutes en violet, Favoris en or, Originaux en vert, Animés en rouge, Jeux vidéo en
   bleu, Comics en sarcelle, Horreur en violet sombre, Internet en orange) : --fc-c la vive, --fc-d la profonde — les noms de
   l'entrée, que ses rayons du fond lisent aussi. Sur #chars : la catégorie choisie (data-cat, posé par js/br/app.js
   filterRoster) pour le panneau, le halo et les rayons ; sur chaque onglet et chaque groupe de la grille : la sienne. */
html:not(.tel) #chars, html:not(.tel) #chars [data-cat="all"] { --fc-c: #8E44E8; --fc-d: #4B1F8A; }
html:not(.tel) #chars[data-cat="fav"], html:not(.tel) #chars [data-cat="fav"] { --fc-c: #FFC531; --fc-d: #C98A00; }
html:not(.tel) #chars[data-cat="base"], html:not(.tel) #chars [data-cat="base"] { --fc-c: #1FB873; --fc-d: #0E6B47; }
html:not(.tel) #chars[data-cat="anime"], html:not(.tel) #chars [data-cat="anime"] { --fc-c: #E5484D; --fc-d: #8E1B2B; }
html:not(.tel) #chars[data-cat="jeux"], html:not(.tel) #chars [data-cat="jeux"] { --fc-c: #2D8CFF; --fc-d: #15479A; }
html:not(.tel) #chars[data-cat="comics"], html:not(.tel) #chars [data-cat="comics"] { --fc-c: #12A99C; --fc-d: #0B6158; }
html:not(.tel) #chars[data-cat="horreur"], html:not(.tel) #chars [data-cat="horreur"] { --fc-c: #6B4FD8; --fc-d: #2B1866; }
html:not(.tel) #chars[data-cat="web"], html:not(.tel) #chars [data-cat="web"] { --fc-c: #FF8A3D; --fc-d: #B4491A; }

/* ─── l'écran : la nuit de l'entrée, son halo à la couleur de la catégorie, ses rayons et ses poussières (la div .hub-deco
   de br.html) ; plus de partie de bots derrière (js/br/app.js frame), plus de badge balldash.io (Js'), les messages en
   haut comme à l'entrée (sauf pendant la revanche : son bandeau est en haut) ─── */
html:not(.tel) body[data-screen="chars"] { background: #100C2C; }
html:not(.tel):has(body[data-screen="chars"]) { background: #100C2C; }
body[data-screen="chars"] .wm { display: none !important; }
html:not(.tel) body.br[data-screen="chars"]:not(:has(#chars.rev)) > .toast { top: calc(var(--sa-t, 0px) + 74px); bottom: auto; left: 50%; transform: translateX(-50%); max-width: calc(100% - 32px); text-align: center; }
html:not(.tel) #chars {
  max-width: none; margin: 0; height: 100vh; height: 100dvh; min-height: 0; box-sizing: border-box;
  gap: calc(var(--u) * 2); padding: calc(var(--u) * 2.4) calc(var(--u) * 3.2) calc(var(--u) * 2.8);
  color: #fff; overflow: hidden; overflow: clip;
  background:
    radial-gradient(ellipse 70% 60% at 64% 46%, color-mix(in srgb, var(--fc-c) 30%, transparent), transparent 72%),
    radial-gradient(ellipse 120% 90% at 50% 120%, rgba(0, 0, 0, 0.45), transparent 60%),
    linear-gradient(160deg, #2E2368, #17123F 58%, #0D0A25);
}
html.tel #chars > .hub-deco { display: none; }
/* (le réglage « Fond animé » coupé, comme à l'entrée : le décor, les rayons de la fiche et le reflet de « Valider »
   s'arrêtent — js/br/app.js syncSegs ; « réduire les animations » du système aussi : plus bas, après les règles qu'il annule) */
html:not(.tel) #chars.still .hub-deco i, html:not(.tel) #chars.still .hero-stage::before, html:not(.tel) #chars.still #charsOk::after { animation: none !important; }

/* ─── la barre du haut : « ← Retour » et ⚙ comme les boutons de l'entrée, le titre en blanc cerné d'encre comme son logo
   (la revanche y glisse son bandeau, sur une deuxième ligne : css/revanche.css) ─── */
html:not(.tel) #chars > .topbar { position: relative; z-index: 3; gap: calc(var(--u) * 1.4); min-height: calc(var(--u) * 6); }
html:not(.tel) #chars .menu-title { margin: 0 0 0 calc(var(--u) * 0.4); padding: 0 calc(var(--u) * 0.5) calc(var(--u) * 0.4) 0; font: italic 800 calc(var(--u) * 5.4)/1 var(--fc); letter-spacing: 0.5px; text-transform: uppercase; color: #fff; text-shadow: var(--out3), calc(var(--u) * 0.45) calc(var(--u) * 0.55) 0 var(--ink); white-space: nowrap; transform: rotate(-2deg); }
html:not(.tel) #chars #charsBack { display: inline-flex; align-items: center; justify-content: center; gap: calc(var(--u) * 0.6); height: calc(var(--u) * 5.6); min-height: 44px; box-sizing: border-box; padding: 0 calc(var(--u) * 2); border: calc(var(--u) * 0.35) solid var(--ink); border-radius: calc(var(--u) * 1.2); background: var(--card); color: var(--ink); box-shadow: calc(var(--u) * 0.4) calc(var(--u) * 0.4) 0 var(--ink); font: italic 800 max(15px, calc(var(--u) * 2.3))/1 var(--fc); letter-spacing: 1px; text-transform: uppercase; white-space: nowrap; }
html:not(.tel) #chars #charsBack:not(.rv-arme):hover { background: #fff; transform: translate(-1px, -1px); }   /* (« Annuler ? » de la revanche reste rouge) */
html:not(.tel) #chars #charsBack:active { transform: translate(2px, 2px); box-shadow: 1px 1px 0 var(--ink); }
html:not(.tel) #chars > .topbar .icon-btn { width: calc(var(--u) * 5.6); height: calc(var(--u) * 5.6); min-width: 44px; min-height: 44px; border-width: calc(var(--u) * 0.35); border-radius: calc(var(--u) * 1.2); box-shadow: calc(var(--u) * 0.4) calc(var(--u) * 0.4) 0 var(--ink); }
html:not(.tel) #chars > .topbar .icon-btn svg { width: 52%; height: 52%; }
/* (au clavier : le contour de l'élément choisi se voit sur la nuit et sur le panneau) */
html:not(.tel) #chars > .topbar :focus-visible, html:not(.tel) #chars .roster-col :focus-visible { outline-color: #fff; }

/* ─── deux colonnes : la fiche à gauche (pas plus large que 80 u : sur un écran très large, la place va à la grille), le
   panneau à droite ─── */
html:not(.tel) #chars .chars-body { position: relative; z-index: 1; flex: 1; min-height: 0; display: grid; grid-template-columns: minmax(calc(var(--u) * 50), min(41%, calc(var(--u) * 80))) minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); gap: calc(var(--u) * 3); align-items: stretch; }

/* ═══ LA FICHE : une carte du lobby — la scène à la couleur de la balle (un soleil de BD, des rayons, le sol), la balle en
   grand ; dessous son nom, son pouvoir et ses barres, puis « Valider » en or ; à droite ses attaques, chacune sur sa carte.
   (js/br/app.js fitHero : le texte et « Valider » dans la même colonne, les attaques à hauteur fixe pour --kfit) ═══ */
html:not(.tel) #chars .hero {
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); grid-template-rows: minmax(0, 1fr) auto auto; grid-template-areas: "stage kit" "txt kit" "ok kit";
  border: calc(var(--u) * 0.5) solid var(--ink); border-radius: calc(var(--u) * 2.2); background: var(--card); color: var(--ink);
  box-shadow: calc(var(--u) * 1) calc(var(--u) * 1) 0 var(--ink);
}
/* (la scène prend toute la hauteur libre de sa colonne ; la balle y est carrée, à la plus petite des deux mesures) */
html:not(.tel) #chars .hero-stage { aspect-ratio: auto; min-height: 0; container-type: size; border-bottom: calc(var(--u) * 0.5) solid var(--ink);
  background:
    radial-gradient(circle at 50% 46%, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 44%),
    radial-gradient(circle at 50% 46%, color-mix(in srgb, var(--c1) 22%, #fff) 0 12%, color-mix(in srgb, var(--c1) 72%, #fff) 44%, var(--c1) 74%, color-mix(in srgb, var(--c1) 72%, #000)); }
html:not(.tel) #chars .hero-stage::before { top: 46%; width: max(250cqw, 250cqh); background: repeating-conic-gradient(rgba(255, 255, 255, 0.24) 0 7deg, rgba(255, 255, 255, 0) 7deg 16deg); animation-duration: 90s; }
html:not(.tel) #chars .hero-stage .hero-cv { top: 46%; height: min(84cqh, 96cqw); width: auto; translate: -50% -50%; }
/* (le sol : une ellipse claire cernée, sous la balle, comme l'arène des cartes du menu) */
html:not(.tel) #chars .hero-stage::after { top: calc(46% + min(84cqh, 96cqw) * 0.36); bottom: auto; width: calc(min(84cqh, 96cqw) * 0.7); height: calc(min(84cqh, 96cqw) * 0.14); translate: -50% 0; box-sizing: border-box; border: calc(var(--u) * 0.35) solid rgba(21, 21, 21, 0.3); background: rgba(255, 255, 255, 0.3); }
/* (sa catégorie : l'étiquette d'encre penchée de l'entrée ; dans une fiche étroite, sur deux lignes plutôt que coupée —
   « COMICS, FILMS & SÉRI… ») */
html:not(.tel) #chars .hero-cat { left: calc(var(--u) * 1.4); top: calc(var(--u) * 1.4); max-width: calc(100% - var(--u) * 2.8); white-space: normal; padding: calc(var(--u) * 0.5) calc(var(--u) * 1.1) calc(var(--u) * 0.6); border: calc(var(--u) * 0.3) solid var(--ink); border-radius: calc(var(--u) * 0.9); background: var(--ink); color: color-mix(in srgb, var(--c1) 45%, #fff); box-shadow: calc(var(--u) * 0.3) calc(var(--u) * 0.3) 0 rgba(0, 0, 0, 0.35); font: italic 800 max(12px, calc(var(--u) * 1.6))/1 var(--fc); letter-spacing: 1.2px; transform: rotate(-3deg); transform-origin: 0 50%; }
html:not(.tel) #chars .hero-txt { padding: calc(var(--u) * 1.6) calc(var(--u) * 2) calc(var(--u) * 0.4); }
html:not(.tel) #chars .hero .slot-tag { font: 800 max(11px, calc(var(--u) * 1.3)) var(--fc); letter-spacing: 2px; }
/* (le nom et le pouvoir : js/br/app.js fitLine rétrécit la police jusqu'à ce que scrollWidth, un entier, ne dépasse plus
   clientWidth d'un demi-pixel ; un texte qui dépassait encore de quelques dixièmes finissait en points de suspension —
   « COSMIC ARMOR SUPERM… » — : on coupe net ces dixièmes, invisibles. Pas de marge intérieure à droite du nom : scrollWidth
   et clientWidth la comptent tous deux, un nom qui n'aurait débordé que dans elle passerait inaperçu.) */
html:not(.tel) #chars .hero h2 { margin: calc(var(--u) * 0.3) 0 0; padding: 0 0 calc(var(--u) * 0.2) 0; font: italic 800 max(24px, calc(var(--u) * 4.6))/0.95 var(--fc); color: var(--ink); text-overflow: clip; }
html:not(.tel) #chars .hero .pw { margin: calc(var(--u) * 0.8) 0 0; padding: calc(var(--u) * 0.3) calc(var(--u) * 0.9) calc(var(--u) * 0.4); border-width: max(2px, calc(var(--u) * 0.3)); border-radius: calc(var(--u) * 0.8); background: color-mix(in srgb, var(--c1) 28%, #fff); box-shadow: calc(var(--u) * 0.25) calc(var(--u) * 0.25) 0 var(--ink); font: 800 max(12px, calc(var(--u) * 1.5))/1.2 var(--fc); letter-spacing: 1px; text-overflow: clip; }
/* (les barres : le nom et la valeur sur une ligne, la barre dessous, sur toute la largeur de la fiche — coincées entre
   leurs deux textes dans cette colonne étroite, elles ne mesuraient que 50 à 80 px sur un écran d'ordinateur courant, et
   4 à 30 px dans une fenêtre de 900 à 1 100 px de large) */
html:not(.tel) #chars .hero-stats { gap: calc(var(--u) * 0.9); margin: calc(var(--u) * 1.4) 0 0; }
html:not(.tel) #chars .hs-row { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "l v" "b b"; align-items: baseline; gap: calc(var(--u) * 0.4) calc(var(--u) * 1); }
html:not(.tel) #chars .hs-l { grid-area: l; font-size: max(11px, calc(var(--u) * 1.3)); }
html:not(.tel) #chars .hs-bar { grid-area: b; height: max(10px, calc(var(--u) * 1.4)); border-width: max(2px, calc(var(--u) * 0.3)); border-radius: calc(var(--u) * 0.8); }
html:not(.tel) #chars .hs-v { grid-area: v; min-width: 0; font-size: max(13px, calc(var(--u) * 1.7)); }
/* « Valider » : le bouton d'or de l'entrée, son reflet qui passe (le style est sur le bouton lui-même : son texte change —
   « Donner au bot », « Confirmer », « Prêt ✓ ») */
html:not(.tel) #chars #charsOk {
  position: relative; overflow: hidden; min-height: calc(var(--u) * 7); margin: calc(var(--u) * 1.2) calc(var(--u) * 2) calc(var(--u) * 2); padding: calc(var(--u) * 1) calc(var(--u) * 2) calc(var(--u) * 1.2);
  border: calc(var(--u) * 0.45) solid var(--ink); border-radius: calc(var(--u) * 1.4); background: var(--gold); color: var(--ink);
  box-shadow: inset 0 calc(var(--u) * -0.6) 0 rgba(180, 110, 0, 0.35), calc(var(--u) * 0.6) calc(var(--u) * 0.6) 0 var(--ink);
  font: italic 800 max(20px, calc(var(--u) * 3.6))/1 var(--fc); letter-spacing: 0.5px; text-transform: uppercase;
  transition: transform 0.1s ease, box-shadow 0.1s ease, background-color 0.15s ease;
}
html:not(.tel) #chars #charsOk:not(:disabled):hover { transform: translate(calc(var(--u) * -0.2), calc(var(--u) * -0.2)); background: #FFDC5E; box-shadow: inset 0 calc(var(--u) * -0.6) 0 rgba(180, 110, 0, 0.35), calc(var(--u) * 0.8) calc(var(--u) * 0.8) 0 var(--ink); }
html:not(.tel) #chars #charsOk:not(:disabled):active { transform: translate(calc(var(--u) * 0.4), calc(var(--u) * 0.4)); box-shadow: calc(var(--u) * 0.2) calc(var(--u) * 0.2) 0 var(--ink); }
html:not(.tel) #chars #charsOk::after { content: ''; position: absolute; inset: 0; pointer-events: none; background: linear-gradient(105deg, transparent 38%, rgba(255, 255, 255, 0.55) 47%, transparent 56%) no-repeat; background-size: 260% 100%; background-position: 160% 0; animation: hubShine 3.6s ease-in-out infinite; }
html:not(.tel) #chars #charsOk:disabled::after { display: none; }
/* les attaques : chacune sur sa petite carte, ses chiffres en pastille d'or (des cartes serrées : avec leurs descriptions
   ENTIÈRES, elles doivent tenir sans défiler au moins aussi bien qu'avant — mesuré sur les 151 balles) */
html:not(.tel) #chars .hero .kit { gap: calc(var(--u) * 1); padding: calc(var(--u) * 1.6) calc(var(--u) * 1.8); border-left: calc(var(--u) * 0.5) solid var(--ink);
  background: repeating-linear-gradient(135deg, rgba(21, 21, 21, 0.035) 0 var(--u), transparent var(--u) calc(var(--u) * 2)), #EFEAE0; }
html:not(.tel) #chars .kit li { grid-template-columns: max(24px, calc(var(--u) * 3.8)) minmax(0, 1fr); gap: calc(var(--u) * 1); padding: calc(var(--u) * 0.6) calc(var(--u) * 0.8) calc(var(--u) * 0.7) calc(var(--u) * 0.7); border: max(2px, calc(var(--u) * 0.25)) solid var(--ink); border-radius: calc(var(--u) * 1.2); background: #fff; box-shadow: calc(var(--u) * 0.3) calc(var(--u) * 0.3) 0 var(--ink); }
html:not(.tel) #chars .kit-ico { width: calc(var(--u) * 3.8); height: calc(var(--u) * 3.8); min-width: 24px; min-height: 24px; border-width: max(2px, calc(var(--u) * 0.3)); box-shadow: calc(var(--u) * 0.2) calc(var(--u) * 0.2) 0 var(--ink); }
html:not(.tel) #chars .kit-h { flex-wrap: wrap; gap: calc(var(--u) * 0.4) calc(var(--u) * 0.8); min-height: calc(var(--u) * 2.6); }
/* (le nom d'une attaque n'est jamais coupé : s'il manque de place, ses chiffres passent dessous) */
html:not(.tel) #chars .kit-h strong { flex: 1 0 auto; max-width: 100%; white-space: normal; font-size: max(15px, calc(var(--u) * 2.2)); }
html:not(.tel) #chars .kit .kit-num { padding: calc(var(--u) * 0.2) calc(var(--u) * 0.7) calc(var(--u) * 0.3); border: max(1.5px, calc(var(--u) * 0.2)) solid var(--ink); border-radius: calc(var(--u) * 0.7); background: var(--gold); color: var(--ink); font: 800 max(11px, calc(var(--u) * 1.3))/1.2 var(--fc); }
html:not(.tel) #chars .kit-d { margin-top: calc(var(--u) * 0.4); font-size: calc(max(12.5px, calc(var(--u) * 1.5)) * var(--kfit, 1)); }
html:not(.tel) #chars .kit-k { padding: 0 calc(var(--u) * 0.6); font-size: max(10px, calc(var(--u) * 1.1)); }
/* (sur un écran haut, la colonne des attaques restait à moitié vide : leurs cartes grandissent de 15 % — leur mesure --u,
   1,15 fois celle de l'écran. Mesuré sur les 151 balles, de 1 440 × 900 à 2 560 × 1 440 : aucune ne défile, --kfit ne
   descend pas sous 0,91.) */
@media (min-height: 860px) { html:not(.tel) #chars .hero .kit { --u: clamp(6px, min(0.599vw, 1.065vh), 17.25px); } }

/* ═══ LE PANNEAU : le contenu d'un onglet du menu (sa lumière en haut, ses rayons, sa trame de points), à la couleur de la
   catégorie choisie ; les onglets à gauche, la recherche et « Au hasard » en haut, la grille dessous (seule la grille
   défile : plus de barre collante qui laissait voir les cases à travers). .roster-tools s'efface (display: contents) : ses
   trois enfants se placent dans la grille du panneau — jamais .roster-col, que la revanche mesure (revPlacer). ═══ */
html:not(.tel) #chars .roster-col {
  position: relative; isolation: isolate; min-width: 0; min-height: 0; overflow: hidden;
  display: grid; grid-template-columns: calc(var(--u) * 21) minmax(0, 1fr) auto; grid-template-rows: auto minmax(0, 1fr);
  grid-template-areas: "tabs srch dice" "tabs list list"; gap: calc(var(--u) * 1.6) calc(var(--u) * 1.4);
  padding: calc(var(--u) * 2.2); box-sizing: border-box;
  border: calc(var(--u) * 0.5) solid var(--ink); border-radius: calc(var(--u) * 2.2); color: #fff; box-shadow: calc(var(--u) * 1) calc(var(--u) * 1) 0 var(--ink);
  background:
    radial-gradient(ellipse 70% 45% at 50% 0%, rgba(255, 255, 255, 0.28), transparent 70%),
    repeating-conic-gradient(from 0deg at 50% 115%, rgba(255, 255, 255, 0.07) 0 5deg, transparent 5deg 13deg),
    linear-gradient(170deg, color-mix(in srgb, var(--fc-c) 92%, #fff), var(--fc-c) 40%, var(--fc-d));
}
html:not(.tel) #chars .roster-col::before { content: ''; position: absolute; z-index: -1; inset: 0; pointer-events: none; background: radial-gradient(circle, rgba(0, 0, 0, 0.16) 0 calc(var(--u) * 0.22), transparent calc(var(--u) * 0.3)) 0 0 / calc(var(--u) * 1.4) calc(var(--u) * 1.4);
  -webkit-mask: radial-gradient(ellipse 70% 70% at 50% 45%, transparent 55%, #000 100%); mask: radial-gradient(ellipse 70% 70% at 50% 45%, transparent 55%, #000 100%); }
html:not(.tel) #chars .roster-tools { display: contents; }
/* (le voile de la revanche, une fois confirmé : posé sur le panneau, il en prend les coins) */
html:not(.tel) #chars .rv-lock { border-radius: calc(var(--u) * 2.2); }

/* la recherche : le champ du code des parties perso (blanc, bord d'encre), sa loupe gardée */
html:not(.tel) #chars #charSearch { grid-area: srch; align-self: center; height: calc(var(--u) * 5.6); min-height: 40px; padding: 0 calc(var(--u) * 1.4) 0 calc(var(--u) * 5); border: calc(var(--u) * 0.35) solid var(--ink); border-radius: calc(var(--u) * 1.1); background-color: #fff; background-position: calc(var(--u) * 1.6) 50%; background-size: calc(var(--u) * 2.4) calc(var(--u) * 2.4); box-shadow: calc(var(--u) * 0.4) calc(var(--u) * 0.4) 0 var(--ink); font: italic 800 max(15px, calc(var(--u) * 2.2))/1 var(--fc); letter-spacing: 0.5px; }
html:not(.tel) #chars #charSearch:focus { background-color: #FFF1B8; box-shadow: 0 0 0 calc(var(--u) * 0.35) var(--gold), calc(var(--u) * 0.4) calc(var(--u) * 0.4) 0 var(--ink); }
/* « Au hasard » : un bouton blanc de l'entrée, avec le dé (il passe à l'or au survol, et le dé roule) */
html:not(.tel) #chars #charRandom { grid-area: dice; align-self: center; display: inline-flex; align-items: center; justify-content: center; gap: calc(var(--u) * 0.8); height: calc(var(--u) * 5.6); min-height: 40px; padding: 0 calc(var(--u) * 1.8) 0 calc(var(--u) * 1.2); border: calc(var(--u) * 0.35) solid var(--ink); border-radius: calc(var(--u) * 1.1); background: var(--card); color: var(--ink); box-shadow: calc(var(--u) * 0.4) calc(var(--u) * 0.4) 0 var(--ink); font: italic 800 max(15px, calc(var(--u) * 2.2))/1 var(--fc); letter-spacing: 0.5px; }
html:not(.tel) #chars #charRandom .ico-de { width: 1.6em; height: 1.6em; }
html:not(.tel) #chars #charRandom:hover { background: var(--gold); transform: translate(-1px, -1px) rotate(-1deg); box-shadow: calc(var(--u) * 0.5 + 1px) calc(var(--u) * 0.5 + 1px) 0 var(--ink); }
html:not(.tel) #chars #charRandom:active { transform: translate(2px, 2px); box-shadow: 1px 1px 0 var(--ink); }

/* LES ONGLETS DES CATÉGORIES : les bandeaux biseautés du menu, chacun à sa couleur ; le choisi s'avance, grossit un peu et
   prend un liseré blanc (sa place est gardée à droite de la colonne : il n'en sort jamais) ; son nombre en pastille sur le
   coin, comme celle des Nouveautés (le nom garde toute la largeur : deux lignes au plus) */
html:not(.tel) #chars .cat-tabs { grid-area: tabs; min-width: 0; min-height: 0; display: flex; flex-direction: column; flex-wrap: nowrap; gap: calc(var(--u) * 1.2); overflow: visible; padding: calc(var(--u) * 0.8) calc(var(--u) * 2) calc(var(--u) * 0.8) calc(var(--u) * 0.4); }
html:not(.tel) #chars .cat-tabs button {
  position: relative; flex: 1 1 0; min-height: 0; max-height: calc(var(--u) * 11); height: auto; display: flex; align-items: center; gap: calc(var(--u) * 0.8);
  box-sizing: border-box; padding: calc(var(--u) * 0.6) calc(var(--u) * 0.9) calc(var(--u) * 0.6) calc(var(--u) * 1.5);
  border: calc(var(--u) * 0.45) solid var(--ink); border-radius: calc(var(--u) * 1.4);
  background: repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0 var(--u), rgba(255, 255, 255, 0) var(--u) calc(var(--u) * 2)), linear-gradient(to bottom, color-mix(in srgb, var(--fc-d) 82%, #fff), var(--fc-d));
  color: #fff; box-shadow: inset 0 calc(var(--u) * -0.6) 0 rgba(0, 0, 0, 0.22), calc(var(--u) * 0.5) calc(var(--u) * 0.5) 0 var(--ink); cursor: pointer; text-align: left;
  font: italic 800 max(14px, calc(var(--u) * 2.2))/1 var(--fc); letter-spacing: 0.5px; text-transform: uppercase;
  transform: skewX(-7deg); transition: transform 0.16s cubic-bezier(0.2, 1.4, 0.4, 1), filter 0.15s ease, box-shadow 0.14s ease;
}
html:not(.tel) #chars .cat-tabs button > * { transform: skewX(7deg); }
html:not(.tel) #chars .cat-tabs button span { flex: 1; min-width: 0; padding: 0 calc(var(--u) * 0.3) calc(var(--u) * 0.2) 0; text-shadow: var(--out), calc(var(--u) * 0.25) calc(var(--u) * 0.3) 0 var(--ink); overflow-wrap: anywhere; text-wrap: balance; }
html:not(.tel) #chars .cat-tabs button i { position: absolute; z-index: 1; top: calc(var(--u) * -1.5); right: calc(var(--u) * -0.9); min-width: calc(var(--u) * 3.2); box-sizing: border-box; padding: calc(var(--u) * 0.3) calc(var(--u) * 0.6) calc(var(--u) * 0.35); border: max(2px, calc(var(--u) * 0.25)) solid var(--ink); border-bottom-width: max(3px, calc(var(--u) * 0.45)); border-radius: calc(var(--u) * 0.8); background: #fff; color: var(--ink); font: normal 800 max(12px, calc(var(--u) * 1.5))/1 var(--fc); text-align: center; text-shadow: none; }
html:not(.tel) #chars .cat-tabs button[aria-pressed="false"] { filter: saturate(0.8) brightness(0.9); }
html:not(.tel) #chars .cat-tabs button:hover { transform: translateX(calc(var(--u) * 0.6)) skewX(-7deg); filter: none; }
html:not(.tel) #chars .cat-tabs button[aria-pressed="true"] {
  /* (pas de z-index : chaque onglet passe devant celui du dessus, la pastille de son nombre comprise) */
  background: repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.16) 0 var(--u), rgba(255, 255, 255, 0) var(--u) calc(var(--u) * 2)), radial-gradient(ellipse 60% 120% at 85% 50%, rgba(255, 255, 255, 0.35), transparent 70%), linear-gradient(to bottom, color-mix(in srgb, var(--fc-c) 80%, #fff), var(--fc-c));
  transform: translateX(calc(var(--u) * 1.3)) skewX(-7deg) scale(1.04);
  box-shadow: inset 0 calc(var(--u) * -0.6) 0 rgba(0, 0, 0, 0.2), 0 0 0 calc(var(--u) * 0.4) #fff, calc(var(--u) * 0.9) calc(var(--u) * 0.9) 0 calc(var(--u) * 0.4) var(--ink);
}
html:not(.tel) #chars .cat-tabs button[aria-pressed="true"] i { background: var(--gold); }
html.touch:not(.tel) #chars .cat-tabs button:hover { transform: skewX(-7deg); }
html.touch:not(.tel) #chars .cat-tabs button[aria-pressed="true"]:hover { transform: translateX(calc(var(--u) * 1.3)) skewX(-7deg) scale(1.04); }

/* LA GRILLE : dans un creux un peu plus sombre du panneau ; seule elle défile */
html:not(.tel) #chars .roster { grid-area: list; min-height: 0; margin: 0; display: flex; flex-direction: column; gap: calc(var(--u) * 2); overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain;
  padding: calc(var(--u) * 1.6) calc(var(--u) * 1.6) calc(var(--u) * 2.2); border-radius: calc(var(--u) * 1.6); background: rgba(10, 6, 34, 0.24); box-shadow: inset 0 calc(var(--u) * 0.5) 0 rgba(0, 0, 0, 0.2), inset 0 0 0 calc(var(--u) * 0.3) rgba(0, 0, 0, 0.12);
  scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, 0.6) transparent;
  /* (la case choisie, amenée à l'écran — à l'ouverture, « Au hasard » — : avec la marge de la grille, jamais collée au
     bord, son anneau d'or entier) */
  scroll-padding-block: calc(var(--u) * 1.6); }
/* (le titre d'un groupe : l'étiquette d'encre de l'entrée, à la couleur de sa catégorie ; un seul groupe à l'écran — un
   onglet de catégorie, les favoris — : il redirait l'onglet, il s'efface) */
html:not(.tel) #chars .roster .group > h3 { display: block; width: max-content; max-width: 100%; box-sizing: border-box; margin: 0 0 calc(var(--u) * 1.2) calc(var(--u) * 0.2); padding: calc(var(--u) * 0.5) calc(var(--u) * 1.2) calc(var(--u) * 0.6); border: calc(var(--u) * 0.3) solid var(--ink); border-radius: calc(var(--u) * 0.9); background: var(--ink); color: color-mix(in srgb, var(--fc-c) 55%, #fff); box-shadow: calc(var(--u) * 0.3) calc(var(--u) * 0.3) 0 rgba(0, 0, 0, 0.35); font: italic 800 max(12px, calc(var(--u) * 1.7))/1 var(--fc); letter-spacing: 1.2px; text-transform: uppercase; transform: rotate(-2deg); transform-origin: 0 50%; }
html:not(.tel) #chars .roster.seul .group > h3 { display: none; }
html:not(.tel) #chars .roster .group .grid { grid-template-columns: repeat(auto-fill, minmax(max(84px, calc(var(--u) * 13.5)), 1fr)); gap: calc(var(--u) * 1.6); }
/* (une case : sa scène, son nom sur le bandeau d'encre ; au survol elle se soulève comme les cartes du menu ; ta balle :
   l'anneau d'or de ta carte au lobby) */
html:not(.tel) #chars .card { border-width: max(2.5px, calc(var(--u) * 0.4)); border-radius: calc(var(--u) * 1.4); box-shadow: calc(var(--u) * 0.5) calc(var(--u) * 0.5) 0 var(--ink); transition: transform 0.14s cubic-bezier(0.2, 1.4, 0.4, 1), box-shadow 0.12s ease; }
html:not(.tel) #chars .card:hover { transform: translate(calc(var(--u) * -0.3), calc(var(--u) * -0.5)) rotate(-0.8deg); box-shadow: calc(var(--u) * 0.8) calc(var(--u) * 0.9) 0 var(--ink); }
html:not(.tel) #chars .card:active { transform: translate(calc(var(--u) * 0.3), calc(var(--u) * 0.3)); box-shadow: calc(var(--u) * 0.2) calc(var(--u) * 0.2) 0 var(--ink); }
html.touch:not(.tel) #chars .card:hover, html.touch:not(.tel) #chars .card:active { transform: none; }
html:not(.tel) #chars .card .txt { height: calc(var(--u) * 4.4); min-height: 30px; padding: 0 calc(var(--u) * 0.6); }
html:not(.tel) #chars .card .n { font-size: max(13px, calc(var(--u) * 1.75)); }
html:not(.tel) #chars .card.sel { outline: calc(var(--u) * 0.5) solid var(--gold); outline-offset: calc(var(--u) * 0.25); transform: translate(calc(var(--u) * -0.2), calc(var(--u) * -0.3)); box-shadow: calc(var(--u) * 0.7) calc(var(--u) * 0.7) 0 var(--ink); }
html:not(.tel) #chars .card.sel::after { top: calc(var(--u) * 0.6); right: calc(var(--u) * 0.6); width: calc(var(--u) * 2.8); height: calc(var(--u) * 2.8); min-width: 20px; min-height: 20px; box-sizing: border-box; border: max(2px, calc(var(--u) * 0.25)) solid #fff; font-size: max(12px, calc(var(--u) * 1.6)); }
html:not(.tel) #chars .card .fav-star { top: calc(var(--u) * 0.6); left: calc(var(--u) * 0.6); width: calc(var(--u) * 3.2); height: calc(var(--u) * 3.2); min-width: 24px; min-height: 24px; }
html:not(.tel) #chars .card .fav-star svg { width: 66%; height: 66%; }
/* (rien à montrer — pas encore de favori, une recherche sans réponse : une phrase à la place de la grille) */
html:not(.tel) #chars .roster-vide { grid-area: list; align-self: center; justify-self: center; z-index: 1; max-width: 80%; box-sizing: border-box; margin: 0; padding: calc(var(--u) * 1.4) calc(var(--u) * 2.4) calc(var(--u) * 1.5); border: calc(var(--u) * 0.35) solid var(--ink); border-radius: calc(var(--u) * 1.4); background: var(--card); color: var(--ink); box-shadow: calc(var(--u) * 0.5) calc(var(--u) * 0.5) 0 var(--ink); font: italic 800 max(15px, calc(var(--u) * 2.2))/1.2 var(--fc); letter-spacing: 0.5px; text-transform: uppercase; text-align: center; transform: rotate(-1.5deg); pointer-events: none; }
html.tel #chars .roster-vide { display: none; }

/* ─── une fenêtre d'ordinateur étroite : une colonne d'onglets plus fine ─── */
@media (max-width: 1100px) {
  html:not(.tel) #chars .chars-body { gap: calc(var(--u) * 2.4); }
  html:not(.tel) #chars .roster-col { grid-template-columns: calc(var(--u) * 20) minmax(0, 1fr) auto; }
}
/* ─── très étroite (moins de 900 px) ou basse (520 px ou moins) : les onglets passent au-dessus de la grille, en rangées
   (pas une rangée qui défile de côté : sans barre visible, la molette d'une souris n'y atteignait jamais les dernières
   catégories) ─── */
@media (max-width: 900px), (max-height: 520px) {
  html:not(.tel) #chars .roster-col { grid-template-columns: minmax(0, 1fr) auto; grid-template-rows: auto auto minmax(0, 1fr); grid-template-areas: "srch dice" "tabs tabs" "list list"; }
  html:not(.tel) #chars .cat-tabs { flex-direction: row; flex-wrap: wrap; gap: calc(var(--u) * 1.2) calc(var(--u) * 1.4); padding: calc(var(--u) * 0.4) calc(var(--u) * 1) calc(var(--u) * 0.8) calc(var(--u) * 0.8); }
  html:not(.tel) #chars .cat-tabs button { flex: none; max-height: none; min-height: 34px; }
  html:not(.tel) #chars .cat-tabs button span { white-space: nowrap; overflow-wrap: normal; }
  html:not(.tel) #chars .cat-tabs button i { position: static; }   /* (en rangées serrées : le nombre dans l'onglet ; sur le coin, il mordrait sur la rangée du dessus) */
  html:not(.tel) #chars .cat-tabs button:hover { transform: skewX(-7deg); }
  html:not(.tel) #chars .cat-tabs button[aria-pressed="true"] { transform: skewX(-7deg) scale(1.04); }
}
@media (max-width: 900px) {
  html:not(.tel) #chars .chars-body { grid-template-columns: minmax(0, 50%) minmax(0, 1fr); gap: calc(var(--u) * 2); }
}
@media (max-height: 520px) {
  html:not(.tel) #chars .chars-body { grid-template-columns: minmax(0, 46%) minmax(0, 1fr); }
  html:not(.tel) #chars #charsBack, html:not(.tel) #chars > .topbar .icon-btn { min-height: 40px; height: 40px; }
  html:not(.tel) #chars > .topbar .icon-btn { min-width: 40px; width: 40px; }
  html:not(.tel) #chars .kit-d { font-size: calc(11px * var(--kfit, 1)); }
}
/* (« réduire les animations » du système, comme à l'entrée : plus de reflet sur « Valider », plus de rebond des onglets et
   des cases — après leurs règles, à force égale) */
@media (prefers-reduced-motion: reduce) {
  html:not(.tel) #chars #charsOk::after { animation: none; }
  html:not(.tel) #chars .cat-tabs button, html:not(.tel) #chars .card, html:not(.tel) #chars #charsOk { transition: none; }
}

/* ─────────────── LE DÉ (« Au hasard ») : un vrai dé façon émoji, en gras, cerné d'encre — sa face aux cinq points, son
   épaisseur rouge sombre, puis l'ombre décalée des boutons (Js', 03/10 : « pareil pour l'icône du dé, fais des trucs dans
   le style du jeu un peu emoji bold avec contour »). Le même partout, au PC comme au téléphone : « Au hasard » du choix des
   balles, « Balle au hasard » du salon, le dé d'un bot (js/br/app.js), et le texte des Nouveautés. Il roule au survol. ─── */
.ico-de { display: inline-block; flex: none; width: 1.35em; height: 1.35em; vertical-align: -0.32em; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'%3E%3Cg transform='translate(1 2) rotate(-12 21 21)'%3E%3Crect x='10' y='10' width='31' height='31' rx='8.5' fill='%23151515'/%3E%3Crect x='7' y='7' width='31' height='31' rx='8.5' fill='%23A9192B' stroke='%23151515' stroke-width='3.6'/%3E%3Crect x='4' y='4' width='31' height='31' rx='8.5' fill='%23E23447' stroke='%23151515' stroke-width='3.6' stroke-linejoin='round'/%3E%3Cpath d='M7.6 26V13.2a5.6 5.6 0 0 1 5.6-5.6h12.6a5.6 5.6 0 0 1 5.6 5.6v.4c-9.6.6-17.2 5.4-23.8 12.4z' fill='%23FF6B78'/%3E%3Cg fill='%23fff' stroke='%23151515' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='3.2'/%3E%3Ccircle cx='27' cy='12' r='3.2'/%3E%3Ccircle cx='19.5' cy='19.5' r='3.2'/%3E%3Ccircle cx='12' cy='27' r='3.2'/%3E%3Ccircle cx='27' cy='27' r='3.2'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") center / contain no-repeat; }
#charRandom:hover .ico-de, #lobbyRandom:not(.locked):hover .ico-de, .hl-x[data-act="roll"]:hover .ico-de { animation: deRoule 0.5s cubic-bezier(0.2, 1.4, 0.4, 1); }
@keyframes deRoule { 0% { transform: rotate(0deg); } 40% { transform: rotate(-30deg) scale(1.15); } 75% { transform: rotate(12deg) scale(0.95); } 100% { transform: rotate(0deg); } }
@media (prefers-reduced-motion: reduce) { .ico-de { animation: none !important; } }
/* (au doigt, « Au hasard » dans la barre du haut — la place que lui garde css/balles.css (Js', 1er/10), où le remet la
   mise à jour « Au hasard » du 03/10 — : quand la place manque (écran étroit), son texte est caché et il ne montrait que
   l'émoji 🎲 : c'est le dé du jeu à la place, à sa taille en px puisque le texte caché n'en a plus. Écrit avec
   l'identifiant du bouton : cette règle passe devant toute autre qui remettrait l'émoji, la revanche comprise.) */
html.tel #chars > .topbar #charRandom.dice-btn::before { content: none; }
html.tel #chars > .topbar #charRandom .ico-de { width: 24px; height: 24px; margin-right: 0.35em; }
@media (max-width: 760px) { html.tel #chars > .topbar #charRandom { letter-spacing: 0; } }   /* (le texte caché ne pousse plus le dé hors du centre) */
