@charset "UTF-8";
/* ═══════════════════════════════════════════════════════════
   PIPSTER PRO · Terminal — design system
   Dark, premium, minimal. L'indicateur (canvas, panneaux
   multi-TF & liquidité) garde ses codes couleur d'origine.
════════════════════════════════════════════════════════════ */

/* Palette neutre du thème noir de TradingView. Les cinq tons demandés sont
   #0F0F0F (fond), #2E2E2E (séparateurs), #3D3D3D (bordure marquée),
   #E4E4E4 (texte) et #F2F2F2 (boutons de la barre du haut). Les trois
   intermédiaires — #1A1A1A, #B0B0B0, #808080 — sont dérivés du même gris :
   sans eux il ne resterait aucune hiérarchie entre un titre, une valeur
   secondaire et une graduation d'axe. */
:root {
  color-scheme: dark;
  --bg:            #0F0F0F;
  --surface:       #0F0F0F;
  --surface-2:     #1A1A1A;
  --raised:        #2E2E2E;
  --chart-bg:      #0F0F0F;
  --grid:          #1E1E1E;

  --border:        #2E2E2E;
  --border-strong: #3D3D3D;

  --text:          #E4E4E4;
  --text-2:        #B0B0B0;
  /* ── TROIS NIVEAUX DE TEXTE, ET PAS UN QUATRIÈME (LOT 2 §12) ────────────
     Toute information secondaire passe par l'un de ces trois jetons — jamais
     par un gris posé à la main, jamais par une `opacity` sur du texte. C'est
     ce qui garantit que le contraste reste mesurable et qu'il ne se dégrade
     pas au fil des ajouts.

       --text    principal   15,08:1 sombre · 17,93:1 clair
       --text-2  secondaire   8,84:1 sombre ·  7,61:1 clair
       --text-3  tertiaire    5,85:1 sombre ·  5,60:1 clair

     Les trois dépassent le seuil AA du texte normal (4,5:1) sur les deux
     thèmes : « tertiaire » veut dire discret, pas illisible. `--text-3` est
     monté de #808080 (4,7:1, sous le seuil sur écran terne) à #8E8E8E. */
  --text-3:        #8E8E8E;
  --toolbar-fg:    #F2F2F2;

  --accent:        #4E7FFF;
  --accent-2:      #8B5CF6;
  --accent-soft:   rgba(78, 127, 255, .13);

  /* ─── Sémantique des couleurs ─────────────────────────────────────────
     Une couleur = un sens, sur tout le terminal. Sans cette règle l'œil doit
     lire le texte pour savoir ce qu'il regarde, et un écran entièrement rouge
     se lit « vente très forte » alors qu'il mélange direction, avertissement
     et danger.

       --down   rouge      Vente · Stop · perte · action destructrice
       --up     turquoise  Achat · profit
       --warn   orange     Avertissement, nuance, break-even — JAMAIS une
                           direction : c'est ce qui tempère une lecture
       --info   ardoise    Fait neutre, sans camp (ATR, force de l'ADX,
                           actualité) — surtout pas de vert ni de rouge, qui
                           feraient croire à un sens de marché
       --accent-2 violet   Marque et pack Pro UNIQUEMENT

     Conséquences appliquées ici : la force de l'ADX n'est plus verte (elle ne
     dit pas d'acheter), l'avertissement de lecture du marché n'est plus rouge
     (il ne dit pas de vendre), et le violet a quitté l'ATR et les actualités.
     ─────────────────────────────────────────────────────────────────────── */
  --up:            #26A69A;
  --down:          #EF5350;
  --warn:          #F0A94B;
  --info:          #6B8299;

  /* ── Aplats sourds ────────────────────────────────────────────────────────
     La même sémantique, à voix basse. Un aplat plein et un texte blanc, c'est
     le niveau d'un STOP ou d'une perte : quand six cases voisines le portent
     pour dire « la tendance descend », l'écran hurle un danger que personne
     n'a constaté. Le fait garde donc sa couleur — portée par le texte et un
     fond teinté — et l'aplat plein reste réservé à ce qui alerte vraiment.
     Le texte reste `--up`/`--down`, dont le contraste est déjà validé sur les
     deux thèmes ; seul le fond change. */
  --up-soft:       rgba(38, 166, 154, .15);
  --down-soft:     rgba(239, 83, 80, .15);
  --info-soft:     rgba(107, 130, 153, .17);
  --warn-soft:     rgba(240, 169, 75, .15);

  --glass:         rgba(15, 15, 15, .82);
  --shadow-lg:     0 20px 50px rgb(var(--shade) / calc(.55 * var(--shade-k))), 0 4px 14px rgb(var(--shade) / calc(.35 * var(--shade-k)));
  --shadow-sm:     0 2px 10px rgb(var(--shade) / calc(.35 * var(--shade-k)));

  --r-sm: 8px;
  --r-md: 10px;
  --r-lg: 14px;

  --font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  /* ─── Thème : jetons partagés ────────────────────────────────────────
     Le sombre reste la version de référence, aux valeurs inchangées.

     `--veil` est le triplet d'un voile de survol, `--shade` celui d'une
     ombre. Les deux sont écrits une fois et lus partout sous la forme
     `rgb(var(--veil) / .05)` : un même alpha décrit alors un éclaircissement
     sur fond sombre et un assombrissement sur fond clair, sans qu'aucune
     règle n'ait à connaître le thème courant.

     `--shade-k` atténue les ombres en clair : une ombre à 55 % de noir,
     juste sur fond sombre, écraserait une interface claire. Le facteur
     conserve la hiérarchie des reliefs sans en transposer l'intensité. */
  --veil:          255 255 255;
  --shade:         0 0 0;
  --shade-k:       1;

  --well:          #10141C;
  --sunken:        #111214;
  --elevated:      #202020;
  --divider:       #444444;

  --on-contrast:   #0F0F0F;
  --on-warn:       #0F0F0F;

  --accent-hover:  #6390FF;
  --up-bright:     #4DD0C4;
  --down-bright:   #FF8A85;
  --accent-bright: #8FAFFF;
  --warn-bright:   #E0A83C;

  --soft-up:       #A7E3DC;
  --soft-down:     #FBBDBB;
  --soft-info:     #C3D4FF;
  --soft-warn:     #F3D9A4;
  --soft-elite:    #C4B5FD;

  /* Surfaces translucides. Un gris figé y trahirait le thème : ces
     couches laissent voir la page au travers, elles doivent donc être
     déclarées, pas devinées.

       --glass   barre collante, étiquette posée sur un visuel
       --scrim   voile qui assombrit la page derrière une fenêtre modale
                 (sombre dans les DEUX thèmes : c'est ce qui fait ressortir
                 la fenêtre, pas une teinte d'ambiance)
       --halo    liseré qui détache un repère du fond du graphique */
  --glass:         rgba(15, 15, 15, .84);
  --scrim:         rgba(4, 5, 8, .60);
  --halo:          rgba(8, 9, 13, .85);
  --rule-strong:   rgba(211, 214, 220, .78);

}

/* ═══════════════════════════════════════════════════════════════════
   THÈME CLAIR
   ─────────────────────────────────────────────────────────────────
   Mêmes jetons, autres valeurs : aucune règle de mise en page ne
   connaît le thème. Le sélecteur porte sur <html data-theme="light">,
   posé par static/theme.js avant le premier rendu.

   Les couleurs sémantiques sont ASSOMBRIES, pas reprises telles quelles :
   le turquoise #26A69A et l'orange #F0A94B, parfaitement lisibles sur
   fond noir, tombent respectivement à 2,4:1 et 2,0:1 sur fond blanc —
   sous le seuil de lisibilité. Les teintes retenues ici tiennent 4,5:1.
   ═══════════════════════════════════════════════════════════════ */
:root[data-theme="light"] {
  color-scheme: light;

  --bg:            #F6F7F9;
  --surface:       #FFFFFF;
  --surface-2:     #F1F3F7;
  --raised:        #E3E7EF;

  --border:        #E3E7EE;
  --border-strong: #CBD2DE;

  --text:          #121722;
  --text-2:        #4A5468;
  --text-3:        #5C6880;

  --accent:        #2F5FE0;
  --accent-2:      #6D3FD4;
  --accent-soft:   rgba(47, 95, 224, .09);

  --up:            #0A7A6E;
  --down:          #C0322E;
  --warn:          #A8660D;
  --info:          #5A6B80;

  /* Sur fond clair un aplat à 15 % vire au pastel sale : on descend l'alpha
     et on garde des teintes plus saturées, la lisibilité venant du texte. */
  --up-soft:       rgba(10, 122, 110, .11);
  --down-soft:     rgba(192, 50, 46, .10);
  --info-soft:     rgba(90, 107, 128, .12);
  --warn-soft:     rgba(168, 102, 13, .11);

  --veil:          17 24 39;
  --shade:         15 23 42;
  --shade-k:       .16;

  --well:          #EDF0F5;
  --sunken:        #F4F6FA;
  --elevated:      #FFFFFF;
  --divider:       #D8DDE6;

  --on-contrast:   #FFFFFF;
  --on-warn:       #FFFFFF;

  --accent-hover:  #244FCB;
  --up-bright:     #0A7A6E;
  --down-bright:   #C0322E;
  --accent-bright: #2B55C9;
  --warn-bright:   #A8660D;

  --soft-up:       #0A6257;
  --soft-down:     #A32521;
  --soft-info:     #1E458F;
  --soft-warn:     #7C4A08;
  --soft-elite:    #5326B8;

  --shadow-lg:     0 20px 50px rgb(var(--shade) / .10), 0 4px 14px rgb(var(--shade) / .07);
  --shadow-sm:     0 1px 3px rgb(var(--shade) / .09);
  --glass:         rgba(255, 255, 255, .86);
  --scrim:         rgba(15, 23, 42, .38);
  --halo:          rgba(255, 255, 255, .92);
  --rule-strong:   rgba(45, 55, 75, .55);

}

/* Le graphique et sa grille suivent le thème : app.js lit ces deux
   variables au montage (cssVar) et saas-theme.js les relit à chaque
   bascule. Une grille à #ECEFF4 sur fond blanc reste perceptible sans
   quadriller l'écran. */
:root[data-theme="light"] {
  --chart-bg:      #FFFFFF;
  --grid:          #ECEFF4;
  --toolbar-fg:    #121722;
  --glass:         rgba(255, 255, 255, .86);
}


/* ─── Reset / base ─────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* ─── Jeu d'icônes (Lucide) ────────────────────────────────────────
   Taille par défaut calée sur le texte voisin : une icône posée dans un
   contexte non prévu suit la typo au lieu de prendre la taille par défaut
   du SVG. Toute règle de contexte plus précise l'emporte. */
.ico {
  width: 1em;
  height: 1em;
  flex: none;
  vertical-align: middle;
}
/* Enveloppe posée par PipsterIcons.element() quand l'icône côtoie du texte. */
.ico-slot { display: inline-flex; flex: none; }
.ico-inline { margin-inline-end: 5px; vertical-align: -.15em; }


html, body { height: 100%; }

body {
  font-family: var(--font);
  font-size: 13px;
  line-height: 1.45;
  color: var(--text);
  background: var(--bg);
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: rgba(78, 127, 255, .35); }

button {
  font-family: inherit;
  font-size: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
}

button:focus-visible,
input:focus-visible,
select:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.hidden { display: none !important; }

.up   { color: var(--up); }
.down { color: var(--down); }

/* Scrollbars discrets */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgb(var(--veil) / .13);
  border-radius: 99px;
}
::-webkit-scrollbar-thumb:hover { background: rgb(var(--veil) / .22); }

/* ═══════════════════════════════════════════════════════════
   HEADER
════════════════════════════════════════════════════════════ */
#toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  height: 56px;
  flex: none;
  padding: 0 16px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: relative;
  z-index: 60;
}

.tb-spacer { flex: 1; }

/* Brand */
.tb-brand {
  display: flex;
  align-items: center;
  gap: 9px;
  flex: none;
  user-select: none;
}

.tb-logo {
  /* L'icône est un peu plus haute que large : on fixe la hauteur et on
     laisse la largeur suivre, sinon le dessin serait écrasé. */
  height: 27px;
  width: auto;
  display: block;
  color: var(--toolbar-fg, #F2F2F2);
}

.tb-word {
  font-size: 14.5px;
  font-weight: 800;
  letter-spacing: .06em;
}

.tb-pro {
  font-size: 9px;
  font-weight: 800;
  letter-spacing: .14em;
  color: #fff;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  padding: 2.5px 6px;
  border-radius: 5px;
  transform: translateY(-1px);
}

/* Recherche symbole */
#symbolWrap {
  position: relative;
  flex: none;
}

.sw-icon {
  position: absolute;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
  width: 14px;
  height: 14px;
  color: var(--text-3);
  pointer-events: none;
}

#symbolInput {
  width: 208px;
  height: 34px;
  padding: 0 12px 0 32px;
  font: 600 12.5px var(--font);
  letter-spacing: .04em;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  transition: border-color .15s, background .15s;
}

#symbolInput::placeholder {
  color: var(--text-3);
  font-weight: 500;
  letter-spacing: 0;
}

#symbolInput:hover { border-color: var(--border-strong); }

#symbolInput:focus {
  outline: none;
  border-color: var(--accent);
  background: var(--surface);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* Dropdown symboles */
#symbolDropdown {
  display: none;
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  width: 316px;
  max-height: 348px;
  overflow-y: auto;
  list-style: none;
  background: var(--well);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  box-shadow: var(--shadow-lg);
  padding: 6px;
  z-index: 100;
}

#symbolDropdown.open { display: block; }

#symbolDropdown .sd-group-header {
  padding: 9px 10px 4px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-3);
}

#symbolDropdown li[data-ticker] {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 7px 10px;
  border-radius: 7px;
  cursor: pointer;
  transition: background .1s;
}

#symbolDropdown li[data-ticker]:hover,
#symbolDropdown li[data-ticker].active {
  background: rgb(var(--veil) / .06);
}

.sd-ticker {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: .03em;
  flex: none;
}

.sd-name {
  font-size: 11.5px;
  color: var(--text-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── SOURCE DE DONNÉES DANS LA RECHERCHE ────────────────────────────────
   `XAUUSD · OANDA` et `XAUUSD · Swissquote` sont deux lignes du MÊME
   instrument. L'étiquette est poussée à droite et volontairement discrète :
   c'est une précision, pas le nom de l'instrument. Elle n'apparaît que
   lorsqu'un choix existe — sur un instrument à source unique, l'écrire
   serait du bruit. */
.sd-src {
  margin-left: auto;
  flex: none;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-3);
  background: rgb(var(--veil) / .07);
  border: 1px solid rgb(var(--veil) / .10);
  border-radius: 5px;
  padding: 2px 6px;
  white-space: nowrap;
}

#symbolDropdown li[data-ticker]:hover .sd-src,
#symbolDropdown li[data-ticker].active .sd-src {
  color: var(--text-2);
  border-color: rgb(var(--veil) / .18);
}

/* Intervalles — segmented control */
/* ── Sélecteur d'unité de temps : favoris + menu complet ──────────────── */
#tfPicker {
  position: relative;
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  flex: none;
}

#ivBtns {
  display: flex;
  align-items: center;
  gap: 2px;
  flex: none;
}

.tf-more {
  display: flex;
  align-items: center;
  gap: 3px;
  height: 26px;
  padding: 0 7px 0 9px;
  margin-left: 3px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-3);
  border-radius: 7px;
  border-left: 1px solid var(--border);
  transition: color .15s, background .15s;
}
.tf-more:hover, .tf-more.open { color: var(--text); background: var(--raised); }
.tf-more svg {
  width: 13px; height: 13px;
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform .18s;
}
.tf-more.open svg { transform: rotate(180deg); }

.tf-menu {
  position: absolute;
  top: calc(100% + 7px);
  left: 0;
  z-index: 90;
  width: 232px;
  max-height: min(70vh, 460px);
  overflow-y: auto;
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg, 0 18px 44px rgb(var(--shade) / calc(.5 * var(--shade-k))));
}
.tf-menu[hidden] { display: none; }

.tf-group {
  padding: 10px 8px 5px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--text-3);
}
.tf-group:first-child { padding-top: 4px; }

.tf-row {
  display: flex;
  align-items: center;
  gap: 2px;
  border-radius: 7px;
}
.tf-row:hover { background: var(--raised); }

.iv-btn.tf-item {
  flex: 1;
  height: 30px;
  justify-content: flex-start;
  text-align: left;
  padding: 0 8px;
  font-weight: 500;
}
.iv-btn.tf-item.active { background: transparent; box-shadow: none; color: var(--accent); font-weight: 700; }

.tf-star {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px; height: 26px;
  margin-right: 3px;
  border-radius: 6px;
  color: var(--text-3);
  opacity: 0;
  transition: opacity .15s, color .15s;
}
.tf-row:hover .tf-star, .tf-star.on { opacity: 1; }
.tf-star svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linejoin: round; }
.tf-star:hover { color: var(--text); }
.tf-star.on { color: var(--warn-bright); }
.tf-star.on svg { fill: currentColor; }

/* Unité que le fournisseur courant ne sert pas (secondes hors OANDA). */
.tf-na, .tf-na .iv-btn { opacity: .38; cursor: not-allowed; }
.tf-row.tf-na:hover { background: transparent; }

.iv-btn {
  height: 26px;
  padding: 0 10px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-3);
  border-radius: 7px;
  transition: color .15s, background .15s;
}

.iv-btn:hover { color: var(--text-2); }

.iv-btn.active {
  color: var(--text);
  background: var(--raised);
  box-shadow: var(--shadow-sm);
}

/* Prix live */
#priceBar {
  display: flex;
  align-items: baseline;
  gap: 7px;
  flex: none;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

#pbSymbol {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .08em;
  color: var(--text-3);
}

#pbPrice {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -.01em;
}

#pbChange { font-size: 11.5px; font-weight: 600; }

/* ── Style des bougies : bouton pictogramme + menu ────────────────────── */
#csPicker { position: relative; flex: none; }

.cs-btn {
  display: flex;
  align-items: center;
  gap: 1px;
  height: 30px;
  padding: 0 5px 0 7px;
  color: var(--text-2);
  border-radius: 7px;
  transition: color .15s, background .15s;
}
.cs-btn:hover, .cs-btn.open { color: var(--text); background: var(--raised); }

.cs-icon { display: flex; }
.cs-glyph { width: 19px; height: 19px; }

.cs-caret {
  width: 12px; height: 12px;
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
  color: var(--text-3);
  transition: transform .18s;
}
.cs-btn.open .cs-caret { transform: rotate(180deg); }

/* Le panneau reprend la chrome du menu d'unités de temps, mais s'aligne à
   droite : ce bouton vit dans la moitié droite de la barre. Le plafond de
   largeur le garde dans l'écran quand la barre se resserre. */
.cs-menu { left: auto; right: 0; width: 214px; max-width: calc(100vw - 16px); }

.cs-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  height: 32px;
  padding: 0 8px;
  font-size: 12px;
  font-weight: 500;
  text-align: left;
  color: var(--text-2);
  border-radius: 7px;
  transition: color .15s, background .15s;
}
.cs-item:hover { color: var(--text); background: var(--raised); }
.cs-item .cs-glyph { width: 17px; height: 17px; flex: none; color: var(--text-3); }
.cs-item:hover .cs-glyph { color: var(--text-2); }
.cs-item.active { color: var(--accent); font-weight: 700; }
.cs-item.active .cs-glyph { color: var(--accent); }

.sm-row-check input {
  appearance: none;
  -webkit-appearance: none;
  width: 34px;
  height: 20px;
  flex: none;
  border-radius: 99px;
  background: var(--raised);
  border: 1px solid var(--border);
  position: relative;
  cursor: pointer;
  transition: background .18s, border-color .18s;
}

.sm-row-check input::before {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--text-2);
  transition: transform .18s, background .18s;
}

.sm-row-check input:checked {
  background: var(--accent);
  border-color: var(--accent);
}

.sm-row-check input:checked::before {
  transform: translateX(14px);
  background: #fff;
}

/* Select preset */
.select-wrap { position: relative; flex: none; }

#presetSelect {
  appearance: none;
  -webkit-appearance: none;
  height: 34px;
  padding: 0 28px 0 12px;
  font: 600 11.5px var(--font);
  color: var(--text-2);
  background: var(--surface-2)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235E6678' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")
    no-repeat right 9px center / 12px;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  cursor: pointer;
  transition: border-color .15s, color .15s;
}

#presetSelect:hover { border-color: var(--border-strong); color: var(--text); }

/* Bouton Actualiser */
#loadBtn {
  display: flex;
  align-items: center;
  gap: 7px;
  height: 34px;
  padding: 0 14px;
  flex: none;
  font-size: 12px;
  font-weight: 600;
  color: #fff;
  background: var(--accent);
  border-radius: var(--r-md);
  box-shadow: 0 2px 10px rgba(78, 127, 255, .28);
  transition: background .15s, transform .1s;
}

#loadBtn:hover { background: var(--accent-hover); }
#loadBtn:active { transform: translateY(1px); }

#loadBtn svg { width: 13px; height: 13px; }

/* Bouton alertes — et, à la même boîte, Rejeu et le calendrier. Les trois
   commandes de la barre partagent UNE règle : un bouton dessiné à part
   aurait fini par dériver d'un demi-pixel à chaque retouche. */
#alertsBtn,
#replayBtn,
#bareBtn,
#ecoBtn {
  position: relative;
  height: 34px;
  padding: 0 12px;
  gap: 7px;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-2);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  transition: color .15s, border-color .15s, background .15s;
}
#alertsBtn .ab-label,
#replayBtn .ab-label,
#bareBtn .ab-label,
#ecoBtn .ab-label { font-size: 12px; font-weight: 600; }
#replayBtn:hover,
#bareBtn:hover,
#ecoBtn:hover { color: var(--text); border-color: var(--border-strong); }
/* Rejeu actif : le bouton reste allumé, comme la cloche. */
#replayBtn.on,
/* Graphique nu actif : même signal que le rejeu — un état qu'on VOIT,
   sinon on cherche pourquoi le graphique est vide. */
#bareBtn.on { color: var(--accent); border-color: rgba(78,127,255,.5); background: var(--accent-soft); }
@media (max-width: 1280px) {
  #alertsBtn, #replayBtn, #bareBtn, #ecoBtn { width: 34px; padding: 0; }
  #alertsBtn .ab-label, #replayBtn .ab-label, #bareBtn .ab-label, #ecoBtn .ab-label { display: none; }
}

#alertsBtn:hover { color: var(--text); border-color: var(--border-strong); }

#alertsBtn.on {
  color: var(--accent-bright);
  border-color: rgba(78, 127, 255, .5);
  background: var(--accent-soft);
}

/* Sans cette extension, le SVG du bouton Rejeu n'avait aucune dimension et
   se réduisait à zéro dans le flex — bouton sans icône. */
#alertsBtn svg,
#replayBtn svg,
#ecoBtn svg { width: 15px; height: 15px; }

#alertsBtn .ab-dot {
  display: none;
  position: absolute;
  top: 6px;
  right: 7px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 6px var(--accent);
}

#alertsBtn.on .ab-dot { display: block; }

/* Toasts d'alerte */
#toastStack {
  position: fixed;
  top: 106px;
  right: 16px;
  z-index: 300;
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 304px;
  max-width: calc(100vw - 32px);
  pointer-events: none;
}

.toast {
  background: var(--glass);
  backdrop-filter: blur(16px) saturate(1.4);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  border: 1px solid var(--border-strong);
  border-left: 3px solid var(--accent);
  border-radius: 12px;
  padding: 10px 13px;
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transform: translateX(14px);
  transition: opacity .25s, transform .25s;
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: 10px;
}

/* L'icône reprend la couleur du liseré : dans une pile, on identifie la nature
   de l'alerte avant même d'avoir lu le titre. */
.toast-ico {
  flex: none;
  width: 16px;
  height: 16px;
  margin-top: 1px;
  color: inherit;
}
.toast-ico svg { width: 16px; height: 16px; }
.toast-main { min-width: 0; flex: 1; }

.toast.signal .toast-ico { color: var(--accent); }
.toast.news   .toast-ico { color: var(--info); }
.toast.price  .toast-ico,
.toast.entry  .toast-ico { color: var(--warn); }
.toast.tp     .toast-ico { color: var(--up); }
.toast.sl     .toast-ico { color: var(--down); }

.toast.show { opacity: 1; transform: none; }

.toast.signal { border-left-color: var(--accent); }
.toast.news   { border-left-color: var(--info); }
.toast.price  { border-left-color: var(--warn); }
.toast.tp     { border-left-color: var(--up); }
.toast.sl     { border-left-color: var(--down); }
.toast.entry  { border-left-color: var(--warn); }

.toast-title { font-size: 12px; font-weight: 700; }

.toast-body {
  font-size: 11px;
  color: var(--text-2);
  margin-top: 2px;
  font-variant-numeric: tabular-nums;
}

/* Bouton réglages */
#settingsBtn {
  width: 34px;
  height: 34px;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-2);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  transition: color .15s, border-color .15s;
}

#settingsBtn:hover { color: var(--text); border-color: var(--border-strong); }

#settingsBtn svg { width: 15px; height: 15px; }

/* ═══════════════════════════════════════════════════════════
   TERMINAL
════════════════════════════════════════════════════════════ */
#chartWrapper {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* Bandeau instrument */
#instrumentStrip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  height: 40px;
  flex: none;
  padding: 0 16px;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

.inst-main {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  overflow: hidden;
}

/* ─── LA PASTILLE D'ÉTAT DU MARCHÉ ──────────────────────────────────────
   ELLE ÉTAIT VERTE ET PULSANTE EN PERMANENCE, week-end compris. Le repos
   est désormais NEUTRE : le vert se mérite, il faut que api/info.php ait
   confirmé que l'instrument se traite. Sans réponse — ou sur une place dont
   nous ne connaissons pas les horaires — la pastille ne prétend rien.
   ──────────────────────────────────────────────────────────────────── */
.inst-dot {
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: 50%;
  background: var(--text-3);
  box-shadow: none;
  animation: none;
}
body[data-market-state="open"] .inst-dot {
  background: var(--up);
  box-shadow: 0 0 0 0 rgba(38, 166, 154, .5);
  animation: pulse 2.4s ease-out infinite;
}
body[data-market-state="closed"] .inst-dot {
  background: var(--warn);
  box-shadow: none;
  animation: none;
}

/* ─── MARCHÉ FERMÉ ──────────────────────────────────────────────────────
   L'ambre, la seule couleur d'alerte de la charte — la même que celle du
   calendrier imminent, pour ne pas inventer un second vocabulaire d'alerte
   sur la même ligne. */
.market-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .01em;
  padding: 2.5px 8px;
  border-radius: 99px;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  margin-left: 6px;
  color: var(--warn);
  border: 1px solid color-mix(in srgb, var(--warn) 38%, transparent);
  background: color-mix(in srgb, var(--warn) 10%, transparent);
}
/* PIÈGE déjà payé sur #streamDot : le `display: inline-flex` ci-dessus BAT
   l'attribut `hidden`, qui n'est qu'un `display: none` à spécificité nulle.
   Sans cette ligne la pastille s'afficherait VIDE en permanence. */
.market-badge[hidden] { display: none; }

/* La variation cesse de se teindre quand plus rien ne varie : « ▲ 0,000
   (+0,00 %) » en vert, un samedi, décrit un marché qui monte. */
body[data-market-state="closed"] #pbChange {
  color: var(--text-3);
  opacity: .75;
}

/* ─── CE QUE LA LIGNE CESSE DE DIRE, MARCHÉ FERMÉ ───────────────────────
   La garde NEWS surveille des publications qu'aucune séance ne jouera, et
   « 0 trade » n'est pas un bilan mais la conséquence mécanique d'un marché
   fermé. Masqués, pas supprimés : tout revient seul à la réouverture. */
body[data-market-state="closed"] #newsGuardBadge,
body[data-market-state="closed"] #ogDayChip { display: none; }

/* L'OHLC ne part que s'il a un remplaçant — `data-market-reopen` n'est posé
   que lorsque le cadran tourne vraiment. Sans heure de réouverture, un vide
   vaudrait moins que la dernière donnée connue. */
body[data-market-reopen="1"] #instOhlc { display: none; }

.market-reopen {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  font-size: 11.5px;
  white-space: nowrap;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.market-reopen .mr-clock {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--warn);
  font-variant-numeric: tabular-nums;
}
.market-reopen[hidden] { display: none; }

@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 rgba(38, 166, 154, .45); }
  70%  { box-shadow: 0 0 0 6px rgba(38, 166, 154, 0); }
  100% { box-shadow: 0 0 0 0 rgba(38, 166, 154, 0); }
}

#instName { font-size: 13px; font-weight: 600; }

.inst-dim { font-size: 12px; color: var(--text-3); }

.dxy-badge {
  font-size: 10.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: .03em;
  padding: 2.5px 8px;
  border-radius: 99px;
  border: 1px solid var(--border-strong);
  color: var(--text-2);
  margin-left: 6px;
}

.dxy-badge.up   { color: var(--up);   border-color: rgba(38, 166, 154, .4);  background: rgba(38, 166, 154, .08); }
.dxy-badge.down { color: var(--down); border-color: rgba(239, 83, 80, .4);   background: rgba(239, 83, 80, .08); }

/* Badge calendrier économique */
.eco-badge {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .02em;
  padding: 2.5px 9px;
  border-radius: 99px;
  margin-left: 6px;
  max-width: 300px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: default;
}

.eco-badge.warn {
  color: var(--warn);
  border: 1px solid rgba(240, 169, 75, .45);
  background: rgba(240, 169, 75, .09);
}

.eco-badge.imminent {
  color: var(--down-bright);
  border: 1px solid rgba(239, 83, 80, .55);
  background: rgba(239, 83, 80, .12);
  animation: ecoPulse 1.6s ease-in-out infinite;
}

/* Résultat publié : couleur = effet mécanique sur l'instrument */
.eco-badge.result-up,
.eco-badge.result-down,
.eco-badge.result-flat {
  max-width: 460px;
  font-weight: 600;
}

.eco-badge.result-up {
  color: #4DD0C4;
  border: 1px solid rgba(38, 166, 154, .45);
  background: rgba(38, 166, 154, .1);
}

.eco-badge.result-down {
  color: var(--down-bright);
  border: 1px solid rgba(239, 83, 80, .45);
  background: rgba(239, 83, 80, .1);
}

.eco-badge.result-flat {
  color: var(--text-2);
  border: 1px solid var(--border-strong);
  background: rgb(var(--veil) / .05);
}

@keyframes ecoPulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: .55; }
}

/* ─── NEWS PROTECTION · la pastille de garde ──────────────────────────────
   Voisine de #ecoBadge, et pourtant autre chose : celle-ci n'annonce pas
   une publication, elle annonce ce que le terminal S'AUTORISE. C'est un
   état permanent, pas un événement — donc discrète par défaut, et elle ne
   monte en couleur que lorsqu'elle refuse quelque chose.

   AUCUNE ANIMATION. #ecoBadge.imminent pulse déjà ; deux clignotements
   côte à côte sur la même ligne, c'est une salle d'alarme, pas un
   terminal. Ce qui distingue les quatre états ici, c'est l'encre. */
.news-guard {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .02em;
  padding: 2.5px 9px;
  border-radius: 99px;
  margin-left: 6px;
  max-width: 320px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: default;
  border: 1px solid var(--border-strong);
  color: var(--text-2);
  background: rgb(var(--veil) / .05);
}
.news-guard[hidden] { display: none; }

/* ─── PLAGE HORAIRE DE TRADING ─────────────────────────────────────────
   Même gabarit que la garde des news, encre différente : celle-ci ne
   signale aucun danger, elle rappelle une décision que l'abonné a prise
   lui-même. Elle n'emprunte donc jamais le rouge du refus. */
.session-guard {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .02em;
  padding: 2.5px 9px;
  border-radius: 99px;
  margin-left: 6px;
  max-width: 320px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: default;
  border: 1px solid var(--border);
  color: var(--text-3);
  background: transparent;
  font-variant-numeric: tabular-nums;
}
.session-guard[hidden] { display: none; }

/* En séance : volontairement PÂLE. « Vous pouvez trader » n'est pas une
   nouvelle, c'est l'état normal — le tirer à l'œil userait l'attention
   qu'il faudra pour l'état inverse. */
.session-guard.is-open {
  color: var(--text-3);
  border-color: var(--border);
  font-weight: 600;
}

/* Hors séance : neutre et non rouge. Le rouge dit « danger » et appartient
   au refus des news ; ici il n'y a aucun danger, seulement une porte que
   l'abonné a lui-même fermée. Deux vocabulaires distincts sur la même
   ligne, sans quoi on ne saurait plus lequel exige une action. */
.session-guard.is-closed {
  color: var(--text-2);
  border-color: var(--border-strong);
  background: rgb(var(--veil) / .07);
}

/* Voie libre. Volontairement PLUS PÂLE que ses voisines : « rien à
   signaler » ne doit pas tirer l'œil autant qu'un refus. */
.news-guard.is-safe {
  color: var(--text-3);
  border-color: var(--border);
  background: transparent;
  font-weight: 600;
}

.news-guard.is-risk {
  color: var(--warn);
  border-color: rgba(240, 169, 75, .45);
  background: rgba(240, 169, 75, .09);
}

/* Le seul état qui INTERDIT quelque chose : il porte l'encre du refus. */
.news-guard.is-lock {
  color: var(--down-bright);
  border-color: rgba(239, 83, 80, .55);
  background: rgba(239, 83, 80, .12);
}

/* Le refroidissement n'est plus un danger, c'est une attente. Neutre. */
.news-guard.is-cool {
  color: var(--text-2);
  border-color: var(--border-strong);
  background: rgb(var(--veil) / .07);
}

/* Le calendrier ne répond pas. Le trait discontinu dit « je ne sais pas »
   sans emprunter l'encre d'un refus, qui serait une affirmation. */
.news-guard.is-degraded {
  color: var(--text-3);
  border-style: dashed;
  background: transparent;
  font-weight: 600;
}

/* La ligne de décision, dans le bandeau de signal. Elle vit à côté de
   #dvDecision sans jamais lui disputer son nœud : deux écrivains sur un
   même élément, c'est un affichage qui clignote. */
.dv-news {
  display: flex;
  align-items: center;
  min-width: 0;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--down-bright);
  background: rgba(239, 83, 80, .12);
  border: 1px solid rgba(239, 83, 80, .4);
}
.dv-news[hidden] { display: none; }

/* La ligne de séance. Même forme que .dv-news, encre neutre : elle
   n'annonce pas un risque de marché mais l'application d'un réglage. */
.dv-session {
  display: flex;
  align-items: center;
  min-width: 0;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text-2);
  background: rgb(var(--veil) / .07);
  border: 1px solid var(--border-strong);
}
.dv-session[hidden] { display: none; }

/* Prévenir n'est pas interdire : l'ambre, pas le rouge. */
.dv-news[data-state="PRE_NEWS"] {
  color: var(--warn);
  background: rgba(240, 169, 75, .12);
  border-color: rgba(240, 169, 75, .4);
}

/* Le refroidissement retient l'entrée sans qu'un chiffre soit imminent :
   il se lit comme une attente, pas comme une alerte. */
.dv-news[data-state="POST_NEWS_COOLDOWN"] {
  color: var(--text-2);
  background: rgb(var(--veil) / .07);
  border-color: var(--border-strong);
}

.inst-right {
  display: flex;
  align-items: center;
  gap: 16px;
  flex: none;
}

#statusMsg { font-size: 11px; color: var(--text-3); }

#instOhlc {
  font-size: 11.5px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--text-2);
  letter-spacing: .02em;
}

/* Scène du graphique */
#chartStage {
  --plot-width: 100%;
  --plot-center-x: 50%;
  --price-scale-width: 0px;
  flex: 1;
  min-height: 0;
  position: relative;
  background: var(--chart-bg);
}

#chartContainer {
  position: relative;
  width: 100%;
  height: 100%;
}

#tvWidgetHost { width: 100%; height: 100%; }

body:not(.widget-mode) #tvWidgetHost { display: none; }

/* Marqueur du dernier prix — axe droit façon TradingView */
.live-price-line {
  --live-price-color: #26a69a;
  position: absolute;
  z-index: 14;
  left: 0;
  right: var(--price-scale-width);
  height: 1px;
  pointer-events: none;
  background: repeating-linear-gradient(
    to right,
    var(--live-price-color) 0,
    var(--live-price-color) 2px,
    transparent 2px,
    transparent 6px
  );
}

.live-price-marker {
  --live-price-color: #26a69a;
  --live-price-symbol-bg: #168c82;
  --live-price-row-height: 26px;
  position: absolute;
  z-index: 18;
  right: 0;
  display: flex;
  align-items: flex-start;
  pointer-events: none;
  color: #fff;
  font-variant-numeric: tabular-nums;
  text-rendering: geometricPrecision;
}

.live-price-marker[hidden],
.live-price-line[hidden] {
  display: none !important;
}

.live-price-marker.up,
.live-price-line.up {
  --live-price-color: #26a69a;
}

.live-price-marker.up {
  --live-price-symbol-bg: #168c82;
}

.live-price-marker.down,
.live-price-line.down {
  --live-price-color: #ef5350;
}

.live-price-marker.down {
  --live-price-symbol-bg: #c53f3d;
}

.live-price-symbol {
  display: inline-flex;
  align-items: center;
  height: var(--live-price-row-height);
  padding: 0 8px;
  transform: translateY(-50%);
  border-radius: 4px 0 0 4px;
  background: var(--live-price-symbol-bg);
  box-shadow: inset -1px 0 rgb(var(--veil) / .22);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .025em;
  white-space: nowrap;
}

.live-price-stack {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  margin-top: calc(var(--live-price-row-height) / -2);
  min-width: 88px;
  overflow: hidden;
  border-radius: 0 4px 4px 0;
  background: var(--live-price-color);
  box-shadow: 0 2px 7px rgb(var(--shade) / calc(.28 * var(--shade-k)));
}

.live-price-value {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  height: var(--live-price-row-height);
  padding: 0 8px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
}

.live-price-countdown {
  display: flex;
  align-items: center;
  height: 18px;
  padding: 0 8px 2px;
  border-top: 1px solid rgb(var(--veil) / .16);
  font-size: 10.5px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: .025em;
  white-space: nowrap;
}

.live-price-countdown:empty {
  display: none;
}

/* Étiquette d’alerte au survol, façon TradingView */
.alert-line-hover {
  position: absolute;
  z-index: 46;
  height: 28px;
  display: flex;
  align-items: center;
  transform: translateY(-50%);
  overflow: hidden;
  color: var(--text);
  background: var(--sunken);
  border: 1px solid #9a9da4;
  border-radius: 5px;
  box-shadow: 0 2px 7px rgb(var(--shade) / calc(.42 * var(--shade-k)));
  font-family: var(--font);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.alert-line-hover-text {
  padding: 0 9px;
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: .005em;
  line-height: 1;
}

.alert-line-delete {
  width: 31px;
  height: 100%;
  display: grid;
  flex: none;
  place-items: center;
  color: var(--text);
  background: transparent;
  border: 0;
  border-left: 1px solid rgb(var(--veil) / .13);
  cursor: pointer;
}

.alert-line-delete:hover,
.alert-line-delete:focus-visible {
  outline: none;
  color: #fff;
  background: rgba(239, 83, 80, .28);
}

.alert-line-delete svg {
  width: 19px;
  height: 19px;
}

/* Confirmation de suppression d’alerte, façon TradingView */
.alert-delete-overlay {
  position: fixed;
  z-index: 220;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 20px;
  background: rgb(var(--shade) / calc(.68 * var(--shade-k)));
}

.alert-delete-overlay[hidden] {
  display: none !important;
}

.alert-delete-dialog {
  position: relative;
  width: min(640px, calc(100vw - 40px));
  padding: 52px 48px 38px;
  color: var(--text);
  background: var(--elevated);
  border: 1px solid rgb(var(--veil) / .025);
  border-radius: 11px;
  box-shadow: 0 18px 54px rgb(var(--shade) / calc(.58 * var(--shade-k)));
  font-family: var(--font);
}

.alert-delete-ico {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  margin-bottom: 18px;
  color: var(--down, #ef5350);
  background: rgba(239, 83, 80, .12);
  border-radius: 10px;
}
.alert-delete-ico svg { width: 19px; height: 19px; }

.alert-delete-dialog h2 {
  margin: 0;
  color: var(--text);
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -.01em;
  line-height: 1.3;
}

.alert-delete-dialog p {
  max-width: 510px;
  margin: 25px 0 0;
  color: var(--text);
  font-size: 13.5px;
  font-weight: 400;
  line-height: 1.65;
}

.alert-delete-close {
  position: absolute;
  top: 21px;
  right: 22px;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  color: var(--text);
  background: transparent;
  border: 0;
  border-radius: 6px;
  cursor: pointer;
}

.alert-delete-close:hover,
.alert-delete-close:focus-visible {
  outline: none;
  color: #fff;
  background: rgb(var(--veil) / .08);
}

.alert-delete-close svg {
  width: 27px;
  height: 27px;
}

.alert-delete-actions {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
  margin-top: 34px;
}

.alert-delete-cancel,
.alert-delete-confirm {
  height: 38px;
  padding: 0 17px;
  border-radius: 7px;
  font-family: var(--font);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}

.alert-delete-cancel {
  color: var(--text);
  background: transparent;
  border: 1px solid #55575b;
}

.alert-delete-cancel:hover,
.alert-delete-cancel:focus-visible {
  outline: none;
  background: rgb(var(--veil) / .06);
  border-color: #71737a;
}

.alert-delete-confirm {
  color: #fff;
  background: #f23645;
  border: 1px solid #f23645;
}

.alert-delete-confirm:hover,
.alert-delete-confirm:focus-visible {
  outline: none;
  background: #ff4a57;
  border-color: #ff4a57;
}

@media (max-width: 640px) {
  .alert-delete-dialog {
    padding: 47px 24px 25px;
  }

  .alert-delete-dialog p {
    margin-top: 19px;
  }

  .alert-delete-actions {
    margin-top: 26px;
  }
}

/* Sélecteur de prix + menu contextuel façon TradingView */
.price-selector-line {
  position: absolute;
  z-index: 24;
  left: 0;
  right: var(--price-scale-width);
  height: 1px;
  pointer-events: none;
  background: repeating-linear-gradient(
    to right,
    var(--rule-strong) 0,
    var(--rule-strong) 6px,
    transparent 6px,
    transparent 13px
  );
}

.price-selector-chip {
  position: absolute;
  z-index: 36;
  right: 0;
  display: flex;
  align-items: center;
  height: 26px;
  padding: 0;
  transform: translateY(-50%);
  color: var(--text);
  background: transparent;
  border: 0;
  border-radius: 3px;
  box-shadow: 0 2px 8px rgb(var(--shade) / calc(.28 * var(--shade-k)));
  cursor: pointer;
  font-family: var(--font);
  font-variant-numeric: tabular-nums;
}

.price-selector-chip[hidden],
.price-selector-line[hidden],
.alert-line-hover[hidden],
.price-action-menu[hidden],
.price-action-row[hidden],
.price-action-divider[hidden] {
  display: none !important;
}

.price-selector-plus {
  width: 34px;
  height: 26px;
  display: grid;
  place-items: center;
  color: var(--text);
  background: #55575d;
  border-radius: 3px 0 0 3px;
}

.price-selector-plus svg {
  width: 21px;
  height: 21px;
}

.price-selector-value {
  min-width: 82px;
  height: 26px;
  display: flex;
  align-items: center;
  padding: 0 7px;
  background: #383c48;
  border-radius: 0 3px 3px 0;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .01em;
  line-height: 1;
  white-space: nowrap;
}

.price-selector-chip:hover .price-selector-plus {
  background: #63666d;
}

/* §11 — Collision avec le prix courant : la pastille s'écarte vers la gauche
   au lieu de le recouvrir. Elle reste à la même hauteur (le lien avec sa ligne
   pointillée est ce qui la rend lisible) et garde toute sa surface cliquable —
   aucune perte d'accessibilité, y compris au doigt. */
.price-selector-chip.is-clear-of-price {
  /* L'ANCRAGE EST CONSERVE. `right: auto` le supprimait : la pastille
     retombait a sa position STATIQUE, c'est-a-dire au bord GAUCHE du
     graphique — 824 px plus loin, contre le rail de dessin, alors que le
     commentaire ci-dessus annonce un ecart de sa propre largeur.

     Et l'ecart se mesure sur le MARQUEUR, pas sur la pastille : le
     marqueur porte le symbole ET le prix, il est donc plus large qu'elle
     (153 px contre 116 sur XAUUSD). Se decaler de sa propre largeur la
     laissait chevaucher de 29 px. app.js publie la mesure dans
     `--clear-by` au moment ou il detecte la collision ; la valeur de
     repli ne sert qu'au tout premier rendu.

     `translate` et non `transform` : la propriete autonome se compose
     avec le `translateY(-50%)` de la regle de base au lieu de le
     remplacer — c'est ce qui gardait la pastille alignee sur sa ligne. */
  translate: calc(-1 * var(--clear-by, 132px)) 0;
  transition: translate .12s ease-out;
}
[dir="rtl"] .price-selector-chip.is-clear-of-price {
  translate: var(--clear-by, 132px) 0;
}
@media (prefers-reduced-motion: reduce) {
  .price-selector-chip.is-clear-of-price { transition: none; }
}

.price-action-menu {
  position: absolute;
  z-index: 55;
  right: var(--price-scale-width);
  width: 600px;
  max-width: calc(100% - var(--price-scale-width) - 16px);
  overflow: hidden;
  color: var(--text);
  background: #1f1f1f;
  border: 1px solid rgb(var(--veil) / .035);
  border-radius: 10px;
  box-shadow: 0 12px 34px rgb(var(--shade) / calc(.48 * var(--shade-k)));
  font-family: var(--font);
}

.price-action-row {
  width: 100%;
  min-height: 48px;
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr) auto;
  align-items: center;
  gap: 9px;
  padding: 0 18px 0 14px;
  color: inherit;
  background: transparent;
  border: 0;
  text-align: left;
  cursor: pointer;
}

.price-action-row:hover,
.price-action-row:focus-visible {
  outline: none;
  background: #2a2a2a;
}

.price-action-row.remove {
  color: #ff7772;
}

.price-action-row.remove .price-action-icon {
  color: #ff7772;
}

.price-action-row.remove:hover,
.price-action-row.remove:focus-visible {
  background: rgba(239, 83, 80, .11);
}

.price-action-icon {
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  color: var(--text);
}

.price-action-icon svg {
  width: 21px;
  height: 21px;
}

.price-action-text {
  overflow: hidden;
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: .003em;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.price-action-shortcut {
  color: #76787d;
  font-size: 10px;
  font-weight: 500;
  white-space: nowrap;
}

.price-action-divider {
  height: 1px;
  background: var(--divider);
}

@media (max-width: 720px) {
  .price-action-menu {
    width: calc(100% - var(--price-scale-width) - 12px);
    max-width: none;
  }

  .price-action-row {
    min-height: 44px;
    grid-template-columns: 32px minmax(0, 1fr);
    gap: 8px;
    padding: 0 14px 0 10px;
  }

  .price-action-icon { width: 24px; height: 24px; }
  .price-action-icon svg { width: 18px; height: 18px; }

  .price-action-text { font-size: 11.5px; }
  .price-action-shortcut { display: none; }
}

/* Overlay de chargement */
.loading-overlay {
  position: absolute;
  inset: 0;
  z-index: 30;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  background: var(--scrim);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  font-size: 12px;
  font-weight: 500;
  color: var(--text-2);
}

.spinner {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 2.5px solid rgb(var(--veil) / .1);
  border-top-color: var(--accent);
  animation: spin .75s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

/* ═══════════════════════════════════════════════════════════
   PANNEAUX DE L'INDICATEUR  (multi-TF + liquidité)
════════════════════════════════════════════════════════════ */
/* ─── Témoin de flux direct ────────────────────────────────────────────────
   Une pastille qui bat, à côté du nom du fournisseur. Turquoise parce qu'elle
   dit « ça vit », pas « achète » : c'est un état de connexion, pas une
   direction de marché — et elle ne s'allume jamais sans ticks réels. */
.stream-dot {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-inline-start: 2px;
  padding: 1px 7px 1px 5px;
  border-radius: 999px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--up);
  background: var(--up-soft);
  border: 1px solid rgba(38, 166, 154, .3);
  cursor: help;
}
.stream-dot[hidden] { display: none; }
.stream-dot i {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
  animation: stream-pulse 1.8s ease-in-out infinite;
}
@keyframes stream-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: .25; }
}
@media (prefers-reduced-motion: reduce) {
  .stream-dot i { animation: none; }
}
/* Sous 900 px la bande d'instrument est déjà serrée : la pastille garde son
   point, qui porte l'information, et abandonne le mot. */
@media (max-width: 900px) {
  .stream-dot span { display: none; }
  .stream-dot { padding: 1px 5px; }
}

#tvDashboard {
  position: absolute;
  top: 14px;
  left: var(--plot-center-x);
  transform: translateX(-50%);
  z-index: 20;
  max-width: calc(var(--plot-width) - 24px);
  display: flex;
  align-items: stretch;
  gap: 2px;
  background: var(--glass);
  backdrop-filter: blur(16px) saturate(1.4);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  padding: 5px;
}

.tv-table {
  border-collapse: separate;
  border-spacing: 4px;
}

.tv-table th {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-3);
  padding: 4px 10px 2px;
  text-align: center;
  white-space: nowrap;
}

.tv-table td {
  font-size: 11px;
  font-weight: 700;
  text-align: center;
  white-space: nowrap;
  padding: 5px 12px;
  border-radius: 7px;
  min-width: 82px;
}

/* Les six unités de temps ne sont pas six verdicts : c'est UNE information —
   « les autres échelles vont-elles dans le même sens ». Six rectangles pleins
   lui donnaient le poids visuel des cinq indicateurs réunis, alors qu'ils
   n'apportent qu'une nuance. Une pastille suffit à porter le sens, le texte
   redevient neutre, et la ligne cesse de peser autant que le tableau. */
.tv-table tfoot td {
  font-size: 10.5px;
  font-weight: 600;
  padding: 4px 10px;
  background: none;
  box-shadow: none;
  color: var(--text-2);
}

.tv-table tfoot td::before {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  margin-inline-end: 6px;
  background: var(--text-3);
  vertical-align: middle;
  position: relative;
  top: -1px;
}

.tv-table tfoot td.tv-bull::before { background: var(--up); }
.tv-table tfoot td.tv-bear::before { background: var(--down); }

.tv-brand {
  color: #fff;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  letter-spacing: .05em;
}

.tv-dash-scroll { overflow-x: auto; min-width: 0; }
.tv-dash-main   { display: flex; flex-direction: column; min-width: 0; }

/* ─── Synthèse du tableau ─────────────────────────────────────────────────
   Une seule ligne qui pèse les cinq jauges. La flèche et le libellé portent
   le SENS (rouge/turquoise), la réserve porte la NUANCE (orange) : les deux
   ne doivent jamais partager une couleur, sinon on retombe sur le problème
   qu'elle est censée résoudre.

   DEUX RANGS depuis le 2026-08-02. Verdict, jauges, réserve et autorisation
   étaient alignés sur la même ligne, au même poids : l'œil devait tout lire
   pour trouver la décision. Le premier rang la porte seul, le second explique
   sur quoi elle repose. */
.dash-verdict {
  display: flex;
  flex-direction: column;
  row-gap: 3px;
  padding: 5px 10px 6px;
  margin: 0 4px 1px;
  font-size: 11.5px;
  line-height: 1.3;
}
.dash-verdict[hidden] { display: none; }
/* Le filet ne sépare que du tableau : déplié, il marque la frontière ; replié,
   il soulignerait un bandeau qui n'a plus rien en dessous. */
#tvDashboard:not(.is-lite) .dash-verdict,
#tvDashboard.no-verdict .dash-verdict { border-bottom: 1px solid var(--border); }

/* Rang 1 — la décision. Le libellé à gauche, la pastille d'autorisation à
   droite : les deux pôles de la ligne se répondent au lieu de laisser le
   flanc droit vide (la carte était plus large que son contenu). */
.dv-top {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.dv-top .dv-validation { margin-inline-start: auto; }
/* Pastille absente (pas de plan) : le chevron reprend le côté droit. */
.dv-top .dv-validation[hidden] + .dv-more { margin-inline-start: auto; }

/* Rang 2 — LE MOTIF (§4). Il porte à lui seul la réponse à « pourquoi » :
   il est donc plus lisible que les jauges qui le suivent, et moins que le
   verdict qui le précède. Trois rangs, trois poids. */
.dv-motif {
  display: flex;
  align-items: baseline;
  gap: 6px;
  min-width: 0;
  font-size: 11.5px;
  line-height: 1.35;
}
.dv-motif[hidden] { display: none; }
.dv-motif-key {
  flex: none;
  font-weight: 600;
  color: var(--text-3);
}
.dv-motif-key::after { content: ' :'; }
[dir="rtl"] .dv-motif-key::after { content: ' :'; }
.dv-motif b {
  min-width: 0;
  font-weight: 700;
  color: var(--warn);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
[dir="rtl"] .dv-motif { unicode-bidi: plaintext; }

/* Rang 3 — le pourquoi */
.dv-why {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  row-gap: 4px;
  gap: 10px;
  min-width: 0;
}
.dv-why:empty { display: none; }

.dv-arrow { font-size: 12px; font-weight: 700; flex: none; }
.dv-label {
  font-weight: 700;
  font-size: 12.5px;
  letter-spacing: .01em;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dash-verdict.up   .dv-arrow, .dash-verdict.up   .dv-label { color: var(--up); }
.dash-verdict.down .dv-arrow, .dash-verdict.down .dv-label { color: var(--down); }
.dash-verdict.flat .dv-arrow, .dash-verdict.flat .dv-label { color: var(--text-2); }

/* ── Bouton de repli du tableau ──
   Le bandeau couvrait en permanence une bande de graphique large de six
   colonnes pour six indicateurs qu'on ne relit pas à chaque bougie. Il se
   replie sur son verdict, et se rouvre d'une pression. */
.dv-more {
  flex: none;
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  padding: 0;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--text-3);
  cursor: pointer;
  transition: color .15s, background .15s;
}
.dv-more:hover { color: var(--text); background: rgb(var(--veil) / .08); }
.dv-more-ico { width: 13px; height: 13px; transition: transform .25s ease-out; }
#tvDashboard:not(.is-lite) .dv-more-ico { transform: rotate(180deg); }
/* Sans verdict à afficher, le tableau est tout ce qui reste : le replier
   viderait le bandeau. Le bouton n'a alors plus d'objet. */
#tvDashboard.no-verdict .dv-more { display: none; }
#tvDashboard.is-lite:not(.no-verdict) .tv-dash-scroll { display: none; }

.dv-meter { display: flex; align-items: center; gap: 6px; white-space: nowrap; }
.dv-meter-label {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .01em;
  /* La casse capitale et l'interlettrage étaient là pour poser un en-tête ;
     sur une ligne d'explication ils ne font que ralentir la lecture — les
     capitales n'ont pas de silhouette, on les épelle. */
  color: var(--text-3);
}
.dv-gauge {
  position: relative;
  width: 44px;
  height: 4px;
  border-radius: 2px;
  background: rgb(var(--veil) / .1);
  overflow: hidden;
}
.dv-gauge i {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  border-radius: 2px;
  background: currentColor;
  transition: width .35s ease-out;
}
/* La jauge suit le sens : elle mesure la solidité DE CE SENS-LÀ. */
.dash-verdict.up   .dv-gauge { color: var(--up); }
.dash-verdict.down .dv-gauge { color: var(--down); }
.dash-verdict.flat .dv-gauge { color: var(--text-3); }

.dv-pct {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  min-width: 32px;
  text-align: right;
}

/* La jauge d'entrée ne suit PAS la direction : elle mesure la qualité du
   moment, pas le sens du marché. La peindre en rouge sur une vente ferait
   croire que « rouge = vends », alors qu'elle dit « n'entre pas ici ». */
.dash-verdict .dv-meter-entry .dv-gauge { color: var(--text-3); }
.dash-verdict .dv-meter-entry[data-level="low"] .dv-gauge { color: var(--warn); }
.dash-verdict .dv-meter-entry[data-level="mid"] .dv-gauge { color: var(--info); }
.dash-verdict .dv-meter-entry[data-level="ok"]  .dv-gauge { color: var(--up); }
.dash-verdict .dv-meter-entry[data-level="low"] .dv-pct   { color: var(--warn); }

/* Sous 1180 px les deux libellés ne tiennent plus : on garde celui de
   l'entrée, qui est le nouveau et le moins devinable. */
@media (max-width: 1180px) {
  #dvCtxMeter .dv-meter-label { display: none; }
}
@media (max-width: 1024px) {
  #dvCtxMeter { display: none; }
}

/* La réserve : toujours orange, jamais rouge — elle tempère le verdict, elle
   n'en énonce pas un second. */
.dv-caveat {
  display: flex;
  align-items: center;
  gap: 5px;
  min-width: 0;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--warn);
  background: rgba(240, 169, 75, .12);
  border: 1px solid rgba(240, 169, 75, .3);
  overflow: hidden;
  text-overflow: ellipsis;
}
.dv-caveat[hidden] { display: none; }

/* La décision : pas une couleur de marché, pas un avertissement — un état.
   Ardoise neutre, même famille que les faits sans camp. */
.dv-decision {
  display: flex;
  align-items: center;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 700;
  color: var(--accent);
  background: var(--accent-soft);
  border: 1px solid rgba(78, 127, 255, .4);
  white-space: nowrap;
}
.dv-decision[hidden] { display: none; }
@media (max-width: 1180px) { .dv-decision { display: none; } }

/* En RTL, « ↑ » et « 64 % » ne doivent pas migrer au milieu de la phrase. */
[dir="rtl"] .dash-verdict { unicode-bidi: plaintext; }

@media (max-width: 1180px) {
  .dv-meter-label { display: none; }
}
@media (max-width: 900px) {
  .dv-caveat { display: none; }
}

/* ─── Lecture du marché ─────────────────────────────────────────────
   Le tableau donne six verdicts ; celui qui ne pratique pas l'ADX ne sait
   pas quoi en faire. La pastille porte l'alerte en continu, l'infobulle
   traduit chaque chiffre et conclut. */
.tv-insight-btn {
  flex: none;
  width: 26px;
  display: grid;
  place-items: center;
  align-self: center;
  margin-inline-start: 2px;
  color: var(--text-3);
  border-radius: 7px;
  cursor: pointer;
  transition: color .2s, background .2s;
}
.tv-insight-btn:hover,
.tv-insight-btn[aria-expanded="true"] { color: var(--text); background: rgb(var(--veil) / .06); }
.tv-insight-btn svg { width: 16px; height: 16px; }

/* La gravité se lit sans ouvrir : rouge quand le contexte contredit un achat,
   vert quand il l'accompagne, gris quand il n'y a rien à dire. */
.tv-insight-btn[data-severity="warn"] { color: var(--warn); }
.tv-insight-btn[data-severity="ok"]   { color: var(--up); }

@media (prefers-reduced-motion: no-preference) {
  .tv-insight-btn[data-severity="warn"] svg { animation: tvi-pulse 2.4s ease-in-out infinite; }
}
@keyframes tvi-pulse {
  0%, 68%, 100% { opacity: 1; }
  84%           { opacity: .45; }
}

.tv-insight {
  position: absolute;
  top: calc(100% + 8px);
  inset-inline-end: 0;
  z-index: 26;
  width: min(430px, calc(var(--plot-width) - 32px));
  padding: 12px 14px 11px;
  text-align: start;
  /* Exactement le fond, le flou et le liseré du dock d'analyse : deux
     panneaux flottants du même terminal n'ont pas à se distinguer par leur
     matière. La gravité se lit sur la pastille et sur l'icône du titre, pas
     sur le cadre — un liseré rouge faisait de l'infobulle un objet à part. */
  background: var(--glass);
  backdrop-filter: blur(16px) saturate(1.4);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  animation: tvi-in .18s ease-out;
}
.tv-insight[hidden] { display: none; }

@keyframes tvi-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .tv-insight { animation: none; } }

.tvi-head { display: flex; align-items: center; gap: 7px; margin-bottom: 8px; }
.tvi-ico { flex: none; display: grid; place-items: center; color: var(--text-3); }
.tvi-ico svg { width: 14px; height: 14px; }
.tv-insight[data-severity="warn"] .tvi-ico { color: var(--warn); }
.tv-insight[data-severity="ok"]   .tvi-ico { color: var(--up); }

.tvi-title {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text);
}
.tvi-scope {
  margin-inline-start: auto;
  font-size: 10px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* La conclusion d'abord : c'est la seule ligne qui pèse les indices entre eux,
   le reste ne fait que traduire une case du tableau. */
.tvi-lead {
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--text);
  margin-bottom: 10px;
}

.tvi-rows {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 5px 10px;
  margin: 0;
  padding-top: 9px;
  border-top: 1px solid var(--border);
}
.tvi-rows dt {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-3);
  padding-top: 3px;
  white-space: nowrap;
}
.tvi-rows dd {
  margin: 0;
  font-size: 10.5px;
  line-height: 1.5;
  color: var(--text-2);
}
.tvi-chip {
  display: inline-block;
  margin-inline-end: 6px;
  padding: 1px 6px;
  border-radius: 5px;
  font-size: 9.5px;
  font-weight: 700;
  vertical-align: 1px;
  white-space: nowrap;
}

.tvi-foot {
  margin-top: 9px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
  font-size: 10px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 640px) {
  .tv-insight { width: calc(100vw - 28px); }
}

/* Codes couleur de l'indicateur.
   `strong` / `weak` qualifient la FORCE de l'ADX, pas un sens de marché : le
   vert d'origine faisait lire « acheter » sur une tendance baissière bien
   installée. La force passe donc en ardoise (fait neutre) et la faiblesse
   garde l'orange (c'est un avertissement : les signaux pris sans tendance
   cassent plus souvent). */
/* ── Verdicts du tableau ───────────────────────────────────────────────────
   Aplats sourds, texte coloré. En pleine couleur, cinq cases « baissier »
   côte à côte plus six unités de temps rouges faisaient un mur d'alerte pour
   dire une chose banale : le prix descend. Le sens est intact — la couleur
   n'a pas changé, elle a changé de support. L'aplat plein reste disponible,
   mais pour ce qui doit vraiment couper la lecture (stop, entrée refusée). */
.tv-bull    { background: var(--up-soft);   color: var(--up);   box-shadow: inset 0 0 0 1px var(--up-soft); }
.tv-bear    { background: var(--down-soft); color: var(--down); box-shadow: inset 0 0 0 1px var(--down-soft); }
.tv-info    { background: var(--info-soft); color: var(--info); box-shadow: inset 0 0 0 1px var(--info-soft); }
.tv-strong  { background: var(--info-soft); color: var(--info); box-shadow: inset 0 0 0 1px var(--info-soft); }
.tv-weak    { background: var(--warn-soft); color: var(--warn); box-shadow: inset 0 0 0 1px var(--warn-soft); }
.tv-neutral { background: rgb(var(--veil) / .05); color: var(--text-3); }

/* ═══════════════════════════════════════════════════════════
   PANNEAU TRADE SETUP  (Entry / SL / TP1-3)
════════════════════════════════════════════════════════════ */
#tradePanel {
  position: absolute;
  top: 14px;
  left: 14px;
  z-index: 20;
  width: 244px;
  background: var(--glass);
  backdrop-filter: blur(16px) saturate(1.4);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

.tp-head {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 9px 9px 8px 12px;
}

.tp-eyebrow {
  flex: 1;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-3);
  white-space: nowrap;
}

.tp-grade {
  font-size: 9.5px;
  font-weight: 800;
  padding: 2px 7px;
  border-radius: 99px;
  background: rgb(var(--veil) / .08);
  border: 1px solid var(--border-strong);
  color: var(--text-2);
  white-space: nowrap;
}

.tp-dir {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .06em;
  padding: 2.5px 8px;
  border-radius: 99px;
  color: #fff;
  background: var(--raised);
  white-space: nowrap;
}

.tp-dir.long  { background: var(--up); }
.tp-dir.short { background: var(--down); }
.tp-dir.closed {
  color: var(--text-2);
  background: rgb(var(--veil) / .08);
  border: 1px solid var(--border-strong);
}

#tpToggle {
  width: 22px;
  height: 22px;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-3);
  border-radius: 6px;
  transition: transform .2s, color .15s, background .15s;
}

#tpToggle:hover { color: var(--text); background: rgb(var(--veil) / .06); }

#tpToggle svg { width: 13px; height: 13px; }

#tradePanel.collapsed #tpToggle { transform: rotate(180deg); }
#tradePanel.collapsed .tp-body { display: none; }

.tp-body { padding: 2px 12px 10px; }

/* Statut du trade en cours */
/* Décomposition encaissé / flottant, sous la ligne d'état. */
.tp-pnl-split {
  margin: 2px 0 8px;
  font-size: 11px;
  color: var(--text-3);
  text-align: end;
  font-variant-numeric: tabular-nums;
}
.tp-pnl-split[hidden] { display: none; }
[dir="rtl"] .tp-pnl-split { unicode-bidi: plaintext; }

/* Stop retiré du jeu après TP1 : la ligne reste (c'est sa position sur le
   rail) mais elle se met en retrait. */
/* .5 rendait « manqué » quasi illisible sur un écran terne : on éteint, on n'efface pas. */
.tp-row.muted { opacity: .65; }
.tp-meta.bev { color: var(--warn); font-weight: 600; }

/* Avertissements du calcul de taille. */
.tp-pos-warn {
  margin-top: 4px;
  font-size: 10px;
  font-weight: 600;
  color: var(--warn);
}
.tp-pos-warn.high { color: var(--down); }
.tp-pos-warn[hidden] { display: none; }
.tp-field[data-risk-level="warn"] input { border-color: rgba(240, 169, 75, .55); }
.tp-field[data-risk-level="high"] input { border-color: rgba(239, 83, 80, .6); }
.tp-pos-row b.warn { color: var(--warn); }
.tp-pos-row b.neg  { color: var(--down); }

/* Fil de vie du trade : cinq jalons, ceux franchis en clair, l'étape en cours
   marquée, le reste en retrait. Aucune couleur de résultat ici — le fil dit où
   l'on en est, pas si l'on gagne. */
.tp-life {
  display: flex;
  align-items: center;
  flex-wrap: wrap;          /* 272 px ne tiennent pas cinq jalons sur une ligne */
  row-gap: 2px;
  gap: 4px;
  margin: 0 0 8px;
  padding: 0;
  list-style: none;
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-3);
}
.tp-life[hidden] { display: none; }

.tp-life li { display: flex; align-items: center; gap: 4px; opacity: .38; white-space: nowrap; }
.tp-life li::after { content: '·'; opacity: .6; }
.tp-life li:last-child::after { content: ''; }
.tp-life li.past    { opacity: 1; color: var(--text-2); }
.tp-life li.past span::after { content: ' ✓'; }
.tp-life li.current { opacity: 1; color: var(--accent); }

@media (max-width: 900px) {
  .tp-life { font-size: 8px; letter-spacing: 0; }
}

/* ─── Conseil de gestion ──────────────────────────────────────────────────
   Orange : c'est une nuance sur la conduite à tenir, pas une direction de
   marché ni une perte. Le rouge dirait « ça tourne mal », le vert « prends
   ça » — les deux seraient faux. Le motif chiffré sous le conseil est ce qui
   distingue une lecture d'une consigne : il est affiché, pas caché en
   infobulle. */
.tp-advice {
  display: flex;
  align-items: flex-start;
  gap: 7px;
  margin: -5px 0 9px;
  padding: 7px 9px;
  border-radius: 8px;
  color: var(--warn);
  background: rgba(240, 169, 75, .1);
  border: 1px solid rgba(240, 169, 75, .28);
  font-size: 11px;
  line-height: 1.35;
}
.tp-advice[hidden] { display: none; }

.tp-advice-ico { flex: none; display: grid; place-items: center; height: 15px; }
.tp-advice-ico svg { width: 13px; height: 13px; }

.tp-advice-text { min-width: 0; }
.tp-advice-text b { display: block; font-weight: 700; }

/* Trade soldé : le bloc change de registre. Ce n'est plus un avertissement
   mais un constat — d'où le retour aux couleurs de résultat (turquoise gagné,
   rouge stoppé, gris break-even) au lieu de l'orange de la nuance. */
/* Un trade soldé est une ARCHIVE : il ne doit plus rivaliser d'intensité avec
   ce qu'il faut faire maintenant. Le fond disparaît, seul le résultat garde sa
   couleur — assez pour savoir si l'on a gagné, trop peu pour croire qu'il y a
   quelque chose à y faire. */
.tp-advice.is-done {
  background: rgb(var(--veil) / .03);
  border-color: var(--border);
  color: var(--text-2);
}
.tp-advice.is-done.tone-win  .tp-advice-ico { color: var(--up); }
.tp-advice.is-done.tone-loss .tp-advice-ico { color: var(--down); }
.tp-advice.is-done.tone-flat .tp-advice-ico { color: var(--text-3); }
.tp-advice.is-done .tp-advice-text b { color: var(--text-2); font-weight: 600; }
.tp-advice.is-done.tone-win  .tp-advice-text b { color: var(--up); }
.tp-advice.is-done.tone-loss .tp-advice-text b { color: var(--down); }

/* Le nouveau contexte est délibérément détaché de la couleur du résultat :
   il parle du marché À VENIR, pas du trade qui vient de finir. */
#tpAdviceNext { color: var(--warn); }
#tpAdviceNext[hidden] { display: none; }

.tp-advice-btn {
  margin-top: 6px;
  padding: 3px 9px;
  font: inherit;
  font-size: 10px;
  font-weight: 700;
  color: var(--text-2);
  background: rgb(var(--veil) / .06);
  border: 1px solid var(--border-strong);
  border-radius: 99px;
  cursor: pointer;
}
.tp-advice-btn:hover { color: var(--text); background: rgb(var(--veil) / .11); }
.tp-advice-btn[hidden] { display: none; }

.tp-advice-text i {
  display: block;
  margin-top: 1px;
  font-style: normal;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

/* Chiffres et sigles latins mêlés à de l'arabe. */
[dir="rtl"] .tp-advice-text b,
[dir="rtl"] .tp-advice-text i { unicode-bidi: plaintext; }

.tp-status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin: 2px 0 9px;
  padding: 6px 8px;
  background: rgb(var(--veil) / .04);
  border: 1px solid var(--border);
  border-radius: 8px;
}

.tp-state {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .04em;
  padding: 2.5px 8px;
  border-radius: 99px;
  white-space: nowrap;
}

.tp-state.active {
  background: var(--accent-soft);
  color: var(--accent-bright);
  border: 1px solid rgba(78, 127, 255, .35);
}

.tp-state.tp {
  background: rgba(38, 166, 154, .15);
  color: #4DD0C4;
  border: 1px solid rgba(38, 166, 154, .4);
}

.tp-state.win  { background: var(--up);   color: #fff; }
.tp-state.stop { background: var(--down); color: #fff; }

.tp-state.be {
  background: rgba(240, 169, 75, .15);
  color: var(--warn);
  border: 1px solid rgba(240, 169, 75, .4);
}

/* Setup publié, non engagé. L'ardoise neutre, à dessein : ce n'est pas une
   direction de marché — c'est un fait, et l'accent bleu de « position active »
   lui donnait exactement le poids qu'il ne doit pas avoir. */
.tp-state.pending {
  background: rgb(var(--veil) / .07);
  color: var(--text-2);
  border: 1px solid var(--border);
}

.tp-pnl {
  font-size: 11.5px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.tp-pnl.pos  { color: var(--up); }
.tp-pnl.neg  { color: var(--down); }
.tp-pnl.flat { color: var(--text-2); }

.tp-grid { display: flex; gap: 11px; }

/* Échelle de prix proportionnelle */
.tp-rail {
  position: relative;
  width: 13px;
  flex: none;
  margin: 8px 0;
}

.tp-rail-track {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  top: 0;
  bottom: 0;
  width: 3px;
  border-radius: 99px;
  background: rgb(var(--veil) / .1);
}

.tp-mark {
  position: absolute;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 7px;
  height: 7px;
  border-radius: 50%;
  box-shadow: 0 0 0 2px var(--halo);
}

/* Le repère de la quatrième part : creux, et un peu plus petit. Il dit « ce
   rang existe » sans dire « il y a un niveau ici » — la nuance est tout le
   sujet de cette part. */
.tp-mark.is-open {
  width: 7px;
  height: 7px;
  background: transparent;
  box-shadow: 0 0 0 2px var(--halo), inset 0 0 0 1.5px var(--text-3);
}
.tp-mark.entry {
  width: 9px;
  height: 9px;
  box-shadow: 0 0 0 2px var(--halo), 0 0 9px rgb(var(--veil) / .3);
}

.tp-cursor {
  position: absolute;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 13px;
  height: 3px;
  border-radius: 2px;
  background: #fff;
  box-shadow: 0 0 7px rgb(var(--veil) / .55);
  transition: top .5s ease;
}

/* Lignes de niveaux */
/* Les libellés portent leur multiple de R (« Objectif 1 · 0.3R ») : la
   largeur fixe de 34 px, taillée pour « TP1 », les repliait sur trois lignes
   et faisait passer la hauteur de ligne de 21,7 px à 50,7 px.

   La grille partagée dimensionne la colonne des libellés sur le plus long
   d'entre eux et aligne les prix d'une ligne à l'autre — sans nombre magique
   à maintenir quand un libellé change de longueur ou de langue. */
.tp-rows {
  flex: 1;
  min-width: 0;
  display: grid;
  /* pastille · libellé · prix · écart. Le libellé est prioritaire
     (max-content) : quand la place manque c'est l'écart qui cède, pas le nom
     du niveau — « Objectif 3 · 1.1R » écrasé à 20 px se superposait au prix.
     L'écart peut descendre sous son contenu (minmax 0) : il s'ellipse au lieu
     de sortir du panneau. */
  grid-template-columns: auto max-content 1fr minmax(0, auto);
  row-gap: 2px;
  column-gap: 7px;
}

.tp-row {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: 1 / -1;
  align-items: center;
  padding: 3.5px 0;
  font-variant-numeric: tabular-nums;
}

/* Repli sans subgrid : on retrouve le flex d'origine, avec une largeur de
   libellé suffisante pour « Objectif 1 · 0.3R » au lieu de 34 px. */
@supports not (grid-template-columns: subgrid) {
  .tp-rows { display: flex; flex-direction: column; gap: 2px; }
  .tp-row  { display: flex; gap: 7px; }
  .tp-label { width: 86px; }
  .tp-meta  { margin-left: auto; }
}

.tp-row.entry {
  background: rgb(var(--veil) / .05);
  border: 1px solid var(--border);
  border-radius: 7px;
  padding: 2.5px 7px;
  margin: 0 -7px;
}

.tp-dot {
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: 50%;
}

.tp-label {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-2);
  width: auto;
  min-width: 0;
  white-space: nowrap;      /* « Objectif 1 · 0.3R » ne se coupe jamais en deux */
}

.tp-price {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--text);
}

/* ── LA LIGNE SANS PRIX ───────────────────────────────────────────────────
   La quatrième part n'a pas de niveau : sa colonne « prix » porte un MOT.
   En 700 tabulaire, au milieu de six nombres alignés, ce mot se lisait comme
   une valeur qui aurait mal tourné. Il prend donc le poids d'une mention —
   plus léger, sans chasse fixe, légèrement espacé — et cesse de se faire
   passer pour un chiffre. */
.tp-price.is-open {
  font-weight: 600;
  color: var(--text-2);
  font-variant-numeric: normal;
  letter-spacing: .03em;
}

/* La pastille suit la même logique : creuse, parce qu'elle ne marque aucun
   point sur le rail — il n'y a rien à y placer. */
.tp-dot.is-open {
  background: transparent;
  box-shadow: inset 0 0 0 1.5px var(--text-3);
}

/* Et son écart reste NEUTRE. En orange — la couleur du stop déplacé — il
   attirait l'œil plus fort que les objectifs eux-mêmes, pour dire une
   règle de gestion et non une alerte. */
.tp-row-open .tp-meta { color: var(--text-3); font-weight: 500; }

.tp-meta {
  margin-left: 0;           /* la grille place la colonne ; `auto` la décalait */
  justify-self: end;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-3);
  white-space: nowrap;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tp-meta.posv { color: var(--up); }
.tp-meta.neg  { color: var(--down); }

.tp-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 9px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}

.tp-foot-item {
  font-size: 11px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

/* La comptabilité du plan, posée à plat sous le rapport pondéré. C'est la
   démonstration du chiffre affiché au-dessus : discrète, mais lisible sans
   survoler quoi que ce soit. */
.tp-rmath {
  margin: 5px 0 0;
  font-size: 10.5px;
  line-height: 1.5;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
}
.tp-rmath[hidden] { display: none; }
.tp-rmath > div { display: flex; justify-content: space-between; gap: 10px; padding: 1.5px 0; }
.tp-rmath dt { flex: none; }
.tp-rmath dd { margin: 0; text-align: end; color: var(--text-2); }
.tp-rmath .tp-rmath-total {
  margin-top: 3px;
  padding-top: 3px;
  border-top: 1px solid var(--border);
}
.tp-rmath .tp-rmath-total dt,
.tp-rmath .tp-rmath-total dd { color: var(--text); font-weight: 700; }

/* ─── STATISTICAL EDGE ────────────────────────────────────────────────────
   Posé sous la comptabilité du plan, avec un filet de séparation : au-dessus
   ce que le plan PROMET, en dessous ce que des plans comparables ont DONNÉ.
   Même graisse, même échelle typographique, même tabulation des chiffres que
   `.tp-rmath` — c'est le même genre d'objet, il ne doit pas crier plus fort.

   Le STATUT est la seule chose colorée. Peindre aussi l'espérance ferait deux
   signaux pour un seul fait dans un panneau déjà dense. */
.tp-se {
  margin: 8px 0 0;
  padding-top: 7px;
  border-top: 1px solid var(--border);
  font-size: 10.5px;
  line-height: 1.5;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
}
.tp-se[hidden] { display: none; }
.tp-se-head {
  display: flex; align-items: center; justify-content: space-between;
  /* LA PASTILLE DESCEND, LE TITRE NE SE COUPE PAS. Dans 240 px de colonne,
     « DONNÉES INSUFFISANTES » ne tient pas à côté de « STATISTICAL EDGE » :
     sans ce `wrap`, c'est le TITRE qui se casse en deux lignes, et un
     intitulé coupé se lit comme un défaut d'affichage. */
  flex-wrap: wrap; gap: 4px 8px; margin-bottom: 4px;
}
.tp-se-title {
  font-size: 9.5px; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-2); opacity: .85;
  white-space: nowrap;
}
.tp-se-badge {
  font-size: 9px; font-weight: 700; letter-spacing: .07em;
  padding: 2px 6px; border-radius: 99px; white-space: nowrap;
  border: 1px solid var(--border); color: var(--text-2);
}
.tp-se-badge.is-positive {
  color: var(--up); border-color: color-mix(in srgb, var(--up) 45%, transparent);
  background: color-mix(in srgb, var(--up) 10%, transparent);
}
.tp-se-badge.is-negative {
  color: var(--down); border-color: color-mix(in srgb, var(--down) 45%, transparent);
  background: color-mix(in srgb, var(--down) 10%, transparent);
}
.tp-se-rows { margin: 0; }
.tp-se-rows > div { display: flex; justify-content: space-between; gap: 10px; padding: 1.5px 0; }
.tp-se-rows dt { flex: none; }
.tp-se-rows dd { margin: 0; text-align: end; color: var(--text-2); }
/* L'ESPÉRANCE EST LA LIGNE DE TÊTE, et elle est la seule en gras : le taux de
   gain vient après, parce qu'un système à 70 % de gagnants peut perdre de
   l'argent. L'ordre de ce bloc est une décision, pas une mise en page. */
.tp-se-rows .tp-se-lead dt,
.tp-se-rows .tp-se-lead dd { color: var(--text); font-weight: 700; }
.tp-se-group {
  margin-top: 4px; font-size: 9.5px; opacity: .7;
  overflow-wrap: anywhere;
}
.tp-se-group[hidden] { display: none; }
.tp-se-note {
  margin-top: 5px; font-size: 9.5px; line-height: 1.45; opacity: .75;
}
.tp-se-note[hidden] { display: none; }
.tp-se-note.is-blocked {
  opacity: 1; color: var(--down);
}

/* ─── Onglets Plan / Risque / Résultat ────────────────────────────────────
   La colonne empilait niveaux, comptabilité, taille de position et bilan :
   ~900 px à parcourir pour trouver un chiffre. Trois questions, trois
   onglets — et l'état du trade + le conseil restent AU-DESSUS, visibles quel
   que soit l'onglet, parce qu'eux seuls parlent du présent. */
/* §3 — En-tête de la position en cours. Petit, gris, mais présent : c'est le
   seul mot qui empêche de lire « Position Short active » et « Nouvelle entrée
   refusée » comme deux affirmations contradictoires sur le même objet. */
.tp-pos-head {
  margin: 6px 0 4px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-3);
}
.tp-pos-head[hidden] { display: none; }


/* Analyse bâtie sur un cache de secours : le fournisseur n'a pas répondu.
   Se lisait exactement comme une analyse en direct. */
.tp-stale {
  margin: 0 0 6px;
  padding: 2px 7px;
  display: inline-block;
  border: 1px solid var(--warn);
  border-radius: 4px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .08em;
  color: var(--warn);
}
.tp-stale[hidden] { display: none; }

/* Une composante NÉGATIVE du score : elle existait déjà dans le calcul
   (le ratio insuffisant, la zone opposée) mais était retranchée après coup,
   invisible dans le détail. */
.gc-sc-row.is-negative .gc-sc-pts { color: var(--warn); }

/* Le titre change de nature avec le plan. Un trade CLOS s'efface un peu — ce
   qu'on lit est de l'histoire, et le mettre au même niveau qu'une position
   ouverte est précisément ce qui trompait. La couleur n'est pas le seul
   signal : le mot lui-même change. */
#tpPosLabel[data-kind="closed"]    { color: var(--text-3); opacity: .78; }
#tpPosLabel[data-kind="candidate"] { color: var(--warn); }
#tpPosLabel[data-kind="open"]      { color: var(--text-2); }

.tp-tabs {
  display: flex;
  gap: 2px;
  margin: 8px 0 6px;
  padding: 2px;
  border-radius: 8px;
  background: rgb(var(--veil) / .05);
}
.tp-tab {
  flex: 1;
  padding: 4.5px 4px;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--text-3);
  font-family: inherit;
  font-size: 11px;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: .01em;
  cursor: pointer;
  transition: color .15s, background .15s;
  white-space: nowrap;
}
.tp-tab:hover { color: var(--text-2); }
.tp-tab.is-on {
  color: var(--text);
  background: var(--surface-2);
  /* Le liseré accent est ce qui distingue « actif » de « survolé » d'un coup
     d'œil — le seul changement de fond ne suffisait pas. */
  box-shadow: inset 0 -2px 0 var(--accent), var(--shadow-sm);
}

.tp-pane { display: none; }
.tp-pane.is-on { display: block; }

/* ─── Récapitulatif du Résultat ─────────────────────────────────────────── */
.tp-outcome {
  margin: 4px 0 6px;
  font-size: 11.5px;
  line-height: 1.5;
}
.tp-outcome[hidden] { display: none; }
.tp-outcome > div { display: flex; justify-content: space-between; gap: 10px; padding: 2px 0; }
.tp-outcome dt { flex: none; color: var(--text-3); }
.tp-outcome dd { margin: 0; text-align: end; color: var(--text-2); font-variant-numeric: tabular-nums; }
.tp-outcome-total {
  margin-top: 3px;
  padding-top: 5px !important;
  border-top: 1px solid var(--border);
}
.tp-outcome .tp-outcome-total dt,
.tp-outcome .tp-outcome-total dd { color: var(--text); font-weight: 700; }
.tp-outcome dd.pos { color: var(--up); }
.tp-outcome dd.neg { color: var(--down); }

.tp-outcome-empty {
  margin: 6px 0 8px;
  font-size: 11px;
  color: var(--text-3);
}
.tp-outcome-empty[hidden] { display: none; }

/* « 45 min » et « +0.12R » mêlent chiffres et latin : sans plaintext, l'arabe
   réordonne les segments (« min 45 »). */
[dir="rtl"] .tp-outcome dd { unicode-bidi: plaintext; }

/* Chiffres latins dans une phrase arabe. */
[dir="rtl"] .tp-rmath > div { unicode-bidi: plaintext; }

.tp-foot-chip {
  font-size: 10.5px;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 99px;
  background: var(--accent-soft);
  border: 1px solid rgba(78, 127, 255, .25);
  color: var(--accent-bright);
  font-variant-numeric: tabular-nums;
}
/* R:R pondéré sous 1 : on risque plus qu'on n'espère. Le bleu « premium »
   maquillait ce rapport en qualité ; l'orange dit ce qu'il est — une réserve,
   pas une interdiction. */
.tp-foot-chip.is-weak {
  color: var(--warn);
  background: var(--warn-soft);
  border-color: rgba(240, 169, 75, .4);
}

/* Calcul de taille de position */
.tp-pos {
  margin-top: 9px;
  padding-top: 9px;
  border-top: 1px solid var(--border);
}

.tp-pos-inputs {
  display: grid;
  grid-template-columns: 1.25fr 1fr;
  gap: 8px;
}

.tp-field span {
  display: block;
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 4px;
  white-space: nowrap;
}

.tp-field input {
  width: 100%;
  height: 28px;
  padding: 0 8px;
  font: 600 11.5px var(--font);
  font-variant-numeric: tabular-nums;
  text-align: right;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 7px;
  transition: border-color .15s;
}

.tp-field input:hover { border-color: var(--border-strong); }

.tp-field input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.tp-field input::-webkit-outer-spin-button,
.tp-field input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.tp-field input[type=number] { -moz-appearance: textfield; appearance: textfield; }

.tp-risk-wrap { position: relative; }

.tp-risk-wrap em {
  position: absolute;
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
  font-style: normal;
  font-size: 10px;
  font-weight: 600;
  color: var(--text-3);
  pointer-events: none;
}

.tp-risk-wrap input { padding-right: 22px; }

.tp-pos-rows {
  margin-top: 8px;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.tp-pos-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
}

.tp-pos-row span { font-size: 10.5px; color: var(--text-2); white-space: nowrap; }

.tp-pos-row b {
  font-size: 11.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

#psLoss { color: var(--down); }

.tp-pos-gains {
  margin-top: 5px;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--up);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ═══════════════════════════════════════════════════════════
   PANNEAU BACKTEST  (stats réelles du système SL/TP)
════════════════════════════════════════════════════════════ */
#btPanel {
  position: absolute;
  left: 14px;
  bottom: 42px;
  z-index: 20;
  width: 244px;
  background: var(--glass);
  backdrop-filter: blur(16px) saturate(1.4);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  padding: 10px 12px;
}

.bt-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 8px;
}

.bt-title {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-3);
}

.bt-meta {
  font-size: 10px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

/* Périmètre des chiffres du backtest. Deux teintes volontairement distinctes :
   la journée est ce qu'on suit, la fenêtre complète n'est qu'un repli. Les
   afficher pareil laissait croire qu'on lisait toujours la journée. */
.bt-scope {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-bottom: 7px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  border: 1px solid transparent;
}

.bt-scope.today {
  color: #7fe0cf;
  background: rgba(38, 166, 154, .12);
  border-color: rgba(38, 166, 154, .32);
}

.bt-scope.window {
  color: var(--text-3);
  background: rgb(var(--veil) / .05);
  border-color: var(--border);
}

/* ─── L'échantillon d'abord ───────────────────────────────────────────────
   « 100 % » en tête de bloc se lisait comme un verdict alors que la seule
   donnée solide était « 9 trades ». Le nombre de trades est donc le grand
   chiffre, son verdict de représentativité accroché à lui, et les taux
   suivent en lignes alignées — même gabarit que les mesures de risque. */
.bt-sample {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 6px;
  margin: 1px 0 5px;
}
.bt-sample b {
  font-size: 17px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
}
.bt-sample-word { font-size: 11px; font-weight: 600; color: var(--text-2); }
/* §7 — L'avertissement prend sa propre ligne, juste sous le nombre : accolé
   en pastille il se lisait comme une étiquette de plus, alors qu'il est le
   deuxième élément de la hiérarchie imposée. */
.bt-sample-verdict {
  display: inline-block;
  margin: 0 0 5px;
  font-style: normal;
  font-size: 10.5px;
  font-weight: 700;
  padding: 2px 9px;
  border-radius: 999px;
  color: var(--text-2);
  background: rgb(var(--veil) / .06);
}
.bt-sample-verdict:empty { display: none; }
.bt-sample-verdict[data-level="tiny"] {
  color: var(--warn);
  background: var(--warn-soft);
  border: 1px solid rgba(240, 169, 75, .3);
}
.bt-sample-verdict[data-level="small"] { color: var(--info); background: var(--info-soft); }

.bt-heads {
  margin: 0 0 5px;
  font-size: 11.5px;
}
.bt-heads > div { display: flex; justify-content: space-between; gap: 10px; padding: 2px 0; }
.bt-heads dt { flex: none; color: var(--text-2); }
.bt-heads dd {
  margin: 0;
  text-align: end;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.bt-heads dd.pos  { color: var(--up); }
.bt-heads dd.neg  { color: var(--down); }
/* §7 — sous 30 trades, aucun vert : un taux qui ne prouve rien ne doit pas
   porter la couleur du gain acquis. */
.bt-heads dd.flat { color: var(--text); }

.bt-range {
  display: inline-block;
  margin: 0 0 6px;
  padding: 3px 9px;
  border-radius: 7px;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-2);
  background: rgb(var(--veil) / .05);
  border: 1px solid var(--border);
  font-variant-numeric: tabular-nums;
}
.bt-range[hidden] { display: none; }

[dir="rtl"] .bt-sample,
[dir="rtl"] .bt-heads > div,
[dir="rtl"] .bt-range { unicode-bidi: plaintext; }

/* ─── Ce que l'échantillon autorise ──────────────────────────────────────
   Un échantillon trop mince est un AVERTISSEMENT sur la lecture, pas une
   perte : orange, jamais rouge — le rouge dirait « tu perds », alors qu'on
   dit « on ne sait pas encore ». Au-delà, la mention redevient neutre : elle
   ne doit se faire remarquer que quand elle a quelque chose à corriger. */
/* Mesures de gestion du risque. Même grille que la comptabilité du plan :
   libellé à gauche, valeur à droite, aucune couleur sauf quand le chiffre
   mérite qu'on s'y arrête. */
.bt-metrics {
  margin: 6px 0 0;
  font-size: 10.5px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.bt-metrics[hidden] { display: none; }
.bt-metrics > div { display: flex; justify-content: space-between; gap: 10px; padding: 1.5px 0; }
.bt-metrics dt { flex: none; }
.bt-metrics dd { margin: 0; text-align: end; color: var(--text-2); font-weight: 600; }
.bt-metrics dd.pos  { color: var(--up); }
.bt-metrics dd.neg  { color: var(--down); }
.bt-metrics dd.warn { color: var(--warn); }

[dir="rtl"] .bt-metrics > div { unicode-bidi: plaintext; }

.bt-trust {
  margin-top: 7px;
  padding-top: 6px;
  border-top: 1px solid var(--border);
  font-size: 10px;
  line-height: 1.45;
}
.bt-trust[hidden] { display: none; }

.bt-trust-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 5px;
  color: var(--text-3);
}
.bt-trust-head b { font-weight: 800; letter-spacing: .01em; }

.bt-trust.low  .bt-trust-head b { color: var(--warn); }
.bt-trust.mid  .bt-trust-head b { color: var(--info); }
.bt-trust.ok   .bt-trust-head b,
.bt-trust.high .bt-trust-head b { color: var(--text-2); }

.bt-trust-n { margin-inline-start: auto; font-variant-numeric: tabular-nums; }
.bt-trust.low .bt-trust-n { color: var(--warn); }

.bt-trust-range {
  margin-top: 2px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

/* Chiffres et signes mêlés à de l'arabe : sans cela « 45 – 94 % » se
   réordonne à l'écran. */
[dir="rtl"] .bt-trust-head,
[dir="rtl"] .bt-trust-range { unicode-bidi: plaintext; }

.bt-stat span {
  display: block;
  margin-top: 1px;
  font-size: 8px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-3);
  white-space: nowrap;
}

/* Histogramme des derniers trades : hauteur = résultat en R */
.bt-strip {
  position: relative;
  display: flex;
  gap: 2px;
  margin-top: 9px;
  height: 27px;
}

.bt-strip::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 9px;
  height: 1px;
  background: rgb(var(--veil) / .16);
}

/* La bande couvre désormais tous les trades, pas les douze derniers : leur
   nombre varie avec l'instrument et l'unité de temps. Les barres se partagent
   donc la largeur au lieu de la fixer, sans jamais dépasser leur taille
   d'origine quand ils sont peu nombreux. */
.bt-bar {
  position: relative;
  flex: 1 1 0;
  min-width: 2px;
  max-width: 11px;
  height: 100%;
}

.bt-bar i {
  position: absolute;
  left: 1px;
  right: 1px;
  border-radius: 2px;
}

.bt-bar.gain i { background: var(--up);   bottom: 9px; }
.bt-bar.loss i { background: var(--down); top: 18px; }
.bt-bar.flat i { background: var(--text-3); bottom: 8px; height: 2px; }

.bt-strip-cap {
  margin-top: 4px;
  font-size: 9.5px;
  color: var(--text-3);
  letter-spacing: .02em;
}

.bt-dist {
  margin-top: 8px;
  font-size: 10px;
  font-weight: 600;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
}

/* Repère sur la fenêtre complète. Il doit se lire comme un contexte, pas
   comme un second résultat qui concurrencerait les chiffres du jour. */
.bt-ref {
  margin-top: 6px;
  font-size: 9.5px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

/* §8 — Confluence repliée par défaut. `<details>` natif : clavier, focus et
   aria-expanded viennent du navigateur, sans une ligne de JavaScript. */
.bt-conf { margin-top: 6px; }
.bt-conf[hidden] { display: none; }
.bt-conf-head {
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  font-size: 10.5px;
  font-weight: 700;
  color: var(--text-2);
  list-style: none;
  padding: 3px 0;
}
.bt-conf-head::-webkit-details-marker { display: none; }
.bt-conf-head::before {
  content: '';
  width: 0; height: 0;
  border-inline-start: 4px solid currentColor;
  border-block: 3.5px solid transparent;
  transition: transform .2s;
  flex: none;
}
.bt-conf[open] .bt-conf-head::before { transform: rotate(90deg); }
[dir="rtl"] .bt-conf[open] .bt-conf-head::before { transform: rotate(-90deg); }
.bt-conf-head:hover { color: var(--text); }
.bt-conf-head:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.bt-conf-note {
  margin: 3px 0 0;
  font-size: 10px;
  line-height: 1.45;
  color: var(--text-3);
}

.bt-grades {
  margin-top: 3px;
  font-size: 10.5px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

.bt-note {
  margin-top: 7px;
  padding-top: 7px;
  border-top: 1px solid var(--border);
  font-size: 8.5px;
  line-height: 1.5;
  color: var(--text-3);
}

/* Panneau liquidité */
#tvLiquidity {
  position: absolute;
  right: calc(var(--price-scale-width) + 12px);
  bottom: 42px;
  z-index: 20;
  background: var(--glass);
  backdrop-filter: blur(16px) saturate(1.4);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  padding: 8px 10px;
}

.liq-table { border-collapse: separate; border-spacing: 0 4px; }

.liq-label {
  font-size: 10.5px;
  font-weight: 500;
  color: var(--text-2);
  padding: 3px 18px 3px 6px;
  white-space: nowrap;
}

.liq-val {
  font-size: 10.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: center;
  white-space: nowrap;
  padding: 3px 10px;
  border-radius: 6px;
  min-width: 96px;
}

/* ═══════════════════════════════════════════════════════════
   BOUSSOLE DE TENDANCE
   Deux niveaux volontairement distincts : la pastille dit l'état
   en continu, le bandeau ne parle que lorsqu'il y a un risque à
   signaler. Les confondre ferait qu'on n'en lirait plus aucun.
════════════════════════════════════════════════════════════ */
.trend-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-inline-start: 8px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .02em;
  font-variant-numeric: tabular-nums;
  border: 1px solid transparent;
  white-space: nowrap;
}

.trend-badge.up {
  color: #7fe0cf;
  background: rgba(38, 166, 154, .13);
  border-color: rgba(38, 166, 154, .34);
}

.trend-badge.down {
  color: #ff9d9b;
  background: rgba(239, 83, 80, .13);
  border-color: rgba(239, 83, 80, .34);
}

.trend-badge.flat {
  color: var(--text-3);
  background: rgb(var(--veil) / .05);
  border-color: var(--border);
}

/* ═══════════════════════════════════════════════════════════
   MODAL RÉGLAGES
════════════════════════════════════════════════════════════ */
/* L'historique réutilise la carcasse de la modale de réglages : même voile,
   même carte, mêmes en-tête et pied. Une seule différence, sa largeur — les
   graphiques ont besoin de place là où un formulaire n'en demande pas. */
#settingsOverlay,
#histOverlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: var(--scrim);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

#settingsModal,
#histModal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 210;
  /* 440 px était trop étroit pour la grammaire « libellé à gauche,
     contrôle à droite » : le pied ne tenait plus ses trois boutons sur un
     rang — 430 px nécessaires pour 408 disponibles, mesuré — et le bouton
     d'administration repliait son intitulé sur deux lignes dans une
     pastille haute de 34 px. 520 px reste une fenêtre, pas une page. */
  width: min(520px, calc(100vw - 32px));
  max-height: min(680px, calc(100vh - 48px));
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 16px;
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

/* Après la règle partagée, sinon la largeur du formulaire l'emporterait. */
#histModal { width: min(720px, calc(100vw - 32px)); }

/* ── LA FENÊTRE DES RÉGLAGES SE MESURE ELLE-MÊME ────────────────────────
   Ses replis doivent regarder SA largeur, jamais celle du navigateur :
   gold-classic.css portait un `@media (max-width: 520px)` écrit pour
   « un panneau étroit », qui ne se déclenchait donc JAMAIS sur un grand
   écran — là où cette fenêtre est pourtant tout aussi étroite, puisque sa
   largeur est fixe. Résultat mesuré : l'intitulé du bouton d'administration
   se repliait sur deux lignes dans une pastille haute de 34 px.

   Déclaré ICI et non sur la règle partagée : `container-type` implique
   `contain: layout`, qui fait de l'élément le bloc conteneur de ses
   descendants en position fixe. #histModal porte des graphiques ; on ne
   lui impose pas un confinement dont il n'a aucun besoin. */
#settingsModal {
  container-type: inline-size;
  container-name: smwin;
}

/* ── Historique du backtest ─────────────────────────────── */
.hist-scope {
  margin: 0 0 4px;
  font-size: 11px;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
}

.hist-warn {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin: 0 0 10px;
  font-size: 10.5px;
  color: var(--warn, #e2c027);
}
.hist-warn-ico { flex: none; display: grid; place-items: center; height: 15px; }
.hist-warn-ico svg { width: 13px; height: 13px; }

.hist-empty {
  padding: 28px 4px;
  text-align: center;
  font-size: 12px;
  color: var(--text-3);
}

.hist-chart { margin: 6px 0 14px; }
.hist-chart svg { display: block; width: 100%; height: auto; }

.hist-months {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.hist-month {
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  gap: 10px;
  align-items: baseline;
  padding: 7px 9px;
  border-radius: 8px;
  background: rgb(var(--veil) / .028);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.hist-month b { font-weight: 600; color: var(--text-1); }
.hist-month .hm-sub { font-size: 10px; color: var(--text-3); }
.hist-month .pos { color: var(--up, #26a69a); }
.hist-month .neg { color: var(--down, #ef5350); }

.bt-history-btn {
  margin-top: 9px;
  padding: 5px 10px;
  font-size: 10px;
  font-weight: 600;
  color: var(--text-2);
  background: rgb(var(--veil) / .04);
  border: 1px solid var(--border);
  border-radius: 7px;
  cursor: pointer;
  transition: color .2s, background .2s;
}

.bt-history-btn:hover { color: var(--accent); background: rgb(var(--veil) / .07); }

.sm-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 18px 12px;
  flex: none;
}

.sm-title {
  font-size: 13.5px;
  font-weight: 800;
  letter-spacing: .05em;
}

.sm-title em {
  display: block;
  font-style: normal;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0;
  color: var(--text-3);
  margin-top: 2px;
}

.sm-close {
  width: 30px;
  height: 30px;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-3);
  border-radius: 8px;
  transition: color .15s, background .15s;
}

.sm-close:hover { color: var(--text); background: var(--surface-2); }

.sm-close svg { width: 15px; height: 15px; }

/* Onglets */
.sm-tabs {
  display: flex;
  gap: 2px;
  margin: 0 18px 4px;
  padding: 3px;
  flex: none;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
}

.sm-tab {
  flex: 1;
  height: 28px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-3);
  border-radius: 7px;
  transition: color .15s, background .15s;
}

.sm-tab:hover { color: var(--text-2); }

.sm-tab.active {
  color: var(--text);
  background: var(--raised);
  box-shadow: var(--shadow-sm);
}

/* Corps */
.sm-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 6px 18px 16px;
}

.sm-panel { display: none; }
.sm-panel.active { display: block; }

.sm-section {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 18px 0 6px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
}

.sm-hint {
  font-size: 11px;
  color: var(--text-3);
  margin: 4px 0 8px;
  line-height: 1.5;
}

.sm-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 5px 0;
}

/* ── `hidden` NE SUFFIT PAS QUAND UNE RÈGLE POSE `display` ────────────────
   L'attribut HTML `hidden` n'agit que par la feuille du navigateur,
   `[hidden] { display: none }`. Toute règle d'auteur qui pose un `display`
   la bat — et `.sm-row` en pose un. Le rang « Version des signaux », né
   `hidden` pour n'être montré qu'à un administrateur, restait donc visible
   pour TOUS : le masquage était écrit dans le gabarit, dans app.js, vérifié
   au banc, et la feuille de style l'annulait en silence.
   `.sm-hint`, qui ne déclare aucun `display`, disparaissait bien — d'où un
   rang orphelin, sans son explication.
   La même règle existe déjà cinq fois ailleurs (`.gc-dash[hidden]`,
   `.gc-restore[hidden]`, `.sm-btn-default[hidden]`…) : c'est la convention
   du dépôt, pas une exception. */
.sm-row[hidden],
.sm-hint[hidden],
.sm-row-check[hidden] { display: none; }

.sm-row label {
  font-size: 12px;
  font-weight: 500;
  color: var(--text-2);
}

.sm-row input[type="number"] {
  width: 88px;
  height: 30px;
  padding: 0 10px;
  font: 600 12px var(--font);
  font-variant-numeric: tabular-nums;
  text-align: right;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  transition: border-color .15s;
}

.sm-row input[type="number"]:hover { border-color: var(--border-strong); }

.sm-row input[type="number"]:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* Select dans le modal */
.sm-select {
  appearance: none;
  -webkit-appearance: none;
  height: 30px;
  padding: 0 26px 0 10px;
  font: 600 11.5px var(--font);
  color: var(--text);
  background: var(--surface-2)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235E6678' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")
    no-repeat right 8px center / 11px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: border-color .15s;
  max-width: 200px;
}

.sm-select:hover { border-color: var(--border-strong); }

.sm-select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* Pastilles couleur */
.sm-row input[type="color"] {
  appearance: none;
  -webkit-appearance: none;
  width: 44px;
  height: 28px;
  padding: 0;
  background: none;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  cursor: pointer;
  overflow: hidden;
  transition: border-color .15s, transform .1s;
}

.sm-row input[type="color"]:hover {
  border-color: var(--accent);
  transform: scale(1.05);
}

.sm-row input[type="color"]::-webkit-color-swatch-wrapper { padding: 3px; }
.sm-row input[type="color"]::-webkit-color-swatch { border: none; border-radius: 5px; }
.sm-row input[type="color"]::-moz-color-swatch { border: none; border-radius: 5px; }

/* Pied de modal */
.sm-footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 18px 16px;
  flex: none;
  border-top: 1px solid var(--border);
}

.sm-btn-cancel,
.sm-btn-ok {
  height: 34px;
  padding: 0 18px;
  font-size: 12.5px;
  font-weight: 600;
  border-radius: var(--r-md);
  transition: background .15s, color .15s;
}

.sm-btn-cancel {
  color: var(--text-2);
  background: var(--surface-2);
  border: 1px solid var(--border);
}

.sm-btn-cancel:hover { color: var(--text); border-color: var(--border-strong); }

.sm-btn-ok {
  color: #fff;
  background: var(--accent);
  box-shadow: 0 2px 10px rgba(78, 127, 255, .28);
}

.sm-btn-ok:hover { background: var(--accent-hover); }

/* ═══════════════════════════════════════════════════════════
   DOCK D'ANALYSE
   ─────────────────────────────────────────────────────────
   Les trois panneaux (plan de trade, backtest, liquidité) sont
   regroupés dans une colonne repliable : d'un clic elle se réduit
   à un rail d'icônes de 46 px, et chaque section garde son propre
   pliage. Les panneaux eux-mêmes ne sont pas modifiés — on
   neutralise simplement leur positionnement flottant d'origine.
════════════════════════════════════════════════════════════ */
#chartDock {
  /* 272 → 300 : « Plan de trade », « Signal d'origine » et « CLÔTURÉE » tronquaient.
     300 → 320 : « BIAIS SHORT » (86 px) a remplacé « VENTE » (40 px) ; dans le
     pire cas — titre + « C · spéculatif » + biais — il manquait 20 px. Mesuré
     à 320 : plus aucune troncature, en français, anglais et arabe. */
  --dock-w: 320px;
  position: absolute;
  top: 14px;
  left: 14px;
  z-index: 22;
  width: var(--dock-w);
  max-height: calc(100% - 28px);
  display: flex;
  flex-direction: column;
  background: var(--glass);
  backdrop-filter: blur(16px) saturate(1.4);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  /* Invisible tant que le graphique n'est pas rendu : app.js pose `ready`
     au premier tracé, et c'est ce moment-là qui déclenche l'ouverture. */
  opacity: 0;
  visibility: hidden;
  transition: width .5s ease-out, opacity .35s ease-out;
}

#chartDock.ready {
  opacity: 1;
  visibility: visible;
  animation: dock-width 1.2s 1 ease-in-out;
}

@keyframes dock-width {
  0%, 40% { width: 46px; }
  100%    { width: var(--dock-w); }
}

@keyframes dock-height {
  0%, 40% { max-height: 0; opacity: .15; }
  100%    { max-height: 640px; opacity: 1; }
}

/* ── En-tête ── */
.dock-head {
  display: flex;
  align-items: center;
  gap: 9px;
  height: 34px;
  padding: 0 11px;
  flex: none;
  border-bottom: 1px solid var(--border);
  position: relative;
}
.dock-head::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  background: linear-gradient(to right, var(--accent), var(--accent-2));
  opacity: .55;
}
.dock-head .dock-label {
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-3);
}

/* ── Liste des sections ── */
.dock-list {
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  overflow-x: hidden;
  flex: 1;
}

.dock-item { border-bottom: 1px solid var(--border); position: relative; }
.dock-item:last-child { border-bottom: 0; }

.dock-link {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  height: 38px;
  padding: 0 9px;
  text-align: left;
  color: var(--text-2);
  transition: color .2s, background .2s;
}
.dock-link:hover { color: var(--text); background: rgb(var(--veil) / .035); }

.dock-ico {
  width: 17px; height: 17px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.9;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.dock-head .dock-ico { width: 15px; height: 15px; color: var(--text-3); }

/* Icônes à tracés pleins (le symbole PIPSTER) : le dock dessine au trait
   par défaut, un logo plein y serait invisible. */
.dock-ico.dock-ico-fill { fill: currentColor; stroke: none; }

.dock-label {
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
  opacity: 1;
  transition: opacity .5s;
}

/* Les pastilles cèdent avant le chevron : elles se rognent, il reste visible. */
.dock-badges {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 5px;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  opacity: 1;
  transition: opacity .5s;
}
.dock-badges > * { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* Quand la place manque, quelque chose doit céder — mais pas n'importe quoi.
   Le SENS du biais est l'information principale de la ligne : il ne se
   tronque jamais. Le grade cède avant lui, et le titre de section en premier,
   son icône l'identifiant déjà. Sans cet ordre, « BIAIS SHORT » s'affichait
   « BIAIS SHOR… ». */
.dock-badges .tp-dir   { flex: none; letter-spacing: .03em; padding: 2.5px 7px; }
.dock-badges .tp-grade { flex: 0 1 auto; }
.dock-link > .dock-label { flex: 1 1 auto; min-width: 2.5rem; }
.dock-link { min-width: 0; }
.dock-label { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }

.dock-chevron {
  width: 14px; height: 14px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  color: var(--text-3);
  transform: rotate(-90deg);
  transition: transform .25s, opacity .5s;
}
.dock-item.open .dock-chevron { transform: rotate(0deg); }

.dock-body { display: none; }
/* L'état de repos est écrit en dur : si l'animation ne joue pas (onglet en
   arrière-plan, mouvement réduit), la section reste dépliée malgré tout. */
.dock-item.open > .dock-body {
  display: block;
  max-height: 640px;
  overflow: hidden auto;
  animation: dock-height 1.2s 1 ease-in-out;
}

/* ── Bouton de repli, en pied de colonne ── */
.dock-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 32px;
  flex: none;
  border-top: 1px solid var(--border);
  color: var(--text-3);
  transition: color .2s, background .2s;
}
.dock-toggle:hover { color: var(--accent); background: rgb(var(--veil) / .035); }
.dock-toggle svg {
  width: 15px; height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform .5s ease-out;
}

/* ── Rail replié : icônes seules, contenu au survol ── */
#chartDock.collapsed { width: 46px; }
#chartDock.collapsed .dock-label,
#chartDock.collapsed .dock-badges,
#chartDock.collapsed .dock-chevron { opacity: 0; pointer-events: none; }
#chartDock.collapsed .dock-list { overflow: visible; }
#chartDock.collapsed .dock-item > .dock-body { display: none; }
#chartDock.collapsed .dock-toggle svg { transform: rotate(180deg); }

#chartDock.collapsed .dock-item:hover > .dock-body {
  display: block;
  position: absolute;
  left: 45px;
  top: 0;
  width: var(--dock-w);
  z-index: 5;
  background: var(--glass);
  backdrop-filter: blur(16px) saturate(1.4);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  border: 1px solid var(--border);
  border-radius: 0 var(--r-lg) var(--r-lg) 0;
  box-shadow: var(--shadow-lg);
  animation: none;
}

/* ── Les panneaux perdent leur flottement : le dock les porte ── */
#chartDock #tradePanel,
#chartDock #btPanel,
#chartDock #tvLiquidity {
  position: static;
  width: auto;
  max-width: none;
  top: auto; right: auto; bottom: auto; left: auto;
  background: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  transform: none;
}
/* Le repli interne du plan de trade est remplacé par celui du dock. */
#chartDock #tradePanel.collapsed .tp-body { display: block; }

/* Une section dont le panneau n'a pas encore de données disparaît — sauf si
   la surcouche SaaS y a posé un verrou : c'est justement ce qu'il faut
   montrer à un compte gratuit. */
.dock-item:has(> .dock-body > .hidden):not(:has(> .dock-body > .saas-lock-mode)) {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  #chartDock,
  .dock-item.open > .dock-body { animation: none; }
  #chartDock,
  .dock-toggle svg,
  .dock-chevron { transition: none; }
}

/* ═══════════════════════════════════════════════════════════
   MODE WIDGET TRADINGVIEW (flag USE_TRADINGVIEW_WIDGET)
════════════════════════════════════════════════════════════ */
body.widget-mode #tvDashboard,
body.widget-mode #chartDock,
body.widget-mode #tvLiquidity,
body.widget-mode #settingsBtn,
body.widget-mode #csPicker {
  display: none;
}

body.widget-mode #tvWidgetHost { display: block; }

/* ═══════════════════════════════════════════════════════════
   RESPONSIVE
════════════════════════════════════════════════════════════ */
@media (max-height: 820px) {
  .dock-item[data-dock="backtest"] { display: none; }
}

@media (max-width: 1180px) {
  #priceBar { display: none; }
}

@media (max-width: 1080px) {
  #symbolInput { width: 160px; }
  .tb-word, .tb-pro { display: none; }
}

@media (max-width: 900px) {
  #toolbar {
    flex-wrap: wrap;
    height: auto;
    padding: 10px 12px;
    row-gap: 8px;
  }
  .tb-spacer { display: none; }
  .select-wrap { display: none; }
  #instOhlc { display: none; }
  #tvDashboard { transform: translateX(-50%) scale(.88); transform-origin: top center; }
  /* Le tableau multi-unités ne se laisse plus rogner par la droite : il
     défile dans son propre cadre. À 768 px, la colonne « momentum » du
     dernier pas de temps disparaissait purement et simplement. */
  #tvDashboard { overflow-x: auto; overflow-y: hidden; scrollbar-width: none; }
  #tvDashboard::-webkit-scrollbar { display: none; }
  /* 284 px et non 268 : sous cette largeur la colonne d'écart des niveaux
     (« sortie · BE », « jamais touché ») passait sous son contenu et
     s'ellipsait dès le premier trade clos. */
  #chartDock { --dock-w: 284px; top: 12px; left: 12px; }
  .dock-badges .tp-grade { display: none; }
  .dock-item[data-dock="backtest"] { display: none; }
}

@media (max-width: 640px) {
  /* ─── La barre du haut sur une seule ligne, qui défile ────────────
     Repliée sur trois rangées, elle mangeait 131 px — un quart de
     l'écran — avant la première bougie. Sur un téléphone, une barre
     d'outils se parcourt du pouce comme un onglet de navigateur : elle
     garde donc UNE rangée et défile latéralement quand la place manque.
     Rien n'est masqué : tout reste atteignable, dans le même ordre.

     `--tb-h` est la hauteur de cette rangée. Elle sert deux fois : ici,
     et plus bas pour poser les menus juste sous la barre. Les garder
     liées évite qu'un menu ne flotte ou ne recouvre la barre le jour où
     l'une des deux valeurs bouge.

     Le sélecteur reprend la forme `body #toolbar` : c'est celle que
     saas-terminal.css emploie pour imposer le repli sur plusieurs
     rangées, et un simple `#toolbar` ne la reprendrait pas. */
  body #toolbar {
    --tb-h: 58px;
    height: var(--tb-h);
    min-height: 0;
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    padding: 0 12px;
    gap: 10px;
    row-gap: 0;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }
  body #toolbar::-webkit-scrollbar { display: none; }
  /* Aucun élément ne se comprime : chacun garde sa taille lisible et
     c'est la barre qui défile. */
  body #toolbar > * { flex: none; }

  #symbolWrap { flex: none; }
  #symbolInput { width: 148px; }
  #loadBtn span { display: none; }
  #loadBtn { padding: 0 11px; }
  .dock-item[data-dock="liquidity"] { display: none; }

  /* Les menus s'échappent du cadre défilant ─────────────────────────
     Une boîte à défilement rogne ce qu'elle contient : ancrés en
     `absolute` sur leur bouton, les trois menus de la barre — symboles,
     unités de temps (et son jumeau, le style de bougie), langue —
     auraient été coupés net. En `fixed` ils se posent sur l'écran et
     non dans la barre ; celle-ci n'a ni `transform` ni `filter`, rien
     ne les y retient donc. Ils prennent toute la largeur : sur 390 px,
     c'est de toute façon la seule forme lisible.

     `--tb-bottom` est posée par app.js : c'est la base RÉELLE de la barre,
     qui descend quand un bandeau la précède (essai, aperçu gratuit — deux
     lignes sous 400 px). Une constante s'y trompait et posait les menus
     par-dessus la barre. */
  #toolbar #symbolDropdown,
  #toolbar .tf-menu {
    position: fixed;
    top: calc(var(--tb-bottom, var(--tb-h, 58px)) + 6px);
    inset-inline: 8px;
    width: auto;
    min-width: 0;
    max-width: none;
    max-height: min(60vh, 420px);
  }

  /* ─── Terminal au format téléphone ──────────────────────────────
     Une colonne de 268 px sur un écran de 390 masquait le graphique et
     ne laissait au tableau multi-unités qu'une bande de quelques pixels,
     qu'il débordait par la droite : c'est de là que venait le défilement
     latéral du terminal entier. Dépliée, la colonne prend maintenant
     toute la largeur utile — un panneau, pas une colonne ; repliée, elle
     rend le graphique au marché. (app.js la replie par défaut ici.) */
  #chartDock { left: 8px; right: 8px; top: 8px; width: auto; max-height: calc(100% - 16px); }
  #chartDock.collapsed { width: 46px; right: auto; }
  [dir="rtl"] #chartDock.collapsed { right: 8px; left: auto; }

  /* Le bandeau instrument défile plutôt que de rogner ses pastilles. */
  .inst-main { overflow-x: auto; scrollbar-width: none; }
  .inst-main::-webkit-scrollbar { display: none; }

  #instExchange { display: none; }

  /* Le verdict tient sur une ligne et défile avec le reste du tableau :
     découpé en trois lignes dans une carte étroite, il devenait un pavé. */
  .dv-label { white-space: nowrap; }
  #dashVerdict { flex-wrap: nowrap; }
}

/* ═══════════════════════════════════════════════════════════
   LE TERMINAL AU DOIGT  (≤ 860 px)
   ───────────────────────────────────────────────────────────
   Deux problèmes distincts, tous deux invisibles à la souris.

   1. Tout champ de moins de 16 px déclenche le zoom automatique de
      Safari sur iOS, qui ne se défait jamais : la fenêtre des réglages
      compte vingt-sept champs numériques à 12 px, donc vingt-sept
      occasions de se retrouver sur une page décalée.
   2. Les commandes mesuraient 26 à 34 px de haut. Le sélecteur d'unité
      de temps — la commande la plus utilisée d'un terminal — tenait sur
      26 px, moitié moins que la cible tactile recommandée.

   Le prix est une vingtaine de pixels de barre d'outils en plus ; le
   graphique les rend en défilant, une commande manquée non.
════════════════════════════════════════════════════════════ */
@media (max-width: 860px) {
  /* Le plancher de 16 px vaut pour TOUT champ de saisie du terminal, où
     qu'il soit : la fenêtre des réglages, mais aussi le capital et le
     risque du panneau de trade, la vitesse du rejeu, le choix de préréglage.
     Les énumérer un à un laissait chaque fois passer les suivants.

     `!important` est ici volontaire : une
     bonne moitié de ces champs porte une taille posée par un sélecteur
     d'identifiant (`#symbolInput`, `#presetSelect`, `#cfg-slMode`…), qu'un
     sélecteur d'élément ne peut pas reprendre. Ce n'est pas un choix
     esthétique mais un plancher : en dessous, iOS zoome la page et ne la
     défait jamais. Aucun composant n'a de raison d'y déroger. */
  input:not([type="checkbox"]):not([type="radio"]):not([type="color"]):not([type="range"]),
  select, textarea { font-size: 16px !important; }

  #symbolInput { height: 40px; }

  .sm-row input[type="number"] { width: 96px; height: 40px; }
  .sm-row input[type="text"],
  .sm-row select,
  #alertOverlay input:not([type="checkbox"]):not([type="color"]),
  #alertOverlay select { height: 40px; }
  #psCapital, #psRisk { height: 38px; }

  .iv-btn { height: 38px; padding: 0 14px; font-size: 12.5px; }
  .iv-btn.tf-item { height: 40px; }
  .tf-star { width: 34px; height: 34px; }

  .tf-more { height: 38px; }

  .sm-tab { height: 38px; font-size: 13px; }
  #settingsClose { width: 38px; height: 38px; }
  .sq-close { width: 34px; height: 34px; }
  /* `#toolbar .themetoggle` (plus bas dans cette feuille) l'emporte sur un
     sélecteur de classe : on reprend sa forme, en plus précis. Ce bouton ne
     subsiste que pour le terminal servi sans la surcouche SaaS — sinon le
     thème est dans le menu compte. */
  #toolbar .themetoggle.tt-terminal { width: 38px; height: 38px; }
  #toolbar .saas-acct-btn .saas-avatar { width: 32px; height: 32px; font-size: 12px; }

  #alertsBtn, #replayBtn, #settingsBtn { width: 38px; height: 38px; }
  #csBtn { height: 38px; }

  .dock-link { min-height: 44px; }
  #dockToggle { height: 40px; }

  /* Les liens de compte de la barre d'outils sont des cibles, pas du texte. */
  #toolbar .saas-link { min-height: 36px; display: inline-flex; align-items: center; }
}


/* ═══ MODALE DES ALERTES ═══ mêmes fondations que la modale des réglages. */
#alertOverlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: var(--scrim);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
#alertModal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 210;
  width: min(440px, calc(100vw - 32px));
  max-height: min(680px, calc(100vh - 48px));
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 16px;
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
#alertOverlay.hidden, #alertModal.hidden { display: none; }

.al-note {
  margin: 8px 0 10px;
  font-size: 10.5px;
  line-height: 1.4;
  color: var(--text-3);
}
.al-actions { display: flex; justify-content: flex-end; gap: 8px; margin-bottom: 6px; }
.al-cancel-edit {
  height: 34px;
  padding: 0 12px;
  font-size: 12px;
  color: var(--text-2);
  background: none;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  cursor: pointer;
}
.al-cancel-edit.hidden { display: none; }

.al-list { display: grid; gap: 6px; padding-bottom: 6px; }
.al-empty { font-size: 11px; color: var(--text-3); padding: 4px 0 8px; }
.al-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 9px;
  border: 1px solid var(--border);
  border-radius: 9px;
  background: rgb(var(--veil) / .03);
  cursor: pointer;
  font-size: 11.5px;
}
.al-item:hover { border-color: var(--border-strong); }
.al-item.off { opacity: .55; }
.al-item .al-cond { font-weight: 700; font-variant-numeric: tabular-nums; }
.al-item .al-sub  { color: var(--text-3); font-size: 10px; }
.al-item .al-state {
  margin-inline-start: auto;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
}
.al-item .al-state.on      { color: var(--up); }
.al-item .al-state.fired   { color: var(--text-3); }
.al-item .al-state.expired { color: var(--warn); }
.al-item button {
  flex: none;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  color: var(--text-3);
  background: none;
  border: 0;
  border-radius: 6px;
  cursor: pointer;
}
.al-item button:hover { color: var(--text); background: rgb(var(--veil) / .08); }
.al-item button svg { width: 13px; height: 13px; }
[dir="rtl"] .al-item .al-cond, [dir="rtl"] .al-item .al-sub { unicode-bidi: plaintext; }


/* ═══ REJEU (bar replay) ═══════════════════════════════════════════════════
   Barre de contrôle posée en bas du tracé, au-dessus de l'axe des temps.
   Volontairement sobre : pendant un rejeu, ce qu'on regarde c'est le
   graphique, pas les boutons. */
.replay-bar {
  position: absolute;
  bottom: calc(var(--time-scale-height, 28px) + 16px);
  /* Le centre du TRACÉ (voir `--plot-mid-x`), pas celui de la bande libre :
     la barre est en bas, rien ne flotte au-dessus d'elle. Le repli à 50 %
     compte : si le script n'a pas encore mesuré, une barre centrée à peu près
     vaut mieux qu'une propriété invalide, qui rendrait `left: auto` et
     poserait la barre à sa position statique — c'est-à-dire n'importe où. */
  left: var(--plot-mid-x, 50%);
  transform: translateX(-50%);
  /* `width: max-content` N'EST PAS DÉCORATIF. Un élément absolu qui n'a que
     `left` de posé se dimensionne sur la place RESTANTE à sa droite, soit
     `largeur du conteneur − left`. Centré, il n'en a donc que la moitié : le
     `flex-wrap` ajouté juste en dessous le repliait aussitôt en colonne —
     mesuré, 134 px de large sur 161 de haut, une pile de boutons au lieu
     d'une barre. `max-content` lui rend sa largeur naturelle ; le repli ne
     sert plus qu'au cas où il n'y a vraiment pas la place. */
  width: max-content;
  max-width: calc(100% - 24px);
  flex-wrap: wrap;
  justify-content: center;
  z-index: 24;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 8px;
  background: var(--glass);
  backdrop-filter: blur(16px) saturate(1.4);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  box-shadow: var(--shadow-lg);
  font-size: 11.5px;
}
.replay-bar[hidden] { display: none; }

.rp-btn {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 28px;
  padding: 0 10px;
  color: var(--text-2);
  background: none;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  font: inherit;
  font-weight: 600;
  transition: color .15s, background .15s;
}
.rp-btn:hover { color: var(--text); background: rgb(var(--veil) / .08); }
.rp-btn svg,
.rp-ico svg { width: 14px; height: 14px; }
.rp-ico { display: grid; place-items: center; }
.rp-icon { width: 28px; padding: 0; justify-content: center; }
.rp-close:hover { color: var(--down); background: rgba(239, 83, 80, .12); }

/* Mode « choisir une barre » : le bouton reste allumé tant que le clic
   attendu n'est pas venu, sinon on ne sait plus ce que le terminal attend. */
.rp-pick.armed { color: var(--accent); background: var(--accent-soft); }

.rp-sep { width: 1px; height: 16px; background: var(--border-strong); }

.rp-speed {
  height: 26px;
  padding: 0 4px;
  color: var(--text-2);
  background: rgb(var(--veil) / .05);
  border: 1px solid var(--border);
  border-radius: 7px;
  font: inherit;
  font-size: 11px;
  font-weight: 600;
  cursor: pointer;
}

.rp-clock {
  min-width: 118px;
  text-align: center;
  color: var(--text);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Pendant le rejeu, le curseur du graphique annonce qu'un clic va choisir la
   barre de départ. */
body.replay-picking #chartContainer { cursor: crosshair; }

/* Bandeau discret : on ne regarde pas des données en direct. */
body.replay-on #instrumentStrip::after {
  content: attr(data-replay-note);
  margin-inline-start: 8px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--warn);
  background: rgba(240, 169, 75, .12);
  border: 1px solid rgba(240, 169, 75, .35);
}

@media (max-width: 900px) {
  .rp-pick span { display: none; }
  .rp-clock { min-width: 92px; font-size: 10.5px; }
}


/* Verdict d'autorisation : la seule ligne qui répond à « puis-je entrer ».
   Vert ou rouge, sans nuance — c'est un feu, pas une jauge de plus. */
.dv-validation {
  display: flex;
  align-items: center;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 700;
  white-space: nowrap;
  /* Une seule ligne depuis le lot 2 : le motif a son propre rang en dessous.
     La pastille ne porte plus qu'un STATUT, et « Nouvelle entrée » dit sans
     ambiguïté qu'elle ne parle pas de la position ouverte. */
  min-width: 0;
  max-width: 260px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.dv-validation[hidden] { display: none; }
.dv-validation[data-state="ok"] {
  color: var(--up);
  background: rgba(38, 166, 154, .12);
  border: 1px solid rgba(38, 166, 154, .4);
}
.dv-validation[data-state="no"] {
  color: var(--down);
  background: rgba(239, 83, 80, .12);
  border: 1px solid rgba(239, 83, 80, .4);
}

/* Objectif jamais atteint sur un trade soldé : il garde sa place — c'est le
   plan tel qu'il était — mais plus sa couleur de gain. */
.tp-meta.tp-missed { color: var(--text-3); font-weight: 500; }


/* Deux lignes affichées : la boîte PRINCIPALE reste centrée sur la pointillée, en une comme en deux
   lignes : c'est elle qui porte le prix de la série, donc le niveau que la
   ligne prolonge. Le mid pend en dessous. */
.live-price-marker.has-book .live-price-value {
  height: var(--live-price-row-height);
  font-size: 11.5px;
}
/* Chaque ligne a SA couleur, comme chez TradingView : celle de la bougie suit
   le sens de la bougie, celle du prix de marché suit le sens du dernier tick.
   C'est ce qui produit un vert au-dessus d'un rouge — une bougie haussière
   dont le dernier tick vient de baisser. La pile perd donc son fond unique. */
.live-price-marker.has-book .live-price-stack { background: none; box-shadow: none; }
.live-price-marker.has-book .live-price-value,
.live-price-marker.has-book .live-price-countdown {
  background: var(--live-price-color);
}
/* Cote fermée ou périmée : gris neutre. Un vert ou un rouge sur une cote de
   vendredi soir raconte un marché qui bouge, alors qu'il est à l'arrêt — c'est
   le seul endroit de l'écran où une couleur peut mentir sur le temps. */
.live-price-marker.has-book .live-price-value.quote-stale {
  background: #5A6672;
  /* Blanc littéral, pas un voile : le fond de cette pastille est ardoise
     dans les deux thèmes, donc le texte ne doit pas suivre le thème. */
  color: rgba(255, 255, 255, .85);
}
.live-price-value.tick-up,
.live-price-marker.has-book .live-price-value.tick-up   { background: #26a69a; }
.live-price-value.tick-down,
.live-price-marker.has-book .live-price-value.tick-down { background: #ef5350; }

/* La boîte du bas est détachée de celle du haut : deux couleurs collées sans
   séparation se liraient comme un dégradé. */
.live-price-marker.has-book #livePriceMidValue {
  margin-top: 2px;
  border-radius: 0 4px 4px 0;
}
.live-price-marker.has-book #livePriceSeriesValue { border-radius: 0 4px 0 0; }
.live-price-marker.has-book .live-price-countdown { border-radius: 0 0 4px 0; border-top-color: rgb(var(--veil) / .22); }

/* ─── LE PRIX DE MARCHÉ EST UNE ÉTIQUETTE D'AXE ───────────────────────────
   Donc il se pose à SON niveau, pas à un décalage convenu sous la bougie.
   `placeMidRow` calcule le décalage et l'écrit dans `--live-price-mid-top` ;
   ici on ne fait que le sortir du flux pour qu'il puisse l'atteindre.

   LE REPÈRE EST LE MARQUEUR, pas la pile : le marqueur est posé sur le prix
   de la série, c'est donc la seule origine dont le décalage ait un sens. La
   pile, elle, est déjà remontée d'une demi-rangée par sa marge négative.

   `overflow: visible` sur la pile est indispensable — elle rogne ses rangées
   pour tenir ses coins arrondis, et la pastille sortie du flux se ferait
   couper net à la première dizaine de pixels d'écart. */
.live-price-marker.has-book .live-price-stack { overflow: visible; }
.live-price-marker.has-book #livePriceMidValue {
  position: absolute;
  inset-inline-end: 0;
  top: 0;
  margin: 0;
  transform: translateY(var(--live-price-mid-top, 33px));
  border-radius: 0 4px 4px 0;
}
.live-price-value[hidden] { display: none; }


/* ─── Bouton de thème ─────────────────────────────────────────────
   Les trois icônes cohabitent dans le bouton ; `data-theme-mode` sur
   <html> décide laquelle est visible. Aucun échange en JavaScript,
   donc aucun risque que l'icône mente sur l'état réel. */
.themetoggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; flex: none;
  border-radius: 9px; border: 1px solid transparent;
  color: var(--text-3); cursor: pointer;
  transition: color .15s, background .15s, border-color .15s;
}
.themetoggle:hover { color: var(--text); background: rgb(var(--veil) / .05); }
.themetoggle svg { width: 15px; height: 15px; display: block; }

.themetoggle .tt-ico { display: none; line-height: 0; }
:root[data-theme-mode="auto"]  .themetoggle .tt-auto,
:root[data-theme-mode="light"] .themetoggle .tt-light,
:root[data-theme-mode="dark"]  .themetoggle .tt-dark { display: block; }
/* Avant que theme.js n'ait posé l'attribut — il est synchrone, donc
   ce cas ne dure jamais — on montre l'icône « système ». */
:root:not([data-theme-mode]) .themetoggle .tt-auto { display: block; }

/* Bouton de thème posé dans la barre du terminal par saas-theme.js :
   il doit s'aligner sur la hauteur des autres boutons de la barre, pas
   sur celle de la navigation du site. */
#toolbar .themetoggle {
  width: 30px; height: 30px; border-radius: 7px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-2);
  margin-inline-end: 6px;
}
#toolbar .themetoggle:hover { color: var(--toolbar-fg); border-color: var(--border-strong); }
#toolbar .themetoggle svg { width: 14px; height: 14px; }
