/* KX-DEPLOI 2026-09-23 M · MODIFIE par la bascule publique /kol/ + /token/ · voir ABTEST.md */
/* kx.css — le système visuel de l'interface connectée.
 *
 * ── D'OÙ VIENNENT CES VALEURS ────────────────────────────────────────────────
 *
 * De la maquette `Account App v3.dc.html`, relevées une par une plutôt
 * qu'approximées. Et elles ne sortent pas de nulle part : 11 des 12 couleurs
 * revendiquées par la maquette sont DÉJÀ dans le `style.css` du site public,
 * avec Poppins et 38 usages de pills à 999px. La maquette ÉTEND la direction
 * artistique existante, elle ne la remplace pas.
 *
 * Deux seules nouveautés : `#0b1230` (fond de hero) et **Space Grotesk**, qui
 * porte tous les chiffres. Ce second point n'est pas décoratif — dans une
 * colonne, des glyphes de largeurs différentes empêchent de comparer deux
 * lignes d'un coup d'œil, ce qui est la seule chose qu'on demande à une colonne.
 *
 * ── LA RÈGLE DE COULEUR ──────────────────────────────────────────────────────
 *
 * Trois rôles, jamais mélangés :
 *   · la MARQUE (dégradé bleu→cyan) : ce qui appartient au produit ;
 *   · l'INTERACTIF (cyan) : ce sur quoi on clique ;
 *   · le RÉSULTAT (vert/rouge) : un PnL, et rien d'autre.
 * Si la marque servait aussi de bouton, un gain et un lien se ressembleraient.
 *
 * ── LA RÉFÉRENCE EST LE MOBILE ───────────────────────────────────────────────
 *
 * 412 px. Cibles tactiles ≥ 44 px, champs de saisie ≥ 16 px — en dessous, iOS
 * zoome au focus et l'utilisateur perd la page.
 */

:root {
  /* ── `color-scheme` VA SUR LA RACINE, PAS SUR `body` ─────────────────────────
   *
   * Il était sur `body`. Mesuré, la racine restait donc en `normal` : le CANEVAS
   * du navigateur — ce qui est peint DERRIÈRE la page — restait **blanc**.
   *
   * Sans transparence, ça ne se verrait pas. Mais `--kx-page` vaut `#08153dc9`,
   * repris de `style.css`, et ce `c9` est un canal alpha à 79 %. Le fond réel de
   * l'application était donc 79 % de bleu de nuit sur 21 % de BLANC, là où le
   * site public — qui déclare `color-scheme: dark` sur `:root`, ligne 2 de
   * `style.css` — pose le même bleu sur un canevas sombre.
   *
   * Deux composites très différents à partir de la même valeur hexadécimale :
   * ~rgb(60,70,102), un ardoise moyen, contre ~rgb(10,20,52), un bleu profond.
   * C'est ce qui restait d'écart après avoir copié la couleur sans copier
   * l'endroit où le schéma est déclaré — la couleur ne suffit pas, il faut aussi
   * ce sur quoi elle est peinte.
   *
   * Et la racine est le seul endroit qui compte : la spécification fait dériver
   * le fond du canevas de l'élément RACINE. Sur `body`, la déclaration teinte
   * les contrôles de formulaire et rien d'autre.
   */
  color-scheme: dark;

  /* Fonds, du plus profond au plus proche */
  /* ── LE FOND VIENT DU SITE PUBLIC, PAS DE LA MAQUETTE ────────────────────
     La maquette proposait `#050a1a`, un quasi-noir. `style.css` déclare
     `#08153dc9` pour `body` — un bleu de nuit nettement plus clair. Comparés
     côte à côte sur la même page, les deux ne se ressemblent pas : l'interface
     connectée avait l'air d'un autre produit que celui d'où l'on vient.
     C'est le site qui fait foi. */
  --kx-page:    #08153dc9;
  --kx-stage:   #08153d;
  --kx-hero:    #0b1230;
  --kx-panel:   #131a2a;
  --kx-raised:  #1b2436;
  --kx-float:   #0d1525;   /* menus déroulants et modales */

  /* Traits. Toujours en alpha : un trait opaque se voit encore sur un fond
     qui change, et l'interface en a plusieurs. */
  --kx-line:    rgba(255,255,255,.08);
  --kx-line-2:  rgba(255,255,255,.12);
  --kx-line-3:  rgba(255,255,255,.18);

  /* Texte, du plus lisible au plus effacé */
  --kx-ink:     #e8f0ff;
  --kx-ink-2:   #cfe0f7;
  --kx-ink-3:   #a9bcd9;
  --kx-muted:   #8fa3c4;
  /* Relevé de #5d7093 à #7186a9. Mesuré sur le panneau #131a2a, l'ancien
     donnait 3,48:1 — sous la barre de 4,5:1 de la WCAG pour du texte
     courant, et c'est précisément la couleur des petites lignes qui
     expliquent ce que les chiffres veulent dire. Le nouveau donne 4,70:1
     sur le panneau et 4,89:1 sur la page. Il reste le ton le plus effacé
     de la gamme : la hiérarchie ne bouge pas, seule la lisibilité. */
  --kx-faint:   #7186a9;
  --kx-ghost:   #3f4f6d;

  /* La marque */
  --kx-brand-a: #4b73ff;
  --kx-brand-b: #19d4ff;
  --kx-brand:   linear-gradient(90deg, #4b73ff, #19d4ff);
  --kx-brand-d: linear-gradient(135deg, #4b73ff, #19d4ff);
  --kx-on-brand:#07101d;

  /* L'interactif */
  --kx-accent:  #19d4ff;
  --kx-accent-2:#9be6ff;
  --kx-nav-on:  #00e5d0;
  --kx-nav-off: #d0d0d8;
  --kx-link-h:  #7ee6ff;

  /* Le résultat — et rien d'autre */
  --kx-up:      #19ff73;
  --kx-up-soft: #8ef0b6;
  --kx-down:    #ff8080;
  --kx-down-soft:#ffb3b3;

  /* L'or : le plan, les badges de rang, ce qui distingue */
  --kx-gold:    #f5c76a;
  --kx-gold-2:  #ffdfaa;
  --kx-gold-g:  linear-gradient(135deg, #f5c76a, #ffdfaa);
  --kx-gold-ink:#1a1200;
  --kx-gold-tx: #f6dfae;

  /* Solana : la barre d'identité, jamais un élément d'interface */
  --kx-sol:     linear-gradient(to right, #14F195, #03E1FF 50%, #9945FF);

  /* Rayons */
  --kx-r-pill:  999px;
  --kx-r-cell:  14px;
  --kx-r-card:  22px;
  --kx-r-hero:  26px;

  /* Ombres */
  --kx-sh-panel: 0 5px 25px rgba(0,0,0,.45);
  --kx-sh-hero:  0 24px 60px rgba(0,0,0,.6);
  --kx-sh-float: 0 16px 48px rgba(0,0,0,.6);
  --kx-sh-modal: 0 30px 90px rgba(0,0,0,.7);

  /* Les deux familles. Les chiffres ont la leur, c'est délibéré. */
  --kx-font: 'Poppins', ui-sans-serif, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --kx-num:  'Space Grotesk', ui-monospace, 'Cascadia Mono', Consolas, monospace;
}

/* ── `[hidden]` DOIT GAGNER, TOUJOURS ─────────────────────────────────────────
 *
 * Le navigateur donne `display:none` à `[hidden]`, mais avec la plus faible
 * priorité qui soit : la moindre règle `display:flex` dans cette feuille la
 * bat. L élément porte alors `hidden`, `el.hidden` rend `true`, et il reste à
 * l écran.
 *
 * Ça a coûté deux fois : la surcouche de partage qui ne se fermait pas, puis
 * la barre de comparaison qui s affichait alors qu on la croyait cachée. Dans
 * les deux cas l assertion disait « caché » et la capture disait le
 * contraire — la pire espèce de bug, celle qu un test valide.
 *
 * Une règle, en tête, pour tous les cas présents et à venir.
 */
[hidden] { display: none !important; }

/* ── Socle ─────────────────────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--kx-page);
  color: var(--kx-ink);
  font: 400 15px/1.55 var(--kx-font);
  -webkit-font-smoothing: antialiased;
  /* Des halos très bas : ils ne se voient pas, ils empêchent seulement le fond
     d'être un aplat mort. */
  /* Les MÊMES halos que `style.css`, aux mêmes opacités et aux mêmes bornes.
     Les miens étaient un peu plus marqués (.35/.18 à 55 %) ; ceux du site
     sont .3/.15 à 50 %. Un écart invisible seul, voyant en passant de l'un
     à l'autre. */
  background-image:
    radial-gradient(ellipse at top left,     rgba(10,35,100,.3) 0%, transparent 50%),
    radial-gradient(ellipse at bottom right, rgba(0,100,200,.15) 0%, transparent 50%);
  background-attachment: fixed;
}

a { color: var(--kx-accent); text-decoration: none; }
a:hover { color: var(--kx-link-h); }
input, button, select, textarea { font-family: inherit; }
h1, h2, h3 { margin: 0; letter-spacing: -.02em; }

/* Tous les chiffres qui se comparent. */
.kx-num { font-family: var(--kx-num); font-weight: 700; font-variant-numeric: tabular-nums; }
.up   { color: var(--kx-up); }
.down { color: var(--kx-down); }
.dim  { color: var(--kx-muted); }

@keyframes kolfade  { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes kolpop   { from { opacity: 0; transform: scale(.94) translateY(12px); } to { opacity: 1; transform: none; } }
@keyframes kolpulse { 0%,100% { opacity: .35; transform: scale(.8); } 50% { opacity: 1; transform: scale(1); } }

/* Le mouvement respecte le réglage système. Une animation qu'on ne peut pas
   couper est une animation subie. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ── L'en-tête ─────────────────────────────────────────────────────────────── */

/* ── CE QUE LA BARRE DU SITE PUBLIC FAIT, REPRIS LIGNE À LIGNE ────────────────
 *
 * Demande : que la barre de bureau ressemble le plus possible à celle que voit
 * un visiteur non inscrit. `style.css` (`.topbar-ken-style`, `.desktop-menu`)
 * la décrit ; les valeurs ci-dessous en sont la transcription, pas une
 * approximation :
 *
 *   · fond `rgba(8,10,18,.65)` — le mien était `rgba(8,21,61,.72)`, plus bleu
 *     et plus opaque ;
 *   · **aucune bordure basse** — j'en avais une, qui doublait le trait Solana ;
 *   · le trait Solana fait **4 px**, pas 2 ;
 *   · `padding: 1rem 0`, et un conteneur à **1400 px** (le corps reste à 1180 :
 *     c'est le site public qui fait ça aussi) ;
 *   · la marque en **1,35 rem / 600**, le logo rond de **40 px** ;
 *   · les liens en `#d0d0d8`, **1 rem / 500**, espacés de **2,5 rem** ;
 *   · l'actif en `#00e5d0` avec un soulignement qui **s'ouvre du centre**
 *     (largeur 0 → 100 %, `bottom: -10px`), et non une bordure fixe.
 */
.kx-top {
  position: sticky; top: 0; z-index: 100;
  padding: 1rem 0;
  background: rgba(8, 10, 18, .65);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  border-bottom: none;
}

/* Le trait Solana, à l'identique : 4 px, opacité .7, même halo. */
.kx-top::after {
  content: ''; position: absolute; left: 0; bottom: 0; width: 100%; height: 4px;
  background: linear-gradient(to right, transparent 0%, #14F195 15%, #03E1FF 50%, #9945FF 85%, transparent 100%);
  opacity: .7; border-radius: 2px; pointer-events: none; z-index: 1;
  box-shadow: 0 0 12px rgba(20,241,149,.3), 0 0 12px rgba(153,69,255,.3);
}

/* Le conteneur interne, comme `.topbar-container`. En dessous de 900 px il
   garde le pas de 18 px de l'interface mobile, qui n'a jamais été en cause. */
/* Trois colonnes plutôt que `space-between` : avec des groupes latéraux de
   largeurs différentes — la marque à gauche, recherche + alertes + compte à
   droite — `space-between` place la nav au milieu de l'ESPACE RESTANT, pas au
   milieu de la barre. `1fr auto 1fr` la centre vraiment. */
.kx-top-in {
  display: grid; grid-template-columns: 1fr auto 1fr;
  align-items: center; gap: 14px;
  max-width: 1400px; margin: 0 auto; padding: 0 18px;
  position: relative;
}
@media (min-width: 900px) { .kx-top-in { padding: 0 2rem; gap: 2rem; } }

.kx-brand {
  display: flex; align-items: center; gap: .8rem; flex-shrink: 0;
  color: #fff; font-size: 1.35rem; font-weight: 600; z-index: 101;
  transition: opacity .3s ease;
}
.kx-brand:hover { opacity: .9; }
.kx-logo { width: 40px; height: 40px; border-radius: 50%; object-fit: contain; }
.kx-brand-name { font-weight: 600; font-size: 1.35rem; letter-spacing: 0; white-space: nowrap; }
.kx-brand-name b { color: var(--kx-accent); font-weight: 600; }

/* Sur mobile la marque reprend une taille de barre d'application : 1,35 rem
   pousse la pastille d'alertes hors de l'écran à 412 px. */
@media (max-width: 899px) {
  .kx-brand, .kx-brand-name { font-size: 1rem; }
  .kx-brand { gap: .55rem; }
  .kx-logo { width: 34px; height: 34px; }
}

/* `flex: 0 1 auto` et non `1 1 auto` : la nav prend sa largeur naturelle et
   les trois groupes se répartissent par `space-between`, exactement comme
   `.topbar-container` du site public. En `1 1 auto`, la nav mangeait toute la
   place et se collait à la marque. */
.kx-nav { flex: 0 1 auto; min-width: 0; display: none; gap: 2.5rem; overflow: visible; }
.kx-nav::-webkit-scrollbar { height: 0; }
.kx-nav a {
  display: flex; align-items: center; gap: .5rem;
  position: relative; padding: 0; white-space: nowrap;
  color: #d0d0d8; font-size: 1rem; font-weight: 500;
  transition: color .3s ease;
}
.kx-nav a .kxi { font-size: 1.1rem; }
.kx-nav a:hover, .kx-nav a.on { color: #00e5d0; }

/* Le soulignement qui s'ouvre, repris de `.desktop-menu a::after`. */
.kx-nav a::after {
  content: ''; position: absolute; bottom: -10px; left: 50%;
  width: 0; height: 2px; background: #00e5d0; border-radius: 1px;
  transition: width .35s ease, left .35s ease;
}
.kx-nav a:hover::after, .kx-nav a.on::after { width: 100%; left: 0; }

/* Le site public resserre sa nav sous 1024 px (`gap: 1.8rem`, `.95rem`). Ici
   le groupe de droite est plus lourd que le sien — il porte la recherche, la
   pastille d'alertes et le compte, là où le site n'a qu'un bouton — donc le
   même resserrement doit arriver PLUS TÔT. Mesuré : à 1 280 px avec 2,5 rem,
   « Watchlist » était coupé. */
@media (max-width: 1340px) {
  .kx-nav { gap: 1.8rem; }
  .kx-nav a { font-size: .95rem; }
}
@media (max-width: 1120px) {
  .kx-nav { gap: 1.1rem; }
  .kx-nav a { font-size: .88rem; }
  .kx-nav a .kxi { font-size: 1rem; }
}
/* Les colonnes sont NOMMÉES, pas laissées au placement automatique : sous
   1 100 px la nav est en `display: none`, donc elle ne produit aucune boîte de
   grille — et le groupe de droite retombait dans la colonne du MILIEU. Mesuré à
   900 px, l'avatar se retrouvait à 335 px du bord droit, avec le menu qui
   s'ouvrait loin de lui. */
.kx-brand { grid-column: 1; }
.kx-nav   { grid-column: 2; }
.kx-right { grid-column: 3; display: flex; align-items: center; gap: 8px; flex-shrink: 0; justify-self: end; }

/* `text-decoration: none` : dans `member/` c'est un <button>, qui n'en a
   jamais. Sur les anciennes pages greffées c'est un <a> — l'overlay de
   recherche vit ici et dans `kx.js`, qu'elles ne chargent pas, donc un bouton
   y serait mort — et `style.css` souligne les liens. Sans cette ligne, la même
   loupe sortait soulignée d'un côté et pas de l'autre. */
.kx-iconbtn {
  display: grid; place-items: center; width: 40px; height: 40px;
  border-radius: var(--kx-r-pill); border: 1px solid var(--kx-line-2);
  background: transparent; color: var(--kx-ink); cursor: pointer;
  text-decoration: none;
}
.kx-iconbtn:hover { background: rgba(255,255,255,.06); }

/* La pastille d'alertes : or, parce qu'elle appartient au produit et non au
   résultat. Le compte de non-lus est un badge, pas une couleur de PnL. */
.kx-alerts {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 40px; padding: 0 14px; border-radius: var(--kx-r-pill);
  border: 0; background: var(--kx-gold-g); color: var(--kx-gold-ink);
  font: 600 .8rem/1 var(--kx-font); cursor: pointer; white-space: nowrap;
}
.kx-alerts .n {
  display: grid; place-items: center; min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: var(--kx-r-pill); background: rgba(26,18,0,.22);
  font: 700 .68rem/1 var(--kx-num);
}

.kx-avatar {
  display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%;
  border: 0; background: var(--kx-brand-d); color: var(--kx-on-brand);
  font: 700 .72rem/1 var(--kx-num); cursor: pointer; text-transform: uppercase;
}

/* Le menu de compte */
.kx-drop {
  /* Ancré sur `.kx-top-in`, et décalé de SA PROPRE marge intérieure.
   *
   * `right: 0` visait le bord de la BOÎTE du conteneur (1 265 px sur un écran de
   * 1 280) et non le bord de son CONTENU (1 233) : le menu dépassait l'avatar de
   * 32 px. On reprend donc les mêmes 18 px / 2 rem que le conteneur — ce qui le
   * fait aussi suivre le centrage quand `max-width: 1400px` s'applique.
   *
   * Et `1rem` sur le `top` : c'est exactement la marge basse de `.kx-top`, que la
   * hauteur de `.kx-top-in` n'inclut pas. Sans elle, mesuré, le menu commençait
   * 4 px AU-DESSUS du bas de la barre et glissait dessous. */
  position: absolute; top: calc(100% + 1rem + 8px); right: 18px; width: 248px; z-index: 30;
  background: var(--kx-float); border: 1px solid rgba(255,255,255,.11);
  border-radius: 16px; box-shadow: var(--kx-sh-float);
  animation: kolfade .14s ease; overflow: hidden;
}
.kx-drop a, .kx-drop button {
  display: block; width: 100%; text-align: left;
  padding: 12px 16px; font-size: .82rem; font-weight: 500;
  color: rgba(232,240,255,.72); background: none; border: 0; cursor: pointer;
}
.kx-drop a:hover, .kx-drop button:hover { background: rgba(255,255,255,.05); color: var(--kx-ink); }
.kx-drop .danger { color: rgba(255,90,90,.75); }

/* La marge de bureau du menu vient APRÈS la règle de base, pas avant : à
   spécificité égale c'est la dernière écrite qui gagne, et une version placée
   plus haut dans le fichier était simplement ignorée — mesuré, `right` valait
   encore 18 px sur un écran de 1 280 et le menu dépassait l'avatar de 14 px. */
@media (min-width: 900px) { .kx-drop { right: 2rem; } }

/* ── Le corps ──────────────────────────────────────────────────────────────── */

.kx-wrap {
  max-width: 1180px; margin: 0 auto;
  padding: 20px 18px 96px;          /* le bas laisse la place au dock */
  animation: kolfade .35s ease;
}

.kx-eyebrow {
  font-size: .68rem; font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--kx-muted);
}

/* ── Surfaces ──────────────────────────────────────────────────────────────── */

/* ── `clip` ET NON `hidden` ──────────────────────────────────────────────────
 *
 * Les deux rognent pareil aux angles arrondis. Mais `overflow: hidden` crée
 * un conteneur de défilement, et **un conteneur de défilement annule le
 * `position: sticky` de tout ce qu il contient** : la barre de réglages
 * collante de ces cartes ne collait à rien, mesurée à -261 px une fois la
 * liste parcourue.
 *
 * `overflow: clip` rogne sans créer ce conteneur. La déclaration `hidden`
 * reste AVANT, en repli : un navigateur qui ignore `clip` garde l ancien
 * comportement plutôt que de laisser déborder les lignes hors des angles. */
.kx-card {
  border-radius: var(--kx-r-card); border: 1px solid var(--kx-line);
  background: var(--kx-panel); box-shadow: var(--kx-sh-panel);
  overflow: hidden; overflow: clip; margin-bottom: 16px;
}
.kx-card-h {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  padding: 16px 18px; border-bottom: 1px solid var(--kx-line);
}
/* `.kx-skel-titre` : le squelette de chargement portait un `<h2>` identique à
   celui de la carte qu'il remplace — deux titres pour une section dans le HTML
   servi. Il porte maintenant un `<span>`, qui doit s'habiller pareil. La marge
   est remise à zéro pour les deux : un `h2` en porte par défaut, un `span`
   non, et la ligne de base du `flex` parent s'en trouverait décalée. */
.kx-card-h h2,
.kx-card-h .kx-skel-titre { font-size: 1rem; font-weight: 600; margin: 0; }
.kx-card-sub { font-size: .74rem; color: var(--kx-muted); }
.kx-card-body { padding: 16px 18px; }

/* Le hero : le seul bloc qui parle de l'utilisateur. Il ne doit pas avoir le
   poids visuel d'un tableau. */
.kx-hero {
  position: relative; border-radius: var(--kx-r-hero);
  border: 1px solid var(--kx-line-2); box-shadow: var(--kx-sh-hero);
  background:
    radial-gradient(90% 130% at 0% 0%, rgba(75,115,255,.18), transparent 62%),
    radial-gradient(80% 120% at 100% 0%, rgba(25,212,255,.12), transparent 60%),
    var(--kx-hero);
  padding: 20px; margin-bottom: 18px; overflow: hidden;
}
.kx-hero::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 4px; background: var(--kx-sol);
}
/* `clamp` plutôt qu'une taille fixe : « +$1.23M » et « 1.13× » n'ont pas la
   même longueur, et le chiffre doit rester dans sa carte à 412 px sans
   cesser d'être ce qu'on regarde en premier. */
.kx-hero-num { font: 800 clamp(38px, 11vw, 46px)/1 var(--kx-num); letter-spacing: -.03em; margin: .2rem 0; }

/* ── Contrôles ─────────────────────────────────────────────────────────────── */

.kx-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
  min-height: 50px; padding: 0 20px; border: 0; border-radius: var(--kx-r-pill);
  background: var(--kx-brand); color: var(--kx-on-brand);
  font: 600 .92rem/1 var(--kx-font); cursor: pointer;
}
.kx-btn:hover { box-shadow: 0 8px 25px rgba(25,212,255,.2); }

.kx-btn-ghost {
  min-height: 48px; padding: 0 18px; border-radius: var(--kx-r-pill);
  border: 1px solid var(--kx-line-2); background: transparent; color: var(--kx-ink);
  font: 600 .86rem/1 var(--kx-font); cursor: pointer;
}
.kx-btn-ghost:hover { background: rgba(255,255,255,.06); }

.kx-btn-gold { background: var(--kx-gold-g); color: var(--kx-gold-ink); }

/* Les chips de filtre. Chacun est une requête réelle ET une bascule : recliquer
   revient à « tout ». Un chip qui ne change pas la liste est un bug. */
.kx-chip {
  display: inline-flex; align-items: center; min-height: 36px;
  padding: 0 15px; border-radius: var(--kx-r-pill);
  border: 1px solid var(--kx-line-2); background: transparent; color: var(--kx-muted);
  font: 600 .74rem/1 var(--kx-font); cursor: pointer; white-space: nowrap;
}
.kx-chip:hover { color: var(--kx-ink); border-color: var(--kx-line-3); }
.kx-chip.on { background: var(--kx-brand); border-color: transparent; color: var(--kx-on-brand); }

.kx-chips { display: flex; flex-wrap: wrap; gap: 8px; }

/* ── Le dock mobile ────────────────────────────────────────────────────────── */

/* z-index 15 : AU-DESSUS de l'overlay de recherche (12), pour que son propre
   bouton puisse refermer l'overlay. Une bascule qui ne se referme pas piège
   l'utilisateur. */
.kx-dock {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 15;
  display: flex; justify-content: space-around; align-items: stretch;
  padding: 6px 4px calc(6px + env(safe-area-inset-bottom, 0px));
  background: rgba(27,36,54,.94); backdrop-filter: blur(18px);
  border-top: 1px solid var(--kx-line);
}
.kx-dock a, .kx-dock button {
  flex: 1 1 0; display: flex; flex-direction: column; align-items: center; gap: 3px;
  min-height: 46px; padding: 6px 2px;          /* ≥ 44 px de cible */
  background: none; border: 0; cursor: pointer;
  color: #8fa3c4; font: 500 .62rem/1 var(--kx-font);
}
.kx-dock .ic { font-size: 1.05rem; line-height: 1; }
.kx-dock .on { color: var(--kx-accent); }

/* ── UN LIEN DANS UNE PHRASE NE SE DISTINGUE PAS PAR SA SEULE COULEUR ────────
 *
 * `a { text-decoration: none }` vaut pour les liens qui SONT des blocs — une
 * ligne de resultat, une carte, un onglet : leur forme dit deja qu'on peut
 * cliquer. Dans une PHRASE, il ne reste que la couleur, et c'est exactement
 * ce que WCAG 1.4.1 refuse : un daltonien ne voit pas le lien.
 *
 * Releve par Lighthouse sur `/kol/yenni` (audit `link-in-text-block`) :
 * « Links rely on color to be distinguishable », sur le lien vers Positions
 * pose au milieu d'un paragraphe.
 *
 * La regle ne vise QUE la prose — les trois paragraphes qualifies de la fiche
 * et le corps de carte. `.kx-res`, `.kx-chip`, `.kx-btn` et les onglets n'en
 * font pas partie : ils ne sont pas du texte courant.
 */
.kx-pnlline a, .kx-walletline a, .kx-rankline a,
.kx-card-body > p a, .kx-card-body > span.dim a, p.dim a {
  text-decoration: underline; text-underline-offset: 2px;
  text-decoration-thickness: from-font;
}

/* ── « RECENTLY VIEWED » DANS LE PANNEAU DE RECHERCHE ─────────────────────
   Le titre et « Clear » sur une ligne, et un écart avant le bloc suivant,
   qui commence à marge nulle quand celui-ci est caché. */
.kx-recents { margin: 0 0 20px; }
.kx-recents-h { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.kx-recents-x { background: none; border: 0; padding: 4px 2px; cursor: pointer;
  font: 600 .7rem/1 var(--kx-font); color: var(--kx-muted); }
.kx-recents-x:hover { color: var(--kx-ink); }

/* ── L'overlay de recherche ────────────────────────────────────────────────── */

.kx-search {
  position: fixed; inset: 0; z-index: 12;
  background: rgba(5,10,26,.92); backdrop-filter: blur(10px);
  padding: 86px 18px 96px; overflow-y: auto;
  animation: kolfade .18s ease;
}
.kx-search input {
  width: 100%; min-height: 52px; padding: 0 16px;
  font-size: 16px;                 /* ≥ 16 px, sinon iOS zoome au focus */
  border-radius: var(--kx-r-cell); border: 1px solid var(--kx-line-2);
  background: rgba(255,255,255,.05); color: var(--kx-ink);
}
.kx-search input::placeholder { color: var(--kx-faint); }
.kx-search-group { margin-top: 22px; }

/* ── Modales ───────────────────────────────────────────────────────────────── */

.kx-modal-back {
  position: fixed; inset: 0; z-index: 80;
  display: grid; place-items: center; padding: 20px;
  background: rgba(2,6,23,.7); backdrop-filter: blur(10px);
}
.kx-modal {
  width: 100%; max-width: 400px;
  border-radius: var(--kx-r-card); border: 1px solid rgba(255,255,255,.14);
  background: radial-gradient(120% 90% at 0% 0%, rgba(25,212,255,.14), transparent 55%), var(--kx-float);
  box-shadow: var(--kx-sh-modal); animation: kolpop .2s ease; overflow: hidden;
}
.kx-modal.wide { max-width: 460px; }
.kx-modal-h {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 16px 18px; border-bottom: 1px solid var(--kx-line);
}
.kx-modal-b { padding: 16px 18px; font-size: .84rem; line-height: 1.65; color: var(--kx-ink-3); }
.kx-modal-f { padding: 0 18px 18px; }
.kx-modal-close {
  display: grid; place-items: center; width: 36px; height: 36px; border-radius: var(--kx-r-pill);
  border: 1px solid var(--kx-line-2); background: transparent; color: var(--kx-ink); cursor: pointer;
}
/* Une ligne clé/valeur dans une modale : encadrée, contrairement au corps de
   page où elle est simplement séparée. */
.kx-kv {
  display: flex; justify-content: space-between; gap: 1rem;
  padding: 11px 14px; margin-bottom: 8px;
  border-radius: var(--kx-r-cell); background: rgba(255,255,255,.04);
  border: 1px solid var(--kx-line);
}
.kx-kv .k { font-size: .78rem; color: var(--kx-muted); }
.kx-kv .v { font: 700 .82rem/1.3 var(--kx-num); }

/* ── Le toast ──────────────────────────────────────────────────────────────── */

/* Au-dessus du dock en mobile : un message masqué par la barre de navigation
   n'est pas un message. */
.kx-toast {
  position: fixed; left: 50%; transform: translateX(-50%); bottom: 104px; z-index: 90;
  padding: 12px 18px; border-radius: var(--kx-r-pill);
  background: rgba(20,20,28,.96); border: 1px solid rgba(255,255,255,.14);
  box-shadow: 0 12px 30px rgba(0,0,0,.55);
  font: 500 .82rem/1 var(--kx-font); color: #fff;
  max-width: calc(100vw - 36px);
  /* PAS kolfade : ses images-clés posent `transform`, ce qui ÉCRASE le
     translateX(-50%) de centrage — le toast entrait alors depuis la moitié
     droite de l’écran, à moitié dehors. Une animation partagée doit reprendre
     la transformation qu’elle recouvre, ou ne pas y toucher. */
  animation: kxtoast .18s ease;
}
.kx-toast.bad { border-color: rgba(255,120,120,.45); color: var(--kx-down-soft); }

/* ── Pastilles ─────────────────────────────────────────────────────────────── */

.kx-pill {
  display: inline-flex; align-items: center; gap: .3rem;
  padding: .22rem .6rem; border-radius: var(--kx-r-pill);
  border: 1px solid var(--kx-line-2); background: rgba(255,255,255,.04);
  font: 600 .68rem/1.3 var(--kx-font); white-space: nowrap;
}
/* Les quatre paliers de fiabilité, et un cinquième état : « en constitution ».
   Ce dernier n'est pas une note basse — c'est l'absence de note, et il ne doit
   surtout pas se lire comme « mauvais ». */
.kx-pill.very    { color: var(--kx-gold-tx); border-color: rgba(245,199,106,.45); background: rgba(245,199,106,.1); }
.kx-pill.good    { color: var(--kx-up-soft); border-color: rgba(25,255,115,.35);  background: rgba(25,255,115,.08); }
.kx-pill.streaky { color: var(--kx-ink-2);   border-color: rgba(255,255,255,.14); }
.kx-pill.erratic { color: var(--kx-down-soft);border-color: rgba(255,120,120,.35); background: rgba(255,120,120,.08); }
.kx-pill.pending { color: var(--kx-faint);   border-style: dashed; background: transparent; }
/* Un résultat en pastille (le latent en $ de « Still holding », page token) :
   les couleurs de `.good` / `.erratic`, nommées pour ce qu'elles disent. */
.kx-pill.up      { color: var(--kx-up-soft);  border-color: rgba(25,255,115,.35);  background: rgba(25,255,115,.08); }
.kx-pill.down    { color: var(--kx-down-soft);border-color: rgba(255,120,120,.35); background: rgba(255,120,120,.08); }

.kx-live {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--kx-accent); animation: kolpulse 1.8s ease-in-out infinite;
}

/* ── Bureau ────────────────────────────────────────────────────────────────── */

/* La nav de bureau n'apparaît qu'à partir de 1 100 px, pas de 900.
   MESURÉ : à 900 et à 1 024, « Watchlist » sortait de la barre. Le groupe de
   droite de l'interface connectée — recherche, pastille d'alertes, compte —
   est plus large que le simple bouton du site public, donc le même nombre de
   liens demande plus de place ici. Le dock reste jusqu'au même seuil : il ne
   doit jamais y avoir de largeur sans aucune navigation.
   `.kx-top` ne reprend PAS de marge horizontale : c'est `.kx-top-in` qui la
   porte, comme `.topbar-container` sur le site public. */
@media (min-width: 1100px) {
  .kx-nav  { display: flex; }
  .kx-dock { display: none; }
}

@media (min-width: 900px) {
  .kx-wrap { padding: 28px 26px 38px; }
  .kx-hero { padding: 26px; }
  .kx-hero-num { font-size: 62px; }
  .kx-toast { bottom: 34px; }
  .kx-search { padding: 96px 26px 30px; }
}

/* ── L'avatar ──────────────────────────────────────────────────────────────── */

/* Le repli ne peut pas être un fichier : un fichier peut manquer, et c'est
   exactement ce qui arrive. L'initiale est DESSINÉE par la feuille de style et
   l'image se pose par-dessus quand elle charge — `avatar()` n'écrit la balise
   <img> que si le fichier existe vraiment sur le disque. */
.av {
  position: relative; flex: 0 0 auto;
  display: grid; place-items: center; width: 34px; height: 34px;
  border-radius: 50%; overflow: hidden;
  background: linear-gradient(135deg, #2a3550, #1b2436);
  border: 1px solid var(--kx-line-2);
}
.av::before {
  content: attr(data-i);
  font: 700 .78rem/1 var(--kx-num); color: var(--kx-ink-3);
}
.av img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.av.sm { width: 26px; height: 26px; }
.av.sm::before { font-size: .64rem; }

/* ── Une ligne de résultat ─────────────────────────────────────────────────── */

.kx-res {
  display: flex; align-items: center; gap: 12px;
  min-height: 56px; padding: 10px 12px; margin-bottom: 8px;
  border-radius: var(--kx-r-cell); border: 1px solid var(--kx-line);
  background: var(--kx-raised); color: var(--kx-ink);
}
.kx-res:hover { border-color: var(--kx-line-3); background: #202a40; color: var(--kx-ink); }
.kx-res-n { flex: 1 1 auto; min-width: 0; font-size: .88rem; font-weight: 600; }
.kx-res-n small { display: block; font-weight: 400; font-size: .68rem; }
.kx-res-v { flex: 0 0 auto; text-align: right; font-size: .84rem; }
.kx-res-v small { display: block; font-size: .64rem; font-weight: 400; }
.kx-res-t {
  display: grid; place-items: center; flex: 0 0 auto; width: 34px; height: 34px;
  border-radius: 10px; background: rgba(25,212,255,.12); color: var(--kx-accent);
  font: 700 .9rem/1 var(--kx-num);
}

/* Une action irréversible ne porte pas la couleur de la marque : le rouge n'est
   pas décoratif ici, il sépare « fermer » de « supprimer ». */
.kx-btn.danger { background: rgba(255,80,80,.18); color: var(--kx-down-soft); }
.kx-btn.danger:hover { background: rgba(255,80,80,.26); box-shadow: none; }

/* Le bouton de recherche, quand l'overlay est ouvert. */
.kx-iconbtn.on { border-color: var(--kx-accent); color: var(--kx-accent); }

@keyframes kxtoast {
  from { opacity: 0; transform: translate(-50%, 8px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}

/* ── L'accueil ─────────────────────────────────────────────────────────────── */

/* La courbe du hero. Une barre PAR JOUR, trous compris : une courbe qui saute
   les jours vides ment sur le rythme — trois barres serrées sur quinze jours se
   liraient comme trois jours d'affilée.
   Un jour sans trade soldé n'a PAS de barre. Une barre plate dirait « ils ont
   fait zéro » ; l'absence dit « ils n'ont rien soldé », et ce n'est pas la même
   information. C'est le trait pointillé de la ligne de base qui la porte. */
.kx-spark {
  display: flex; align-items: flex-end; gap: 3px;
  height: 74px; margin: 16px 0 6px;
  border-bottom: 1px dashed var(--kx-line-2);
}
.kx-spark i {
  flex: 1 1 0; min-width: 2px; border-radius: 3px 3px 0 0;
  background: linear-gradient(180deg, var(--kx-accent), rgba(25,212,255,.25));
  display: block;
}
.kx-spark i.dn { background: linear-gradient(180deg, rgba(255,128,128,.75), rgba(255,128,128,.2)); }
.kx-spark i.na { background: none; }
.kx-spark-x {
  display: flex; justify-content: space-between;
  font-size: .62rem; color: var(--kx-faint);
}

/* Le rail des traders. Défilement horizontal avec accroche : sur un téléphone,
   une carte coupée en deux au repos indique qu'il y en a d'autres — un rail qui
   s'arrête pile au bord passe pour une liste complète. */
.kx-rail {
  display: flex; gap: 12px; overflow-x: auto; scroll-snap-type: x mandatory;
  padding: 2px 18px 14px; margin: 0 -18px;
  scrollbar-width: none;
}
.kx-rail::-webkit-scrollbar { height: 0; }
.kx-rail > * { scroll-snap-align: start; flex: 0 0 auto; width: 162px; }

.kx-pulse {
  display: flex; flex-direction: column; gap: 10px;
  padding: 15px; border-radius: var(--kx-r-card);
  border: 1px solid var(--kx-line); background: var(--kx-raised); color: var(--kx-ink);
}
.kx-pulse.live {
  border-color: rgba(25,212,255,.45);
  background: radial-gradient(circle at 0% 0%, rgba(25,212,255,.12), transparent 60%), var(--kx-raised);
}
.kx-pulse-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.kx-tag {
  padding: 4px 9px; border-radius: var(--kx-r-pill);
  font: 700 .6rem/1 var(--kx-font); letter-spacing: .06em; text-transform: uppercase;
  background: rgba(255,255,255,.05); color: var(--kx-muted);
}
.kx-tag.live  { background: rgba(25,212,255,.14); color: var(--kx-accent-2); }
.kx-tag.today { background: rgba(255,255,255,.07); color: var(--kx-ink-2); }

/* Le fil. Le trait vertical relie les points : sans lui, une liste de pastilles
   se lit comme des éléments sans rapport plutôt que comme une chronologie. */
.kx-tape { position: relative; padding-left: 22px; }
.kx-tape::before {
  content: ''; position: absolute; left: 5px; top: 8px; bottom: 14px;
  width: 1px; background: var(--kx-line-2);
}
.kx-tape-row {
  position: relative; display: flex; align-items: flex-start;
  justify-content: space-between; gap: 12px;
  padding: 0 0 16px; color: var(--kx-ink);
}
.kx-tape-row::before {
  content: ''; position: absolute; left: -22px; top: 5px;
  width: 11px; height: 11px; border-radius: 50%;
}
.kx-tape-row.buy::before  { background: var(--kx-up);   box-shadow: 0 0 10px var(--kx-up); }
.kx-tape-row.sell::before { background: var(--kx-down); box-shadow: 0 0 10px var(--kx-down); }
.kx-tape-row small { display: block; font-size: .68rem; color: var(--kx-muted); margin-top: 3px; }

/* Le consensus. La barre dit « combien de VOTRE liste », pas une performance —
   d'où le dégradé de marque et non le vert du résultat. */
/* `display:block` n'est pas décoratif : la barre est portée par un <span>, et
   une boîte EN LIGNE ignore `height` et `width` — la barre se rendait donc
   avec 0 px de haut, invisible, alors que son remplissage intérieur avait
   bien la bonne largeur. */
.kx-bar { display: block; height: 7px; border-radius: var(--kx-r-pill); background: rgba(255,255,255,.07); overflow: hidden; }
.kx-bar i { display: block; height: 100%; border-radius: var(--kx-r-pill); background: var(--kx-brand); }

/* L'écran vide. Il ne dit jamais « aucune donnée » : il dit ce qui manque et par
   où commencer, sinon l'utilisateur conclut que le produit est cassé. */
.kx-empty { text-align: center; padding: 26px 18px; }
.kx-empty p { color: var(--kx-ink-3); font-size: .86rem; margin: 0 0 16px; max-width: 42ch;
              margin-left: auto; margin-right: auto; line-height: 1.6; }

/* ── Le classement ─────────────────────────────────────────────────────────── */

/* Une ligne, c'est DEUX zones cliquables distinctes : le corps mène au profil,
   les pastilles ouvrent la modale ou suivent le trader. Imbriquer un bouton
   dans le lien produirait un lien dans un lien — HTML invalide, et le
   navigateur suit alors l'un ou l'autre selon son humeur. Ils sont donc frères,
   pas l'un dans l'autre. */
.kx-row { border-bottom: 1px solid rgba(255,255,255,.05); }
.kx-row:last-child { border-bottom: 0; }
.kx-row:hover { background: rgba(25,212,255,.05); }
/* Un trader suivi porte un liseré or à gauche : repérable en balayant la
   colonne, sans avoir à lire chaque nom. */
.kx-row.watched { border-left: 3px solid var(--kx-gold); }

.kx-row-main {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 18px 8px; color: var(--kx-ink);
}
.kx-row-main:hover { color: var(--kx-ink); }
.kx-rank {
  flex: 0 0 auto; width: 26px;
  font: 700 1.25rem/1 var(--kx-num); color: var(--kx-ghost);
}
.kx-row-id { flex: 1 1 auto; min-width: 0; }
.kx-row-name { display: block; font-size: .92rem; font-weight: 600; }
.kx-row-meta { display: block; font-size: .66rem; color: var(--kx-muted); margin-top: 2px; }
/* « out $12.1K » : encaisse, donc la couleur des gains. Le reste de la ligne
   reste en gris — c est un contexte, pas un tableau de chiffres. */
.kx-row-meta .kx-out { font: 700 inherit/1 var(--kx-num); font-size: .68rem; color: var(--kx-up); }
.kx-row-num { flex: 0 0 auto; text-align: right; font-size: 1rem; }
.kx-row-num small { display: block; font-size: .62rem; font-weight: 400; margin-top: 2px; }

/* ── LA PAIRE D'UNE LIGNE DE « CURRENT HOLDINGS » ────────────────────────────
 *
 * Deux chiffres de MÊME rang : la valeur de la position, et le latent qu'elle
 * porte. Même famille, même corps, même graisse — ni l'un ni l'autre n'est le
 * commentaire de l'autre, et c'est tout le propos : la taille et l'enjeu se
 * lisent d'un seul regard.
 *
 * La couleur reste le seul écart. Elle vient de `kxNum()`, décidée sur la
 * valeur ARRONDIE — celle qui est imprimée. La valeur, elle, n'est jamais
 * colorée : une position n'est ni un gain ni une perte, c'est un montant.
 *
 * Le filet entre les deux lignes vaut mieux qu'un écart : à corps égal, deux
 * montants collés se lisent comme un seul nombre coupé en deux.
 */
.kx-pair { display: flex; flex-direction: column; align-items: flex-end; gap: 0; }
.kx-pair-l {
  display: flex; align-items: baseline; justify-content: flex-end; gap: 6px;
  padding: 4px 0;
  font-size: .94rem;
  white-space: nowrap;
}
.kx-pair-l + .kx-pair-l { border-top: 1px solid rgba(255, 255, 255, .07); }
.kx-pair-l .kx-num { font-size: inherit; }
/* Le libellé ne prend pas sa propre ligne ici : il suit le montant, en bout de
   ligne, pour que les deux montants restent alignés à droite l'un sous
   l'autre. `.kx-row-num small` l'aurait mis en bloc. */
.kx-pair-l small {
  display: inline; margin: 0;
  font: 400 .58rem/1 var(--kx-font);
  letter-spacing: .04em; text-transform: uppercase;
  color: var(--kx-ink-3);
}

.kx-row-tags {
  display: flex; flex-wrap: wrap; align-items: center; gap: 7px;
  padding: 0 18px 14px 56px;     /* aligné sous le nom, pas sous le rang */
}
.kx-pill[data-kx-open]:hover { filter: brightness(1.3); }

@media (min-width: 900px) {
  /* En bureau, les pastilles tiennent sur la même ligne que le nom : la largeur
     est là, et une ligne de tableau qui fait deux étages se compare mal. */
  .kx-row { display: flex; align-items: center; gap: 10px; padding-right: 18px; }
  .kx-row-main { flex: 1 1 auto; padding: 14px 0 14px 18px; }
  .kx-row-tags { padding: 0; flex: 0 0 auto; justify-content: flex-end; }
}

/* ── Le terminal ───────────────────────────────────────────────────────────── */

/* Une colonne en mobile, deux dès qu'il y a la place. `auto-fill` plutôt qu'un
   nombre fixe : la carte a une largeur minimale au-dessous de laquelle ses
   quatre statistiques se replient, et c'est elle qui décide du nombre de
   colonnes, pas une valeur de point de rupture choisie au jugé. */
.kx-grid {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
}

.kx-tok {
  display: block; padding: 18px;
  border-radius: 24px; border: 1px solid var(--kx-line-2);
  background: radial-gradient(120% 100% at 0% 0%, rgba(25,212,255,.12), transparent 55%), rgba(8,10,24,.9);
  box-shadow: 0 16px 42px rgba(0,0,0,.55);
  color: var(--kx-ink);
}
.kx-tok:hover { border-color: rgba(25,212,255,.45); color: var(--kx-ink); }
.kx-tok-h { display: flex; align-items: center; gap: 11px; }
.kx-tok-mark {
  display: grid; place-items: center; flex: 0 0 auto; width: 44px; height: 44px;
  border-radius: 14px; background: var(--kx-brand-d); color: var(--kx-on-brand);
  font: 700 .76rem/1 var(--kx-num);
}

/* Quatre statistiques sur une ligne. Chacune met son CHIFFRE au-dessus de son
   nom : dans une rangée, l'œil descend une colonne de nombres, il ne relit pas
   quatre étiquettes. */
.kx-tok-stats {
  display: flex; justify-content: space-between; gap: 10px;
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--kx-line);
}
.kx-tok-stats > span {
  display: flex; flex-direction: column; gap: 2px; min-width: 0;
  font-size: .6rem; color: var(--kx-muted);
}
.kx-tok-stats b, .kx-tok-stats .kx-num { font-size: .92rem; color: var(--kx-ink); }
.kx-tok-stats .kx-num.up   { color: var(--kx-up); }
.kx-tok-stats .kx-num.down { color: var(--kx-down); }
.kx-tok-stats small { font-size: .6rem; color: var(--kx-muted); }

.kx-tok-who {
  display: flex; align-items: center; gap: 12px;
  margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--kx-line);
}
/* Les visages se chevauchent : quatre pastilles alignées prendraient la largeur
   d'une phrase pour dire « quatre personnes ». */
.kx-faces { display: flex; flex: 0 0 auto; }
.kx-faces .av { margin-right: -9px; border: 2px solid #0b1018; }
.kx-faces .av:last-child { margin-right: 0; }

.kx-tok-exit { margin: 10px 0 0; font-size: .68rem; color: var(--kx-muted); line-height: 1.5; }

/* L'avatar du profil : la seule taille où le visage est le sujet de la page. */
.av.big { width: 62px; height: 62px; border-width: 2px; }
.av.big::before { font-size: 1.3rem; }

/* ── L'interrupteur ────────────────────────────────────────────────────────── */

/* Un vrai <button role="switch">, pas un <span> dessiné : un interrupteur en
   <span> n'existe ni pour le clavier ni pour un lecteur d'écran, et c'est
   exactement le composant qu'on est tenté de bâcler parce qu'il « n'est que
   visuel ». */
.kx-switch {
  flex: 0 0 auto; position: relative;
  width: 48px; height: 28px; padding: 3px;
  border-radius: var(--kx-r-pill); border: 1px solid var(--kx-line-2);
  background: rgba(255,255,255,.06); cursor: pointer;
  transition: background .15s ease, border-color .15s ease;
}
.kx-switch > span {
  display: block; width: 20px; height: 20px; border-radius: 50%;
  background: var(--kx-faint);
  transition: transform .15s ease, background .15s ease;
}
.kx-switch.on { background: var(--kx-brand); border-color: transparent; }
.kx-switch.on > span { background: var(--kx-on-brand); transform: translateX(20px); }
/* Le focus clavier doit se voir : sans anneau, on ne sait plus où l'on est. */
.kx-switch:focus-visible { outline: 2px solid var(--kx-accent); outline-offset: 2px; }

/* ── La marque, alignée sur la barre publique ───────────────────────────────── */

/* Le vrai logo du site, au même diamètre de 40 px et avec le même
   `object-fit: contain` que `.logo-img` de `style.css`. Une pastille dessinée
   « dans l'esprit » ne fait pas le même produit — un utilisateur qui passe du
   site public à l'interface connectée doit reconnaître la même marque. */
.kx-logo { width: 40px; height: 40px; border-radius: 50%; object-fit: contain; flex: 0 0 auto; }
/* ⚠ Il y avait ICI un second `.kx-brand-name { font-weight: 700; font-size: 1rem }`,
   écrit APRÈS celui de la barre (ligne ~230) et qui gagnait donc à spécificité
   égale. Résultat mesuré : la marque sortait en 16 px / 700 au lieu des
   21,6 px / 600 de `style.css`. Le logo faisait bien ses 40 px — c est le TEXTE
   qui était petit. Deuxième collision de ce type après `.kx-rank` : un nom de
   classe réutilisé ne casse rien, il applique silencieusement l ancienne
   valeur.
   Seul `white-space: nowrap` méritait de survivre ; il est remonté sur la
   règle canonique. */

/* Les icônes de navigation : même jeu que le menu public. Elles sont posées à
   la même taille que le texte et n'ont pas de couleur propre — c'est l'état
   actif qui colore le lien entier, icône comprise. */
/* La taille d'icone de la nav est fixee plus haut (1.1rem, comme le site
   public) ; ici il ne reste que le dock. */
.kx-dock .ic .kxi { font-size: .9em; }
.kx-dock .ic { font-size: 1rem; line-height: 1; }

/* ── Le logo d'un token ────────────────────────────────────────────────────── */

/* L'initiale est dessinée ici, l'image se pose par-dessus. Si l'image n'arrive
   pas — URL de métadonnées JSON, fichier disparu — `onerror` la retire et
   l'initiale réapparaît. Aucune règle CSS ne sait détecter un 404 ; c'est la
   seule façon d'avoir raison dans les deux cas. */
.tl {
  position: relative; flex: 0 0 auto;
  display: grid; place-items: center; width: 34px; height: 34px;
  border-radius: 11px; overflow: hidden;
  background: var(--kx-brand-d); color: var(--kx-on-brand);
  border: 1px solid var(--kx-line);
}
.tl::before { content: attr(data-i); font: 700 .68rem/1 var(--kx-num); }
.tl img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.tl.sm { width: 26px; height: 26px; border-radius: 9px; }
.tl.sm::before { font-size: .56rem; }
.tl.lg { width: 44px; height: 44px; border-radius: 14px; }
.tl.lg::before { font-size: .78rem; }
.tl.xl { width: 52px; height: 52px; border-radius: 16px; }
.tl.xl::before { font-size: .88rem; }

/* ── Partager ─────────────────────────────────────────────────────────────────
 *
 * `share-card.php` fabrique une image d'un COUPLE (wallet, token) — c'est le
 * seul objet qu'il sache dessiner. Le bouton vit donc sur les lignes qui sont
 * ce couple : une position d'un trader, un détenteur d'un token. Nulle part
 * ailleurs, parce que nulle part ailleurs la paire n'existe.
 *
 * 34 px de haut dans une rangée de pills de 32, mais 44 de cible tactile grâce
 * au pseudo-élément : la règle des 44 px tient sans grossir le dessin. */
.kx-share {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  position: relative;
  min-height: 32px; padding: 0 11px;
  border-radius: var(--kx-r-pill);
  border: 1px solid var(--kx-line); background: transparent;
  color: var(--kx-ink-3); font: 600 .68rem/1 var(--kx-font);
  text-decoration: none; cursor: pointer;
  transition: color .15s, border-color .15s, background .15s;
}
.kx-share::after {
  content: ''; position: absolute; inset: -6px -2px;   /* la cible, pas le dessin */
}
.kx-share:hover, .kx-share:focus-visible {
  color: var(--kx-ink); border-color: rgba(75,115,255,.5); background: rgba(75,115,255,.12);
}
.kx-share .kxi { font-size: .72rem; }

/* Le logo d'une plateforme de copy-trading. Carré arrondi comme un logo de
   token, pas rond comme un avatar : ce n'est pas quelqu'un. */
.kx-plat {
  flex: 0 0 auto; width: 34px; height: 34px;
  border-radius: 11px; object-fit: cover;
  border: 1px solid var(--kx-line);
}

/* ── Marché / Flux / Sûreté, dans l'en-tête du token ──────────────────────────
 *
 * Trois volets pliés. Repliés ils tiennent sur une ligne chacun et portent leur
 * réponse ; dépliés ils rendent les six clés-valeurs qu'ils avaient en carte.
 *
 * `<details>` et non un bouton avec du JavaScript : l'ouverture marche avant que
 * le script ne charge, au clavier, et la recherche du navigateur (Ctrl+F) trouve
 * le texte replié. Aucune de ces trois choses n'est vraie d'un volet maison.
 */
.kx-facts { display: grid; gap: 8px; margin-top: 18px; }

.kx-fact {
  border: 1px solid var(--kx-line-2); border-radius: 14px;
  background: rgba(255, 255, 255, .04);
}
.kx-fact > summary {
  display: flex; align-items: center; gap: 10px;
  min-height: 44px; padding: 0 14px;
  cursor: pointer; list-style: none;
  font-size: .76rem; color: var(--kx-ink-3);
}
/* Le triangle par défaut de Safari et de Chrome, retiré des deux façons qu'ils
   attendent — on dessine le nôtre. */
.kx-fact > summary::-webkit-details-marker { display: none; }
.kx-fact > summary::marker { content: ''; }

.kx-fact-k { font-weight: 600; letter-spacing: .02em; }
.kx-fact-v {
  margin-left: auto;
  font: 700 .86rem/1 var(--kx-num); color: var(--kx-ink);
}
.kx-fact-v.up   { color: var(--kx-up); }
.kx-fact-v.down { color: var(--kx-down); }

.kx-fact > summary > .kxi {
  font-size: .6rem; color: var(--kx-muted);
  transition: transform .18s ease;
}
.kx-fact[open] > summary > .kxi { transform: rotate(180deg); }
.kx-fact[open] > summary { border-bottom: 1px solid var(--kx-line); }

.kx-fact-body { padding: 4px 14px 8px; }
.kx-fact-body .kx-kv:last-child { border-bottom: 0; }

/* Trois de front dès qu'il y a la place : en large, les plier n'apporte rien. */
@media (min-width: 720px) {
  .kx-facts { grid-template-columns: repeat(3, 1fr); align-items: start; }
}

/* ── Les icônes SVG ───────────────────────────────────────────────────────────
 *
 * Elles remplacent les `<i class="fa-...">` de Font Awesome. `vertical-align`
 * est le seul réglage indispensable : un SVG en ligne s'assoit sur la ligne de
 * base et dépasse donc sous le texte, là où un glyphe de police est déjà calé.
 * `-.125em` le remonte au même endroit que l'ancien glyphe.
 */
.kxi { display: inline-block; vertical-align: -.125em; flex: 0 0 auto; }
.kxi.mr { margin-right: 7px; }
.kxi.dim { color: var(--kx-muted); }

/* Les tailles réglées pour les anciens `<i>` valaient par la taille de POLICE ;
   le SVG fait 1em de côté, donc elles continuent de s'appliquer telles quelles. */

/* ── Deux colonnes : profil et token ───────────────────────────────────────
 *
 * Un rail d'identité collé à gauche, le contenu à droite. Voir le commentaire
 * en tête de `member/kol.php` pour le pourquoi.
 *
 * Le seuil est 1000 px et non 900 : à 900, un rail de 340 px laisse 540 px pour
 * l'histogramme à sept barres et les lignes de position, où le symbole, la mise,
 * l'entrée, la date, le PnL et le multiple doivent tenir. Mesuré, ça se tasse.
 */
.kx-split { display: block; }

@media (min-width: 1000px) {
  .kx-split {
    display: grid;
    grid-template-columns: 340px minmax(0, 1fr);   /* minmax(0,1fr) : sans lui,
        une ligne large de la colonne de droite (un tableau, une barre) impose sa
        largeur à la grille et la page déborde horizontalement. */
    gap: 20px;
    align-items: start;                            /* sinon les deux colonnes
        s'étirent à la même hauteur et le `sticky` du rail n'a plus de course. */
  }

  /* ── PAS DE RAIL COLLANT, ET C'EST UNE CORRECTION ────────────────────────
   *
   * Premier jet : `position: sticky` + `max-height` + défilement interne, pour
   * garder l'identité sous les yeux. Deux choses l'ont démenti.
   *
   * La MESURE d'abord : le rail de la page de token fait **1 646 px** une fois
   * « Market », « Flow » et « Safety » déroulés, contre 806 px de hauteur utile.
   * Un rail collant plus haut que l'écran ne garde rien sous les yeux : il
   * emprisonne son bas derrière une seconde barre de défilement, à l'intérieur
   * d'un bloc qui, lui, ne bouge pas.
   *
   * La MAQUETTE ensuite, qui tranchait déjà : ses captures de bureau montrent la
   * colonne de gauche qui a défilé avec la page — on y voit « Market » puis
   * « Flow » puis « Safety » se succéder pendant que la droite avance. Elle n'est
   * pas collante.
   *
   * Les deux colonnes défilent donc ensemble, comme n'importe quelle page.
   */
  /* ── LA MARGE DU HERO, ET POURQUOI ELLE EST REVENUE ────────────────────
   *
   * Écrit quand le rail de gauche ne portait QUE la carte d identité : le
   * `gap` de la grille espaçait les deux colonnes, et la marge basse du hero
   * n avait plus d objet.
   *
   * Depuis, cinq cartes sont descendues sous lui. Or un `gap` de grille ne
   * sépare pas deux frères À L INTÉRIEUR d une colonne : « Trading style »
   * se retrouvait **collé** à la carte d identité, 0 px, quand toutes les
   * autres paires du rail avaient 16 px. Mesuré, pas supposé.
   *
   * La marge ne tombe donc que si le hero est bel et bien le DERNIER de sa
   * colonne — sur la page de token, par exemple, où il est seul. */
  .kx-col-a > .kx-hero:last-child { margin-bottom: 0; }

  /* La première carte de droite s'aligne sur le haut du rail. */
  .kx-col-b > :first-child { margin-top: 0; }
}

/* Un écran vraiment large : le rail gagne un peu, sans que la colonne de
   droite ne devienne une ligne de texte interminable. */
@media (min-width: 1240px) {
  .kx-split { grid-template-columns: 380px minmax(0, 1fr); gap: 24px; }
}

/* L'adresse du wallet dans le rail d'identité, avec son bouton de copie.
   `min-width:0` sur le <code> : sans lui, une chaîne base58 de 44 caractères
   sans espace refuse de se réduire et pousse le bouton hors de la carte. */
/* Remontée sous le nom : la marge du haut se resserre, celle du bas apparaît —
   elle sépare l adresse des pastilles de style qui la suivent maintenant. */
.kx-wallet {
  display: flex; align-items: center; gap: 8px; margin: 12px 0 14px;
  padding: 7px 8px 7px 12px;
  background: rgba(255, 255, 255, .06);
  border: 1px solid var(--kx-line-2); border-radius: 12px;
}
.kx-wallet code {
  flex: 1 1 auto; min-width: 0;
  font: 400 .66rem/1.45 ui-monospace, monospace; color: var(--kx-ink-2);
  word-break: break-all;
}
.kx-wallet-copy { flex: 0 0 auto; min-height: 32px; padding: 0 11px; font-size: .68rem; }

/* ── Market / Flow / Safety : pliés sur téléphone, ouverts dans le rail ───────
 *
 * La maquette de bureau les montre déroulés, en trois cartes du rail de gauche.
 * Sur téléphone ils doivent rester pliés — dix-huit lignes de clé-valeur au-
 * dessus du pli repousseraient hors de l'écran ce que cette page sait dire de
 * mieux : qui est encore dedans.
 *
 * `<details>` ne s'ouvre pas en CSS, mais son contenu se ré-affiche : la règle
 * de l'agent qui cache les enfants d'un `details` fermé se surcharge. On garde
 * donc UN seul balisage, et c'est la largeur qui décide de l'apparence. Le
 * chevron et le curseur disparaissent avec, sinon le sommaire promettrait un
 * pli qui n'existe plus.
 */
@media (min-width: 1000px) {
  /* ── LES TROIS VOLETS RESTENT FERMÉS, MÊME SUR GRAND ÉCRAN ────────────────
     Ils étaient forcés ouverts ici : `content-visibility: visible`, corps en
     `block`, chevron masqué, curseur par défaut. La maquette de bureau les
     montre dépliés, et c'est ce que j'avais suivi.

     DEUX RAISONS DE REVENIR DESSUS. Ils coûtaient **906 px du rail** à eux
     trois — mesuré — pour des chiffres qu'on consulte une fois. Et surtout
     l'état affiché ne correspondait plus à l'état réel : `details.open` valait
     `false` pendant que le corps était visible, si bien qu'un premier clic sur
     le résumé ne fermait rien.

     Un `<details>` se comporte maintenant comme un `<details>` à toutes les
     largeurs : fermé, cliquable, chevron visible. */}

/* Dans le rail, les trois volets s'empilent : la règle « trois de front » vaut
   pour une pleine largeur, pas pour 340 px — mesuré, « Safety » y était coupé.
   C'est la maquette de bureau qui les montre empilés, l'un sous l'autre. */
.kx-col-a .kx-facts { grid-template-columns: 1fr; }

/* ── Les pastilles « live » du classement ─────────────────────────────────────
 *
 * Reprises telles quelles de `index.php` (lignes 114-124), où elles sont
 * déclarées en CSS critique et non dans `style.css` :
 *
 *     .badge { display:inline-flex; gap:.35rem; align-items:center;
 *              padding:.14rem .55rem; border-radius:999px;
 *              border:1px solid var(--ui-line); background:rgba(255,255,255,.04);
 *              font-size:.74rem; color:rgba(232,240,255,.86) }
 *     .b-live { border-color:rgba(255,77,77,.25); background:rgba(255,77,77,.10) }
 *
 * ⚠ `--ui-line` N'EST DÉFINIE NULLE PART dans `index.php` — seulement dans les
 * copies archivées de `avantregsiter.1806/`, où elle vaut
 * `rgba(255,255,255,.09)`. Une `var()` non résolue rend la déclaration invalide
 * au calcul, donc `border` retombe sur son initiale : `border-style: none`. Les
 * pastilles publiques n'ont donc **aucune bordure** aujourd'hui, et le
 * `border-color` de `.b-live` ne peint rien.
 *
 * On reproduit ce qui est RENDU, puisque c'est ce qui a été demandé. Remettre la
 * bordure voulue est une ligne à ajouter dans `index.php`, pas ici.
 */
.kx-badge {
  display: inline-flex; gap: .35rem; align-items: center;
  position: relative;
  padding: .14rem .55rem;
  border: 0; border-radius: 999px;
  background: rgba(255, 77, 77, .10);
  font: 400 .74rem/1.5 var(--kx-font);
  color: rgba(232, 240, 255, .86);
}
.kx-badge[data-kx-open] { cursor: pointer; }
.kx-badge[disabled] { opacity: .55; cursor: default; }
/* La cible tactile des 44 px sans grossir le dessin — même procédé que
   `.kx-share`. Les pastilles publiques ne sont pas cliquables ; celles-ci
   ouvrent la liste des traders concernés. */
.kx-badge[data-kx-open]::after { content: ''; position: absolute; inset: -11px -6px; }
.kx-badge[data-kx-open]:hover { background: rgba(255, 77, 77, .16); }

/* Le point, à l'identique : 8 px, `#ff4d4d`, battement de 1,4 s. Les deux
   classes publiques (`dotlive` / `dotlive2`) ne diffèrent que par la couleur
   d'une ombre que l'animation écrase aussitôt — elles rendent le même point. */
.kx-dotlive {
  width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto;
  background: #ff4d4d;
  animation: kxpulse 1.4s infinite;
}
@keyframes kxpulse {
  0%   { box-shadow: 0 0 0 0    rgba(255, 77, 77, .55); }
  70%  { box-shadow: 0 0 0 12px rgba(255, 77, 77, 0); }
  100% { box-shadow: 0 0 0 0    rgba(255, 77, 77, 0); }
}

/* Deux cartes côte à côte dès qu'il y a la place : « meilleur » et « pire » se
   lisent l'un contre l'autre, empilés ils se lisent l'un après l'autre. */
.kx-duo { display: grid; gap: 14px; margin-bottom: 18px; }
@media (min-width: 560px) { .kx-duo { grid-template-columns: 1fr 1fr; } }

/* ── La carte d'identité d'un trader ──────────────────────────────────────────
 * Reprise de l'ordre du rail de bureau de la maquette. Voir le commentaire en
 * tête de `member/kol.php` pour ce qu'elle montre et ce qu'elle omet. */

/* `.kx-idrank` et non `.kx-rank` : ce dernier existe depuis le classement, où
   il porte le NUMÉRO de rang d une ligne — `width: 26px`, `1.25rem`. Réutiliser
   le nom héritait de ces deux valeurs : l exergue se retrouvait large de 26 px,
   un mot par ligne, en corps 20. Une collision que seule la mesure attrape,
   puisque ma propre règle s appliquait bien — elle ne redéclarait simplement
   pas tout. */
.kx-idrank {
  display: inline-block; margin: 0 0 10px;
  color: var(--kx-ink-2); text-decoration: none;
}
.kx-idrank:hover { color: var(--kx-ink); }

.kx-idpills { display: flex; gap: 7px; flex-wrap: wrap; margin-bottom: 14px; }
.kx-idpills:empty { display: none; }

.kx-idhead { display: flex; align-items: center; gap: 14px; margin-bottom: 14px; }
/* `margin: 0` : cette classe habille un <h1> depuis l'audit SEO — le nom du
   trader et le symbole du token sont le SUJET de leurs pages, et ils n'étaient
   que des <span>. Sans cette remise à zéro, la marge par défaut d'un h1
   (0.67em au-dessus ET en dessous) décalerait les deux en-têtes. */
.kx-idname {
  display: block; font-size: 1.35rem; font-weight: 700; letter-spacing: -.02em;
  line-height: 1.2; margin: 0;
}
/* Le qualificatif du `<h1>` — « — Solana Wallet & Trader Profile ». Il dit à
   un moteur, et à qui arrive d'une recherche, ce qu'est cette page. Il est
   dans le titre pour compter comme tel, et assez discret pour que le NOM
   reste ce qu'on lit. Masqué sous 560 px : sur un téléphone il prendrait deux
   lignes au-dessus du chiffre qui compte. */
/* Les trois phrases qualifiees — adresse, PnL, rang. Meme registre : elles
   expliquent ce que les chiffres au-dessus signifient, elles ne les repetent
   pas pour le plaisir. `62ch` parce qu au-dela une ligne se relit mal. */
.kx-walletline, .kx-pnlline {
  margin: 10px 0 0; font-size: .74rem; line-height: 1.6;
  color: var(--kx-ink-3); max-width: 62ch;
}
.kx-walletline strong, .kx-pnlline strong { color: var(--kx-ink); font-weight: 600; }

/* La phrase du rang, sous le bloc d identite. Discrete — elle explique, elle
   ne crie pas — et elle respire au-dessus des cartes qui suivent. */
.kx-rankline {
  margin: 14px 0 0; font-size: .78rem; line-height: 1.6; color: var(--kx-ink-3);
  max-width: 62ch;
}
.kx-rankline strong { color: var(--kx-ink); font-weight: 600; }
.kx-rankline a { color: var(--kx-accent); }
/* 29/09 — les deux phrases (fenêtres, rang) vivent dans la carte About. */
.kx-about-lignes { margin: 0 0 14px; }
.kx-about-lignes > p:first-child { margin-top: 0; }

.kx-idqual { font-size: .78rem; font-weight: 500; color: var(--kx-ink-3); letter-spacing: 0; }
/* Page token (29/09) : le nom du token et l'objet de la page font partie du
   `<h1>`, sur leur propre ligne pâle — là où le nom était déjà affiché. */
/* Sélecteur à deux classes : il doit l'emporter sur `.kx-idqual { display:none }`
   sous 560 px (règle de la fiche KOL, plus bas) — ici la ligne porte le NOM du
   token, qui a toujours été visible. */
.kx-idname .kx-tok-qual { display: block; font-size: .74rem; margin-top: 2px; }
@media (max-width: 560px) { .kx-idqual { display: none; } }
.kx-idsub { display: block; font-size: .74rem; color: var(--kx-ink-3); margin-top: 2px; }
.kx-idsub a { color: var(--kx-accent-2); }

/* La réglette de chiffres. `auto-fit` plutôt qu'un nombre fixe de colonnes :
   à 412 px elle tient sur trois, dans un rail de 340 px sur deux, et sur une
   pleine largeur sur six — sans qu'aucun de ces cas soit écrit à la main. */
/* ── UN FILET, ET UN SEUL ENDROIT QUI LE MÉRITE ────────────────────────────
 *
 * La maquette sépare des groupes de données par de fins traits horizontaux.
 * L application en emploie déjà : en-têtes de cartes, lignes de listes,
 * pied de la carte de partage — quinze règles au total.
 *
 * Les ajouter partout serait un CINQUIÈME moyen de grouper, après les
 * cartes pleines, les cartes plates, les bordures de lignes et les
 * pastilles. Quatre suffisent ; au-delà, le lecteur ne sait plus lequel
 * porte du sens.
 *
 * Cette grille-ci les mérite : cinq statistiques posées côte à côte, sans
 * rien entre elles, où « 1,0 h · médiane » et « il y a 15 j · dernier trade »
 * se touchent et se lisent comme une phrase. Un filet horizontal au-dessus de
 * chaque ligne de la grille les range sans les encadrer.
 *
 * `gap` de ligne porté à 0 et remplacé par du `padding` : sinon le filet
 * flotterait au milieu du vide au lieu de border la ligne suivante. */
.kx-idgrid {
  display: grid; gap: 0 12px; margin-top: 18px;
  grid-template-columns: repeat(auto-fit, minmax(84px, 1fr));
}
.kx-idgrid > span { padding: 12px 0 0; border-top: 1px solid var(--kx-line-2); }
/* Les premières de chaque ligne n ont pas de filet au-dessus : la grille
   commence sous la réglette, qui en tient déjà lieu. Impossible de savoir
   lesquelles sans JavaScript — on accepte donc le filet partout, y compris
   en haut, où il sépare la grille de ce qui la précède. */
.kx-idgrid > span { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.kx-idgrid b, .kx-idgrid .kx-num {
  font: 700 1rem/1.1 var(--kx-num); color: var(--kx-ink);
}
/* ── LE RÉSULTAT GARDE SA COULEUR ────────────────────────────────────────────
 *
 * La règle ci-dessus a une spécificité de 0-2-0 et bat `.up`/`.down`, qui
 * n en ont que 0-1-0 : le latent de la grille sortait en encre neutre alors
 * que `kxNum()` lui avait bien posé sa classe. Un PnL décoloré au milieu de
 * quatre chiffres neutres se lit comme une mesure de plus, pas comme un gain
 * ou une perte.
 *
 * Même correction que `.kx-tok-stats` a déjà demandée. Partout où une grille
 * impose sa couleur, il faut lui reprendre celle du résultat. */
.kx-idgrid .kx-num.up   { color: var(--kx-up); }
.kx-idgrid .kx-num.down { color: var(--kx-down); }
.kx-idgrid .kx-num.vide { color: var(--kx-faint); }
/* L'étiquette SOUS la valeur, en capitales discrètes — comme « WIN RATE » sur
   la maquette. */
.kx-idgrid > span > small,
.kx-idgrid > span { font-size: .6rem; }
.kx-idgrid > span { color: var(--kx-muted); text-transform: uppercase; letter-spacing: .07em; }

/* ── Le meilleur trade, semaine par semaine ───────────────────────────────────
 * Quatre colonnes de front dès qu'il y a la place, deux sur téléphone. Les
 * comparer suppose de les voir ensemble : empilées, elles se lisent l'une après
 * l'autre et la régularité ne se voit plus. */
.kx-weeks { display: grid; gap: 10px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 720px) { .kx-weeks { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.kx-week {
  padding: 12px; border-radius: var(--kx-r-cell);
  border: 1px solid var(--kx-line); background: rgba(255, 255, 255, .03);
  min-width: 0;
}
/* Une semaine sans gain reste une carte, en retrait : elle dit quelque chose. */
.kx-week.vide { background: transparent; border-style: dashed; }

/* La ligne du haut de la carte : rang à gauche, partage à droite. */
.kx-idtop {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin-bottom: 10px;
}
.kx-idtop .kx-idrank { margin: 0; }

/* Le SECOND grand chiffre — le réalisé, sous le panier. Nettement plus petit que
   le premier : deux chiffres de même taille se disputeraient le regard, et c'est
   le panier qui classe. */
.kx-idsecond {
  font: 800 26px/1 var(--kx-num); letter-spacing: -.02em; margin: 14px 0 0;
}
.kx-idsecond.up   { color: var(--kx-up); }
.kx-idsecond.down { color: var(--kx-down); }

/* ── Les repères sur un graphique ─────────────────────────────────────────────
 *
 * Posés en HTML par-dessus le SVG, et non dedans : le tracé est en
 * `preserveAspectRatio="none"`, donc étiré horizontalement — une image ronde y
 * deviendrait un ovale. En HTML, l'avatar garde sa forme quelle que soit la
 * largeur de l'écran.
 */
.kx-chart { position: relative; }

.kx-mark {
  position: absolute; transform: translate(-50%, -50%);
  z-index: 2; line-height: 0;
  border-radius: 50%;
  box-shadow: 0 0 0 2px var(--kx-panel), 0 2px 8px rgba(0, 0, 0, .55);
  transition: transform .15s ease;
}
.kx-mark:hover { transform: translate(-50%, -50%) scale(1.25); z-index: 3; }
/* Encore en position : l'anneau reprend le cyan de la marque. Sorti : discret. */
.kx-mark.in { box-shadow: 0 0 0 2px var(--kx-accent-2), 0 2px 10px rgba(25, 212, 255, .5); }
/* Hors échelle : épinglé au bord, et il faut que ça se voie. */
.kx-mark.off { opacity: .55; box-shadow: 0 0 0 2px var(--kx-gold), 0 2px 8px rgba(0, 0, 0, .55); }
.kx-mark .av { width: 24px; height: 24px; }
.kx-mark .av::before { font-size: .58rem; }

/* Un repère qui porte un logo de token plutôt qu'un visage : carré arrondi, pas
   rond — ce n'est pas quelqu'un. */
.kx-mark .tl { width: 24px; height: 24px; border-radius: 8px; }
.kx-mark:has(.tl) { border-radius: 8px; }

/* ── « Trading style » : le tableau des paliers de détention ──────────────────
 *
 * Quatre colonnes — palier, part, taux, PnL moyen — alignées en grille et non
 * en `<table>` : la barre de part doit pouvoir occuper toute sa cellule, et une
 * cellule de tableau lui imposerait sa largeur de contenu.
 */
.kx-style { display: grid; gap: 2px; }

.kx-style-h, .kx-style-r {
  display: grid;
  grid-template-columns: 68px minmax(0, 1fr) 46px 74px;
  align-items: center; gap: 10px;
}
.kx-style-h {
  font: 600 .58rem/1 var(--kx-font); letter-spacing: .09em; text-transform: uppercase;
  color: var(--kx-muted); padding: 0 0 8px;
}
.kx-style-h > span:nth-child(3), .kx-style-h > span:nth-child(4),
.kx-style-r > .kx-style-win, .kx-style-r > .kx-style-pnl { text-align: right; }

.kx-style-r { padding: 7px 0; border-top: 1px solid var(--kx-line); }
.kx-style-lab { font-size: .72rem; color: var(--kx-ink-2); white-space: nowrap; }

/* La barre et son pourcentage partagent la cellule : le nombre reste lisible
   même quand la barre est très courte. */
.kx-style-bar { display: flex; align-items: center; gap: 8px; min-width: 0; }
/* ⚠ `flex: 0 0 auto` et non `1 1 auto` : avec `flex-grow: 1` la barre remplit
   toute la cellule quelle que soit la `width` posée en ligne — six paliers de
   50 %, 13 % et 5 % rendaient six barres IDENTIQUES. La largeur est la donnée,
   c est elle qui doit décider. */
.kx-style-bar i {
  flex: 0 0 auto; height: 7px; min-width: 2px; max-width: 100%;
  border-radius: var(--kx-r-pill);
  background: linear-gradient(90deg, var(--kx-accent), var(--kx-accent-2));
}
/* La piste derrière la barre, pour que 5 % se lise comme 5 % d une largeur et
   non comme un trait perdu au milieu du vide. */
.kx-style-bar { background: none; }
.kx-style-bar > span.piste {
  flex: 1 1 auto; min-width: 0; height: 7px;
  border-radius: var(--kx-r-pill); background: rgba(255,255,255,.07);
  display: flex; overflow: hidden;
}
.kx-style-bar b {
  flex: 0 0 auto; font: 700 .68rem/1 var(--kx-num); color: var(--kx-ink-3);
}
.kx-style-win { font: 700 .74rem/1 var(--kx-num); color: var(--kx-ink-3); }
.kx-style-win.up   { color: var(--kx-up-soft); }
.kx-style-win.down { color: var(--kx-down-soft); }
.kx-style-pnl { font: 700 .74rem/1 var(--kx-num); }

/* À 412 px, la colonne du palier se resserre plutôt que de pousser le reste. */
@media (max-width: 460px) {
  .kx-style-h, .kx-style-r { grid-template-columns: 52px minmax(0, 1fr) 38px 60px; gap: 7px; }
  .kx-style-lab { font-size: .64rem; }
}

/* Le coche « compte revendiqué », à côté du nom. Bleu du site public
   (`.profile-verified-icon` de `style.css` : #3b82f6), pas le vert du résultat —
   ce n'est pas une performance. */
.kx-verif { color: #3b82f6; font-size: .62em; vertical-align: .18em; margin-left: .22em; }

/* ── La carte à bulles ────────────────────────────────────────────────────────
 *
 * L'aire de chaque bulle suit la mise engagée ; la couleur suit le résultat.
 * Voir le commentaire en tête du bloc dans `member/token.php` pour l'échelle et
 * pour ce qui n'est PAS encodé.
 *
 * `align-items: flex-end` : les bulles s'alignent par le BAS, comme sur la carte
 * du site public. Alignées par le haut, une petite bulle flotterait au milieu
 * d'un vide et se lirait comme un écart de valeur.
 */
.kx-bubbles {
  display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: center;
  gap: 18px 14px; padding: 10px 0 4px;
}

.kx-bubble {
  display: flex; flex-direction: column; align-items: center;
  text-decoration: none; color: inherit; max-width: 96px;
  transition: transform .2s ease;
}
.kx-bubble:hover { transform: translateY(-3px); }

.kx-bubble-d {
  display: grid; place-items: center; border-radius: 50%; overflow: hidden;
  border: 2px solid var(--kx-line-2);
  background: var(--kx-raised);
  box-shadow: 0 6px 20px rgba(0, 0, 0, .45);
  transition: border-color .2s ease, box-shadow .2s ease;
}
/* L'avatar remplit la bulle : c'est la bulle qui porte la taille, pas lui. */
.kx-bubble-d .av { width: 100%; height: 100%; border-radius: 50%; }
.kx-bubble-d .av::before { font-size: .7rem; }

.kx-bubble.gain  .kx-bubble-d { border-color: rgba(25, 255, 115, .5); }
.kx-bubble.perte .kx-bubble-d { border-color: rgba(255, 128, 128, .5); }
.kx-bubble.gain:hover  .kx-bubble-d { box-shadow: 0 10px 26px rgba(25, 255, 115, .28); }
.kx-bubble.perte:hover .kx-bubble-d { box-shadow: 0 10px 26px rgba(255, 128, 128, .28); }
/* Encore en position : un second anneau, cyan, comme les repères du graphique. */
.kx-bubble.ouvert .kx-bubble-d { box-shadow: 0 0 0 3px rgba(25, 212, 255, .35), 0 6px 20px rgba(0, 0, 0, .45); }

.kx-bubble-v { margin-top: 8px; font: 700 .72rem/1 var(--kx-num); }
.kx-bubble-n {
  margin-top: 3px; font-size: .62rem; color: var(--kx-muted);
  max-width: 96px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

@media (max-width: 460px) { .kx-bubbles { gap: 14px 10px; } }

/* ── L'anneau « encore dedans » ────────────────────────────────────────────────
 *
 * Le même bleu que l'accent de l'interface, autour de l'avatar d'un wallet qui
 * détient toujours. La pastille « Holding 74% » le dit aussi, mais à l'autre
 * bout de la ligne : sur vingt-cinq wallets, on veut le voir sans lire.
 *
 * `inline-flex` et `line-height: 0` : sans eux, l'enveloppe prend la hauteur
 * d'une ligne de texte et l'anneau se décale vers le haut de l'avatar.
 */
.kx-hold { display: inline-flex; line-height: 0; border-radius: 50%; flex: 0 0 auto; }
.kx-hold.on {
  box-shadow: 0 0 0 2px var(--kx-accent-2), 0 0 10px rgba(25, 212, 255, .45);
}
/* Sur la carte à bulles, le même anneau, à l'échelle de la bulle. */
.kx-bubble.ouvert .kx-bubble-d {
  box-shadow: 0 0 0 3px var(--kx-accent-2), 0 0 16px rgba(25, 212, 255, .5), 0 6px 20px rgba(0, 0, 0, .45);
}

/* ── La pagination unique (`kxPager()`) ──────────────────────────────────────
   Trois rangées : les deux gros boutons, les numéros, puis la position. Les
   numéros disparaissent sous 560 px — c'est la seule des trois qui déborde à
   412 px, et la seule dont on peut se passer au doigt. */
.kx-pg { margin: 2px 0 4px; }
.kx-pg-row { display: flex; gap: 10px; }
.kx-pg-b {
  flex: 1; display: flex; align-items: center; justify-content: center;
  min-height: 48px; padding: 0 14px;
  font: 600 .78rem/1 var(--kx-font); color: var(--kx-ink-1);
  background: rgba(255, 255, 255, .05);
  border: 1px solid var(--kx-line-2); border-radius: 14px;
  text-decoration: none; transition: background .15s, border-color .15s;
}
.kx-pg-b:hover { background: rgba(255, 255, 255, .09); border-color: rgba(255, 255, 255, .22); }
.kx-pg-b.off { opacity: .32; cursor: default; pointer-events: none; }

.kx-pg-nums { display: none; }
@media (min-width: 560px) {
  .kx-pg-nums {
    display: flex; align-items: center; justify-content: center;
    gap: 6px; flex-wrap: wrap; margin-top: 10px;
  }
}
.kx-pg-n {
  min-width: 38px; height: 38px; padding: 0 9px;
  display: inline-flex; align-items: center; justify-content: center;
  font: 600 .75rem/1 var(--kx-num); color: var(--kx-ink-2);
  background: rgba(255, 255, 255, .04);
  border: 1px solid var(--kx-line-2); border-radius: 11px;
  text-decoration: none; transition: background .15s, color .15s, border-color .15s;
}
.kx-pg-n:hover { background: rgba(255, 255, 255, .1); color: var(--kx-ink-1); }
.kx-pg-n.on {
  color: #06122c; border-color: transparent;
  background: var(--kx-brand); box-shadow: 0 3px 12px rgba(75, 115, 255, .35);
}
.kx-pg-gap { color: var(--kx-ink-3); font-size: .75rem; padding: 0 2px; user-select: none; }

.kx-pg-foot {
  display: flex; align-items: center; gap: 10px; margin-top: 10px;
  font-size: .7rem; white-space: nowrap;
}
.kx-pg-foot .kx-bar { flex: 1; }

/* ── Le réalisé sur trois fenêtres, sous le grand chiffre ────────────────────
   Trois cibles de 44 px de haut, la fenêtre courante marquée. Elles changent la
   fenêtre de TOUTE la page : le liseré teal est celui de la navigation active,
   pas une couleur de résultat — il dit « vous êtes ici », pas « c'est bon ». */
.kx-pnlwin {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 6px; margin: 14px 0 0;
}
.kx-pnlwin-c {
  display: flex; flex-direction: column; justify-content: center; gap: 3px;
  min-height: 52px; padding: 8px 6px;
  background: rgba(255, 255, 255, .04);
  border: 1px solid var(--kx-line-2); border-radius: 13px;
  text-decoration: none; text-align: center;
  transition: background .15s, border-color .15s;
}
.kx-pnlwin-c:hover { background: rgba(255, 255, 255, .08); }
.kx-pnlwin-c.on {
  background: rgba(0, 229, 208, .08);
  border-color: rgba(0, 229, 208, .38);
}
.kx-pnlwin-k {
  font: 700 .58rem/1 var(--kx-font); letter-spacing: .1em;
  text-transform: uppercase; color: var(--kx-ink-3);
}
.kx-pnlwin-c.on .kx-pnlwin-k { color: var(--kx-nav-on); }
.kx-pnlwin-c .kx-num { font-size: .84rem; font-weight: 700; }

/* Un chiffre qui n'existe pas : même place, même chasse, mais visiblement
   absent. `kxNum(null)` pose cette classe partout dans l'application. */
.kx-num.vide { color: var(--kx-faint); font-weight: 400; }

/* L'état « un filtrage est en cours » est décrit en UN seul endroit, tout en
   bas de ce fichier, avec la pastille qui l'accompagne. Il vivait ici ET
   là-bas, à deux opacités différentes ; c'est la plus spécifique qui gagnait,
   et ce n'était pas celle qu'on relisait. */

/* ═══ TROIS FAÇONS DE DONNER DE LA COULEUR SANS EN INVENTER ══════════════════
 *
 * Constat mesuré sur la page KOL à 1 440 px : **12 cartes, UN seul fond**
 * (`#131a2a`). Les textes vont bien — 6,79:1 pour le ton dominant, 15,17:1 pour
 * le plus clair — le problème n'était pas le contraste mais la MONOTONIE : la
 * fiche d'identité, la courbe et « About » avaient exactement le même poids.
 *
 * La contrainte du projet tient : la couleur dit un RÉSULTAT, jamais autre
 * chose. Les trois règles ci-dessous s'y plient — deux hiérarchisent avec de la
 * matière (fond, bordure, ombre) et non avec une teinte ; la troisième colore,
 * mais à partir du chiffre lui-même.
 */

/* ── 1. Deux rangs de cartes, au lieu d'un ───────────────────────────────────
   Les cartes de CONTEXTE — celles qu'on lit une fois, dans le rail — perdent
   leur panneau plein et leur ombre. Les cartes de DONNÉES gardent les leurs.
   L'œil trouve où sont les chiffres sans lire les titres. Aucune teinte
   ajoutée : c'est une différence de matière, pas de couleur. */
.kx-card.kx-soft {
  background: rgba(255, 255, 255, .028);
  border-color: rgba(255, 255, 255, .06);
  box-shadow: none;
}
.kx-card.kx-soft .kx-card-h { border-bottom-color: rgba(255, 255, 255, .06); }

/* ── 2. La fiche d'identité porte la couleur de son résultat ─────────────────
   Un lavis à 7 % en haut, éteint à mi-hauteur, par-dessus les halos de marque
   existants. Vert si le réalisé est positif, rouge sinon, RIEN s'il n'y a pas
   de résultat mesuré — un fond neutre est la seule réponse honnête à « on ne
   sait pas ». La teinte descend du même nombre que le grand chiffre et par la
   même règle d'arrondi : elle ne peut pas le contredire.

   7 % et pas davantage : au-delà, le fond se met à concurrencer les pastilles
   et les chiffres colorés qu'il porte, et on ne sait plus quelle couleur
   répond à quelle question. */
.kx-hero.gagne {
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(25, 255, 115, .07), transparent 58%),
    radial-gradient(90% 130% at 0% 0%, rgba(75, 115, 255, .18), transparent 62%),
    radial-gradient(80% 120% at 100% 0%, rgba(25, 212, 255, .12), transparent 60%),
    var(--kx-hero);
  border-color: rgba(25, 255, 115, .2);
}
.kx-hero.perd {
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(255, 128, 128, .08), transparent 58%),
    radial-gradient(90% 130% at 0% 0%, rgba(75, 115, 255, .18), transparent 62%),
    radial-gradient(80% 120% at 100% 0%, rgba(25, 212, 255, .12), transparent 60%),
    var(--kx-hero);
  border-color: rgba(255, 128, 128, .2);
}

/* ── 3. Meilleur et pire trade cessent d'être deux dalles identiques ─────────
   Elles ne différaient que par la couleur de leur chiffre — à deux mètres, ou
   du coin de l'œil, c'était la même carte deux fois. Le liseré haut et le halo
   les séparent avant qu'on ait lu quoi que ce soit. La couleur est ici encore
   celle du résultat, et ces deux cartes n'existent QUE lorsque leur signe est
   certain : `kolCycle()` met le meilleur à NULL sur un cycle entièrement
   perdant, et le pire à NULL sur un cycle entièrement gagnant. */
.kx-tcard { position: relative; }
.kx-tcard::before { content: ''; position: absolute; inset: 0 0 auto 0; height: 3px; }
.kx-tcard.gagne::before { background: linear-gradient(90deg, #19ff73, rgba(25, 255, 115, 0)); }
.kx-tcard.perd::before  { background: linear-gradient(90deg, #ff8080, rgba(255, 128, 128, 0)); }
.kx-tcard.gagne {
  border-color: rgba(25, 255, 115, .22);
  box-shadow: var(--kx-sh-panel), inset 0 22px 44px -32px rgba(25, 255, 115, .55);
}
.kx-tcard.perd {
  border-color: rgba(255, 128, 128, .22);
  box-shadow: var(--kx-sh-panel), inset 0 22px 44px -32px rgba(255, 128, 128, .55);
}

/* ── « Qui monte cette semaine » ─────────────────────────────────────────────
   Trois cartes égales : contrairement à un podium, il n'y a pas de premier à
   surélever — une progression de 72 places et une de 16 sont deux faits, pas
   deux marches. */
.kx-mv-grid {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 10px; margin-top: 14px;
}
@media (max-width: 560px) { .kx-mv-grid { grid-template-columns: 1fr; } }
.kx-mv {
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  padding: 16px 10px; text-align: center; color: var(--kx-ink);
  border: 1px solid var(--kx-line-2); border-radius: 20px;
  background: radial-gradient(circle at 50% 0%, rgba(25, 255, 115, .1), transparent 62%),
              rgba(255, 255, 255, .04);
  text-decoration: none; transition: border-color .15s, background .15s;
}
.kx-mv:hover { border-color: rgba(25, 255, 115, .4); }
.kx-mv-n { font-size: .8rem; font-weight: 600; }
.kx-mv-d { font: 700 1.15rem/1 var(--kx-num); color: var(--kx-up); }
.kx-mv-r { font-size: .62rem; color: var(--kx-muted); }

/* ── La barre de comparaison ─────────────────────────────────────────────────
   Au-dessus du dock mobile, jamais dessous : une barre qui recouvre la
   navigation piège l'utilisateur dans l'écran où il vient de cocher. */
.kx-cmpbar {
  position: fixed; z-index: 60; left: 50%; transform: translateX(-50%);
  bottom: calc(66px + env(safe-area-inset-bottom, 0px) + 12px);
  display: flex; align-items: center; gap: 10px;
  width: max-content; max-width: min(94vw, 620px); padding: 10px 12px;
  background: rgba(13, 21, 40, .97);
  border: 1px solid var(--kx-line-2); border-radius: 16px;
  box-shadow: 0 10px 34px rgba(0, 0, 0, .55);
  font-size: .74rem;
  animation: kxbar .2s ease-out;
}
@keyframes kxbar {
  from { opacity: 0; transform: translateX(-50%) translateY(14px); }
  to   { opacity: 1; transform: translateX(-50%); }
}
@media (min-width: 1000px) { .kx-cmpbar { bottom: 20px; } }
.kx-cmpbar-a {
  flex: 0 1 auto; min-width: 3.2rem; font-weight: 600; color: var(--kx-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kx-cmpbar-v { flex: 0 0 auto; color: var(--kx-ink-3); }
.kx-cmpbar-go { flex: 0 0 auto; min-height: 38px; padding: 0 14px; display: inline-flex; align-items: center; }
.kx-cmpbar-x {
  flex: 0 0 auto; width: 32px; height: 32px; border-radius: 10px;
  background: transparent; border: 1px solid var(--kx-line-2);
  color: var(--kx-ink-3); font-size: 1rem; cursor: pointer;
}
.kx-cmpbar-x:hover { color: var(--kx-ink); border-color: rgba(255, 255, 255, .25); }

/* ═══ LA CARTE DE PARTAGE ════════════════════════════════════════════════════
 *
 * Le gabarit de la maquette, au pixel : liseré Solana, bandeau de marque,
 * titre, grand nombre en dégradé, sous-titre, trois lignes, pied signé.
 *
 * **Format 4:5.** C'est la proportion qu'Instagram et X affichent en entier
 * dans un fil ; un carré perd de la hauteur utile et un 16:9 se fait rogner.
 *
 * Tout est en unités ABSOLUES, pas en `rem`. La carte est capturée en image :
 * elle doit sortir identique quel que soit le réglage de taille de police du
 * navigateur, sinon deux utilisateurs partagent deux cartes différentes.
 */
/* `display:flex` bat le `display:none` que le navigateur donne à `[hidden]` :
   sans la règle ci-dessous, fermer la carte vidait son contenu et laissait la
   surcouche et ses quatre boutons à l écran. Mesuré `hidden=true`, visible à
   la capture — le genre d écart qu une assertion seule ne voit pas. */
.kx-shareback {
  position: fixed; inset: 0; z-index: 90;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 18px; padding: 22px; overflow-y: auto;
  background: rgba(2, 6, 23, .78);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
}
.kx-sharebox { width: 100%; max-width: 380px; display: flex; flex-direction: column; gap: 18px; }

.kx-sc {
  width: 100%; aspect-ratio: 4 / 5;
  display: flex; flex-direction: column; overflow: hidden;
  border: 1px solid rgba(255, 255, 255, .16); border-radius: 26px;
  background:
    radial-gradient(120% 90% at 0% 0%, rgba(25, 212, 255, .24), transparent 55%),
    radial-gradient(110% 100% at 100% 100%, rgba(153, 69, 255, .24), transparent 55%),
    #070f2b;
  box-shadow: 0 40px 90px rgba(0, 0, 0, .75);
  animation: kolpop .22s ease-out;
}
/* Les trois couleurs de Solana, dans leur ordre officiel. */
.kx-sc-sol { display: block; height: 5px; width: 100%; background: linear-gradient(to right, #14F195, #03E1FF 50%, #9945FF); }
.kx-sc-in {
  flex: 1; min-height: 0; padding: 24px;
  display: flex; flex-direction: column; justify-content: space-between; gap: 14px;
}
.kx-sc-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.kx-sc-eyebrow {
  font: 700 10px/1.2 var(--kx-font); letter-spacing: .18em;
  text-transform: uppercase; color: #9fb6d8;
}
.kx-sc-brand { display: flex; align-items: center; gap: 7px; font: 600 11px/1 var(--kx-font); color: #fff; }
.kx-sc-k1 {
  width: 22px; height: 22px; border-radius: 50%; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  font: 700 10px/1 var(--kx-font); color: #07101d;
  background: linear-gradient(135deg, #4b73ff, #19d4ff);
}
.kx-sc-mid { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.kx-sc-title { font: 600 15px/1.35 var(--kx-font); color: #cfe0f7; }
/* Le grand nombre en dégradé — le seul endroit du produit où un CHIFFRE est
   peint : sur une carte qui circule, il est le sujet, pas une mesure à
   comparer. Ailleurs, un chiffre coloré veut dire gain ou perte, et cette
   règle ne bouge pas. */
.kx-sc-num {
  font: 700 clamp(38px, 13vw, 52px)/.9 var(--kx-num); letter-spacing: -.03em;
  background: linear-gradient(120deg, #fff, #9be6ff 55%, #f5c76a);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  overflow-wrap: anywhere;
}
/* Quand la valeur a un SENS — un gain, une perte — la couleur passe devant la
   signature. `-webkit-text-fill-color` est obligatoire : sans lui, le
   `background-clip: text` de la règle du dessus continue de vider le texte et
   `color` ne se voit pas. Le fond est remis à plat au passage, sinon le dégradé
   reste peint derrière le glyphe. */
.kx-sc-num.up, .kx-sc-num.down, .kx-sc-num.gold {
  background: none; -webkit-background-clip: border-box; background-clip: border-box;
}
.kx-sc-num.up   { color: var(--kx-up);      -webkit-text-fill-color: var(--kx-up); }
.kx-sc-num.down { color: var(--kx-down);    -webkit-text-fill-color: var(--kx-down); }
.kx-sc-num.gold { color: var(--kx-gold-tx); -webkit-text-fill-color: var(--kx-gold-tx); }
.kx-sc-logo { width: 22px; height: 22px; border-radius: 50%; flex: 0 0 auto; display: block; }

/* ── LA CARTE PENDANT QU'ELLE SE FABRIQUE ─────────────────────────────────────
 *
 * Le clic sur « Share » ouvrait une boîte VIDE, et elle le restait le temps de
 * l'aller-retour vers `share.php` — qui fait de vraies requêtes. Sur la carte
 * d'un trade, c'est un trou noir de plusieurs centaines de millisecondes après
 * un clic : on croit que ça n'a pas marché, et on reclique.
 *
 * Le squelette a la FORME de la carte à venir — même proportion 4:5, même
 * liseré Solana, mêmes zones aux mêmes places. Ce qui arrive ensuite ne
 * déplace donc rien : le nombre se pose là où la barre claire l'annonçait.
 *
 * Il réutilise `kxskel`, l'animation des autres squelettes du produit. Aucune
 * couleur de marque : ce n'est pas du contenu, ça ne doit pas se lire comme
 * tel. */
.kx-sc-skel {
  width: 100%; max-width: 380px; aspect-ratio: 4 / 5; margin: 0 auto;
  border-radius: 18px; overflow: hidden; background: #131a2a;
  border: 1px solid rgba(255, 255, 255, .07);
  display: flex; flex-direction: column;
}
.kx-sc-skel > .kx-sc-sol { flex: 0 0 auto; }
.kx-sc-skel-in {
  flex: 1 1 auto; display: flex; flex-direction: column; gap: 18px; padding: 22px;
}
.kx-sc-skel b, .kx-sc-skel i, .kx-sc-skel u {
  display: block; border-radius: 6px; background: rgba(255, 255, 255, .07);
  animation: kxskel 1.6s ease-in-out infinite;
}
.kx-sc-skel b { height: 22px; width: 46%; }
.kx-sc-skel .kx-sc-skel-faces { display: flex; gap: 6px; }
.kx-sc-skel .kx-sc-skel-faces u { width: 40px; height: 40px; border-radius: 50%; }
.kx-sc-skel i.t { height: 13px; width: 72%; }
.kx-sc-skel i.n { height: 44px; width: 64%; border-radius: 10px; background: rgba(255, 255, 255, .1); }
.kx-sc-skel i.s { height: 11px; width: 52%; }
.kx-sc-skel-rows { margin-top: auto; display: flex; flex-direction: column; gap: 11px; }
.kx-sc-skel-rows i { height: 10px; }
.kx-sc-skel-rows i:nth-child(1) { width: 88%; }
.kx-sc-skel-rows i:nth-child(2) { width: 76%; }
.kx-sc-skel-rows i:nth-child(3) { width: 82%; }
.kx-sc-load {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  margin-top: 12px; font: 500 12px/1 var(--kx-font); color: rgba(190, 210, 240, .6);
}
.kx-sc-load::before {
  content: ''; width: 12px; height: 12px; border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .18); border-top-color: rgba(255, 255, 255, .6);
  animation: kxspin .8s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  .kx-sc-skel b, .kx-sc-skel i, .kx-sc-skel u, .kx-sc-load::before { animation: none; }
}
.kx-sc-sub { font: 600 13px/1.4 var(--kx-font); color: #9be6ff; }
.kx-sc-sub.up { color: var(--kx-up); } .kx-sc-sub.down { color: var(--kx-down); }
.kx-sc-sub.gold { color: var(--kx-gold-tx); } .kx-sc-sub.accent { color: #9be6ff; }

.kx-sc-rows { display: flex; flex-direction: column; gap: 9px; }
.kx-sc-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 11px 14px; border-radius: 14px;
  background: rgba(255, 255, 255, .06); border: 1px solid rgba(255, 255, 255, .08);
}
.kx-sc-k { font: 400 12px/1.3 var(--kx-font); color: #b6c9e4; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kx-sc-v { font: 700 14px/1 var(--kx-num); color: #fff; flex: 0 0 auto; }
.kx-sc-v.up { color: var(--kx-up); } .kx-sc-v.down { color: var(--kx-down); }
.kx-sc-v.gold { color: var(--kx-gold-tx); } .kx-sc-v.accent { color: #9be6ff; }

.kx-sc-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding-top: 14px; border-top: 1px solid rgba(255, 255, 255, .12);
}
.kx-sc-foot > span:first-child { font: 400 11px/1.4 var(--kx-font); color: #9fb6d8; }
.kx-sc-dom {
  font: 700 10px/1 var(--kx-font); letter-spacing: .16em;
  text-transform: uppercase; color: rgba(255, 255, 255, .5); flex: 0 0 auto;
}

/* Les quatre boutons. Deux lignes, cibles de 50 et 46 px. */
.kx-sharebtns { display: flex; flex-direction: column; gap: 9px; }
.kx-sharebtns > div { display: flex; gap: 9px; }
.kx-sharebtns button, .kx-sharebtns a {
  flex: 1; min-height: 46px; cursor: pointer; border-radius: var(--kx-r-pill);
  display: inline-flex; align-items: center; justify-content: center;
  font: 600 13px/1 var(--kx-font); text-decoration: none;
  border: 1px solid rgba(255, 255, 255, .12); background: transparent; color: var(--kx-muted);
  transition: background .15s, color .15s, opacity .15s;
}
.kx-sharebtns button:hover, .kx-sharebtns a:hover { color: var(--kx-ink); }
.kx-sharebtns .primaire {
  min-height: 50px; border: 0; font-size: 14px;
  background: var(--kx-brand); color: var(--kx-on-brand);
}
.kx-sharebtns .primaire:hover { opacity: .88; color: var(--kx-on-brand); }
.kx-sharebtns .second {
  min-height: 50px; font-size: 14px;
  border-color: rgba(255, 255, 255, .16); background: rgba(255, 255, 255, .06); color: var(--kx-ink);
}
.kx-sharebtns .second:hover { background: rgba(255, 255, 255, .12); }
.kx-share-note { text-align: center; font: 400 11px/1.5 var(--kx-font); color: var(--kx-muted); }

/* Le bouton de partage des lignes : c'est un `<button>` maintenant, plus un
   lien — il ouvre une modale, il ne va nulle part. */
button.kx-share { cursor: pointer; font: inherit; }

/* Un en-tête de carte qui porte un RÉGLAGE et non un sous-titre : les puces
   s'alignent sur le titre plutôt que sur sa ligne de base, et passent sous lui
   quand la carte devient étroite. */
.kx-card-h-reg { align-items: center; flex-wrap: wrap; row-gap: 10px; }
.kx-card-h-reg .kx-chips { margin: 0; flex: 0 0 auto; }

/* ── L'ADN du wallet ─────────────────────────────────────────────────────────
   Quatre cases, deux par ligne comme la maquette. Le rang se pose en haut à
   droite de sa case : il commente la valeur, il ne la remplace pas. */
.kx-dna { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.kx-dna-c {
  position: relative; padding: 12px 14px; border-radius: 14px;
  background: rgba(255, 255, 255, .05); border: 1px solid var(--kx-line-2);
}
.kx-dna-v { display: block; font: 700 1rem/1.2 var(--kx-num); color: var(--kx-ink); }
.kx-dna-k { display: block; font-size: .68rem; color: var(--kx-muted); margin-top: 2px; }
/* Neutre, jamais vert ni rouge : toucher mille tokens n'est ni bien ni mal,
   c'est une manière de faire. Colorer un rang en résultat serait une opinion
   déguisée en mesure. */
.kx-dna-r {
  position: absolute; top: 10px; right: 11px;
  font: 700 .62rem/1 var(--kx-num); letter-spacing: .02em;
  padding: 3px 7px; border-radius: var(--kx-r-pill);
  background: rgba(168, 85, 247, .12); border: 1px solid rgba(168, 85, 247, .4);
  color: rgba(216, 180, 254, .95);
}
.kx-dna-r small { font-weight: 500; opacity: .7; }
/* Le bas du classement se distingue du haut sans porter de jugement. */
.kx-dna-r.bas { background: rgba(255, 255, 255, .06); border-color: var(--kx-line-2); color: var(--kx-ink-3); }

/* Les visages sur la carte de partage. On voit QUI avant de lire COMBIEN — une
   carte sans image est un tableau de chiffres, et elle ne se reconnaît pas dans
   un fil. Tailles absolues : la carte est capturée en image. */
.kx-sc-faces { display: flex; align-items: center; gap: -6px; margin-bottom: 2px; }
.kx-sc-faces > * { flex: 0 0 auto; }
.kx-sc-faces .av, .kx-sc-faces .tl {
  width: 40px; height: 40px; border-radius: 50%;
  box-shadow: 0 0 0 2px #070f2b, 0 3px 10px rgba(0, 0, 0, .5);
}
.kx-sc-faces .av img, .kx-sc-faces .tl img { width: 40px; height: 40px; border-radius: 50%; }
/* Les suivantes chevauchent la précédente : une rangée de quatre visages tient
   alors dans la largeur sans rétrécir chaque visage. */
.kx-sc-faces > * + * { margin-left: -10px; }
.kx-sc-faces .av[data-i]::before { font-size: 14px; }

/* La barre de choix d'un adversaire : chercher, ou ne voir que sa liste. */
.kx-pickbar { display: flex; gap: 8px; align-items: center; margin-bottom: 12px; flex-wrap: wrap; }
.kx-pickq {
  flex: 1 1 160px; min-width: 0; min-height: 40px; padding: 0 12px;
  font: 400 .84rem/1 var(--kx-font); color: var(--kx-ink);
  background: rgba(255, 255, 255, .05);
  border: 1px solid var(--kx-line-2); border-radius: 12px;
}
.kx-pickq::placeholder { color: var(--kx-faint); }
.kx-pickfav { flex: 0 0 auto; min-height: 40px; }
.kx-pickvide { font-size: .82rem; padding: 14px 2px; }

/* ── LE CLAVIER VOIT OÙ IL EST ───────────────────────────────────────────────
 *
 * Les lignes de liste sont des `<a>`, donc atteignables à la tabulation depuis
 * toujours — mais rien ne les marquait au passage : on tabulait à l'aveugle
 * dans vingt-cinq lignes identiques. Le navigateur dessine bien un contour par
 * défaut, que `border-radius` et les fonds sombres rendaient quasi invisible.
 *
 * `:focus-visible` et non `:focus` : la bordure n'apparaît qu'au clavier, jamais
 * après un clic — un contour qui suit la souris se lit comme un bug. */
.kx-row-main:focus-visible,
.kx-res:focus-visible,
.kx-chip:focus-visible,
.kx-pg-b:focus-visible,
.kx-pg-n:focus-visible,
.kx-mv:focus-visible,
.kx-pnlwin-c:focus-visible,
.kx-btn:focus-visible,
.kx-btn-ghost:focus-visible {
  outline: 2px solid var(--kx-accent);
  outline-offset: 2px;
  border-radius: 12px;
}
/* La ligne entière se teinte, pas seulement son contour : sur une liste dense,
   un liseré de 2 px ne suffit pas à dire « je suis ici ». */
.kx-row:has(.kx-row-main:focus-visible) { background: rgba(255, 255, 255, .05); }

/* ── LE RACCOURCI N'EXISTE QUE LÀ OÙ IL EXISTE ───────────────────────────────
 * « / » et « Ctrl K » ne veulent rien dire sur un téléphone : il n'y a pas de
 * clavier pour les taper. Les afficher quand même, c'est occuper la ligne du
 * champ de recherche avec une instruction que le lecteur ne peut pas suivre.
 *
 * Le SEUIL est celui du pointeur, pas celui de la largeur : `pointer: fine`
 * désigne une souris ou un trackpad, donc une machine qui a un clavier —
 * une fenêtre étroite sur un ordinateur portable garde le raccourci, et une
 * tablette large ne l'affiche pas. C'est la question à laquelle il faut
 * répondre, et une requête de largeur y répond de travers. */
.kx-kbd { display: none; }
@media (pointer: fine) {
.kx-kbd {
  display: inline-flex; align-items: center; gap: 2px;
  padding: 2px 6px; margin-left: 6px;
  font: 600 .62rem/1 var(--kx-font); color: var(--kx-faint);
  background: rgba(255, 255, 255, .06);
  border: 1px solid var(--kx-line-2); border-radius: 6px;
}
}

/* La fraîcheur, sous le titre d'un écran : discrète mais toujours au même
   endroit, pour qu'on sache où la chercher sans la chercher. */
.kx-fresh {
  font: 400 .66rem/1.5 var(--kx-font); color: var(--kx-faint);
  margin: 2px 0 14px; cursor: help;
}

/* Le lien vers la chaîne : même gabarit que le partage, mais il SORT du site —
   la flèche oblique le dit avant le clic. */
.kx-chain:hover, .kx-chain:focus-visible { color: var(--kx-accent); border-color: rgba(25, 212, 255, .45); }

/* Le rang devient un bouton : il garde exactement la place et l'allure du
   nombre qu'il remplace, mais il s'annonce cliquable au survol et au clavier.
   Il est SORTI du lien de la ligne — un bouton dans un lien est invalide, et le
   clavier n'atteindrait jamais que le premier des deux. */
.kx-row > .kx-rankbtn {
  flex: 0 0 auto; align-self: center; margin-left: 18px;
  background: transparent; border: 0; padding: 0; cursor: pointer;
  font: inherit; color: inherit;
}
.kx-row > .kx-rankbtn:hover,
.kx-row > .kx-rankbtn:focus-visible { color: var(--kx-accent); }
/* La ligne se réorganise : le rang d'abord, le lien ensuite, les pastilles après. */
.kx-row:has(> .kx-rankbtn) { display: flex; flex-wrap: wrap; align-items: center; }
.kx-row:has(> .kx-rankbtn) > .kx-row-main { flex: 1 1 260px; padding-left: 10px; }
.kx-row:has(> .kx-rankbtn) > .kx-row-tags { flex: 1 1 100%; }

/* « N nouveaux depuis votre dernière ouverture » : un lien, parce qu'il MÈNE au
   fil qu'il annonce. Le point vert est celui des pastilles « live » — même
   signal, même couleur, on ne réinvente pas un vocabulaire par écran. */
.kx-depuis {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 2px 0 14px; padding: 9px 13px;
  font: 400 .74rem/1.4 var(--kx-font); color: var(--kx-ink-2);
  background: rgba(25, 255, 115, .07);
  border: 1px solid rgba(25, 255, 115, .28); border-radius: 14px;
  text-decoration: none; transition: background .15s;
}
.kx-depuis:hover { background: rgba(25, 255, 115, .12); }
.kx-depuis b { font: 700 .86rem/1 var(--kx-num); color: var(--kx-up); }

/* ── LES FILTRES RESTENT ATTEIGNABLES PENDANT QU'ON LIT ──────────────────────
 *
 * Les puces sont en tête de carte. Sur téléphone, dès qu'on descend dans une
 * liste de vingt-cinq lignes elles sont hors écran : changer de tri demande de
 * remonter tout en haut, changer, puis redescendre chercher où l'on en était.
 *
 * La barre de réglages d'une carte se colle donc sous l'en-tête du site pendant
 * qu'on parcourt SA carte, et repart avec elle. Uniquement sur petit écran :
 * au-dessus de 1000 px la liste et ses puces tiennent ensemble à l'œil, et une
 * barre collante y mangerait de la hauteur pour rien.
 *
 * `top: 72px` — le bas réel de l'en-tête mobile, mesuré au navigateur. Le fond est opaque,
 * sans quoi les lignes défileraient visiblement dessous.
 */
/* ── ET POURQUOI ELLE NE L'EST PLUS ──────────────────────────────────────────
 *
 * Ce qui précède valait pour des listes de dix et six lignes. À cinq lignes
 * par page, il n'y a plus rien à parcourir : mesuré à 412 px, le contenu SOUS
 * la barre fait 643 px pour « Current holdings » et 670 px pour « Positions »
 * — moins d'un écran dans les deux cas. Les puces ne sortent jamais du champ,
 * et n'ont donc rien à suivre.
 *
 * Ce qu'elle coûtait, en revanche, était mesurable : la barre des holdings
 * fait 232 px — **26 % d'un écran de 900** — parce qu'elle porte aussi le
 * résumé en deux phrases et la note des positions cachées. Coller au sommet
 * une phrase qu'on vient de lire, pour toute la traversée de la carte, c'est
 * payer un quart de l'écran pour trois puces.
 *
 * Le filet et l'ombre restent : ils séparent les réglages de la liste, et
 * c'était leur vrai travail.
 */
@media (max-width: 999px) {
  .kx-card-body.kx-reglages {
    background: var(--kx-panel);
    border-bottom: 1px solid var(--kx-line);
    box-shadow: 0 6px 12px -8px rgba(0, 0, 0, .8);
  }
  /* ── UN TRI HORS CHAMP EST UN TRI QUI N'EXISTE PAS ─────────────────────────
     Cette rangée défilait horizontalement. Mesuré à 412 px sur « Current
     holdings » : 469 px de puces pour 338 px visibles — « Biggest unrealized »
     était entièrement hors de l'écran, et rien ne disait qu'elle existait. */
  .kx-reglages .kx-chips { flex-wrap: wrap; }
}

/* ── LE REPLI DES RÉGLAGES ───────────────────────────────────────────────────
 *
 * Il AFFICHE son état — « 90d · Featured » — plutôt que de dire « Filtres ».
 * On ne cache pas un réglage, on cache ses options : la différence est qu'on
 * sait où l'on en est sans rien ouvrir.
 */
.kx-reg { margin-bottom: 12px; }
.kx-reg > summary {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 34px; padding: 0 13px; cursor: pointer; list-style: none;
  font: 600 .72rem/1 var(--kx-font); color: var(--kx-ink-2);
  background: rgba(255, 255, 255, .05);
  border: 1px solid var(--kx-line-2); border-radius: var(--kx-r-pill);
  transition: background .15s, color .15s;
}
.kx-reg > summary::-webkit-details-marker { display: none; }
.kx-reg > summary:hover { background: rgba(255, 255, 255, .09); color: var(--kx-ink); }
.kx-reg > summary:focus-visible { outline: 2px solid var(--kx-accent); outline-offset: 2px; }
.kx-reg-fleche { width: 11px; height: 11px; transition: transform .15s; }
.kx-reg[open] > summary .kx-reg-fleche { transform: rotate(180deg); }
.kx-reg-in {
  display: flex; flex-direction: column; gap: 8px;
  margin-top: 10px; padding: 12px 14px;
  background: rgba(255, 255, 255, .03);
  border: 1px solid var(--kx-line-2); border-radius: 16px;
  animation: kolfade .18s ease-out;
}
.kx-reg-in .kx-eyebrow { align-self: center; margin-right: 2px; min-width: 52px; }

/* Le va-et-vient d'une semaine à l'autre, sur la carte d'un grimpeur : deux
   montants et une flèche. C'est lui qui rend le bond lisible plutôt que
   spectaculaire. */
.kx-mv-sw { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; justify-content: center; }
.kx-mv-sw .kx-num { font-size: .74rem; font-weight: 700; }
.kx-mv-d { font: 700 1.05rem/1 var(--kx-num); color: var(--kx-up); }

/* ── LA BARRE D'ONGLETS D'UNE FICHE (`.kx-tabs`, member/kol.php) ─────────────
 *
 * TÉLÉPHONE SEULEMENT, EN TÊTE DE FICHE (décision du 29/09). Remplace la grille
 * de six raccourcis `.kx-jump`.
 *
 * La forme « plat », retenue parmi quatre comparées sur la vraie page : pas de
 * panneau, cinq liens sur un filet, le langage de la barre du site — libellés
 * #d0d0d8 en 500, cyan #00e5d0 sur l'onglet actif, soulignement de 2 px qui
 * s'ouvre depuis le centre (`.kx-nav a::after`). La carte vitrée à ombre de la
 * première version se lisait comme un second en-tête.
 *
 * COLLANTE sous la barre du site (72 px, mesurés). Collée (`.colle`, posé par
 * `kx.js`), elle prend le fond de `.kx-top`, prolongé bord à bord par une ombre
 * pleine rognée à sa hauteur : elle devient la seconde ligne de l'en-tête. */
.kx-tabs { display: none; }
@media (max-width: 999px) {
  /* `--kx-top-h` : la hauteur RÉELLE de la barre du site, mesurée par `kx.js`
     (82 px à 390 de large, 72 ailleurs — une valeur écrite en dur faisait
     passer les onglets SOUS l'en-tête sur iPhone, capture du 29/09). 72 px si
     le script n'a pas tourné. */
  .kx-tabs {
    position: sticky; top: var(--kx-top-h, 72px); z-index: 50;
    display: flex; align-items: stretch; justify-content: space-between; gap: 10px;
    height: 48px; margin: 0 0 16px; padding: 0;
    border-bottom: 1px solid var(--kx-line-2);
    transition: background .2s ease;
  }
  .kx-tabs.colle {
    background: rgba(8, 10, 18, .92);
    box-shadow: 0 0 0 100vmax rgba(8, 10, 18, .92); clip-path: inset(0 -100vmax);
  }
}
/* La rangée défile À L'HORIZONTALE SEULEMENT (capture du 29/09 : en la faisant
   glisser, la page défilait aussi de haut en bas). `touch-action: pan-x` donne
   le geste à la rangée ; `overscroll-behavior-x: contain` empêche la fin de
   course de passer à la page (retour arrière de Safari).
   Les bords s'estompent (masque) : un onglet coupé net se lit comme un bug,
   un onglet qui s'efface se lit comme « il y en a d'autres ». */
.kx-tabs-l {
  display: flex; align-items: stretch; gap: 1.35rem; min-width: 0; flex: 1 1 auto;
  padding: 0 14px 0 2px;
  overflow-x: auto; overflow-y: hidden; scrollbar-width: none;
  touch-action: pan-x; overscroll-behavior-x: contain; -webkit-overflow-scrolling: touch;
  scroll-behavior: smooth;
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 10px, #000 calc(100% - 22px), transparent);
          mask-image: linear-gradient(to right, transparent 0, #000 10px, #000 calc(100% - 22px), transparent);
}
@media (prefers-reduced-motion: reduce) { .kx-tabs-l { scroll-behavior: auto; } }
.kx-tabs-l::-webkit-scrollbar { display: none; }
.kx-tab {
  position: relative; display: flex; align-items: center; flex: 0 0 auto;
  white-space: nowrap; text-decoration: none;
  color: #d0d0d8; font: 500 .88rem/1 var(--kx-font);
  transition: color .3s ease;
}
.kx-tab::after {
  content: ''; position: absolute; bottom: -1px; left: 50%;
  width: 0; height: 2px; background: #00e5d0; border-radius: 1px;
  transition: width .35s ease, left .35s ease;
}
.kx-tab:hover, .kx-tab.on { color: #00e5d0; }
.kx-tab:hover::after, .kx-tab.on::after { width: 100%; left: 0; }
.kx-tab:focus-visible { outline: 2px solid var(--kx-accent); outline-offset: -4px; border-radius: 6px; }
/* Le fil d'Ariane de la fiche porte la pastille « Last on-chain move » (29/09).
   En flex qui passe à la ligne : sur 375 px, ou avec un nom long, la pastille
   se range dessous, alignée à gauche, au lieu de se couper. */
.kx-ariane { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; }
/* L'action, en petit bouton discret : la barre navigue, elle ne crie pas. */
.kx-tabs-cta {
  flex: 0 0 auto; align-self: center;
  min-height: 32px; padding: 0 12px; font-size: .74rem;
  background: rgba(255, 255, 255, .04); color: var(--kx-ink);
  border: 1px solid var(--kx-line-2); box-shadow: none;
}
.kx-tabs-cta:hover { background: rgba(255, 255, 255, .08); box-shadow: none; }
@media (prefers-reduced-motion: reduce) {
  .kx-tab, .kx-tab::after { transition: none; }
}

/* L'en-tête est collant : sans ce creux, sauter à une section la place SOUS lui
   et on croit avoir raté sa cible. */
.kx-card[id], .kx-hero[id], [id="holdings"], [id="positions"], [id="cycle"] { scroll-margin-top: 84px; }
/* Sur téléphone, la barre d'onglets de la fiche s'ajoute : 72 + 50 + un souffle. */
@media (max-width: 999px) {
  [data-kx-view="kol"] .kx-card[id], [data-kx-view="kol"] .kx-hero[id], [data-kx-view="kol"] [id="holdings"], [data-kx-view="kol"] [id="positions"], [data-kx-view="kol"] [id="cycle"] { scroll-margin-top: calc(var(--kx-top-h, 72px) + 72px); }
}

/* ── L'ORDRE MOBILE N'EST PAS L'ORDRE DE BUREAU ──────────────────────────────
 *
 * En une seule colonne, le DOM sort tout le rail AVANT la colonne de droite.
 * `display: contents` fait disparaître les deux conteneurs sans toucher au
 * HTML : leurs cartes deviennent enfants directs de la grille, et `order` peut
 * alors les classer une par une.
 *
 * Les treize cartes sont ordonnées explicitement, et non par quelques valeurs
 * posées sur les premières : une carte ajoutée plus tard tomberait sinon au
 * milieu du peloton sans que personne l'ait décidé. Ici elle tombe à la fin,
 * ce qui est visible et se corrige.
 *
 * SUR PETIT ÉCRAN, LA SÉQUENCE DEMANDÉE EST RENDUE EXACTEMENT. Sur grand
 * écran elle ne peut pas l'être : le rail fait 380 px et la colonne large
 * 724 px, et une carte ne se déplace pas de l'un à l'autre sans changer de
 * forme. Les deux colonnes portent donc chacune une sous-suite CROISSANTE de
 * cette séquence — le meilleur repli possible d'un ordre linéaire sur deux
 * colonnes.
 */
/* ── CE BLOC EST RÉSERVÉ À LA FICHE D'UN TRADER ──────────────────────────────
 *
 * TROUVÉ EN PRODUCTION, ET C'ÉTAIT MA FAUTE. Ces règles n'étaient pas
 * délimitées. `.kx-split` sert aussi à la page token, qui a elle aussi un
 * `.kx-col-a > .kx-hero` : il recevait `order: 1` pendant que toutes ses autres
 * cartes gardaient `order: 0`. Le hero d'un token passait donc **derrière
 * l'intégralité de la page**.
 *
 * Une règle d'ordre ne vaut que pour la suite qu'elle décrit. `[data-kx-view]`
 * porte déjà le nom de l'écran sur `<main>` : elle s'y accroche.
 */
[data-kx-view="kol"] .kx-split { display: grid; }
@media (max-width: 999px) {
  [data-kx-view="kol"] .kx-split { display: flex; flex-direction: column; }
  [data-kx-view="kol"] .kx-col-a,
  [data-kx-view="kol"] .kx-col-b { display: contents; }

  [data-kx-view="kol"] .kx-col-a > .kx-hero { order: 1; }  /* Hero KOL          */
  [data-kx-view="kol"] .kx-tabs             { order: 0; }  /* les onglets, EN TÊTE : sous la carte d identité (1 147 px sur téléphone) il fallait un écran de défilement pour les atteindre */
  [data-kx-view="kol"] #cycle               { order: 3; }  /* Cumulative PnL    */
  [data-kx-view="kol"] .kx-col-b > .kx-duo  { order: 4; }  /*   ses deux bornes */
  [data-kx-view="kol"] #duo-weeks           { order: 5; }  /* Week by week      */
  [data-kx-view="kol"] #style               { order: 6; }  /* Trading Style     */
  [data-kx-view="kol"] #dna                 { order: 7; }  /* Wallet DNA        */
  [data-kx-view="kol"] #copy                { order: 8; }  /* Copy-trade        */
  [data-kx-view="kol"] #holdings            { order: 9; }  /* Current Holdings  */
  [data-kx-view="kol"] #positions           { order: 10; } /* Positions         */
  [data-kx-view="kol"] #hours               { order: 11; } /* When They Trade   */
  [data-kx-view="kol"] #alerts-promo        { order: 11; } /* l'encart Telegram, juste après (même rang : l'ordre du document départage). Sans rang, il valait 0 et remontait AVANT la carte d'identité. */
  [data-kx-view="kol"] #land                { order: 12; } /* Where trades land */
  [data-kx-view="kol"] #about               { order: 13; } /* About             */
  [data-kx-view="kol"] #similar             { order: 14; } /* Same Tokens       */
}

/* ── LE PODIUM DU CLASSEMENT ─────────────────────────────────────────────────
 *
 * Il était écrit en `style="…"` dans `board.php`, sur six attributs. Un podium
 * décrit en ligne ne peut pas répondre à une largeur d'écran, et c'est
 * précisément ce qu'il doit faire : trois colonnes à 1 000 px, trois colonnes
 * serrées en dessous.
 *
 * L'or n'est pas une couleur de plus : c'est la seule chose qui distingue la
 * première marche des deux autres quand les trois cartes ont la même taille.
 */
.kx-podium { padding: 18px 16px 20px; margin-bottom: 16px; }
.kx-pod-h { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.kx-pod-sub { font-size: .66rem; color: var(--kx-ink-3); }
.kx-pod-grid {
  display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px;
  margin-top: 14px; align-items: end;
}
.kx-pod {
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  text-align: center; padding: 14px 8px; min-width: 0;
  color: var(--kx-ink); text-decoration: none;
  border: 1px solid var(--kx-line-2); border-radius: 20px;
  background: rgba(255, 255, 255, .04);
  transition: border-color .15s, background .15s, transform .08s;
}
.kx-pod:hover, .kx-pod:focus-visible { background: rgba(255, 255, 255, .075); }
.kx-pod:active { transform: scale(.98); }
.kx-pod.or {
  padding: 20px 8px;
  border-color: rgba(245, 199, 106, .75);
  background:
    radial-gradient(circle at 50% 0%, rgba(245, 199, 106, .16), transparent 65%),
    rgba(255, 255, 255, .05);
}
.kx-pod-medal { font-size: 1.2rem; line-height: 1; }
/* `min-width: 0` plus haut et l'ellipse ici : un pseudonyme long poussait sa
   colonne et cassait les trois parts égales de la grille. */
.kx-pod-n {
  max-width: 100%; font-size: .8rem; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kx-pod-v { font-size: .95rem; }
.kx-pod-m { font-size: .62rem; color: var(--kx-muted); line-height: 1.35; }

/* ── LE MOUVEMENT DE RANG ────────────────────────────────────────────────────
 *
 * Quatre états, quatre traitements — et « New » n'est PAS une montée. Un
 * trader absent de la fenêtre précédente n'avait pas de rang ; le peindre en
 * vert avec une flèche dirait qu'il a gagné des places qu'il n'a jamais eues.
 */
.kx-pod-mv {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 8px; border-radius: var(--kx-r-pill);
  font: 700 .64rem/1 var(--kx-num); white-space: nowrap;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis;
}
.kx-pod-mv .dim { font-weight: 400; }
.kx-pod-mv.up   { color: var(--kx-up);    background: rgba(25, 255, 115, .12); }
.kx-pod-mv.down { color: var(--kx-down);  background: rgba(255, 128, 128, .12); }
.kx-pod-mv.flat { color: var(--kx-muted); background: rgba(255, 255, 255, .05); }
.kx-pod-mv.neuf { color: var(--kx-accent); background: rgba(0, 229, 208, .12); }

/* ── LE MOUVEMENT SUR LA FICHE D'UN TRADER ───────────────────────────────────
   Le même vocabulaire que sur le podium, en plus petit : c'est le même fait,
   il ne doit pas se lire comme deux mesures différentes. */
.kx-idmv {
  display: inline-flex; align-items: center; gap: 4px;
  margin-left: 6px; padding: 2px 7px; border-radius: var(--kx-r-pill);
  font: 700 .62rem/1 var(--kx-num); white-space: nowrap;
}
.kx-idmv.up   { color: var(--kx-up);    background: rgba(25, 255, 115, .12); }
.kx-idmv.down { color: var(--kx-down);  background: rgba(255, 128, 128, .12); }
.kx-idmv.flat { color: var(--kx-muted); background: rgba(255, 255, 255, .05); }
.kx-idmv.neuf { color: var(--kx-accent); background: rgba(0, 229, 208, .12); }

@media (max-width: 520px) {
  /* Trois colonnes tiennent encore : c'est un podium, il perd son sens empilé
     en liste. Seules les marges se resserrent. */
  .kx-pod { padding: 12px 5px; gap: 6px; border-radius: 16px; }
  .kx-pod.or { padding: 16px 5px; }
  .kx-pod-n { font-size: .72rem; }
  .kx-pod-v { font-size: .84rem; }
  .kx-pod-mv { padding: 3px 6px; font-size: .6rem; }
  /* Le rang d'avant passe à la ligne plutôt que de rogner la pastille. */
  .kx-pod-mv .dim { display: none; }
}

/* ── « SEARCHING… » PENDANT QU'UN FILTRE CHARGE ──────────────────────────────
 *
 * Trois choses arrivent ensemble quand `kxSwap()` part chercher une page
 * filtrée, et chacune répond à un doute précis :
 *
 *   · le corps s'éteint à 45 % — « ce que tu lis n'est plus à jour » ;
 *   · il cesse d'être cliquable — sans quoi un second clic part sur une liste
 *     qui n'existe déjà plus, et deux requêtes courent pour un geste ;
 *   · la pastille dit ce qui se passe, en toutes lettres.
 *
 * LE DÉLAI DE 150 ms EST LA PIÈCE IMPORTANTE. La plupart des filtrages
 * reviennent plus vite que ça : l'indicateur ne s'allume alors jamais, et
 * l'écran ne clignote pas. Il n'apparaît que quand il y a vraiment une attente
 * — c'est-à-dire quand il sert.
 */
main.kx-wrap[aria-busy="true"] {
  opacity: .45;
  pointer-events: none;
  transition: opacity .2s ease .15s;
}
main.kx-wrap { transition: opacity .18s ease; }

.kx-loading {
  position: fixed; z-index: 14;
  left: 50%; transform: translateX(-50%) translateY(6px);
  bottom: calc(84px + env(safe-area-inset-bottom, 0px));
  display: flex; align-items: center; gap: 9px;
  padding: 10px 16px;
  border-radius: var(--kx-r-pill);
  background: rgba(12, 18, 38, .94);
  border: 1px solid rgba(255, 255, 255, .12);
  box-shadow: 0 10px 34px rgba(0, 0, 0, .55);
  opacity: 0; pointer-events: none;
  transition: opacity .18s ease, transform .18s ease;
}
main.kx-wrap[aria-busy="true"] ~ .kx-loading {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
  transition-delay: .15s;
}
/* ── LES ANIMATIONS NE TOURNENT QUE PENDANT L'ATTENTE ────────────────────────
 *
 * Elles étaient déclarées sur la pastille elle-même, donc elles tournaient EN
 * PERMANENCE — sur chaque écran, chaque seconde, derrière un `opacity: 0`.
 * Invisible ne veut pas dire gratuit : un navigateur fait avancer une animation
 * qu'il ne peint pas, et sur un téléphone cela se paie en batterie pour
 * strictement rien.
 *
 * Elles ne démarrent donc qu'avec l'attribut qui les justifie. */
main.kx-wrap[aria-busy="true"] ~ .kx-loading .kx-loading-ring {
  animation: kxspin .8s linear infinite;
}
main.kx-wrap[aria-busy="true"] ~ .kx-loading .kx-loading-t i { animation: kxdots 1.2s infinite; }
main.kx-wrap[aria-busy="true"] ~ .kx-loading .kx-loading-t i:nth-child(2) { animation-delay: .2s; }
main.kx-wrap[aria-busy="true"] ~ .kx-loading .kx-loading-t i:nth-child(3) { animation-delay: .4s; }
@media (min-width: 1000px) { .kx-loading { bottom: 28px; } }

/* L'anneau reprend le dégradé de marque — `conic-gradient` plutôt qu'une
   bordure colorée : une seule couche, et il tourne sans repeindre le texte. */
.kx-loading-ring {
  width: 15px; height: 15px; flex: 0 0 auto; border-radius: 50%;
  background: conic-gradient(from 0deg, transparent 0deg, #4b73ff 140deg, #19d4ff 300deg, transparent 360deg);
  -webkit-mask: radial-gradient(circle, transparent 4.5px, #000 5px);
          mask: radial-gradient(circle, transparent 4.5px, #000 5px);
}
@keyframes kxspin { to { transform: rotate(360deg); } }

.kx-loading-t {
  font: 600 .74rem/1 var(--kx-font);
  letter-spacing: .02em; color: var(--kx-ink);
}
/* Les trois points s'allument l'un après l'autre. Ils ne mesurent rien — ils
   disent seulement que quelque chose court, et c'est tout ce qu'on sait. */
.kx-loading-t i { font-style: normal; opacity: .25; }
@keyframes kxdots { 0%, 60%, 100% { opacity: .25; } 30% { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  main.kx-wrap[aria-busy="true"] ~ .kx-loading .kx-loading-ring { animation: none; }
  main.kx-wrap[aria-busy="true"] ~ .kx-loading .kx-loading-t i { animation: none; opacity: .7; }
  main.kx-wrap, main.kx-wrap[aria-busy="true"], .kx-loading { transition-duration: .01ms; }
}

/* ── « LAST TRADE 4 MIN AGO » : LE DESSIN DE LA PRODUCTION ───────────────────
 *
 * `.time-pill` existe déjà sur `kolexplorer.com` et cette pastille est le même
 * objet : dégradé radial or, petites capitales espacées, horloge en contour,
 * ombre portée. Les valeurs sont recopiées à l'identique — un or légèrement
 * différent au même endroit se remarque immédiatement quand on passe d'une page
 * publique à une page membre.
 *
 * LA SEULE CHOSE AJOUTÉE est l'état « en ce moment », sous deux heures : le
 * point clignotant prend la place de l'horloge. La pastille garde son or, si
 * bien qu'elle reste reconnaissable comme une pastille de temps.
 */
.kx-lt {
  display: inline-flex; align-items: center; gap: .25rem;
  padding: .16rem .6rem;
  border-radius: var(--kx-r-pill);
  font: 600 .7rem/1.5 var(--kx-font);
  letter-spacing: .05em; text-transform: uppercase;
  white-space: nowrap;
  background: radial-gradient(circle at 0% 0%, rgba(245, 199, 106, .95), rgba(60, 42, 10, .95));
  color: #fffaf0;
  border: 1px solid rgba(255, 215, 128, .5);
  box-shadow: 0 4px 12px rgba(0, 0, 0, .55);
}
.kx-lt .kxi { width: .72em; height: .72em; flex: 0 0 auto; opacity: .85; }
/* Une mesure absente n'est pas une mesure : la pastille s'éteint au lieu de
   briller en or sur un tiret. */
.kx-lt.vide {
  background: rgba(255, 255, 255, .04);
  color: var(--kx-muted);
  border-color: var(--kx-line-2);
  box-shadow: none;
}
/* « En ce moment » : le vert de « KOLs live », même seuil, même point. */
.kx-lt.vif {
  background: radial-gradient(circle at 0% 0%, rgba(25, 255, 115, .9), rgba(6, 46, 22, .95));
  border-color: rgba(25, 255, 115, .5);
  color: #f2fff7;
}
.kx-lt .kx-dotlive { flex: 0 0 auto; }
/* Dans une carte de vitrine ou une rangée serrée, elle se resserre sans changer
   de nature. */
.kx-vit-c .kx-lt, .kx-row-tags .kx-lt { font-size: .62rem; padding: .14rem .5rem; }
.kx-ltline { margin: 0 0 18px; }

/* ── LE CHAMP DE RECHERCHE DE L'ACCUEIL ──────────────────────────────────────
 *
 * Il rend les deux sections de `search.php` — Traders et Tokens — dans le corps
 * de la page plutôt que dans l'overlay. Même HTML, donc `.kx-res` habille déjà
 * les lignes ; il n'y a que le champ et son cadre à écrire.
 */
.kx-homefind { padding: 16px; margin-bottom: 16px; }
.kx-homefind-in {
  display: flex; align-items: center; gap: 10px;
  padding: 0 14px; min-height: 50px;
  background: rgba(255, 255, 255, .05);
  border: 1px solid var(--kx-line-2); border-radius: var(--kx-r-pill);
  transition: border-color .15s, background .15s;
}
.kx-homefind-in:focus-within {
  border-color: rgba(0, 229, 208, .5);
  background: rgba(255, 255, 255, .07);
}
.kx-homefind-in svg { flex: 0 0 auto; width: 17px; height: 17px; color: var(--kx-muted); }
/* 16px minimum : en dessous, Safari iOS zoome sur le champ au focus et
   l'utilisateur se retrouve sur une page agrandie qu'il n'a pas demandée. */
.kx-homefind-in input {
  flex: 1 1 auto; min-width: 0;
  background: none; border: 0; outline: none;
  font: 400 16px/1.2 var(--kx-font); color: var(--kx-ink);
}
.kx-homefind-in input::placeholder { color: var(--kx-faint); }
.kx-homefind-in input::-webkit-search-cancel-button { filter: invert(.6); }
.kx-homefind-h { font-size: .7rem; color: var(--kx-ink-3); margin: 10px 2px 0; }
.kx-homefind-r:not(:empty) { margin-top: 12px; }

/* Un nom accessible qui ne prend pas de place : le champ doit s'annoncer aux
   lecteurs d'écran sans qu'un libellé double le texte indicatif. */
.kx-sr {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* ── LA CARTE DU TERMINAL PORTE DEUX LIENS ───────────────────────────────────
 *
 * Le titre est le lien principal ; son `::after` couvre toute la carte, si bien
 * qu'elle reste cliquable d'un bout à l'autre comme lorsqu'elle était elle-même
 * un `<a>`. Le bouton Axiom repasse au-dessus avec son propre `z-index`.
 *
 * C'est le seul agencement qui permette deux destinations dans une carte sans
 * imbriquer deux `<a>` — ce que le HTML interdit et que les navigateurs défont
 * en silence, à un endroit qu'on ne choisit pas.
 */
.kx-tok { position: relative; }
.kx-tok-link {
  display: block; font-size: 1.02rem; font-weight: 700; letter-spacing: -.01em;
  color: var(--kx-ink); text-decoration: none;
}
.kx-tok-link::after { content: ""; position: absolute; inset: 0; z-index: 1; }
.kx-tok-link:focus-visible { outline: 2px solid var(--kx-accent); outline-offset: 3px; }

/* ── LE LOGO AXIOM, DANS LA RANGÉE DES VISAGES ───────────────────────────────
 * C'était une barre pleine largeur en couleur de marque, sous chaque carte —
 * douze fois par page. Elle criait plus fort que la carte, et répétait douze
 * fois une phrase qu'on comprend la première.
 *
 * La case garde ses 44 px de cible tactile : un logo plus discret ne doit pas
 * devenir plus dur à toucher. */
.kx-tok-ax {
  position: relative; z-index: 2;
  display: grid; place-items: center; flex: 0 0 auto;
  width: 44px; height: 44px; margin-left: auto;
  border-radius: 13px; border: 1px solid var(--kx-line-2);
  background: rgba(255, 255, 255, .05);
  font: 700 .64rem/1 var(--kx-num); color: var(--kx-ink-2); text-decoration: none;
  transition: border-color .15s, background .15s, transform .08s;
}
.kx-tok-ax img { width: 26px; height: 26px; border-radius: 8px; object-fit: cover; }
.kx-tok-ax:hover, .kx-tok-ax:focus-visible {
  border-color: rgba(25, 212, 255, .5); background: rgba(25, 212, 255, .1);
}
.kx-tok-ax:active { transform: scale(.94); }
/* La rangée porte maintenant trois choses : les visages, le texte, le logo. */
.kx-tok-who { display: flex; align-items: center; gap: 10px; }
@media (prefers-reduced-motion: reduce) { .kx-tok-ax { transition: none; } .kx-tok-ax:active { transform: none; } }

/* ── LE SQUELETTE D'UNE CARTE QU'ON ATTEND ───────────────────────────────────
 *
 * Il tient la place d'une liste qui arrive après le reste de la page. Sans lui,
 * la page semble finir là où le serveur en est rendu.
 *
 * Il porte le VRAI titre de la carte : un rectangle gris anonyme ne dit pas ce
 * qu'on attend, et c'est pourtant la seule chose utile pendant l'attente.
 *
 * Aucune couleur de marque, aucun dégradé animé qui traverse : ce n'est pas un
 * contenu, et il ne doit pas se lire comme tel. Une respiration très lente
 * suffit à dire que quelque chose travaille.
 */
.kx-skel { opacity: .55; }
.kx-skel .kx-card-sub { font-variant-numeric: normal; }
.kx-skel-row {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 0; border-bottom: 1px solid rgba(255, 255, 255, .05);
}
.kx-skel-row:last-child { border-bottom: 0; }
.kx-skel-av {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 11px;
  background: rgba(255, 255, 255, .07);
}
.kx-skel-l { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 7px; }
.kx-skel-l i { display: block; height: 9px; border-radius: 5px; background: rgba(255, 255, 255, .07); }
.kx-skel-l i:last-child { height: 7px; background: rgba(255, 255, 255, .045); }
.kx-skel-n {
  flex: 0 0 auto; width: 62px; height: 13px; border-radius: 6px;
  background: rgba(255, 255, 255, .07);
}
.kx-skel-av, .kx-skel-l i, .kx-skel-n { animation: kxskel 1.6s ease-in-out infinite; }
@keyframes kxskel { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
@media (prefers-reduced-motion: reduce) {
  .kx-skel-av, .kx-skel-l i, .kx-skel-n { animation: none; }
}

/* Le lien vers la chaîne, dans « About ». Discret : c'est une vérification, pas
   une action qu'on propose. */
.kx-solscan { color: var(--kx-accent-2); text-decoration: none; font-weight: 600; }
.kx-solscan:hover, .kx-solscan:focus-visible { text-decoration: underline; }

/* ── LES TROIS VITRINES DE L'ACCUEIL ─────────────────────────────────────────
 *
 * Trois listes courtes de visages. Chacune porte sa légende : trois grilles sans
 * explication se lisent comme trois fois la même chose, alors qu'elles
 * répondent à trois questions.
 *
 * Deux colonnes sur téléphone, quatre au-delà : huit noms tiennent en deux
 * rangées, ce qui est exactement ce qu'on parcourt du regard sans décider de
 * lire.
 */
.kx-vit { margin-bottom: 18px; }
.kx-vit-s + .kx-vit-s { margin-top: 20px; }
.kx-vit-h h2 { font-size: .96rem; font-weight: 700; margin: 0; letter-spacing: -.01em; }
.kx-vit-h p {
  font-size: .72rem; color: var(--kx-ink-3);
  margin: 4px 0 11px; line-height: 1.55; max-width: 62ch;
}
.kx-vit-g { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
@media (min-width: 720px)  { .kx-vit-g { grid-template-columns: repeat(4, 1fr); } }
.kx-vit-c {
  display: flex; align-items: center; gap: 9px; min-width: 0;
  padding: 10px 12px; min-height: 56px;
  color: var(--kx-ink); text-decoration: none;
  background: rgba(255, 255, 255, .04);
  border: 1px solid var(--kx-line-2); border-radius: 15px;
  transition: background .15s, border-color .15s;
}
.kx-vit-c:hover, .kx-vit-c:focus-visible {
  background: rgba(255, 255, 255, .075); border-color: rgba(255, 255, 255, .16);
}
/* `min-width: 0` sur la carte ET l'ellipse ici : un pseudonyme long poussait sa
   colonne et cassait les parts égales de la grille. */
.kx-vit-n {
  flex: 1 1 auto; min-width: 0;
  font-size: .78rem; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kx-vit-m { flex: 0 0 auto; text-align: right; font: 700 .72rem/1.2 var(--kx-num); }
.kx-vit-m small { display: block; font: 400 .6rem/1 var(--kx-font); color: var(--kx-ink-3); margin-top: 3px; }
/* La pastille « Traded 4 min ago » est déjà petite ; dans une carte de vitrine
   elle se resserre encore, sinon elle chasse le nom. */
.kx-vit-c .kx-lt { flex: 0 0 auto; padding: 3px 7px; font-size: .6rem; }
.kx-vit-c .kx-lt b { font-size: .62rem; }

/* ── « COMMENT LIRE CETTE CARTE » ────────────────────────────────────────────
 *
 * Trois phrases AVANT les dessins. Un graphique qu'on comprend au troisième
 * coup d'œil a déjà perdu la moitié de ses lecteurs, et celui-ci porte deux
 * échelles dont une logarithmique.
 *
 * Le bloc est visiblement une note, pas une donnée : fond très léger, filet à
 * gauche, aucun chiffre en gros. On doit pouvoir le sauter d'un regard une fois
 * qu'on a compris.
 */
.kx-howto {
  border-left: 2px solid rgba(0, 229, 208, .4);
  background: rgba(0, 229, 208, .045);
}
.kx-howto p { font-size: .74rem; color: var(--kx-ink-2); margin: 0; line-height: 1.6; }
.kx-howto p.dim { font-size: .68rem; margin-top: 10px; }
.kx-howto ol { margin: 8px 0 0; padding-left: 20px; }
.kx-howto li {
  font-size: .74rem; color: var(--kx-ink-2);
  margin-bottom: 6px; line-height: 1.55;
}
.kx-howto li:last-child { margin-bottom: 0; }
.kx-howto li::marker { color: var(--kx-accent); font-weight: 700; }
.kx-howto .kx-num { font-size: .78rem; }

/* La réglette des entrées partage désormais la carte de la courbe. Le filet dit
   qu'on change de dessin sans changer de sujet. */
.kx-entries-rail { border-top: 1px solid var(--kx-line); padding-top: 14px; }

/* ── L'AVERTISSEMENT D'UNE MODALE ────────────────────────────────────────────
 *
 * Ambre, pas rouge : le rouge dit « une erreur vient de se produire ». Ici rien
 * ne s'est produit — on prévient de ce qui va suivre, et la nuance change la
 * façon dont on le lit.
 *
 * Il se voit AVANT d'être lu : filet à gauche, icône, fond teinté. Une mise en
 * garde qui ressemble à un paragraphe se saute avec les paragraphes.
 */
.kx-warn {
  display: flex; gap: 10px; align-items: flex-start;
  margin: 0 0 14px; padding: 12px 14px;
  font-size: .76rem; line-height: 1.6; color: var(--kx-ink-2);
  background: rgba(245, 199, 106, .09);
  border: 1px solid rgba(245, 199, 106, .28);
  border-left-width: 3px;
  border-radius: 14px;
}
.kx-warn-i { flex: 0 0 auto; font-size: .95rem; line-height: 1.35; color: var(--kx-gold); }

/* ── LE PRIX, MAINTENANT ─────────────────────────────────────────────────────
 *
 * Deux fenêtres côte à côte, parce qu'une seule ment dans les deux sens : +1 %
 * sur l'heure après −40 % sur la journée n'est pas une reprise.
 *
 * La couleur est décidée sur la valeur ARRONDIE — celle qui est imprimée. Sur
 * la valeur brute, un −0,04 % s'affichait « 0.0% » en rouge : le texte disait
 * l'équilibre et la couleur disait la perte.
 */
.kx-mv-now { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 16px; }
.kx-mv-now-c {
  display: inline-flex; align-items: baseline; gap: 5px;
  padding: 7px 12px; border-radius: 13px;
  border: 1px solid var(--kx-line-2); background: rgba(255, 255, 255, .04);
}
.kx-mv-now-c b { font: 700 1rem/1 var(--kx-num); }
.kx-mv-now-c small { font: 600 .62rem/1 var(--kx-font); color: var(--kx-ink-3); }
.kx-mv-now-a { font-size: .66rem; line-height: 1; }
.kx-mv-now-c.up   { color: var(--kx-up);   border-color: rgba(25, 255, 115, .32);  background: rgba(25, 255, 115, .1); }
.kx-mv-now-c.down { color: var(--kx-down); border-color: rgba(255, 128, 128, .32); background: rgba(255, 128, 128, .1); }
.kx-mv-now-c.flat { color: var(--kx-muted); }
.kx-mv-now-c.up small, .kx-mv-now-c.down small { color: inherit; opacity: .75; }
.kx-mv-now-s { font-size: .64rem; color: var(--kx-ink-3); }

/* ── LES VISAGES DE CEUX QUI L'ONT TOUCHÉ ────────────────────────────────── */
.kx-tok-faces {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 16px; padding: 10px 12px;
  color: var(--kx-ink); text-decoration: none;
  background: rgba(255, 255, 255, .035);
  border: 1px solid var(--kx-line-2); border-radius: 15px;
  transition: background .15s, border-color .15s;
}
.kx-tok-faces:hover, .kx-tok-faces:focus-visible {
  background: rgba(255, 255, 255, .07); border-color: rgba(255, 255, 255, .16);
}
.kx-tok-faces-t { font-size: .72rem; color: var(--kx-ink-2); line-height: 1.45; }
.kx-tok-faces-t b { font: 700 .78rem/1 var(--kx-num); }

/* ── LES TROIS NOMS QU'ON CHERCHE EN ARRIVANT ────────────────────────────────
 *
 * Trois réponses différentes à trois questions voisines, et c'est le propos :
 * le plus gros gain est souvent le plus gros portefeuille, le meilleur multiple
 * souvent une petite mise.
 */
.kx-tok-top {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 8px; margin-top: 12px;
}
.kx-tok-top-c {
  display: flex; flex-direction: column; gap: 7px; min-width: 0;
  padding: 12px; color: var(--kx-ink); text-decoration: none;
  background: rgba(255, 255, 255, .04);
  border: 1px solid var(--kx-line-2); border-radius: 16px;
  transition: background .15s, border-color .15s;
}
.kx-tok-top-c:hover, .kx-tok-top-c:focus-visible {
  background: rgba(255, 255, 255, .075); border-color: rgba(255, 255, 255, .16);
}
.kx-tok-top-l {
  font: 600 .58rem/1 var(--kx-font); letter-spacing: .07em;
  text-transform: uppercase; color: var(--kx-ink-3);
}
.kx-tok-top-w { display: flex; align-items: center; gap: 7px; min-width: 0; }
.kx-tok-top-n {
  min-width: 0; font-size: .8rem; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kx-tok-top-v { font-size: .95rem; }
.kx-tok-top-v .kx-num { font-size: inherit; }

/* Le logo d'une plateforme, en petit : sur un bouton, pas dans une liste. */
.kx-plat.sm { width: 20px; height: 20px; border-radius: 6px; }

/* ── L'EN-TÊTE D'UN TOKEN, EN QUATRE BANDES ──────────────────────────────────
 *
 * MESURÉ AVANT : 1 227 px — 1,36 écran — pour DIX blocs empilés, chacun d'une
 * forme différente. Trois traitements distincts pour des chiffres, deux pour
 * les porteurs, de la prose au milieu. Rien ne disait quoi lire en premier.
 *
 * Un filet entre chaque bande. Deux blocs collés sans filet se lisent comme un
 * seul — c'était le cas de six d'entre eux, et c'est très exactement ce qui
 * donnait l'impression de dispersion.
 */
.kx-th-band { margin-top: 16px; padding-top: 16px; border-top: 1px solid rgba(255, 255, 255, .08); }
.kx-th-band > .kx-eyebrow { margin: 0 0 10px; color: #9fb6d8; }

/* Les actions, remontées de la neuvième place à la deuxième : ce sont les seuls
   verbes de l'en-tête, et ils étaient sous huit blocs de constats. */
.kx-th-act { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 14px; }
.kx-th-act > * {
  display: inline-flex; align-items: center; gap: 8px; min-height: 46px;
}

/* ── UNE SEULE FORME DE TUILE ────────────────────────────────────────────────
 * Le prix, la capitalisation et la liquidité sont trois mesures du même marché.
 * Elles avaient trois habillages et trois hauteurs de page ; elles partagent
 * maintenant une grille, et seule la couleur du prix les distingue.
 */
/* Deux par deux sur téléphone, quatre au-delà. `auto-fit` en donnait TROIS à
   412 px, et la quatrième restait seule sur sa ligne — une grille qui casse
   se remarque plus qu'une grille serrée. */
/* ── LA GRILLE SUIT SON CONTENEUR, PAS LA FENÊTRE ───────────────────────────
   MESURÉ : à 1 440 px, une requête de largeur mettait quatre tuiles de
   **75,5 px** dans un rail de 380 px, et « $133.05M » demande 95 px avec sa
   marge — le montant sortait de sa case. La requête posait la mauvaise
   question : ce n'est pas la fenêtre qui est étroite, c'est le rail.

   `auto-fit` avec un plancher règle ça sans rien mesurer : 124 px est la
   largeur du plus long montant qu'on puisse y écrire, et la grille pose
   autant de colonnes que le conteneur en accepte — deux dans le rail,
   quatre sur une pleine largeur. */
.kx-th-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(124px, 1fr)); gap: 8px; }
/* Un montant reste sur sa ligne : il se réduit plutôt que de sortir. */
.kx-th-t b { overflow: hidden; text-overflow: ellipsis; }
.kx-th-t {
  display: flex; flex-direction: column; gap: 5px; min-width: 0;
  padding: 11px 12px;
  border: 1px solid var(--kx-line-2); border-radius: 14px;
  background: rgba(255, 255, 255, .04);
}
.kx-th-t b { font: 700 .95rem/1 var(--kx-num); white-space: nowrap; }
.kx-th-t small {
  font: 600 .58rem/1 var(--kx-font); letter-spacing: .06em;
  text-transform: uppercase; color: var(--kx-ink-3);
}
.kx-th-t.up   { border-color: rgba(25, 255, 115, .32);  background: rgba(25, 255, 115, .09); }
.kx-th-t.down { border-color: rgba(255, 128, 128, .32); background: rgba(255, 128, 128, .09); }
.kx-th-t.up b   { color: var(--kx-up); }
.kx-th-t.down b { color: var(--kx-down); }

/* Les visages et les trois noms partagent la bande : un seul cadre, pas deux. */
.kx-th-band .kx-tok-faces { margin-top: 0; }
.kx-th-band .kx-tok-top   { margin-top: 8px; }
.kx-th-band .kx-tok-stats { margin-top: 0; }

/* ── UNE MODALE NE DÉPASSE JAMAIS L'ÉCRAN ────────────────────────────────────
 *
 * TROUVÉ EN USAGE, et le diagnostic « coupée par la barre du haut » était la
 * moitié du problème. MESURÉ à 412 × 900 sur le sélecteur de comparaison : la
 * modale faisait **2 436 px de haut**. Le fond la centre, elle débordait donc
 * de 768 px EN HAUT et de 768 px EN BAS — son titre, son champ de recherche et
 * son bouton « Watching only » étaient hors de l'écran, inatteignables. Trente
 * lignes de liste, aucun conteneur qui défile, et `overflow: hidden` sur la
 * modale pour finir de les enfermer.
 *
 * L'autre moitié était réelle aussi : le fond était en `z-index: 80`, la barre
 * du haut en `100`. Même à la bonne taille, ses 72 premiers pixels passaient
 * DERRIÈRE la barre.
 *
 * Trois corrections, et il fallait les trois :
 *
 *   · le fond passe au-dessus de tout (`120`) ;
 *   · la modale ne dépasse jamais la hauteur visible, encoches comprises ;
 *   · c'est son CORPS qui défile, pas la page — l'en-tête et le pied restent,
 *     donc la recherche et le bouton de fermeture ne partent jamais.
 */
.kx-modal-back {
  z-index: 120;
  padding: max(16px, env(safe-area-inset-top, 0px)) 16px max(16px, env(safe-area-inset-bottom, 0px));
}
.kx-modal {
  display: flex; flex-direction: column;
  /* `dvh` et non `vh` : sur mobile, `vh` compte la barre d'adresse comme si
     elle était toujours repliée, et la modale dépasse de sa hauteur. */
  max-height: calc(100dvh - 32px);
}
.kx-modal-h, .kx-modal-f { flex: 0 0 auto; }
/* `min-height: 0` : sans lui, un enfant flex refuse de rétrécir sous la taille
   de son contenu et le `overflow` ne s'applique jamais. */
.kx-modal-b { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }

/* La barre de recherche reste sous les yeux pendant qu'on fait défiler les
   trente noms : chercher en aveugle après avoir scrollé n'a aucun sens. */
.kx-pickbar {
  position: sticky; top: 0; z-index: 1;
  padding: 2px 0 10px; margin-bottom: 2px;
  background: var(--kx-float);
}

/* ── LE TEXTE DE BAS DE PAGE DE « COMPARE » ──────────────────────────────────
 *
 * De la prose, et elle doit se lire comme de la prose : mesure de ligne bornée,
 * interlignage large, titres discrets. Rien de la densité du reste de
 * l'interface, qui est faite pour être balayée.
 */
.kx-seo {
  margin-top: 22px; padding: 20px 18px;
  background: rgba(255, 255, 255, .025);
  border: 1px solid var(--kx-line); border-radius: var(--kx-r-card);
}
.kx-seo h2 { font-size: 1.02rem; font-weight: 700; margin: 0 0 12px; letter-spacing: -.01em; }
.kx-seo h3 {
  font-size: .8rem; font-weight: 700; margin: 18px 0 6px;
  color: var(--kx-ink-2);
}
/* 68 caractères : au-delà, l'œil perd sa ligne en revenant à la marge. */
.kx-seo p { font-size: .82rem; line-height: 1.75; color: var(--kx-ink-3); margin: 0; max-width: 68ch; }
.kx-seo p + p { margin-top: 10px; }
.kx-seo b { color: var(--kx-ink-2); font-weight: 600; }
.kx-seo em { font-style: italic; color: var(--kx-ink-2); }
.kx-seo-links { margin-top: 18px !important; font-size: .78rem !important; }
.kx-seo-links a { color: var(--kx-accent); text-decoration: none; font-weight: 600; }
.kx-seo-links a:hover, .kx-seo-links a:focus-visible { text-decoration: underline; }

/* Les deux sommes dans le titre de « Current holdings ». Elles remplacent un
   compte de lignes — que le lecteur voit déjà — par ce qui pèse. */
.kx-hsum { display: inline-flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.kx-hsum b, .kx-hsum .kx-num { font-size: .82rem; font-weight: 700; }
.kx-hsum small { font: 400 .62rem/1 var(--kx-font); color: var(--kx-ink-3); }

/* ── LES DÉPARTS DE /COMPARE/ ────────────────────────────────────────────────
 *
 * Des duels tout faits. La carte porte les deux visages et le « vs » au milieu :
 * c'est la forme de la chose qu'on va voir, donc on la reconnaît avant de lire
 * les noms.
 */
.kx-cmpstart { margin-bottom: 20px; }
.kx-cmpstart-g { display: grid; grid-template-columns: 1fr; gap: 8px; }
@media (min-width: 640px) { .kx-cmpstart-g { grid-template-columns: 1fr 1fr; } }
.kx-cmpstart-c {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 10px;
  padding: 12px 14px; min-height: 60px;
  color: var(--kx-ink); text-decoration: none;
  background: rgba(255, 255, 255, .04);
  border: 1px solid var(--kx-line-2); border-radius: 16px;
  transition: background .15s, border-color .15s;
}
.kx-cmpstart-c:hover, .kx-cmpstart-c:focus-visible {
  background: rgba(255, 255, 255, .075); border-color: rgba(255, 255, 255, .16);
}
.kx-cmpstart-s { display: flex; align-items: center; gap: 8px; min-width: 0; }
/* Le second camp regarde vers le centre : c'est ce qui fait lire la carte comme
   un affrontement plutôt que comme deux lignes côte à côte. */
.kx-cmpstart-s:last-child { flex-direction: row-reverse; text-align: right; }
.kx-cmpstart-s b {
  min-width: 0; font-size: .8rem; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kx-cmpstart-s small { font: 600 .6rem/1 var(--kx-num); color: var(--kx-ink-3); }
.kx-cmpstart-v {
  font: 700 .62rem/1 var(--kx-font); letter-spacing: .08em;
  text-transform: uppercase; color: var(--kx-faint);
}

/* La barre de recherche collante déborde jusqu'aux bords du corps de la modale :
   sans ces marges négatives, les lignes défilaient VISIBLEMENT dans les 18 px
   de marge intérieure, de part et d'autre d'un fond qui s'arrêtait trop tôt. */
.kx-modal-b .kx-pickbar {
  margin-left: -18px; margin-right: -18px;
  padding-left: 18px; padding-right: 18px;
  padding-top: 16px; margin-top: -16px;
  border-bottom: 1px solid var(--kx-line);
}
/* Un pied de modale vide ne prend pas sa marge. */
.kx-modal-f:empty { padding: 0; }

/* Le second chiffre d'une fiche : il qualifie le premier sans le concurrencer.
   « +40,3 K$ » puis « $12.4K still in » — plus petit, sur sa propre ligne. */
.kx-tok-top-s { font: 600 .68rem/1.3 var(--kx-font); color: var(--kx-ink-3); }
.kx-tok-top-s .kx-num { font-size: .72rem; }

/* Les trois chiffres de sortie d'un token, sous la médiane. Même corps, même
   famille : ils décrivent la même distribution par trois bouts, aucun ne prime
   sur les autres. */
.kx-tok-ex3 { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 6px; }
.kx-tok-ex3 > span { display: inline-flex; align-items: baseline; gap: 5px; }
.kx-tok-ex3 .kx-num { font-size: .78rem; font-weight: 700; }
.kx-tok-ex3 small {
  font: 600 .58rem/1 var(--kx-font); letter-spacing: .06em;
  text-transform: uppercase; color: var(--kx-ink-3);
}

/* La rampe de lancement, à côté du nom du token. Une étiquette, pas un bouton :
   elle dit d'où vient ce token, elle ne mène nulle part. */
/* ── LE LATENT, SUR LA FICHE D'UN TRADER ──────────────────────────────────────
 *
 * Il occupe la place laissée par le panier à mise égale, et il en prend le
 * poids visuel : grand nombre, légende, puis une barre qui dit d'un coup d'œil
 * ce qui est encaissé et ce qui est encore en jeu.
 *
 * La part « banked » est neutre et la part « on the table » porte la couleur :
 * l'encaissé est un fait, le latent est ce qui peut encore bouger. Deux parts
 * colorées se seraient disputé le regard sans rien dire de plus. */
.kx-unreal { margin-top: 14px; }
.kx-unreal-bar {
  display: flex; height: 8px; margin-top: 11px; border-radius: 99px; overflow: hidden;
  background: rgba(255, 255, 255, .06);
}
.kx-unreal-bar i { display: block; height: 100%; }
.kx-unreal-bar i.banked { background: rgba(255, 255, 255, .28); }
.kx-unreal-bar i.table  { background: var(--kx-up); }
.kx-unreal-bar i.table.neg { background: var(--kx-down); }
.kx-unreal-k {
  display: flex; justify-content: space-between; gap: 10px; flex-wrap: wrap;
  margin-top: 7px; font: 400 .7rem/1.4 var(--kx-font); color: var(--kx-ink-3);
}
.kx-unreal-k b { font-weight: 700; }
.kx-unreal-p {
  font-size: .72rem; color: var(--kx-ink-3); margin: 8px 0 0; line-height: 1.55;
}
.kx-unreal-p b { color: var(--kx-ink); }

/* ── LE PRIX ET LA TAILLE, SOUS LE NOM DU TOKEN ───────────────────────────────
 *
 * Le prix en chiffres de tableau (`--kx-num`) et à la taille du nom : c'est lui
 * qu'on vient chercher. La capitalisation le suit, plus petite et plus pâle —
 * elle qualifie le prix, elle ne le concurrence pas.
 *
 * `white-space: nowrap` sur la capitalisation : « $1.2M mcap » coupé entre le
 * nombre et son unité se lit comme deux choses. */
.kx-tok-px {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 10px; margin-top: 5px;
}
.kx-tok-px > b {
  font: 700 .98rem/1.1 var(--kx-num); letter-spacing: -.01em; color: var(--kx-ink);
  overflow-wrap: anywhere;
}
.kx-tok-px-mc {
  font: 600 .72rem/1.1 var(--kx-num); color: var(--kx-ink-3); white-space: nowrap;
}
.kx-tok-px-mc small { font: 400 .66rem/1 var(--kx-font); color: var(--kx-muted); }

.kx-lp {
  display: inline-flex; align-items: center; align-self: flex-start;
  margin-top: 6px; padding: 3px 9px;
  font: 600 .62rem/1 var(--kx-font); letter-spacing: .03em;
  color: var(--kx-ink-3);
  background: rgba(255, 255, 255, .05);
  border: 1px solid var(--kx-line-2); border-radius: var(--kx-r-pill);
}

/* ── LES DEUX CARTES D'UNE COMPARAISON ───────────────────────────────────────
 *
 * C'est le cœur de `/compare/` du site public, repris ici dans le vocabulaire
 * de cette interface : chaque côté a sa carte, ses chiffres, les catégories
 * qu'il a remportées et ce qu'il tient encore.
 *
 * SUR PETIT ÉCRAN, UNE SEULE À LA FOIS. Côte à côte, elles feraient deux
 * colonnes de 190 px ; empilées, il faudrait remonter de 700 px pour comparer
 * une ligne avec son équivalent — ce qui est exactement ce qu'on vient faire.
 * Les onglets règlent les deux. Au-dessus de 900 px ils disparaissent et les
 * deux cartes tiennent côte à côte.
 */
.kx-vs-tabs { display: flex; gap: 8px; margin-bottom: 12px; }
.kx-vs-tab {
  flex: 1 1 0; min-width: 0;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 46px; padding: 0 12px;
  font: 600 .78rem/1 var(--kx-font); color: var(--kx-ink-2);
  background: rgba(255, 255, 255, .04);
  border: 1px solid var(--kx-line-2); border-radius: 14px;
  cursor: pointer; transition: background .15s, border-color .15s, color .15s;
}
.kx-vs-tab span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kx-vs-tab.on {
  color: var(--kx-ink);
  background: rgba(75, 115, 255, .16);
  border-color: rgba(75, 115, 255, .5);
}
@media (min-width: 900px) { .kx-vs-tabs { display: none; } }

.kx-vs { display: grid; grid-template-columns: 1fr; gap: 12px; margin-bottom: 16px; }
@media (min-width: 900px) { .kx-vs { grid-template-columns: 1fr 1fr; } }
/* Au-dessus de 900 px, les deux sont montrées quoi qu'ait fait l'onglet. */
@media (min-width: 900px) { .kx-vs-c[hidden] { display: block !important; } }

.kx-vs-c {
  padding: 16px;
  border-radius: var(--kx-r-card); border: 1px solid var(--kx-line-2);
  background: var(--kx-panel);
}
/* Le côté est dit par un liseré, pas par un fond : deux fonds colorés côte à
   côte se lisent comme deux interfaces différentes. */
.kx-vs-c.cote-a { border-left: 3px solid rgba(75, 115, 255, .8); }
.kx-vs-c.cote-b { border-left: 3px solid rgba(255, 128, 128, .8); }
.kx-vs-c.mene { box-shadow: 0 0 0 1px rgba(245, 199, 106, .35), var(--kx-sh-hero); }

.kx-vs-h { display: flex; align-items: center; gap: 11px; }
.kx-vs-id { min-width: 0; flex: 1 1 auto; }
.kx-vs-n {
  display: block; font-size: .95rem; font-weight: 700; color: var(--kx-ink);
  text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kx-vs-at { font-size: .68rem; color: var(--kx-muted); }
.kx-vs-crown { flex: 0 0 auto; font-size: 1.2rem; color: var(--kx-gold); line-height: 1; }

.kx-vs-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: 8px; margin-top: 14px; }
.kx-vs-k {
  display: flex; flex-direction: column; gap: 5px; min-width: 0;
  padding: 9px 10px;
  border: 1px solid var(--kx-line-2); border-radius: 12px;
  background: rgba(255, 255, 255, .03);
}
.kx-vs-k small {
  font: 600 .56rem/1 var(--kx-font); letter-spacing: .06em;
  text-transform: uppercase; color: var(--kx-ink-3);
}
.kx-vs-k .kx-num, .kx-vs-k b { font-size: .84rem; font-weight: 700; white-space: nowrap; }

.kx-vs-won { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.kx-vs-w {
  font: 600 .64rem/1 var(--kx-font);
  padding: 5px 9px; border-radius: var(--kx-r-pill);
  color: var(--kx-up); background: rgba(25, 255, 115, .1);
  border: 1px solid rgba(25, 255, 115, .28);
}
.kx-vs-none { font-size: .72rem; color: var(--kx-ink-3); margin: 12px 0 0; }

.kx-vs-best {
  display: flex; align-items: center; gap: 9px; margin-top: 12px;
  padding: 10px 12px; text-decoration: none;
  border: 1px solid rgba(245, 199, 106, .3); border-radius: 13px;
  background: rgba(245, 199, 106, .07);
}
.kx-vs-best-l {
  font: 600 .58rem/1 var(--kx-font); letter-spacing: .06em;
  text-transform: uppercase; color: var(--kx-gold-tx);
}
.kx-vs-best-s { font-size: .78rem; font-weight: 600; color: var(--kx-ink); }
.kx-vs-best-v { margin-left: auto; font-size: .84rem; }

.kx-vs-hold { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--kx-line); }
.kx-vs-hold-h {
  display: flex; align-items: baseline; gap: 7px; margin-bottom: 4px;
  font: 600 .6rem/1 var(--kx-font); letter-spacing: .06em;
  text-transform: uppercase; color: #9fb6d8;
}
.kx-vs-hold-h .dim { text-transform: none; letter-spacing: 0; font-weight: 400; }
.kx-vs-hr {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 0; text-decoration: none; color: var(--kx-ink);
  border-bottom: 1px solid rgba(255, 255, 255, .04);
}
.kx-vs-hr:last-of-type { border-bottom: 0; }
.kx-vs-hs {
  flex: 1 1 auto; min-width: 0; font-size: .76rem; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kx-vs-hv { flex: 0 0 auto; font-size: .78rem; }
/* La pastille de temps se resserre : dans une ligne de holding elle accompagne,
   elle ne domine pas. */
.kx-vs-hr .kx-lt { flex: 0 0 auto; padding: .12rem .45rem; font-size: .56rem; }
.kx-vs-hr .kx-lt b { font-size: .58rem; }
.kx-vs-more {
  display: block; margin-top: 8px;
  font: 600 .7rem/1 var(--kx-font); color: var(--kx-accent); text-decoration: none;
}
@media (prefers-reduced-motion: reduce) { .kx-vs-tab { transition: none; } }

/* ── LA FAQ D'UNE COMPARAISON ────────────────────────────────────────────────
   Des `<details>` et pas un accordéon en JavaScript : le contenu est dans le
   HTML, lisible avant qu'un script ne charge, et trouvable par la recherche du
   navigateur même replié. */
.kx-faq { margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--kx-line); }
.kx-faq h3 { font-size: .8rem; font-weight: 700; margin: 0 0 10px; color: var(--kx-ink-2); }
.kx-faq-q { border-bottom: 1px solid rgba(255, 255, 255, .05); }
.kx-faq-q:last-child { border-bottom: 0; }
.kx-faq-q > summary {
  display: flex; align-items: center; gap: 8px;
  padding: 11px 0; min-height: 44px;
  font-size: .8rem; font-weight: 600; color: var(--kx-ink-2);
  cursor: pointer; list-style: none;
}
.kx-faq-q > summary::-webkit-details-marker { display: none; }
.kx-faq-q > summary::marker { content: ''; }
/* Le chevron est dessiné en CSS : une icône de plus dans le jeu pour un seul
   usage se paie en octets sur toutes les pages. */
.kx-faq-q > summary::after {
  content: ''; margin-left: auto; flex: 0 0 auto;
  width: 7px; height: 7px;
  border-right: 2px solid var(--kx-faint); border-bottom: 2px solid var(--kx-faint);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform .15s;
}
.kx-faq-q[open] > summary::after { transform: rotate(-135deg) translate(-2px, -2px); }
.kx-faq-q > p {
  font-size: .78rem; line-height: 1.7; color: var(--kx-ink-3);
  margin: 0 0 12px; max-width: 68ch;
}
.kx-faq-q b { color: var(--kx-ink-2); }
@media (prefers-reduced-motion: reduce) { .kx-faq-q > summary::after { transition: none; } }

/* ── Les trois classements de la page token (member/token.php) ─────────────
 * « Top KOLs by PnL », « Still holding », « Biggest volume » : QUATRE cartes
 * au plus par bloc, en grille — pas de défilement. Quatre colonnes, deux sur
 * téléphone. `minmax(0, 1fr)` : sans lui, un nom long imposerait sa largeur à
 * la colonne et la grille déborderait. Les chiffres viennent de `positionFrom()`. */
.kx-tt-row { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
@media (max-width: 600px) { .kx-tt-row { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.kx-tt {
  position: relative;               /* le texte invisible (`.kx-sr`) se rattache à SA carte */
  min-width: 0;
  display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
  padding: 14px; border-radius: 14px;
  border: 1px solid rgba(255,255,255,.06); background: rgba(0,0,0,.18);
  color: var(--kx-ink); text-decoration: none;
}
.kx-tt:hover { border-color: rgba(255,255,255,.14); }
.kx-tt .av { width: 34px; height: 34px; margin-bottom: 4px; }
.kx-tt-n { font-weight: 700; font-size: .86rem; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kx-tt-v { font-weight: 700; font-size: .95rem; display: flex; align-items: center; flex-wrap: wrap; gap: 4px 6px; }
/* Achat, vente, multiple, sous le réalisé de « Top KOLs by PnL ». */
.kx-tt-stats { display: flex; flex-wrap: wrap; gap: 2px 8px; font-size: .68rem; font-weight: 600; color: var(--kx-ink-2); }
.kx-tt-s { font-size: .74rem; font-weight: 600; margin-top: -2px; }
.kx-tt-m { font-size: .68rem; color: var(--kx-ink-3); }
/* ── « KOLs traded this token » (member/token.php, #wallets) ─────────────────
 * Une ligne par trader : en tête le nom, le wallet (bouton de copie), le PnL
 * total et la part détenue ; dessous, dix mesures en grille — cinq colonnes,
 * trois sur téléphone. `.kx-wr-vue` teinte les traders que l'on suit. */
.kx-wr { padding: 16px 18px; border-top: 1px solid rgba(255,255,255,.05); }
/* Les teintes (voir `TOK_TEINTES`, member/token.php) : un DÉGRADÉ de gauche à
 * droite, qui s'éteint vers le milieu de la ligne. Une teinte par ligne.
 *
 * CALÉES AU PIXEL SUR LA MAQUETTE. Mesurée sur le même fond de carte
 * (19,26,42) : la ligne suivie y vaut (19,38,56) au bord gauche, (19,32,49) à
 * 31 %, (19,28,43) à 50 %, le fond pur à 55 % — soit du cyan à 6,5 % qui tombe
 * à zéro à 55 %. La première version montait à 14 % et durait jusqu'au bord
 * droit : (20,52,72) à gauche, deux fois trop franc.
 *
 * Les trois autres couleurs ont la MÊME force apparente, pas la même opacité :
 * chaque alpha éclaircit le fond d'environ 10 points de luminance, comme le
 * cyan de la maquette (le vert est plus lumineux, il en demande moins). */
.kx-wr-vue   { background: linear-gradient(90deg, rgba(25,212,255,.065),  transparent 55%); }
.kx-wr-live  { background: linear-gradient(90deg, rgba(167,139,250,.075), transparent 55%); }
.kx-wr-gagne { background: linear-gradient(90deg, rgba(25,255,115,.057),  transparent 55%); }
.kx-wr-perd  { background: linear-gradient(90deg, rgba(255,128,128,.075), transparent 55%); }
/* La légende : une pastille du même dégradé, et le nom de la teinte. */
.kx-wr-legende { display: flex; flex-wrap: wrap; gap: 4px 14px; margin: 2px 0 8px; font-size: .64rem; color: var(--kx-ink-3); }
.kx-wr-legende span { display: inline-flex; align-items: center; gap: 6px; }
.kx-wr-pastille { display: inline-block; width: 18px; height: 10px; border-radius: 3px; border: 1px solid rgba(255,255,255,.1); }
/* L'en-tête d'une ligne, sur UNE rangée : nom · adresse + Copy wallet ·
 * badge · (vide) · PnL. Le nom peut rétrécir (ellipse), jamais l'adresse ni
 * le bouton. Sur téléphone, l'adresse passe sous le nom, alignée sur lui. */
.kx-wr-tete {
  display: grid; grid-template-columns: minmax(0, max-content) auto auto minmax(0, 1fr) auto;
  align-items: center; column-gap: 12px;
}
.kx-wr-qui { grid-column: 1; grid-row: 1; position: relative; display: flex; align-items: center; gap: 12px;
  min-width: 0; color: var(--kx-ink); text-decoration: none; }
.kx-wr-adr { grid-column: 2; grid-row: 1; display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
.kx-wr-code { font: .68rem/1.4 ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--kx-ink-3);
  white-space: nowrap; }
.kx-wr-copy { flex: 0 0 auto; min-height: 28px; padding: 0 10px; font-size: .64rem; white-space: nowrap; }
.kx-wr-qui .av { width: 34px; height: 34px; flex: 0 0 34px; }
.kx-wr-nom { font-weight: 700; font-size: .95rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kx-wr-qui:hover .kx-wr-nom { color: var(--kx-accent); }
.kx-wr-badge { grid-column: 3; grid-row: 1; font-size: .64rem; font-weight: 700; white-space: nowrap;
  color: var(--kx-accent); background: rgba(25,212,255,.12); border-radius: 999px; padding: 2px 8px; }
.kx-wr-droite { grid-column: 5; grid-row: 1; display: flex; flex-direction: column; align-items: flex-end; }
.kx-wr-pnl { font-size: 1.05rem; font-weight: 800; }
.kx-wr-etat { font-size: .68rem; color: var(--kx-accent); }
/* Share partage la rangée de Copy wallet, à la même taille (28 px). */
.kx-wr-adr .kx-share { min-height: 28px; padding: 0 10px; font-size: .64rem; }
/* Téléphone : nom et badge en haut, l'adresse et « Copy wallet » dessous,
   alignés sur le nom (46 px = avatar + écart). Après les règles de colonnes
   ci-dessus, sinon elles l'emportent à spécificité égale. */
@media (max-width: 600px) {
  .kx-wr-tete   { grid-template-columns: minmax(0, max-content) auto minmax(0, 1fr) auto; row-gap: 6px; }
  .kx-wr-badge  { grid-column: 2; }
  .kx-wr-adr    { grid-column: 1 / -1; grid-row: 2; margin-left: 46px; flex-wrap: wrap; }
  .kx-wr-droite { grid-column: 4; }
}
.kx-wr-grille { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 10px 14px; margin-top: 12px; }
@media (max-width: 600px) { .kx-wr-grille { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.kx-wr-c { min-width: 0; }
.kx-wr-l { display: block; font-size: .58rem; letter-spacing: .06em; text-transform: uppercase; color: var(--kx-ink-3); }
.kx-wr-v { display: block; font-size: .84rem; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.kx-wr-ouvert { color: var(--kx-accent); }
/* Les pastilles de la légende : le même dégradé, en plus soutenu — sur 18 px,
   celui des lignes s'éteint avant d'avoir montré sa couleur. */
.kx-wr-pastille.kx-wr-vue   { background: linear-gradient(90deg, rgba(25,212,255,.75),  rgba(25,212,255,.2)); }
.kx-wr-pastille.kx-wr-live  { background: linear-gradient(90deg, rgba(167,139,250,.8),  rgba(167,139,250,.2)); }
.kx-wr-pastille.kx-wr-gagne { background: linear-gradient(90deg, rgba(25,255,115,.7),   rgba(25,255,115,.18)); }
.kx-wr-pastille.kx-wr-perd  { background: linear-gradient(90deg, rgba(255,128,128,.75), rgba(255,128,128,.2)); }
.kx-wr-legende .kx-wr-absente { opacity: .45; }
/* ── « Trade History » de la fiche KOL, au format « Latest trades » ──────────
 * Une ligne : logo, $SYMBOLE et « Entry MC · il y a », puis le PnL et l'état en
 * capitales (OPEN en accent, CLOSED en gris) ; Share en icône seule au bout.
 * La pastille dorée de l'en-tête est `.kx-lt` (`kxDernierTrade()`). */
.kx-ptr-h { align-items: center; }
.kx-ptr { display: flex; align-items: center; gap: 10px; padding: 12px 18px;
  border-top: 1px solid rgba(255,255,255,.05); }
.kx-ptr-main { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: 12px;
  color: var(--kx-ink); text-decoration: none; }
.kx-ptr-main:hover .kx-ptr-sym { color: var(--kx-accent); }
.kx-ptr-id { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.kx-ptr-sym { font-weight: 800; font-size: .95rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kx-ptr-meta { font-size: .72rem; color: var(--kx-ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kx-ptr-r { flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-end; gap: 3px; }
.kx-ptr-pnl { font-size: 1.05rem; font-weight: 800; }
.kx-ptr-etat { font-size: .6rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--kx-ink-3); }
.kx-ptr-etat.ouvert { color: var(--kx-accent); }
.kx-ptr-meta b { color: var(--kx-ink-2); font-weight: 700; }
.kx-ptr-sous { display: inline-flex; align-items: baseline; gap: 8px; }
.kx-ptr-mult { font-size: .74rem; font-weight: 700; }
.kx-ptr-mult small { font-size: .6rem; color: var(--kx-ink-3); font-weight: 600; }
/* « Alert me only on big trades » (29/09), sous les filtres de Trade History. */
.kx-ptr-alerte { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin: 12px 0 0; }
/* `inline-flex` : pour un visiteur ce bouton est un `<a>`, et un élément EN
   LIGNE ignore `min-height` — le texte débordait du cadre (capture du 29/09). */
.kx-ptr-alerte-b { display: inline-flex; align-items: center; justify-content: center; text-align: center;
  min-height: 36px; padding: 6px 14px; font-size: .76rem; line-height: 1.25; text-decoration: none; }
.kx-ptr-alerte-on { font-size: .76rem; font-weight: 600; color: var(--kx-accent); }
.kx-ptr-alerte-x { background: none; border: 0; padding: 0; cursor: pointer;
  font: 600 .7rem/1.4 var(--kx-font); color: var(--kx-ink-3); text-decoration: underline; }
.kx-ptr-alerte-x:hover { color: var(--kx-ink); }
.kx-ptr-alerte-n { font-size: .7rem; }
a.kx-ptr-alerte-n { color: var(--kx-accent); font-weight: 600; }
/* Position ouverte : ce qui est encaissé et ce qui reste en jeu (29/09). */
.kx-ptr-split { font-size: .64rem; color: var(--kx-ink-3); white-space: nowrap; }
/* Téléphone (capture du 29/09) : la colonne de droite écrasait la gauche, et
   « Bought $1.4K · held … » était coupé après six caractères. La ligne de
   détail passe à la ligne au lieu de se couper, la colonne de droite se
   resserre et ses deux sous-lignes peuvent se replier. */
@media (max-width: 600px) {
  .kx-ptr { padding: 12px 14px; gap: 8px; }
  .kx-ptr-main { gap: 10px; align-items: flex-start; }
  .kx-ptr-meta { white-space: normal; overflow: visible; line-height: 1.45; }
  .kx-ptr-r { max-width: 46%; }
  .kx-ptr-pnl { font-size: .98rem; }
  .kx-ptr-split, .kx-ptr-sous { white-space: normal; text-align: right; justify-content: flex-end; flex-wrap: wrap; }
}
.kx-ptr-split .kx-num { font-size: inherit; font-weight: 700; }
.kx-ptr .kx-share { flex: 0 0 auto; padding: 0 9px; }
/* ── L'encart « alerte Telegram » de la fiche KOL (visiteur) ─────────────────
 * D'après la maquette : une carte au bord fin, une pastille ronde aux couleurs
 * de Telegram, le titre, deux lignes, et le bouton or du site (`.kx-btn-gold`)
 * sur toute la largeur. */
.kx-tgpromo {
  margin-bottom: 16px; padding: 18px 20px 16px; border-radius: var(--kx-r-card);
  border: 1px solid var(--kx-line-2); background: var(--kx-panel); box-shadow: var(--kx-sh-panel);
}
.kx-tgpromo-h { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.kx-tgpromo-h h2 { margin: 0; font-size: 1rem; font-weight: 700; line-height: 1.3; }
.kx-tgpromo-ic {
  flex: 0 0 32px; width: 32px; height: 32px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, #37bbfe, #1d93d2); color: #fff; font-size: .9rem;
}
.kx-tgpromo-ic .kxi { transform: translateX(-1px); }
.kx-tgpromo p { margin: 0 0 16px; font-size: .84rem; line-height: 1.6; color: var(--kx-ink-2); }
.kx-tgpromo-cta { display: flex; width: 100%; font-weight: 700; }
.kx-tgpromo .kx-tgpromo-s { margin: 10px 0 0; font-size: .74rem; text-align: center; color: var(--kx-ink-3); }
.kx-tgpromo-s a { color: var(--kx-accent); font-weight: 600; }
