/* dashboard bot99 — sobre, sombre, lisible sur mobile comme sur desktop
 *
 * Contraste : toutes les couleurs de texte tiennent au moins 4,5:1 sur le plus clair des
 * trois fonds (--fond3). Les valeurs mesurees sont en commentaire ; ne pas assombrir sans
 * refaire le calcul.
 *
 * Couleur : le vert et le rouge sont reserves au RESULTAT FINANCIER (gagne/perdu, PnL).
 * Le cote du marche (Up / Down) utilise une paire neutre et distincte, bleu et violet,
 * pour qu'un « Down gagnant » ne s'affiche pas en rouge.
 *
 * Taille : plancher de 12 px sur tout texte, 13 px sur les en-tetes de tableau.
 */

:root {
  --fond:      #0e1116;
  --fond2:     #151a21;
  --fond3:     #1c222b;
  --bord:      #2c3542;
  --txt:       #d8dee7;   /* 11.8:1 */
  --txt2:      #b9c4d2;   /*  9.0:1 */
  --txt3:      #9aa6b6;   /*  6.5:1 */

  --ok:        #56d364;   /*  8.3:1  — gain */
  --ko:        #ff7b72;   /*  6.3:1  — perte */
  --warn:      #eab54a;   /*  8.5:1 */
  --accent:    #6cb9ea;   /*  7.4:1 */
  --neutre:    #9aa6b6;

  --cote-up:   #89b4fa;   /*  7.6:1  — bleu   : cote Up,   jamais « gain » */
  --cote-down: #cba6f7;   /*  7.9:1  — violet : cote Down, jamais « perte » */

  --mono: ui-monospace, "SFMono-Regular", "JetBrains Mono", Menlo, Consolas, monospace;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
}

* { box-sizing: border-box; }

html, body {
  margin: 0; padding: 0;
  background: var(--fond); color: var(--txt);
  font-family: var(--sans); font-size: 15px; line-height: 1.45;
  -webkit-text-size-adjust: 100%;
}

h1, h2 { font-weight: 600; letter-spacing: -0.01em; }
h2 { font-size: 0.95rem; text-transform: uppercase; letter-spacing: 0.08em;
     color: var(--txt2); margin: 0 0 14px; }
a { color: var(--accent); }
code { font-family: var(--mono); font-size: 0.85em; color: var(--txt2); }

.k { display: block; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.06em;
     color: var(--txt3); margin-bottom: 3px; }          /* 12 px */
.d { color: var(--txt3); font-size: 0.8rem; }           /* 12 px */
.n { text-align: right; }
.ok  { color: var(--ok); }
.ko  { color: var(--ko); }
.warn { color: var(--warn); }
.neutre { color: var(--txt2); }

/* ------------------------------------------------------------------ connexion */

.page-login { display: flex; align-items: center; justify-content: center; min-height: 100vh; }
.login { width: 100%; max-width: 340px; padding: 28px 24px; margin: 16px;
         background: var(--fond2); border: 1px solid var(--bord); border-radius: 10px; }
/* Les 4 px d'origine menaient a la note « Lecture seule… », qui portait elle-meme les 20 px
   jusqu'au premier champ (§19.39). La note supprimee, c'est au titre de tenir cet ecart :
   sans quoi la marge haute du premier <label> (14 px) resterait seule, et le titre
   toucherait presque le champ. La marge basse du titre fusionne avec elle — 18 px, pas 32. */
.login h1 { font-size: 1.3rem; margin: 0 0 18px; }
.login label { display: block; font-size: 0.8rem; text-transform: uppercase;
               letter-spacing: 0.06em; color: var(--txt3); margin: 14px 0 5px; }
.login input { width: 100%; padding: 9px 11px; background: var(--fond);
               border: 1px solid var(--bord); border-radius: 6px; color: var(--txt);
               font-family: var(--mono); font-size: 0.95rem; }
.login input:focus { outline: 2px solid var(--accent); outline-offset: 1px;
                     border-color: var(--accent); }
.login #code { letter-spacing: 0.35em; text-align: center; }
.login button { width: 100%; margin-top: 20px; padding: 10px; background: var(--accent);
                border: 0; border-radius: 6px; color: #06121b; font-weight: 700;
                font-size: 0.92rem; cursor: pointer; }
.login button:hover { filter: brightness(1.1); }
.erreur { background: rgba(255,123,114,0.14); border: 1px solid rgba(255,123,114,0.45);
          color: #ffb3ae; padding: 9px 11px; border-radius: 6px; font-size: 0.85rem;
          margin: 0 0 4px; }

/* ------------------------------------------------------------------ bandeau */

.bandeau { border-bottom: 1px solid var(--bord); background: var(--fond2);
           padding: 12px 18px; }
/* Titre a gauche, session et deconnexion a droite, sur une seule ligne. Quand les deux ne
   tiennent plus cote a cote, le bloc de session passe SOUS le titre — jamais comprime ni
   tronque : c'est `flex-wrap` sur le conteneur, et `flex: none` sur le bloc. */
.bandeau-tete { display: flex; justify-content: space-between; align-items: baseline;
                gap: 4px 18px; flex-wrap: wrap; margin-bottom: 10px; }
.marque { font-size: 0.95rem; font-weight: 600; }

/* Six tuiles, en trois rangs de poids visuel :
     .majeure  solde et PnL cumule      — les deux chiffres qu'on regarde en premier
     (defaut)  PnL du jour, garde-fous  — l'etat de la journee en cours
     .mineure  statut, flux             — le contexte
   Le nombre de colonnes est fixe a chaque palier plutot que laisse a `auto-fit`. Le palier
   a six colonnes n'ouvre qu'a 1120 px : en dessous, une tuile passerait sous 175 px et la
   date longue (« samedi 12 septembre 2026 », ~149 px) ne tiendrait plus sur une ligne. */
.tuiles { display: grid; gap: 1px; background: var(--bord);
          grid-template-columns: repeat(2, 1fr);
          border: 1px solid var(--bord); border-radius: 8px; overflow: hidden; }
@media (min-width: 560px)  { .tuiles { grid-template-columns: repeat(3, 1fr); } }
/* ACTIVITÉ et ÉTAT ont besoin de plus de largeur que les tuiles a un seul chiffre. Un
   element de N colonnes ne peut demarrer qu'a un indice multiple de N : les etalements sont
   donc choisis pour que la grille se remplisse EXACTEMENT, dans l'ordre
   solde, PnL cumule, PnL du jour, activite, garde-fous, etat.
     2 colonnes : PnL du jour 2 + activite 2 -> 8 cellules, 4 rangees pleines
                  (sans l'etalement du PnL du jour, l'activite ne pourrait pas demarrer
                   en colonne 1 et laisserait un trou)
     3 colonnes : activite 3 + etat 2         -> 9 cellules, 3 rangees pleines
     6 colonnes : rien ne s'etale             -> 6 cellules, 1 rangee */
#t-pnl-jour { grid-column: span 2; }
#t-activite { grid-column: span 2; }
@media (min-width: 560px) {
  #t-pnl-jour { grid-column: auto; }
  #t-activite { grid-column: span 3; }
  #t-etat     { grid-column: span 2; } }
/* Le palier a six colonnes n'ouvre qu'a 1640 px. A 1120 px il produisait un effet de seuil
   contre-intuitif : la grille passait de trois a six colonnes, chaque tuile perdait la moitie
   de sa largeur, et les chiffres RETRECISSAIENT alors que la fenetre s'elargissait. Entre
   1120 et 1639 px la grille reste donc a trois colonnes sur deux rangees, ou tous les corps
   sont deja au maximum. */
/* La part de l'activite vaut 2 fractions, avec un plancher : la tuile doit loger le cadre
   fixe de 474 px plus ses 26 px de padding. Sans plancher, 2 x (W - 43) / 7 - 26 ne donne
   474 px qu'a partir de 1793 px de fenetre ; le plancher de 510 px l'assure des 1760. */
@media (min-width: 1760px) {
  /* Deux fractions, avec un plancher : le cadre fixe reclame 579 px, plus 26 px de padding
     de tuile, plus 10 px de marge, soit 510 px — sans quoi 2fr ne rendrait que 465 px a
     1760 px de fenetre. Le plancher descend de 545 a 510 px : les cinq autres tuiles y
     gagnent encore 7 px chacune. */
  .tuiles { grid-template-columns: repeat(3, 1fr) minmax(510px, 2fr) repeat(2, 1fr); }
  #t-pnl-jour, #t-etat, #t-activite { grid-column: auto; } }
/* Meme hauteur pour toutes les tuiles : l'anneau de 42 px de la tuile ACTIVITÉ est le
   contenu le plus haut, et `min-height` aligne les rangees entre elles. */
.tuile { background: var(--fond2); padding: 10px 13px; min-width: 0; overflow: hidden;
         min-height: 88px;
         display: flex; flex-direction: column; justify-content: center; }
.tuile .v { display: block; font-family: var(--mono); font-size: 1rem; font-weight: 600;
            font-variant-numeric: tabular-nums;
            white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Une seule ligne, quoi qu'il arrive : un motif de garde-fou qui passerait a la ligne
   ferait grandir toute la rangee, les tuiles d'une grille s'alignant sur la plus haute. */
.tuile .d { display: block; margin-top: 1px;
            white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tuile.majeure { background: var(--fond3); }
.tuile.majeure .v { font-size: 1.75rem; letter-spacing: -0.015em; }
.tuile.majeure .k { color: var(--txt2); }
.tuile.mineure .v { font-size: 0.95rem; }

/* Corps adaptatif des trois tuiles a valeur unique, meme principe que les montants de PnL :
 * `corps = place disponible / (nb de caracteres du pire cas x 0,61 em)`, avec 4 % de marge,
 * borne entre 0,8rem (le plancher de lisibilite de la page) et 1,75rem (le corps du solde).
 *
 * La contrainte est calculee tuile par tuile, sur SON contenu le plus large :
 *   garde-fous  « 10.00$ »           6 caracteres  -> 1,75rem des 320 px
 *   flux        « 527,2 s »          7 caracteres  -> 1,75rem des 320 px
 *   statut      « INCONNU · PAPER » 15 caracteres  -> le seul a rester bride
 *
 * `INCONNU · PAPER` et non `ARRETE · PAPER` : `inconnu` est un etat reel (instantane
 * absent ou d'une version anterieure), et c'est le libelle le plus large des six. */
/* Le solde n'avait pas de clamp : a 1,75rem fixe, un solde a quatre chiffres
   (« 9999.99$ », 8 caracteres) debordait d'une tuile d'une colonne a 320 px. */
#t-solde  .v { font-size: clamp(0.8rem,  9.84vw -  7.6px, 1.75rem); }
/* Garde-fous : gabarit porte de 6 a 7 caracteres, pour couvrir « 100.00$ ». */
/* Garde-fous : gabarit « 4.50$ » (5 car.) + l'ecart + « par trade » a 14 px, soit 71,5 px
   de constante qui s'ajoutent au montant. */
#t-gardes .v { font-size: clamp(0.8rem, 15.74vw - 34.6px, 1.75rem); }
#t-etat   .v { font-size: clamp(0.8rem,  5.25vw -  4.0px, 1.75rem); }
/* Le cadre ayant une largeur fixe par palier, le corps des chiffres l'est aussi : une
   expression en `vw` ne correspondrait plus a la place reellement offerte.
   Les cinq pastilles tenant desormais sur UNE rangee a toutes les largeurs, le corps
   descend a 13 px aux paliers etroits — le plancher autorise — avant de remonter. */
#t-activite .past b, #t-activite .past-col b { font-size: 0.8667rem; }   /* 13 px */
@media (min-width: 440px) {
  #t-activite .past b, #t-activite .past-col b { font-size: 1.133rem; } } /* 17 px */
@media (min-width: 504px) {
  #t-activite .past b, #t-activite .past-col b { font-size: 1.5rem; } }   /* 22,5 px */
@media (min-width: 560px) {                     /* trois colonnes */
  #t-solde  .v { font-size: clamp(0.8rem, 6.56vw -  7.6px, 1.75rem); }
  #t-gardes .v { font-size: clamp(0.8rem, 10.49vw - 34.7px, 1.75rem); }
  #t-etat   .v { font-size: clamp(0.8rem, 6.99vw -  5.3px, 1.75rem); }
  }
@media (min-width: 1760px) {                    /* six colonnes (cf. .tuiles) */
  #t-solde  .v { font-size: clamp(0.8rem, 2.81vw -  6.3px, 1.75rem); }
  #t-gardes .v { font-size: clamp(0.8rem, 4.50vw - 32.5px, 1.75rem); }
  #t-etat   .v { font-size: clamp(0.8rem, 1.50vw -  3.3px, 1.75rem); }
  }

/* Deux montants cote a cote, meme taille et meme poids.
 *
 * Le corps n'est plus fige au pire cas : il suit la largeur reellement disponible. La place
 * pour DEUX montants de sept caracteres (« -12.34$  -12.34$ ») vaut, dans une tuile,
 * `largeur_fenetre / colonnes - marges`, et le corps maximal en est deduit en divisant par
 * 14 chasses (0,61 em chacune) plus l'ecart de 0,5 em. D'ou une expression lineaire en `vw`
 * par palier, bornee a 1,75rem — le corps du solde, que l'on ne depasse pas.
 *
 * Le bandeau occupe toute la largeur de la fenetre (pas de `max-width`), donc `vw` mesure
 * bien la place disponible.
 *
 * Consequence chiffree : 1,75rem est atteint des 852 px a trois colonnes, et des 1664 px a
 * six colonnes. En dessous, le corps decroit continument au lieu de tomber d'un cran.
 *
 * L'ecart est en `em` : il se resserre avec le corps au lieu de manger la place quand elle
 * manque. */
.tuile .v.duo, .tuile.majeure .v.duo {
  display: flex; align-items: baseline; gap: 0.5em;
  letter-spacing: 0; white-space: nowrap;
  /* deux colonnes : 1,05rem, sauf sur un ecran trop etroit pour l'y loger */
  font-size: min(1.05rem, 5.4vw - 4.4px); }
@media (min-width: 560px) {                     /* trois colonnes */
  .tuile .v.duo, .tuile.majeure .v.duo {
    font-size: clamp(1.05rem, 3.6vw - 4.4px, 1.75rem); } }
@media (min-width: 1760px) {                    /* six colonnes (cf. .tuiles) */
  .tuile .v.duo, .tuile.majeure .v.duo {
    font-size: clamp(1.05rem, 1.52vw - 3.4px, 1.75rem); } }
.tuile .v.duo > span { display: inline-block; }

/* --- reservations conservees du §19.25 : elles valent quelle que soit la grille ---
   Le statut reserve la largeur de l'etat le plus long qu'il puisse afficher, pour que rien
   ne se deplace quand le bot passe d'ACTIF a STOP. Les garde-fous et la fraicheur du flux
   sont reserves cote script. */
#t-etat .v { min-width: 15ch; }
/* ------------------------------------------------------------------ tuile ACTIVITÉ
 *
 * Un cadre fin englobe les cinq pastilles et porte l'etat courant : neutre au repos, orange
 * quand un ordre est pose, vert quand il est rempli.
 *
 * L'anneau fait 42 px pour 5 px d'epaisseur, donc un rayon de (42 - 5) / 2 = 18,5 px ;
 * l'arc part de midi (`rotate(-90)`) et sa longueur est posee en `stroke-dasharray` depuis
 * le script — un attribut SVG, pas un style en ligne, donc rien que la CSP puisse bloquer. */

/* Le cadre est un CONTENANT de dimensions constantes : ni sa largeur ni sa hauteur ne
 * dependent de ce qu'il contient. Quand un compteur passe de 999 a 1000, ou qu'un ordre est
 * pose, le cadre ne bouge pas. Les cinq pastilles se partagent exactement sa largeur
 * interieure — toutes les colonnes valent 1fr — et sa hauteur interieure — `grid-auto-rows:
 * 1fr` —, sans residu.
 *
 * Les deux dimensions sont calculees sur le GABARIT le plus large : compteurs a quatre
 * chiffres — la seule reserve que l'on ne serre pas —, et le plus long des libelles, qui est
 * desormais le contexte de timer « aucun ordre » depuis que « remplissage » est devenu
 * « taux ». Le mono est majore a 0,61 em et les libelles a 0,56 em, pour couvrir les polices
 * systeme les plus larges.
 *
 * La LARGEUR vaut `colonnes x pastille + ecarts + padding + bordures`, ou la pastille est la
 * plus large des cinq : celle du taux, anneau 42 + ecart 4 + « 100% ». La HAUTEUR vaut
 * `rangees x pastille + ...`, ou la pastille est la plus HAUTE : celle du timer, seule a
 * porter trois lignes (chiffres, mini-barre, contexte).
 *
 * Les ecarts sont serres au minimum lisible : padding de pastille 3 x 5 px, ecart entre
 * pastilles 3 px, padding du cadre 5 px, ecart anneau/pourcentage 3 px, marges de la
 * mini-barre 2 et 1 px.
 *
 * L'anneau ramene a 26 px, la pastille du taux (93,9 px) passe SOUS celle du timer
 * (96,6 px) : ce n'est plus elle qui fixe la largeur commune, mais le timer, dont
 * « 59:59 » et le contexte « aucun ordre » ne se serrent pas davantage. C'est donc le
 * plancher de la tuile, et reduire encore l'anneau ne rendrait plus un pixel.
 *
 * Le nombre de colonnes par palier est le plus grand dont le cadre tienne encore dans la
 * tuile A LA BORNE BASSE du palier. Retenu :
 *
 *     fenetre    corps  col  rangees  pastille   cadre     marge dans la tuile
 *     320-343     17     2      3       83,9     184 x 161      +72
 *     344-431     17     3      2       83,9     271 x 111       +9
 *     432-519     17     4      2       83,9     358 x 111      +10
 *     520-583     17     5      1       83,9     445 x  61      +11
 *     >= 584      22,5   5      1       96,6     509 x  67      +11
 *
 * Chaque cadre porte 1 px de plus que le strict minimum calcule : sans lui, plusieurs
 * paliers tombaient a exactement 0,0 px de marge, ce qui ne laisse aucun jeu au sous-pixel.
 *
 * `overflow: hidden` n'est plus qu'une ceinture : les parts calculees couvrent deja le
 * pire cas dans les trois etats. */
.act-cadre { --cadre-w: 250px; --cadre-h:  65px; --cols: 5;
             width: var(--cadre-w); height: var(--cadre-h);
             display: grid; grid-template-columns: repeat(var(--cols), 1fr);
             grid-auto-rows: 1fr; align-items: stretch;
             gap: 2px; overflow: hidden;
             border: 1px solid var(--bord); border-radius: 8px; padding: 4px;
             background: transparent;
             transition: background 0.25s, border-color 0.25s; }
/* Chaque palier : le plus grand nombre de colonnes dont la largeur de cadre tient dans la
   tuile A LA BORNE BASSE du palier, et la hauteur qui va avec le nombre de rangees.
   `grid-auto-rows: 1fr` partage la hauteur fixe entre les rangees, si bien qu'aucune rangee
   ne peut reclamer plus que sa part — plus de debordement vertical possible. */
@media (min-width: 376px)  { .act-cadre { --cadre-w: 302px; } }
@media (min-width: 390px)  { .act-cadre { --cadre-w: 318px; } }
@media (min-width: 440px)  { .act-cadre { --cadre-w: 367px; } }
@media (min-width: 504px)  { .act-cadre { --cadre-w: 434px; } }
@media (min-width: 544px)  { .act-cadre { --cadre-w: 474px; } }
.act-cadre.pose   { border-color: rgba(234,181,74,0.55); background: rgba(234,181,74,0.07); }
.act-cadre.rempli { border-color: rgba(86,211,100,0.5);  background: rgba(86,211,100,0.07); }
.sfx-etat { text-transform: uppercase; letter-spacing: 0.06em; }
.act-pose   .sfx-etat { color: var(--warn); }
.act-rempli .sfx-etat { color: var(--ok); }

/* Chaque pastille recoit une part EGALE de la largeur interieure du cadre : toutes les
   colonnes valent `1fr`, soit (interieur - ecarts) / nombre de colonnes, sans residu.
   `min-width: 0` empeche qu'une pastille plus large que sa part n'elargisse sa colonne et
   ne rompe l'egalite.
   Contenu CENTRE dans les deux sens. Les cinq pastilles ayant la meme largeur, celle du
   plus gourmand, les pastilles a contenu court en heritent d'une dont elles n'ont pas
   besoin ; aligne a gauche, tout ce residu s'accumulait a droite. Centre, il se partage
   entre les deux bords. En colonne, c'est `align-items` qui centre horizontalement. */
.past { min-width: 0; border-radius: 6px; padding: 3px;
        display: flex; flex-direction: column; justify-content: center;
        align-items: center; }
.past-n { display: flex; align-items: center; justify-content: center; gap: 4px;
          min-width: 0; }
.past-n b { font-family: var(--mono); font-weight: 700; line-height: 1.15;
            font-variant-numeric: tabular-nums; text-align: center; }
.past .ico { flex: none; width: 14px; height: 14px; stroke: currentColor; fill: none;
             stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.past-l { font-size: 0.6667rem; line-height: 1.3; white-space: nowrap; }   /* 10 px */
@media (min-width: 390px) { .past-l { font-size: 0.8rem; } }               /* 12 px */

/* Contexte du timer : version pleine a partir de 504 px, abregee en dessous. Les deux sont
   dans le HTML et ecrites ensemble par le script ; c'est la feuille qui choisit. Aucun
   `matchMedia`, aucun ecouteur de redimensionnement, aucune desynchronisation possible. */
.ctx-long  { display: none; }
.ctx-court { display: inline; }
@media (min-width: 504px) {
  .ctx-long  { display: inline; }
  .ctx-court { display: none; } }

/* Icones : retirees sous 376 px. A 320 px chaque pastille ne dispose que de 46,4 px, dont
   31,7 pour les quatre chiffres et 6 pour le padding ; l'icone et son ecart en reclament 17
   de plus, soit 54,7 au total pour 46,4 disponibles. Aucun corps admissible — meme le
   plancher de 13 px — ne les fait tenir : il manque 8,3 px. C'est le seul element sacrifie,
   et seulement sous 376 px ; il revient des que la place existe. */
@media (max-width: 375px) { .past .ico { display: none; } }

/* Pastille du taux : l'anneau A GAUCHE, pourcentage et libelle a sa droite.
   C'est cette disposition en RANGEE qui tient la hauteur : empile en colonne, l'anneau de
   42 px plus les deux lignes de texte demandent 91 px, la ou une rangee n'en offre que 58 —
   c'etait la cause du debordement par le bas. En rangee, la pastille ne demande que 50 px. */
/* Sous 384 px, l'anneau se met AU-DESSUS du pourcentage : a cote, il reclamerait
   18 + 3 + 31,7 = 52,7 px quand la pastille n'en offre que 41,6. Empile, la pastille ne
   demande plus que la largeur du nombre. La hauteur y suffit : 3 + 18 + 15,0 + 13 + 3 =
   51,95 px, sous les 53,48 px de la rangee. */
.past-remplissage { flex-direction: column; align-items: center; justify-content: center;
                    gap: 0; }
@media (min-width: 390px) {
  .past-remplissage { flex-direction: row; gap: 3px; } }
.past-col { display: flex; flex-direction: column; align-items: center; min-width: 0; }
.past-col b { font-family: var(--mono); font-weight: 700; line-height: 1.15;
              font-variant-numeric: tabular-nums; }
.anneau { flex: none; display: block; width: 18px; height: 18px; }
@media (min-width: 544px) { .anneau { width: 26px; height: 26px; } }
/* L'anneau passe de 42 a 26 px, a toutes les largeurs. Le viewBox reste « 0 0 42 42 » :
   rayon et epaisseur du trait suivent l'echelle, les proportions sont intactes.
   26 px est le point ou la pastille du taux (93,9 px) passe SOUS celle du timer (96,6 px)
   et cesse de tirer la largeur commune ; en dessous de 28 px, reduire davantage ne gagne
   plus rien puisque c'est alors le timer qui fait le plancher.
   Tout tient dans la regle unique ci-dessous : au §19.33, deux regles separees sur
   `.anneau` s'etaient annulees l'une l'autre sans que cela se voie. */
.anneau .piste { fill: none; stroke: #39424e; stroke-width: 5; }
.anneau .arc   { fill: none; stroke: var(--txt3); stroke-width: 5; stroke-linecap: round;
                 transition: stroke-dasharray 0.3s, stroke 0.25s; }
/* Gris au repos — plus de vert permanent —, puis la teinte de l'etat. */
.act-cadre.pose   .anneau .arc { stroke: var(--warn); }
.act-cadre.rempli .anneau .arc { stroke: var(--ok); }
.past-remplissage           { background: rgba(154,166,182,0.14); }
.past-remplissage b         { color: var(--txt2); }
.past-remplissage .past-l   { color: var(--txt3); }
.act-cadre.pose   .past-remplissage b { color: var(--warn); }
.act-cadre.rempli .past-remplissage b { color: var(--ok); }

.past-slots   { background: #262d36; }
.past-slots   b, .past-slots   .ico { color: var(--txt); }
.past-slots   .past-l { color: var(--txt2); }
.past-postes  { background: #17303f; }
.past-postes  b, .past-postes  .ico { color: #a5d6f5; }
.past-postes  .past-l { color: #8fc0e0; }
.past-remplis { background: #16341f; }
.past-remplis b, .past-remplis .ico { color: #8ef09a; }
.past-remplis .past-l { color: #77c985; }
/* Le fond des trois compteurs suit la teinte de la tuile, leurs chiffres gardent la leur. */
.act-cadre.pose   .past-slots, .act-cadre.pose   .past-postes,
.act-cadre.pose   .past-remplis { background: rgba(234,181,74,0.13); }
.act-cadre.rempli .past-slots, .act-cadre.rempli .past-postes,
.act-cadre.rempli .past-remplis { background: rgba(86,211,100,0.13); }

/* Pastille du timer : elle s'etire pour finir sa rangee. */
.past-timer { background: rgba(154,166,182,0.14); }
.past-timer b, .past-timer .ico { color: var(--txt2); }
.past-timer .past-l { color: var(--txt3); overflow: hidden; text-overflow: ellipsis; }
.act-cadre.pose   .past-timer { background: rgba(234,181,74,0.16); }
.act-cadre.pose   .past-timer b, .act-cadre.pose   .past-timer .ico,
.act-cadre.pose   .past-timer .past-l { color: var(--warn); }
/* Derniere minute : le chiffre du timer passe en orange, et lui seul. Le selecteur porte
   l'identifiant de la tuile pour l'emporter sur les regles d'etat quel que soit leur ordre
   dans la feuille — la lecon du §19.33, ou deux regles de meme poids s'annulaient. */
#t-activite .past-timer b.alerte { color: var(--warn); }
.act-cadre.rempli .past-timer { background: rgba(86,211,100,0.16); }
.act-cadre.rempli .past-timer b, .act-cadre.rempli .past-timer .ico,
.act-cadre.rempli .past-timer .past-l { color: var(--ok); }
.mini-barre { display: block; align-self: stretch; height: 3px; margin: 2px 0 1px;
              border-radius: 2px;
              background: rgba(154,166,182,0.25); overflow: hidden; }
.mini-barre > span { display: block; height: 100%; width: 0; border-radius: 2px;
                     background: var(--txt3); }
.act-cadre.pose   .mini-barre > span { background: var(--warn); }
.act-cadre.rempli .mini-barre > span { background: var(--ok); }

/* « par trade » accompagne la mise, en 14 px gris, sur la meme ligne que le montant. */
.tuile .v .sfx { font-family: var(--sans); font-size: 14px; font-weight: 500;
                 color: var(--txt3); margin-left: 6px; letter-spacing: 0; }
/* Quand un garde-fou s'approche, le montant de la marge se colore : a 12 px, le fond de la
   tuile ne suffit pas a le signaler. */
.tuile.attention .d.gardes-alerte .marge { color: var(--warn); font-weight: 700; }
.tuile.alerte    .d.gardes-alerte .marge { color: var(--ko);   font-weight: 700; }

/* La ligne secondaire de la tuile ÉTAT porte le flux : son alerte de fraicheur est
   independante de la couleur du statut. */
.tuile .d.warn { color: var(--warn); }
/* La fraicheur du flux reserve trois caracteres plus l'unite : le « · » qui suit ne se
   deplace donc pas quand elle passe de 1,8 a 12,4. */
.tuile .d .fx { display: inline-block; min-width: 3ch; text-align: right; }

/* Les montants du bandeau sont tronques : le survol donne la valeur exacte. */
.tuile .v[title] { cursor: help; }
/* Idem pour les pastilles de la tuile ACTIVITE, dont le survol donne le chiffre du jour. */
.past [title], .act-cadre[title] { cursor: help; }
.tuile.alerte { background: rgba(255,123,114,0.16); }
.tuile.alerte .v { color: var(--ko); }
.tuile.attention { background: rgba(234,181,74,0.14); }
.tuile.attention .v { color: var(--warn); }
.deco { display: flex; gap: 12px; align-items: baseline; flex: none;
        font-size: 0.8rem; flex-wrap: wrap; }
.deco .d { white-space: nowrap; }

/* Pleine largeur, comme le bandeau, et le MEME padding lateral (18 px, 12 px sous 640 px)
   pour que les bords gauche et droit des cartes s'alignent verticalement sur ceux des
   tuiles du bandeau.
   Ces regles sont celles du TABLEAU DE BORD et de lui seul : elles sont donc portees par
   `.page-dash`, la classe que dashboard.html pose sur <body>. Ecrites sur `main` nu, elles
   s'appliquaient aussi a <main class="login"> — la carte de connexion devenait une grille,
   et au-dela de 860 px une grille a DEUX colonnes de 340 px dans une carte large de 292 px :
   la note passait en deuxieme colonne, hors de la carte, un mot par ligne (rapport §19.38). */
.page-dash main { padding: 18px;
       display: grid; gap: 18px;
       /* Sans ce minmax(0,…), la largeur mini du tableau d'historique s'impose a la
          colonne de grille : la colonne depasse `main`, les cartes se decalent et le
          cadre a defilement horizontal ne sert plus a rien. */
       grid-template-columns: minmax(0, 1fr); }
.page-dash main > * { min-width: 0; }

/* ------------------------------------------------------------------ deux colonnes
 *
 * A partir de 820 px, la carte du slot passe a gauche dans une colonne FIXE de 340 px et
 * les statistiques occupent le reste. L'historique et la carte « ordre en cours » restent
 * sur toute la largeur, en dessous.
 *
 * Les 340 px viennent d'une mesure, pas d'un choix : c'est le plus large des elements que
 * la carte du slot ne peut pas replier —
 *     grille des mesures sur deux colonnes de 150 px   301 px   <- contrainte retenue
 *     ligne de reference Polymarket, 41 caracteres     256 px
 *     identifiant du slot + fleche, 0,95rem            224 px
 *     chronometre en 8rem, « 9,4 »                     220 px
 *     legende de la barre, repere a 80 %               160 px
 * soit 304 px de contenu, plus 2 x 18 px de padding de carte.
 *
 * Le seuil de 860 px est mesure de meme. Les statistiques ont besoin de 422 px de CONTENU
 * pour tenir trois tuiles de 140 px, soit 458 px de carte une fois son propre padding
 * compte :   340 + 18 (ecart) + 458 + 36 (padding de main) = 852 px, arrondi a 860.
 * En dessous, la page repasse en empilement vertical. */
@media (min-width: 860px) {
  .page-dash main { grid-template-columns: 340px minmax(0, 1fr); align-items: start; }
  #carte-slot  { grid-column: 1; grid-row: 1; }
  #carte-stats { grid-column: 2; grid-row: 1; }
  #carte-ordre, #carte-hist { grid-column: 1 / -1; }
  /* La colonne est fixe : le chronometre n'a plus a dependre de la largeur de fenetre. */
  .chrono-val { height: 8rem; font-size: 5.5rem; }
  .chrono.final .chrono-val { font-size: 8rem; }
}

.carte { background: var(--fond2); border: 1px solid var(--bord); border-radius: 10px;
         padding: 16px 18px; min-width: 0; }

/* ------------------------------------------------------------------ slot */

/* En-tete du slot : l'heure de Paris en principal, la reference Polymarket dessous, le
   slug en bas. Chaque ligne a une hauteur fixe pour que l'arrivee du titre Gamma
   (~4 s apres le debut du slot) ne fasse pas sauter la carte. */
/* Disposition compacte en permanence, et plus seulement sur telephone : identite du slot
   puis heure de cloture empilees, c'est elle qui libere la place pour les statistiques. */
.slot-tete { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; }
.slot-ident { min-width: 0; }
.slot-tete h2 { font-size: 0.95rem; text-transform: none; letter-spacing: -0.01em;
                color: var(--txt); margin: 0; min-height: 1.5em; }
.slot-titre { font-family: var(--mono); font-weight: 600; }
/* L'identifiant est atomique : il se replie en bloc, jamais en plein milieu. */
.slot-titre .lien-poly { white-space: nowrap; }
.slot-titre #v-slot-paris { font-family: var(--sans); }
.ref-poly { margin: 1px 0 0; font-size: 0.8rem; color: var(--txt3); min-height: 1.35em;
            white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ref-poly .pref { text-transform: uppercase; letter-spacing: 0.05em; font-size: 0.92em;
                  opacity: 0.75; }
/* Lien externe vers polymarket.com : discret, souligne au survol, avec une fleche qui
   annonce qu'on quitte le site. Le soulignement n'apparait qu'au survol pour ne pas
   transformer le tableau en champ de liens bleus. */
.lien-poly { color: inherit; text-decoration: none; border-radius: 3px; }
.lien-poly:hover, .lien-poly:focus-visible { color: var(--accent);
                                             text-decoration: underline;
                                             text-underline-offset: 2px; }
.lien-poly:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.lien-poly .ext { font-family: var(--sans); font-size: 0.85em; margin-left: 3px;
                  color: var(--txt3); vertical-align: baseline; }
.lien-poly:hover .ext, .lien-poly:focus-visible .ext { color: var(--accent); }

.slot-fin { text-align: left; flex: none; }
.slot-fin b { display: block; font-family: var(--mono); font-size: 1.35rem;
              font-variant-numeric: tabular-nums; line-height: 1.15; }
.slot-fin .d { display: block; font-family: var(--mono); min-height: 1.35em; }

/* La hauteur maximale est reservee des le depart : le passage en rouge a T-10 s change la
   taille du chiffre mais ne doit rien pousser sur la page. */
.chrono { text-align: center; padding: 14px 0 8px; }
.chrono-val { height: clamp(4.2rem, 20vw, 8rem); line-height: 1;
              display: flex; align-items: center; justify-content: center;
              font-family: var(--mono); font-size: clamp(3rem, 14vw, 5.5rem);
              font-weight: 700; letter-spacing: -0.02em;
              font-variant-numeric: tabular-nums;
              transition: color 0.2s, font-size 0.2s; }
.chrono-lbl { color: var(--txt3); font-size: 0.8rem; text-transform: uppercase;
              letter-spacing: 0.1em; margin-top: 4px; height: 1.2em; }
.chrono.decision .chrono-val { color: var(--warn); }
.chrono.final .chrono-val { color: var(--ko); font-size: clamp(4.2rem, 20vw, 8rem);
                            animation: pouls 1s steps(1, end) infinite; }
.chrono.final .chrono-lbl { color: var(--ko); font-weight: 700; }
@keyframes pouls { 0%, 49% { opacity: 1; transform: scale(1); }
                   50%, 100% { opacity: 0.55; transform: scale(0.96); } }
@media (prefers-reduced-motion: reduce) { .chrono.final .chrono-val { animation: none; } }

.barre { position: relative; height: 10px; background: var(--fond3);
         border-radius: 5px; margin: 6px 0 32px; }
.barre-plein { position: absolute; inset: 0 auto 0 0; width: 0;
               background: linear-gradient(90deg, #3c7ea8, var(--accent));
               border-radius: 5px; }
.barre.decision .barre-plein { background: linear-gradient(90deg, #9a7a1e, var(--warn)); }
.barre.final .barre-plein { background: linear-gradient(90deg, #a4433c, var(--ko)); }
.barre-marque { position: absolute; top: -4px; bottom: -4px; width: 2px;
                background: var(--warn); left: 80%; }
.barre-legende { position: absolute; left: 0; right: 0; top: 15px; display: flex;
                 justify-content: space-between; font-size: 0.8rem; color: var(--txt3); }
/* Le libelle se termine SUR la marque au lieu d'etre centre dessus : centre, il heurtait
   « fin » tant que la barre n'atteignait pas 348 px, ce qui aurait impose une colonne de
   384 px au lieu de 340. */
.barre-legende .mq { position: absolute; left: 80%; transform: translateX(-100%);
                     padding-right: 5px; color: var(--warn); white-space: nowrap; }

.mesures { display: grid; gap: 1px; background: var(--bord);
           grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
           border: 1px solid var(--bord); border-radius: 8px; overflow: hidden; }
.mesure { background: var(--fond2); padding: 11px 13px; min-width: 0; }
.mesure b { font-family: var(--mono); font-size: 1.05rem; font-variant-numeric: tabular-nums; }

/* L'information la plus importante de la page : elle occupe deux colonnes et porte un
   fond plein, pas un gris pale. */
.mesure.verdict { grid-column: span 2; display: flex; flex-direction: column;
                  justify-content: center; }
.mesure.verdict b { font-size: 1.5rem; font-weight: 700; letter-spacing: -0.01em;
                    font-family: var(--sans); }
.mesure.verdict.suffisant { background: #164524; box-shadow: inset 4px 0 0 var(--ok); }
.mesure.verdict.suffisant b { color: #8ef09a; }
.mesure.verdict.suffisant .k { color: #8ef09a; opacity: 0.9; }
.mesure.verdict.insuffisant { background: var(--fond3); box-shadow: inset 4px 0 0 var(--txt3); }
.mesure.verdict.insuffisant b { color: var(--txt2); }

/* Rappel de la decision prise a T-60 : figee par nature, donc nettement detachee de
   l'ecart temps reel affiche juste au-dessus. */
.decision-t60 { display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap;
                margin: 14px 0 0; padding: 9px 12px; border-radius: 7px;
                background: var(--fond3); border-left: 3px solid var(--bord); }
.decision-t60 .et-fige { flex: none; font-size: 0.8rem; font-weight: 700;
                         text-transform: uppercase; letter-spacing: 0.06em;
                         color: var(--txt3); border: 1px solid var(--bord);
                         border-radius: 4px; padding: 2px 7px; }
.decision-t60 .txt { font-family: var(--mono); font-size: 0.85rem; color: var(--txt2); }
.decision-t60.prise { border-left-color: var(--accent); }
.decision-t60.prise .et-fige { color: var(--accent); border-color: var(--accent); }

/* ------------------------------------------------------------------ stats */

/* Les tuiles cessent de grandir a 240 px : au-dela, la place supplementaire se repartit en
   ECART entre elles plutot que de les etirer a vide. Ce qui oblige a abandonner le bandeau
   continu — un fond de conteneur qui transparait dans des interstices de 1 px ne survit pas
   a des ecarts variables — au profit de pastilles distinctes posees sur la carte. */
/* Selecteur de periode de la carte des statistiques.
 *
 * Deux jeux de tuiles cote a cote auraient double le nombre de tuiles — 7 deviennent 14 — et
 * la grille `auto-fit minmax(140px, 240px)` ne tient que deux colonnes sous 500 px : la carte
 * serait passee de 4 a 7 rangees sur telephone. Le selecteur, lui, se loge sur la ligne du
 * titre qui existe deja : hauteur inchangee a toutes les largeurs.
 *
 * `align-self: baseline` et la casse normale distinguent les puces du titre, qui est en
 * capitales espacees ; sans cela elles se lisaient comme la suite du titre. */
h2 .portees { display: inline-flex; flex-wrap: wrap; gap: 4px; margin-left: 10px;
              vertical-align: baseline; text-transform: none; letter-spacing: 0; }
.portee { font: inherit; font-size: 0.78rem; text-transform: none; letter-spacing: 0;
          padding: 2px 9px; border-radius: 999px; cursor: pointer;
          color: var(--txt3); background: var(--fond3);
          border: 1px solid var(--bord); }
.portee:hover { color: var(--txt2); border-color: var(--txt3); }
.portee.actif { color: var(--fond); background: var(--accent); border-color: var(--accent);
                font-weight: 600; }
.portee:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.stats { display: grid; gap: 8px; justify-content: space-between;
         grid-template-columns: repeat(auto-fit, minmax(140px, 240px)); }
.stat { background: var(--fond3); border-radius: 8px; padding: 12px 13px; min-height: 86px;
        display: flex; flex-direction: column; justify-content: center; }
.stat b { font-family: var(--mono); font-size: 1.25rem; font-variant-numeric: tabular-nums; }
.stat .d { margin-top: 2px; white-space: nowrap; }
.stat.vedette { background: var(--fond); box-shadow: inset 4px 0 0 var(--accent); }
.stat.vedette b { font-size: 2.1rem; color: var(--accent); display: block; line-height: 1.1; }
.stat.vedette .k { color: var(--accent); opacity: 0.9; }

.graphe-tete { display: flex; justify-content: space-between; align-items: baseline;
               gap: 12px; margin: 20px 0 6px; flex-wrap: wrap; }
.graphe-tete h3 { margin: 0; font-size: 0.9rem; font-weight: 600; color: var(--txt); }
.graphe { position: relative; height: 260px; }
@media (max-width: 640px) { .graphe { height: 210px; } }

/* ------------------------------------------------------------------ tableaux */

.tete-hist { display: flex; justify-content: space-between; align-items: center;
             gap: 12px; flex-wrap: wrap; }
.tete-hist h2 { margin: 0 0 10px; }
.filtres { display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
           margin-bottom: 10px; font-size: 0.8rem; color: var(--txt3); }
.filtres select { background: var(--fond); color: var(--txt); border: 1px solid var(--bord);
                  border-radius: 5px; padding: 4px 7px; font-size: 0.8rem; }
.filtres .case { display: flex; gap: 5px; align-items: center; cursor: pointer; }

/* Mesure faite sur le rendu reel : le tableau d'historique sature a 1484 px, colonnes et
   marges comprises. Au-dela, les colonnes ne font plus que s'espacer. On plafonne donc le
   CADRE — l'historique seul, pas la page — a 1520 px, et le reste de la carte demeure en
   pleine largeur. */
.tableau-cadre { overflow-x: auto; border: 1px solid var(--bord); border-radius: 8px;
                 max-width: min(100%, 1520px); }
.tbl { width: 100%; border-collapse: collapse; font-size: 0.85rem; white-space: nowrap; }
.tbl th { text-align: left; font-weight: 600; font-size: 0.87rem;   /* 13 px */
          letter-spacing: 0.02em; color: var(--txt2); padding: 10px 11px;
          background: var(--fond3); border-bottom: 1px solid var(--bord); position: sticky;
          top: 0; }
.tbl th.n { text-align: right; }
.tbl td { padding: 9px 11px; border-bottom: 1px solid var(--bord);
          font-family: var(--mono); font-variant-numeric: tabular-nums; }
.tbl tr:last-child td { border-bottom: 0; }
.tbl tbody tr:hover { background: var(--fond3); }
.tbl td.marche { white-space: nowrap; color: var(--txt2); cursor: help; }
.tbl td.slug { color: var(--txt3); font-size: 0.8rem; }             /* 12 px */
.tbl td.slug .lien-poly { color: var(--txt3); }
.tbl td.slug .lien-poly:hover, .tbl td.slug .lien-poly:focus-visible { color: var(--accent); }
.tbl .vide { text-align: center; color: var(--txt3); padding: 22px; font-family: var(--sans); }
.tbl .sec { color: var(--txt3); font-size: 0.8rem; }
/* Ligne secondaire dans une cellule : l'heure ET de Polymarket sous l'heure de Paris. */
.tbl .sous { display: block; color: var(--txt3); font-size: 0.8rem; line-height: 1.3;
             margin-top: 1px; }

.et { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 0.8rem;
      font-weight: 700; letter-spacing: 0.02em; font-family: var(--sans); }
.et-rempli    { background: rgba(108,185,234,0.2);  color: #a5d6f5; }
.et-partiel   { background: rgba(234,181,74,0.2);   color: #f2ce7c; }
.et-nonrempli { background: rgba(154,166,182,0.18); color: var(--txt2); }
.et-poste     { background: rgba(108,185,234,0.15); color: #a5d6f5; }
.et-gagne     { background: rgba(86,211,100,0.2);   color: #8ef09a; }
.et-perdu     { background: rgba(255,123,114,0.22); color: #ffaba5; }

/* Cote du marche : bleu / violet, strictement separes du vert et du rouge financiers. */
.cote { display: inline-block; font-family: var(--sans); font-weight: 700;
        font-size: 0.8rem; padding: 2px 8px; border-radius: 4px; letter-spacing: 0.02em; }
.cote-up   { background: rgba(137,180,250,0.2); color: var(--cote-up); }
.cote-down { background: rgba(203,166,247,0.2); color: var(--cote-down); }

.pagination { display: flex; gap: 12px; align-items: center; justify-content: center;
              margin-top: 12px; font-size: 0.85rem; color: var(--txt2); }
.pagination button { background: var(--fond3); border: 1px solid var(--bord); color: var(--txt);
                     border-radius: 6px; padding: 6px 12px; cursor: pointer;
                     font-size: 0.85rem; }
.pagination button:disabled { opacity: 0.4; cursor: default; }

.pied { padding: 0 18px 26px; color: var(--txt3);
        font-size: 0.8rem; }
.pied span { margin-left: 8px; }

@media (max-width: 480px) {
  /* Conserve du §19.25 : un peu de hauteur rendue sur telephone, sans toucher au corps des
     chiffres. L'ecart reste a 1 px — ce sont les separations de la grille. */
  .tuile { min-height: 72px; padding: 8px 11px; } }
@media (max-width: 640px) {
  .page-dash main { padding: 12px; gap: 12px; }
  .carte { padding: 13px 12px; }
  .bandeau { padding: 10px 12px; }
  .mesure.verdict { grid-column: span 2; }
  .tuile { padding: 9px 11px; }
  .tuile.majeure .v { font-size: 1.45rem; }
  .pied { padding: 0 12px 20px; }
}
