/* =====================================================================
   app.pavapi.com — le système solaire des coffres.
   ===================================================================== */

.solar-hero{padding:24px 0 56px; border-top:none;}
.solar-title{
  font-size:clamp(2rem,4.4vw,3.1rem); line-height:1.08; letter-spacing:-0.02em;
  margin:0 0 20px; text-align:center;
}
.solar-sub{
  color:var(--paper-dim); font-size:1rem; line-height:1.7;
  max-width:56ch; margin:0 auto; text-align:center;
}

/* Le badge de galaxie vit maintenant juste au-dessus du champ de planètes,
   pas au-dessus du titre : c'est CE groupe de planètes qu'il nomme, pas la
   page entière. Marge haute et basse généreuses pour bien le détacher du
   texte d'intro et de la première planète. */
.galaxy-tag{
  display:flex; align-items:center; justify-content:center; gap:8px;
  font-family:var(--mono); font-size:.76rem; letter-spacing:.06em; text-transform:uppercase;
  color:var(--paper-dim); margin:56px 0 8px;
}
/* La première galaxie n'a rien au-dessus d'elle que le header : la marge de
   56px, pensée pour détacher une galaxie de la précédente, n'a plus lieu
   d'être une fois qu'il n'y a plus de titre de page entre les deux. */
.galaxy:first-child .galaxy-tag{margin-top:28px;}
.galaxy-tag .dot{width:6px; height:6px; border-radius:50%; background:var(--gold); box-shadow:0 0 8px var(--gold);}

/* Une phrase sous le badge : ce qui distingue cette galaxie des autres. Sans
   elle, « Galaxie EURO » ne dirait que la monnaie, pas pourquoi ses taux sont
   plus bas — et un visiteur lirait l'écart avec le dollar comme une
   contre-performance de pavapi plutôt que comme un écart de taux directeur. */
.galaxy-note{
  display:block; max-width:52ch; margin:0 auto; text-align:center;
  color:var(--paper-faint); font-size:.86rem; line-height:1.6;
}

/* ---------------------------------------------------------------------
   En-tête de galaxie
   Un simple bandeau, pas un bouton : il n'y a plus de caméra à déclencher,
   chaque planète est déjà son propre lien vers son coffre.
   --------------------------------------------------------------------- */
.galaxy-head{ display:block; width:100%; }

/* Le détail : masqué au repos, découvert au survol ou au focus clavier —
   le remplaçant léger de l'ancien zoom, sans caméra ni geste à apprendre. */
.asset-node .pn-detail{
  display:none; flex-direction:column; align-items:center; gap:5px; margin-top:4px;
  animation:detail-in .35s cubic-bezier(.25,.46,.45,.94) both;
}
.asset-node:hover .pn-detail, .asset-node:focus-visible .pn-detail{display:flex;}
@keyframes detail-in{from{opacity:0; transform:translateY(-4px);} to{opacity:1; transform:none;}}
.asset-node .pn-top{
  font-size:clamp(.66rem, calc(var(--size,120px) * .0085), .78rem);
  color:var(--paper-dim);
}
.asset-node .pn-chains{display:flex; gap:5px; align-items:center;}
.asset-node .pn-chain{width:16px; height:16px; display:inline-flex;}
.asset-node .pn-chain .logo-img{width:100%; height:100%; border-radius:50%; object-fit:cover;}
.asset-node .pn-chain .logo-img.glyph{border-radius:0; object-fit:contain; background:none;}
.asset-node .pn-chain svg{width:100%; height:100%; color:var(--paper-dim);}
.asset-node .pn-chain .logo-init{font-family:var(--mono); font-size:.5rem; color:var(--paper-faint);}

/* `.galaxy` est une <section>, qui porte par défaut (app.css) 70px de
   padding et un filet en haut — pensés pour les sections d'une page de
   coffre, pas pour un champ de planètes collé sous le header. On repart de
   zéro ici, puis chaque galaxie SAUF la première regagne un filet : de quoi
   voir qu'on change de famille d'actifs avant même de lire le badge, sans
   que la première n'en porte un contre le header.

   Le padding HORIZONTAL, lui, reste : `#galaxies` n'est pas posé dans un
   `.wrap` comme le reste du site (la scène a besoin de toute la largeur
   disponible, jusqu'à 1600px), donc rien d'autre ne tient `.solar-stage` à
   distance du bord de la fenêtre. Sans cette marge, une planète tirée près
   du bord de l'ellipse (voir `sampleInEllipse`, root.js) vient carrément
   toucher le bord de l'ÉCRAN, pas seulement le bord de sa scène — le système
   entier a alors l'air posé de travers plutôt que centré, sur toute fenêtre
   plus étroite que 1600px, donc la plupart des écrans réels. */
.galaxy{padding:0 32px; border-top:none;}
.galaxy + .galaxy{border-top:1px solid var(--line); padding-top:8px;}

/* `.galaxy-scene` porte le centrage et la largeur maximale que `.solar-stage`
   portait seul avant l'arrivée du bot : la scène ET le vaisseau doivent
   grandir et se centrer ensemble, pas l'un sans l'autre. */
.galaxy-scene{
  position:relative; display:flex; align-items:stretch; gap:28px;
  width:100%; max-width:1600px; margin:24px auto 88px;
}
/* ---------------------------------------------------------------------
   Les actifs de la galaxie, à sa gauche.

   Cette liste occupait une section entière de la page d'accueil, loin des
   systèmes qu'elle décrit : il fallait se souvenir d'un chiffre en
   descendant vers l'autre. Posée ici, elle se lit EN MÊME TEMPS que le
   système — le tableau à gauche, les planètes au centre, le meilleur marché
   à droite disent la même galaxie de trois façons.

   Les styles de ligne (`.asset-row`, `.ar-*`) restent ceux de landing.css,
   que cette page charge déjà : une seconde définition finirait par diverger
   de la première.
   --------------------------------------------------------------------- */
.galaxy-assets{
  position:relative; z-index:10; flex:0 0 clamp(300px, 26vw, 420px);
  /* Une hauteur bornée, sinon une galaxie de douze actifs étire la section
     bien au-delà de son système et la scène perd son équilibre. Au-delà,
     on fait défiler la liste, pas la page. */
  align-self:center;
  padding:6px; border:1px solid var(--line-strong); border-radius:16px;
  background:rgba(20,17,15,.55); backdrop-filter:blur(6px);
}

/* L'en-tête du repli : ce qu'on voit quand tout est fermé. Il porte déjà le
   chiffre qui compte — le meilleur rendement de la galaxie — pour que
   replier ne coûte aucune information décisive. */
.ga-summary{
  display:flex; align-items:center; gap:10px;
  padding:9px 10px; border-radius:11px; cursor:pointer;
  list-style:none; user-select:none;
  transition:background .15s cubic-bezier(.25,.46,.45,.94);
}
.ga-summary::-webkit-details-marker{display:none;}
.ga-summary:hover{background:rgba(242,237,230,.045);}
.ga-sum-label{flex:1; min-width:0; font-size:.82rem;}
.ga-sum-figures{display:flex; align-items:baseline; gap:8px; white-space:nowrap;}
.ga-sum-figures b{font-size:.92rem;}
.ga-sum-figures .dim{font-size:.68rem;}
.ga-chev{
  color:var(--paper-faint); font-size:.7rem; flex:0 0 auto;
  transition:transform .2s cubic-bezier(.25,.46,.45,.94);
}
.ga-fold[open] .ga-chev{transform:rotate(180deg);}

/* Le défilement est porté par la liste ouverte, pas par le panneau : replié,
   le panneau doit faire la hauteur de son seul en-tête. */
.ga-rows{
  max-height:min(64vh, 560px); overflow-y:auto;
  display:flex; flex-direction:column; gap:2px;
  margin-top:4px;
}
/* La grille à cinq colonnes de landing.css était dessinée pour un tableau
   pleine largeur ; dans une colonne de 400 px elle écrase tout — « aucun
   marché ne passe le filtre » s'y empilait sur six lignes. Ici la ligne se
   relit sur DEUX rangées : l'actif et son taux d'abord, ce qui les explique
   ensuite. Même contenu, même ordre de lecture, une autre mise en page.

   Aucune couleur, aucune taille de police n'est redéfinie : seuls la grille
   et les espacements changent. Ce qui identifie un actif reste ce qu'il est
   sur la vitrine. */
.galaxy-assets .asset-row{
  --d:0ms;
  /* La colonne de droite est bornée : sans plancher ni plafond, un
     sous-titre long ('aucun marché ne passe le filtre') la faisait gonfler
     jusqu'à manger la moitié de la ligne. */
  grid-template-columns:minmax(0,1fr) minmax(64px, 96px);
  grid-template-areas:'id apy' 'venue num';
  gap:4px 12px; padding:11px 10px;
  border-radius:10px;
}
.galaxy-assets .asset-row:hover{background:rgba(242,237,230,.045);}
.galaxy-assets .ar-id{grid-area:id; gap:10px;}
.galaxy-assets .ar-apy-cell{grid-area:apy; text-align:right;}
.galaxy-assets .ar-venue{grid-area:venue;}
.galaxy-assets .ar-num-cell{grid-area:num; text-align:right;}
/* La flèche disait « cette ligne est un lien » dans un tableau large où le
   clic n'était pas évident. Dans un panneau serré elle vole une colonne
   entière pour redire ce que le survol montre déjà. */
.galaxy-assets .ar-go{display:none;}

.galaxy-assets .ar-mark{width:28px; height:28px;}
.galaxy-assets .ar-sym{font-size:.9rem;}
.galaxy-assets .ar-name{font-size:.68rem; margin-top:1px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
.galaxy-assets .ar-apy{font-size:1.05rem;}
.galaxy-assets .ar-sub{font-size:.66rem; margin-top:1px;}
.galaxy-assets .ar-venue{font-size:.72rem; line-height:1.35; color:var(--paper-dim);}
.galaxy-assets .ar-num{font-size:.8rem;}
.galaxy-assets .ar-chains{margin-top:4px; justify-content:flex-end;}
.galaxy-assets .ar-chain{width:14px; height:14px;}

/* Le sous-titre du taux ('sans commission', 'aucun marché ne passe le
   filtre') redit ce que la colonne de droite chiffre déjà — « 0 retenus
   sur 0 ». Dans un panneau serré, il coûte une ligne pour rien. */
.galaxy-assets .ar-apy-cell .ar-sub{display:none;}

/* L'en-tête nommait cinq colonnes ; il n'y en a plus cinq. */
.galaxy-assets .asset-row.head{display:none;}

/* En dessous de la largeur où les trois colonnes tiennent, la scène passe
   en pile : la liste vient AVANT le système, parce qu'elle est ce qu'on
   vient lire ; le système, lui, se regarde. */
@media(max-width:1100px){
  .galaxy-scene{flex-direction:column;}
  .galaxy-assets{flex:0 0 auto; width:100%; align-self:stretch;}
  /* Sur petit écran la liste ouverte ne doit pas non plus manger la page :
     un peu plus de la moitié de la hauteur visible, puis elle défile. */
  .ga-rows{max-height:56vh;}
}

.solar-stage{
  position:relative; flex:1 1 auto; min-width:0; aspect-ratio:16/10;
  z-index:1;
}
.solar-stage canvas{position:absolute; inset:0; width:100%; height:100%;}
/* Page de dépôt d'un bot (bot.js) : une scène sans corps ni canevas — le
   bot n'y tient jamais qu'UN actif à la fois, affiché en texte dans `.gbot`
   plutôt qu'en planète. Une lueur douce, à la teinte de l'actif tenu
   (`--asset`, mis à jour par `renderDepositTarget`), évite que la scène ne
   paraisse vide plutôt que délibérément sobre. */
html[data-galaxy] .solar-stage{
  background:radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--asset,#E4B767) 16%, transparent), transparent 68%);
}

/* ---------------------------------------------------------------------
   Le bot de dépôt — un panneau texte à côté de la scène, et un vaisseau qui
   vole EN PERMANENCE au-dessus de la planète qu'il tient, posé DANS le
   `.solar-stage` pour partager le système de coordonnées des planètes
   (`--px`/`--py`, voir `placeNode` dans root.js et `positionShip` dans
   ui/galaxybot.js). `left`/`top` transitionnent (le trajet, aussi rare qu'il
   ait lieu, quand le bot bascule de planète) ; `gbot-hover` fait le survol
   continu par-dessus, sur `transform` — les deux animations ne se marchent
   jamais dessus, chacune sa propriété.
   --------------------------------------------------------------------- */
.gbot-shipfloat{
  position:absolute; z-index:6; left:50%; top:50%;
  width:72px; height:72px; margin-left:-36px; margin-top:-36px;
  color:#C97A3D; opacity:0; pointer-events:none;
  filter:drop-shadow(0 0 16px rgba(201, 122, 61, 0.6)) drop-shadow(0 0 24px rgba(228, 183, 103, 0.4));
  transition:left .9s cubic-bezier(.25,.46,.45,.94), top .9s cubic-bezier(.25,.46,.45,.94);
  will-change:transform, opacity;
  backface-visibility:hidden;
}
.gbot-shipfloat svg{width:100%; height:100%;}
/* Deux animations, deux propriétés : `gbot-hover` fait voler le vaisseau
   (transform), `gbot-blink` le fait clignoter (opacity) — jamais la même
   image-clé pour les deux, sans quoi l'une écraserait l'autre. */
.gbot-shipfloat.on{animation:gbot-hover 3.6s cubic-bezier(.25,.46,.45,.94) infinite, gbot-blink 1.1s cubic-bezier(.25,.46,.45,.94) infinite;}
.gbot-shipfloat.paused{animation-play-state:paused;}
@media(prefers-reduced-motion:reduce){ .gbot-shipfloat.on{animation:gbot-hover-still 0s forwards;} }
@keyframes gbot-hover-still{ to{ opacity:1; transform:translate(calc(-50% + var(--off-x,30px)), calc(-50% + var(--off-y,-16px))); } }
@keyframes gbot-hover{
  0%,100%{transform:translate(calc(-50% + var(--off-x,30px)), calc(-50% + var(--off-y,-16px))) rotate(-7deg);}
  50%{transform:translate(calc(-50% + var(--off-x,30px)), calc(-50% + var(--off-y,-22px))) rotate(7deg);}
}
@keyframes gbot-blink{
  0%,100%{opacity:1;}
  50%{opacity:.45;}
}

.gbot{
  position:relative; z-index:10; flex:0 0 240px; align-self:center;
  display:flex; flex-direction:column; gap:12px;
  padding:18px; border:1px solid var(--line-strong); border-radius:16px;
  background:rgba(20,17,15,.55); backdrop-filter:blur(6px);
}
.gbot-head{display:flex; align-items:center; gap:10px;}
.gbot-ship{
  width:34px; height:34px; flex-shrink:0; color:#C97A3D;
  filter:drop-shadow(0 0 8px rgba(228,183,103,.5));
}
.gbot-ship svg{width:100%; height:100%;}
.gbot-title{display:flex; flex-direction:column; gap:2px; min-width:0;}
.gbot-title b{font-size:.88rem;}
.gbot-sim{font-family:var(--mono); font-size:.62rem; letter-spacing:.03em; color:var(--paper-faint);}

/* ---------------------------------------------------------------------
   L'esquisse de chargement.

   Les marchés d'une galaxie arrivent d'une dizaine de flux, et le premier
   chiffre ne peut pas s'afficher avant que les plus lents aient répondu.
   Une phrase figée pendant ce temps ne dit pas si la page travaille ou si
   elle est bloquée. Une esquisse animée le dit — et comme elle a EXACTEMENT
   la structure du panneau rempli, le remplissage ne fait pas sauter la mise
   en page quand il survient.

   Le mouvement est une seule propriété, `background-position`, sur un
   dégradé : rien à recalculer, rien à repeindre hors de la boîte.
   --------------------------------------------------------------------- */
.gbot-skel{display:flex; flex-direction:column; gap:8px; width:100%;}
.gbot-skel-head{display:flex; align-items:center; gap:10px;}
.gbot-skel .sk-lines{display:flex; flex-direction:column; gap:5px; flex:1; min-width:0;}
.gbot-skel-rows{display:flex; flex-direction:column; gap:6px; margin-top:4px;}
.gbot-skel-row{display:grid; grid-template-columns:minmax(58px,auto) minmax(0,1fr) auto; align-items:center; gap:8px;}

.sk{
  display:block; height:9px; border-radius:4px;
  background:linear-gradient(90deg,
    rgba(242,237,230,.045) 0%, rgba(242,237,230,.045) 35%,
    rgba(242,237,230,.11)  50%,
    rgba(242,237,230,.045) 65%, rgba(242,237,230,.045) 100%);
  background-size:280% 100%;
  animation:sk-sweep 1.5s cubic-bezier(.4,0,.6,1) infinite;
}
.sk-disc{width:34px; height:34px; border-radius:50%; flex:0 0 auto;}
.sk-btn{height:34px; border-radius:8px; margin-top:2px;}
.sk-chip{width:52px; height:11px;}
.sk-rail{height:5px;}
.sk-val{width:var(--w,44%); height:9px; justify-self:end;}

@keyframes sk-sweep{ from{background-position:120% 0;} to{background-position:-120% 0;} }

/* Préférence « moins d'animations » : l'esquisse reste, immobile. Elle dit
   toujours la forme de ce qui arrive ; c'est le balayage qui disparaît. */
@media(prefers-reduced-motion:reduce){ .sk{animation:none;} }

.gbot-position{display:flex; align-items:center; gap:10px; min-height:32px;}
.gbot-position .faint{font-size:.8rem; color:var(--paper-faint);}
.gbot-mark{
  width:30px; height:30px; flex-shrink:0; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  background:radial-gradient(circle at 32% 28%, var(--c), rgba(0,0,0,.62) 72%);
  box-shadow:0 0 0 1px rgba(242,237,230,.14), 0 0 12px -3px var(--c);
}
.gbot-mark .logo-img{width:100%; height:100%; border-radius:50%; object-fit:cover;}
.gbot-mark .logo-img.glyph{width:70%; height:70%; border-radius:0; object-fit:contain; background:none;}
.gbot-what{display:flex; flex-direction:column; gap:1px; font-size:.78rem; min-width:0;}
.gbot-what b{font-size:.86rem;}
/* La surbrillance du bot : le dégradé du vaisseau, écrit dans le texte. Une
   seule déclaration pour les deux endroits qui la portent — le panneau
   (`.gbot-apy`) et l'étiquette de la planète tenue (`.planet-node.bot-position
   .pn-apy`) —, sinon les deux dérivent et la planète cesse de se lire comme
   « c'est celle-là que le bot tient ».

   `@supports` : sans `background-clip:text`, le texte transparent serait
   INVISIBLE. Le dégradé n'est donc posé que là où il peut être découpé ;
   partout ailleurs, l'or plein du vaisseau prend le relais.

   Animation de défilement des 3 couleurs du logo pavapi */
@keyframes pavapi-gradient{
  0%{background-position:0% 50%}
  50%{background-position:100% 50%}
  100%{background-position:0% 50%}
}
.gbot-apy, .planet-node.bot-position .pn-apy{ color:#E4B767; }
@supports ((background-clip:text) or (-webkit-background-clip:text)){
  .gbot-apy, .planet-node.bot-position .pn-apy{
    background:linear-gradient(135deg,#C97A3D,#E4B767,#4FA8A0,#C97A3D);
    background-size:300% 300%;
    -webkit-background-clip:text; background-clip:text;
    -webkit-text-fill-color:transparent; color:transparent;
    animation:pavapi-gradient 4s ease infinite;
  }
}
.gbot-apy{font-family:var(--mono); font-size:.82rem; animation:gbot-blink 1.1s ease-in-out infinite;}

/* Mène à la même page qu'un clic sur la planète tenue (voir root.js) : le
   vrai dépôt, pas simulé, se fait là — ce bouton n'est qu'un raccourci. */
.gbot-deposit-btn{
  display:block; width:100%; text-align:center; box-sizing:border-box;
  padding:9px 14px; font-size:.82rem;
}

.gbot-reason{
  margin:0; font-size:.74rem; line-height:1.5; color:var(--paper-dim);
}

/* ---------------------------------------------------------------------
   Le meilleur rendement par chaîne — le graphique sur lequel se joue le
   choix du port d'attache du bot.

   EMPHASE, pas série catégorielle : une seule teinte pour toutes les
   barres, l'or pour la chaîne où le bot travaille. Une couleur par chaîne
   aurait dépensé le seul canal libre à redire ce que la longueur dit déjà,
   et l'or et le vert du site ne se distinguent pas sous deutéranopie
   (ΔE 7,8). La couleur ne porte donc jamais seule : nom, logo et valeur
   exacte sont écrits sur chaque ligne.
   --------------------------------------------------------------------- */
.gbot-chains{display:flex; flex-direction:column; gap:6px; margin-bottom:2px;}
/* Le montant de dépôt : ce n'est pas un réglage de confort, c'est LA
   variable du calcul. Les mêmes 0,35 $ de frais coûtent 1,05 point de
   rendement sur 100 $ déposés et 0,01 point sur 10 000 $ — cacher ce choix
   dans une constante rendrait le graphique soit décoratif, soit alarmiste,
   selon le nombre choisi. Aucun des deux n'est vrai pour tout le monde. */
.gchain-notional{
  display:flex; align-items:center; flex-wrap:wrap; gap:5px;
  font-size:.66rem; color:var(--paper-faint); margin:-1px 0 1px;
}
.gchain-notional button{
  font-family:var(--mono); font-size:.64rem; color:var(--paper-dim);
  background:transparent; border:1px solid var(--line-strong); border-radius:999px;
  padding:2px 8px; cursor:pointer;
  transition:color .15s cubic-bezier(.25,.46,.45,.94), border-color .15s cubic-bezier(.25,.46,.45,.94);
}
.gchain-notional button:hover{color:var(--paper); border-color:var(--paper-faint);}
.gchain-notional button.on{color:var(--ink); background:var(--gold); border-color:var(--gold);}

.gchains{list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:4px;}
.gchain{
  display:grid; grid-template-columns:minmax(58px,auto) minmax(0,1fr) auto;
  align-items:center; gap:8px;
}
.gchain-id{
  display:flex; align-items:center; gap:5px; min-width:0;
  font-size:.68rem; color:var(--paper-dim);
}
.gchain-id > span{overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
/* `markContent('chain', …)` pose la même vignette que la rangée des frais. */
.gchain-id .logo-img, .gchain-id svg{width:13px; height:13px; flex:0 0 auto; border-radius:50%; object-fit:cover;}
.gchain-id .logo-img.glyph{border-radius:0; object-fit:contain; background:none;}
.gchain-id .logo-init{
  width:13px; height:13px; flex:0 0 auto; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  font-family:var(--mono); font-size:.5rem; color:var(--paper-faint);
  background:var(--surface-3);
}

/* L'axe : une règle discrète, du minimum au maximum affichés. Ce n'est
   PAS une barre — rien ne se remplit depuis une origine. Le point seul
   porte la valeur, ce qui autorise l'échelle bornée sans mentir sur les
   proportions ; les deux bouts sont écrits sous le graphique. */
.gchain-track{
  position:relative; height:11px; align-self:center;
}
.gchain-track::before{
  content:''; position:absolute; left:0; right:0; top:50%;
  height:1px; background:rgba(242,237,230,.09);
}
.gchain-track i{
  position:absolute; top:50%; width:9px; height:9px; border-radius:50%;
  margin:-4.5px 0 0 -4.5px;
  background:var(--copper);
  /* Un anneau de la couleur du fond détache le point de la règle et des
     points voisins quand deux chaînes paient presque pareil. */
  box-shadow:0 0 0 2px var(--surface-2);
  transition:left .5s cubic-bezier(.25,.46,.45,.94);
}
/* Hors échelle : les frais mangent plus qu'une année entière de rendement.
   Le point est épinglé au bord, en rouge, et sa valeur exacte reste écrite
   à droite — également en rouge. Ce n'est pas la couleur seule qui le dit :
   la position au bord et le nombre négatif écrit le disent aussi. Seule sa
   place sur l'axe lui est retirée, pour que les chaînes encore comparables
   le restent. */
.gchain-track.is-off i{background:var(--danger); box-shadow:0 0 0 2px var(--surface-2);}

.gchain-val{
  font-family:var(--mono); font-size:.7rem; color:var(--paper-dim);
  font-weight:400; white-space:nowrap;
}
/* Frais supérieurs à une année entière de rendement : ce n'est pas un
   détail de mise en forme, c'est le seul cas où déposer fait perdre. */
.gchain-val.neg{color:var(--danger);}

/* La chaîne du marché retenu : c'est elle, le sujet. Elle est en tête par
   construction — le classement et la sélection sortent du même chiffre. */
.gchain.is-pick .gchain-id{color:var(--paper);}
.gchain.is-pick .gchain-track i{background:var(--gold); width:11px; height:11px; margin:-5.5px 0 0 -5.5px;}
.gchain.is-pick .gchain-val{color:var(--gold);}

/* Les deux bornes de l'échelle, écrites : une échelle zoomée qui ne dit
   pas où elle commence est une échelle qui trompe. Portée par la MÊME
   grille que les lignes, sinon elle se décale sous la colonne des
   valeurs au lieu de border la règle qu'elle légende. */
.gchain-axis{margin-top:1px;}
.gchain-scale{display:flex; justify-content:space-between;}
.gchain-scale em{
  font-family:var(--mono); font-style:normal; font-size:.6rem; color:var(--paper-faint);
}

.gchain-note{
  font-size:.66rem; line-height:1.5; color:var(--paper-faint);
}
.gchain-note b{color:var(--paper-dim); font-weight:500;}

@media(prefers-reduced-motion:reduce){ .gchain-track i{transition:none;} }

.gbot-fees{display:flex; flex-direction:column; gap:6px;}
.gbot-fees-lbl{font-family:var(--mono); font-size:.62rem; letter-spacing:.04em; color:var(--paper-faint); text-transform:uppercase;}
.gbot-fees-row{display:flex; flex-wrap:wrap; gap:6px;}
.gbot-fee{
  display:flex; align-items:center; gap:5px;
  font-family:var(--mono); font-size:.66rem; color:var(--paper-dim);
  border:1px solid var(--line); border-radius:999px; padding:3px 8px 3px 3px;
}
.gbot-fee .logo-img, .gbot-fee svg{width:14px; height:14px; border-radius:50%;}
.gbot-fee.live{border-color:rgba(228,183,103,.4);}
.gbot-fee.live b{color:#C97A3D;}

/* Le panneau du bot passe SOUS la scène bien avant le mobile : posé à côté,
   il prend 240 px + 28 px de gouttière sur une largeur qui n'en a pas de
   trop. À 1024 px de fenêtre il ne laissait que ~690 px à une galaxie de
   douze planètes, et leurs étiquettes — larges et basses — finissaient par
   se recouvrir (mesuré : cinq paires par écran contre une au-delà). Sous la
   scène, il rend cette largeur à la galaxie sans rien perdre lui-même. */
@media(max-width:1150px){
  .galaxy-scene{flex-direction:column;}
  .gbot{flex-basis:auto; align-self:stretch;}
}

.planet-node{
  position:absolute; left:var(--px); top:var(--py); transform:translate(-50%,-50%);
  display:flex; flex-direction:column; align-items:center; gap:6px;
  text-decoration:none; color:inherit;
  z-index:5;
}
/* Zone de clic généreuse SANS toucher au positionnement : un `padding` +
   `margin` négatif égal semblait ne rien changer visuellement, mais un
   élément positionné en absolu place `left`/`top` sur le bord de la MARGE,
   pas du contenu — la marge négative décalait donc silencieusement l'étiquette
   de 14 px vers le haut-gauche par rapport au corps peint sur le canevas.
   Invisible sur bureau (planètes très espacées), flagrant sur mobile (grille
   serrée) : le texte semblait appartenir à la planète voisine. Un pseudo-
   élément agrandi ne participe pas au calcul de position de son parent. */
.planet-node::before{
  content:''; position:absolute; inset:-14px; border-radius:50%;
}
.planet-node:focus-visible{outline:2px solid var(--gold); outline-offset:6px;}

.asset-node{
  --c:#5FB0E0;
  /* `--i` (0,72 → 1,35) suit l'intensité posée par root.js : la même valeur
     qui éclaire le système sur le canevas fait aussi respirer son étiquette —
     plus l'APY est haut, plus le halo ET le texte sont lumineux. */
  --i:1;
  transition:transform .18s cubic-bezier(.25,.46,.45,.94);
  will-change:transform;
}
.asset-node:hover, .asset-node:focus-visible{transform:translate(-50%,-50%) scale(1.05);}
/* Boîte invisible : elle ne dessine rien (le canevas s'en charge), elle
   donne au lien sa taille et son centre. Calée sur l'étendue RÉELLE du
   système (`--span` = 2 R), pas sur `--size` qui n'échelonne que le texte. */
.asset-node .pn-body{
  width:var(--span,60px); height:var(--span,60px);
  border-radius:50%;
}
/* Le logo EST le corps : la sphère a disparu, les marchés lui tournent
   autour en satellites. Sur un système à neuf actifs, celui qu'on cherche
   se reconnaît ainsi au premier coup d'œil, avant même de lire un nom.
   Même marque que partout ailleurs sur le site (`markContent`, ui/logo.js)
   — logo réel, sinon la marque dessinée, jamais un disque vide — à
   l'échelle de son système : il grandit avec l'APY, comme l'étiquette. */
.asset-node .pn-emblem{
  position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);
  /* `--body` est le diamètre que le canevas RÉSERVE au logo au centre du
     système (LOGO_FRACTION du rayon, voir ui/planet.js) — surtout pas
     `--size`, qui sert le texte sur une plage volontairement plus large
     pour rester lisible quand le système est petit (mobile, deux colonnes).
     Un logo calé sur le texte mordrait sur la première orbite. */
  width:var(--body,44px); height:var(--body,44px);
  display:flex; align-items:center; justify-content:center;
  filter:drop-shadow(0 0 calc(7px * var(--i)) rgba(0,0,0,.55));
  pointer-events:none;
  will-change:filter,transform;
}
.asset-node .pn-emblem .logo-img{
  width:100%; height:100%; border-radius:50%; object-fit:cover;
}
/* Un logo « glyphe » (sans fond propre, ex. USDe) flotte dans le disque au
   lieu de le remplir — même distinction que partout ailleurs. */
.asset-node .pn-emblem .logo-img.glyph{
  width:76%; height:76%; margin:auto; border-radius:0; object-fit:contain;
  background:none; box-shadow:none;
  filter:drop-shadow(0 0 3px rgba(0,0,0,.7));
}
.asset-node .pn-emblem .logo-init{
  font-family:var(--mono); font-weight:600; color:var(--paper);
  font-size:clamp(.6rem, calc(var(--size,120px) * .014), 1.1rem);
}
/* L'étiquette est posée en absolu depuis le centre du système, JUSTE sous
   ses orbites (`--reach`). En la laissant dans le flux, sa hauteur entrait
   dans le calcul du centre du lien et décalait tout ; et calée sur `--size`,
   elle flottait loin sous un petit système, au point de sembler appartenir
   au voisin sur la grille mobile. */
.asset-node .pn-info{
  position:absolute; top:50%; left:50%;
  transform:translate(-50%, calc(var(--reach,24px) + 12px));
  display:flex; flex-direction:column; align-items:center; gap:1px;
  pointer-events:none; white-space:nowrap;
  max-width:38vw;
  will-change:transform;
}
/* Typographie proportionnelle à la taille de la planète (donc à son APY) :
   un rendement faible n'affiche plus le même corps de texte qu'un rendement
   qui domine tout le système. `clamp()` garde chaque ligne lisible même à la
   plus petite planète, et raisonnable même à la plus grande. */
.asset-node .pn-sym{
  font-family:var(--mono); color:var(--c);
  /* Le terme en `--size` ne joue presque aucun rôle : sur toute la plage
     réelle de `--size` (72–168px), il reste bien en dessous du plancher —
     `clamp()` retombe donc toujours sur ce plancher. Il est monté ici plutôt
     que retiré, pour qu'un système exceptionnellement grand continue de
     pouvoir dépasser le plancher un jour sans qu'on touche à nouveau ce
     fichier. */
  font-size:clamp(.92rem, calc(var(--size,120px) * .0125), 1.05rem);
  display:flex; align-items:center; gap:6px;
}
.asset-node .pn-sym .pn-dot{width:7px;height:7px;border-radius:50%;background:var(--c);box-shadow:0 0 8px var(--c);}
.asset-node .pn-sym .pn-icon{
  width:clamp(16px, calc(var(--size,120px) * .0125), 18px);
  height:clamp(16px, calc(var(--size,120px) * .0125), 18px);
  border-radius:50%; flex-shrink:0;
}
.asset-node .pn-apy{
  font-family:var(--mono); color:#C97A3D; line-height:1.15;
  font-size:clamp(1.2rem, calc(var(--size,120px) * .02), 2.05rem);
  /* La lueur derrière le chiffre grandit avec `--i` : le meilleur rendement
     du système ne se contente pas d'être écrit plus gros, il brille plus. */
  text-shadow:0 0 calc(10px * var(--i)) rgba(228,183,103, calc(.22 * var(--i)));
  will-change:text-shadow;
}

/* La planète que le bot tient : son rendement porte la surbrillance du bot
   (déclarée avec `.gbot-apy` plus haut), et il la porte SANS CLIGNOTER. Le
   vaisseau clignote parce qu'il est un objet en vol qu'on doit repérer ; ce
   chiffre-ci est une valeur qu'on lit, et il doit rester lisible tant que le
   bot est sur cet actif. La lueur, elle, tombe : sous un texte au
   remplissage transparent, `text-shadow` repeint une copie floue du chiffre
   par-dessous et brouille le dégradé. */
.planet-node.bot-position .pn-apy{ text-shadow:none; }

.asset-node .pn-meta{
  color:var(--paper-faint);
  font-size:clamp(.72rem, calc(var(--size,120px) * .009), .82rem);
}
.asset-node .pn-go{
  color:var(--copper); opacity:0; transition:opacity .15s cubic-bezier(.25,.46,.45,.94);
  font-size:clamp(.62rem, calc(var(--size,120px) * .009), .82rem);
  margin-top:2px;
}
.asset-node:hover .pn-go, .asset-node:focus-visible .pn-go{opacity:1;}

/* ---------------------------------------------------------------------
   Mobile (≤640px) : les systèmes (logo + orbites) sont dessinés sur le
   canevas exactement comme sur grand écran — voir root.js pour la
   disposition « grille agitée » qui garantit l'absence de chevauchement
   même sur un plateau étroit. Seuls les réglages de mise en page changent
   ici : un plateau plus haut que large (`aspect-ratio` posé dynamiquement
   par root.js) et une étiquette un peu plus contrainte en largeur pour
   laisser chaque colonne respirer.
   --------------------------------------------------------------------- */
@media(max-width:640px){
  .galaxy{ padding:0 18px; }
  .galaxy-scene{ max-width:100%; margin:24px auto 56px; }
  /* Le nom et le rendement sont ce qu'on doit pouvoir lire d'un coup d'œil
     sur un téléphone — davantage de place et un corps de texte nettement
     plus grand que sur bureau, où l'œil est plus proche de l'écran. */
  .asset-node .pn-info{ max-width:36vw; }
  .asset-node .pn-sym{ font-size:.95rem; gap:6px; }
  .asset-node .pn-sym .pn-icon{ width:17px; height:17px; }
  .asset-node .pn-apy{ font-size:1.2rem; }
  .asset-node .pn-meta{ font-size:.68rem; }
}

/* ---------- pastille planète (miniature) pour les tableaux/listes ---------- */
.mini-planet{
  width:26px; height:26px; border-radius:50%; flex-shrink:0;
  background:radial-gradient(circle at 32% 28%, var(--c), rgba(0,0,0,.6) 72%);
  box-shadow:0 0 0 1px rgba(242,237,230,.12), 0 0 16px -4px var(--c);
}
