/* ============================================================================
   WhiteScale — feuille de style de l'application.
   Elle est issue d'une maquette (design/mockup-pilotage.html) supprimée avec la
   page qu'elle décrivait : ce fichier fait foi, seul.

   MOBILE-FIRST : le style par défaut est celui du téléphone ; le bureau est un
   élargissement (@media min-width: 1024px), jamais l'inverse.
   Règle directrice : le décor est cyberpunk, les CHIFFRES ne le sont pas —
   un P&L se lit, il ne se devine pas.
   ========================================================================== */


:root {
  --bg:        #04060a;
  --bg-grid:   #0a1016;
  --panel:     #070c12;
  --panel-2:   #0a1119;
  --line:      #122430;
  --line-hot:  #1b3d4d;

  --txt:       #c8dbe4;
  --txt-dim:   #5a7383;
  --txt-faint: #33474f;

  --cyan:      #22d3ee;
  --green:     #00ff9f;
  --amber:     #ffb020;
  --red:       #ff2e5b;

  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Encoches et barre d'accueil iOS. Le fallback 0px sert aux navigateurs qui
     ne connaissent pas env() — sans lui, la règle entière est ignorée. */
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);

  --topbar-h: 52px;
  --update-h: 54px;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body { height: 100%; margin: 0; }

body {
  background: var(--bg);
  color: var(--txt);
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1.45;
  background-image:
    linear-gradient(var(--bg-grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--bg-grid) 1px, transparent 1px),
    radial-gradient(ellipse 90% 45% at 50% -8%, #0b2430 0%, transparent 70%);
  background-size: 40px 40px, 40px 40px, 100% 100%;
  background-attachment: fixed;
}

/* Lignes de balayage CRT : une texture, pas un gadget. */
body::after {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 200;
  background: repeating-linear-gradient(to bottom, rgba(0,0,0,.2) 0 1px, transparent 1px 3px);
  mix-blend-mode: multiply;
}

/* ============================================================ ossature mobile
   100dvh et pas 100vh : sur iOS, vh inclut la barre d'adresse et fait dépasser
   la page sous le pouce. */
.app {
  min-height: 100dvh;
  padding-top: calc(var(--topbar-h) + var(--safe-t));
  padding-bottom: var(--safe-b);
}
/* La bannière est en position fixe pour rester visible pendant le défilement :
   c'est donc à l'app de réserver sa hauteur, sinon elle mange les chiffres.
   Classe posée par le JS quand un service worker attend. */
.app.has-update { padding-top: calc(var(--topbar-h) + var(--safe-t) + var(--update-h)); }

/* ------------------------------------------------------------------ topbar */
.topbar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  height: calc(var(--topbar-h) + var(--safe-t));
  padding: var(--safe-t) 13px 0;
  display: flex; align-items: center; gap: 11px;
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, rgba(8,16,24,.97), rgba(4,8,13,.97));
  backdrop-filter: blur(8px);
}

.brand { font-weight: 700; font-size: 14px; letter-spacing: .18em; color: #eafcff;
         text-shadow: 0 0 12px rgba(34,211,238,.55); white-space: nowrap;
         text-decoration: none; -webkit-tap-highlight-color: transparent; }
.brand > span { color: var(--cyan); }
.brand .long { display: none; }
/* « HITE » doit rester blanc quand il réapparaît : seul « S…CALE » est cyan. */
.brand > span.long:first-of-type { color: #eafcff; }
/* La version vit DANS la marque pour se déplacer avec elle, ce qui l'oblige à
   défaire tout ce que la marque impose : le cyan, le gras, le halo, l'interlettre. */
.brand .ver { margin-left: 9px; font-size: 9.5px; font-weight: 400; letter-spacing: .08em;
              color: var(--txt-dim); text-shadow: none; }

.dot { width: 6px; height: 6px; border-radius: 50%; flex: none; }
.dot.on   { background: var(--green); box-shadow: 0 0 8px var(--green); animation: pulse 2.4s infinite; }
.dot.warn { background: var(--amber); box-shadow: 0 0 8px var(--amber); }
.dot.off  { background: var(--red);   box-shadow: 0 0 8px var(--red); }
.dot.cy   { background: var(--cyan);  box-shadow: 0 0 8px var(--cyan); }
@keyframes pulse { 0%,100% { opacity: 1 } 50% { opacity: .35 } }

.clock { display: none; }

/* ------------------------------------------------- bannière mise à jour PWA
   Le point qui justifie tout le service worker : une app installée sur iOS ne
   se recharge jamais toute seule. Sans cette bannière, on pilote un moteur
   avec une interface vieille de trois versions. */
.update {
  position: fixed; z-index: 60;
  top: calc(var(--topbar-h) + var(--safe-t)); left: 0; right: 0;
  display: flex; align-items: center; gap: 10px;
  padding: 9px 13px;
  background: linear-gradient(90deg, #06242c, #04161c);
  border-bottom: 1px solid var(--cyan);
  box-shadow: 0 6px 24px rgba(0,0,0,.6);
}
.update .ic { color: var(--cyan); text-shadow: 0 0 10px var(--cyan); }
.update .tx { font-size: 11px; letter-spacing: .08em; color: var(--txt); flex: 1; }
.update .tx small { display: block; color: var(--txt-dim); font-size: 10px; letter-spacing: .04em; }
.update .go {
  border: 1px solid var(--cyan); background: transparent; color: var(--cyan);
  font-family: var(--mono); font-size: 10px; letter-spacing: .16em; text-transform: uppercase;
  padding: 7px 12px; cursor: pointer;
  clip-path: polygon(6px 0, 100% 0, 100% calc(100% - 6px), calc(100% - 6px) 100%, 0 100%, 0 6px);
}
.update .go:active { background: var(--cyan); color: #04161c; }

/* ------------------------------------------------------------------ panels */
.panel {
  background: var(--panel); border: 1px solid var(--line);
  margin: 10px; padding: 12px 13px 14px; position: relative;
}
.panel::before, .panel::after {
  content: ""; position: absolute; width: 9px; height: 9px;
  border-color: var(--cyan); border-style: solid; opacity: .7;
}
.panel::before { top: -1px; left: -1px; border-width: 1px 0 0 1px; }
.panel::after  { bottom: -1px; right: -1px; border-width: 0 1px 1px 0; }

.panel-title {
  display: flex; align-items: center; gap: 8px; margin: 0 0 11px;
  font-size: 10px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--cyan); font-weight: 500;
}
.panel-title::after { content: ""; flex: 1; height: 1px;
  background: linear-gradient(90deg, var(--line-hot), transparent); }
.panel-title .idx { color: var(--txt-faint); }

.btn {
  border: 1px solid var(--line-hot); background: #061017; color: var(--txt);
  font-family: var(--mono); font-size: 11px; letter-spacing: .14em;
  text-transform: uppercase; padding: 13px 8px; cursor: pointer;
  clip-path: polygon(7px 0, 100% 0, 100% calc(100% - 7px), calc(100% - 7px) 100%, 0 100%, 0 7px);
}
.btn[disabled] { opacity: .4; cursor: not-allowed; }

/* Les couleurs d'une valeur. Elles portent un ÉTAT, jamais une décoration. */
.v.gr { color: var(--green); } .v.cy { color: var(--cyan); } .v.am { color: var(--amber); }
.v.rd { color: var(--red); } .v.dim { color: var(--txt-dim); font-weight: 400; }

/* Ligne clé/valeur générique — le motif le plus fréquent de l'app (un libellé à
   gauche, un chiffre à droite). `tabular-nums` est ce qui aligne les colonnes de
   chiffres d'une ligne à l'autre : sans lui, une somme « saute » quand elle
   change. */
.row { display: flex; align-items: baseline; justify-content: space-between;
       gap: 10px; padding: 4px 0; }
.row + .row { border-top: 1px dashed #0e1d26; }
.k { color: var(--txt-dim); font-size: 11px; letter-spacing: .06em; }
.v { font-variant-numeric: tabular-nums; font-weight: 500; }
/* Les liens de la barre — discrets, à droite. Le graphe reste la page ; les
   deux autres sont une lecture (l'historique) et un réglage (le compte). */
.topnav { display: flex; align-items: center; gap: 4px; margin-left: auto; }
.topnav-item {
  display: flex; align-items: center; gap: 6px;
  padding: 5px 10px; border: 1px solid transparent;
  color: var(--txt-faint); text-decoration: none;
  font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase;
  transition: .12s;
}
.topnav-item .g { font-size: 12px; line-height: 1; }
.topnav-item .l { display: none; }
.topnav-item:hover { color: var(--txt); border-color: var(--line-hot); }
.topnav-item.on { color: var(--cyan); border-color: var(--line-hot); background: #071820;
                  text-shadow: 0 0 10px rgba(34,211,238,.5); }

/* ============================================================ ≥ 1024 px : console
   Le téléphone d'abord ; le bureau déplie. */
@media (min-width: 1024px) {
  body { overflow: hidden; }
  .app {
    height: 100dvh; padding: 0;
    display: grid; grid-template-rows: var(--topbar-h) auto 1fr;
  }
  .topbar { position: static; height: var(--topbar-h); padding: 0 16px; gap: 18px; }
  .brand { font-size: 15px; letter-spacing: .22em; }
  .brand .long { display: inline; }
  .app.has-update { padding-top: 0; }
  .clock { display: block; margin-left: auto; color: var(--txt-dim);
           font-size: 11px; letter-spacing: .1em; }
  .clock b { color: var(--cyan); font-weight: 400; }
  .update { position: static; }
  /* Sur téléphone l'horloge est masquée : c'est le lien du compte qui prend la
     droite. Sur bureau, l'horloge la prend, et le lien la suit. */
  .topnav { margin-left: 14px; }
  .topnav-item .l { display: inline; }
}

/* ---------------------------------------------------------------- utilitaires
   `display: flex` sur .update l'emporte sur le style par défaut de [hidden] :
   sans cette règle, la bannière de mise à jour est visible en permanence. */
[hidden] { display: none !important; }

/* Bandeau d'avertissement permanent (authentification coupée). Volontairement
   laid et impossible à rater : il doit gêner. */
.warn-strip {
  background: var(--red); color: #14020a;
  font-size: 10px; font-weight: 700; letter-spacing: .18em;
  text-align: center; padding: 5px 10px;
}

/* Message d'erreur de formulaire. */
.form-error { margin-top: 14px; font-size: 11.5px; color: var(--red); }

/* Page hors ligne / état vide : centré, sobre, sans fausse promesse. */
.blank {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; padding: 48px 24px; text-align: center; color: var(--txt-dim);
  min-height: 50dvh;
}
.blank .big { font-size: 15px; color: var(--txt); letter-spacing: .1em; }
.blank code { color: var(--txt); }

/* Formulaire de connexion. */
.login-wrap { display: flex; min-height: 100dvh; align-items: center; justify-content: center; padding: 24px; }
.login-card { width: 100%; max-width: 340px; }
.login-card h1 { font-size: 17px; letter-spacing: .2em; margin: 0; color: #eafcff;
                 text-shadow: 0 0 12px rgba(34,211,238,.5); }
.login-card h1 span { color: var(--cyan); }
.login-card .sub { color: var(--txt-dim); font-size: 11px; margin: 4px 0 22px; }
/* Un champ, partout pareil : la connexion, l'amorçage et le compte s'en
   servent. Ils vivaient dans la carte de connexion ; les y laisser aurait rendu
   le formulaire du compte sans style, sans que rien ne le signale. */
.field-group { margin-bottom: 14px; }
.field-group label { display: block; font-size: 10px; letter-spacing: .12em;
                     text-transform: uppercase; color: var(--txt-dim); margin-bottom: 5px; }
.field-group input {
  width: 100%; background: #040a0f; color: var(--txt);
  border: 1px solid var(--line); border-left: 2px solid var(--line-hot);
  padding: 10px 11px; font-family: var(--mono); font-size: 13px;
}
.field-group input:focus { outline: none; border-left-color: var(--cyan); }
.login-card .note, .panel .note { margin-top: 16px; font-size: 10px; color: var(--txt-faint); line-height: 1.5; }

/* Pile de panneaux — les pages Compte et Historique. */
.stack { display: flex; flex-direction: column; gap: 12px; padding: 12px; }
@media (min-width: 1024px) {
  .stack { max-width: 560px; margin: 0 auto; padding: 20px 12px; overflow-y: auto; }
  .stack.wide { max-width: 760px; }
}

/* ------------------------------------------------------------- historique
   Le relevé du courtier, en lignes. Les montants sont tabulaires et à droite,
   comme dans n'importe quel relevé : c'est la colonne qu'on lit de haut en bas.
   La couleur y porte le SIGNE et rien d'autre. */
.period { display: flex; align-items: center; gap: 10px; padding: 0 2px; }
.period .k { flex: none; }
.period .seg { margin-left: 0; }
.period a.seg-b { text-decoration: none; }
/* Démo ou réel, à côté de la période : un historique démo n'est pas de
   l'argent, et il faut le lire sur la même ligne que le reste. */
.period .env {
  margin-left: auto; padding: 1px 6px;
  border: 1px solid var(--line-hot); color: var(--txt-dim);
  font-size: 9px; letter-spacing: .12em;
}

.totals { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 12px; }
.totals > div {
  border: 1px solid var(--line); background: var(--panel-2); padding: 8px 10px;
}
.totals dt { margin: 0 0 3px; font-size: 9px; letter-spacing: .16em; text-transform: uppercase;
             color: var(--txt-dim); }
.totals dd { margin: 0; font-size: 14px; font-variant-numeric: tabular-nums; font-weight: 500;
             overflow-wrap: anywhere; }
.totals dd.gr { color: var(--green); } .totals dd.rd { color: var(--red); }
.totals dd.dim { color: var(--txt-dim); font-weight: 400; }

.ledger { width: 100%; border-collapse: collapse; font-size: 11px;
          font-variant-numeric: tabular-nums; }
.ledger th {
  text-align: left; padding: 0 6px 6px 0; font-weight: 400;
  font-size: 9px; letter-spacing: .16em; text-transform: uppercase; color: var(--txt-faint);
}
.ledger td { padding: 6px 6px 6px 0; border-top: 1px dashed #0e1d26; vertical-align: baseline; }
.ledger th:last-child, .ledger td:last-child { text-align: right; padding-right: 0; white-space: nowrap; }
.ledger td.when { color: var(--txt-dim); white-space: nowrap; }
.ledger td.what { color: var(--txt); }
.ledger td.what small { display: block; color: var(--txt-faint); font-size: 9.5px; }
.ledger td.gr { color: var(--green); } .ledger td.rd { color: var(--red); }
.ledger td.dim { color: var(--txt-dim); }
/* Un statut autre que « passé » est un fait, pas une mesure : il s'écrit en
   ambre, à côté du libellé. */
.ledger .st { color: var(--amber); font-size: 9.5px; letter-spacing: .1em; margin-left: 6px; }
.ledger-empty { margin: 0; font-size: 10.5px; color: var(--txt-faint); }

/* ------------------------------------------------------------------ graphe
   Le canvas occupe tout ce qui reste sous l'en-tête : sur téléphone, un graphe
   qui tient dans un tiers d'écran ne sert à rien. `100dvh` et pas `100vh` — cf.
   le commentaire en tête de fichier, c'est le même piège iOS.

   Un seul bloc : l'actif est celui que le serveur ingère, il n'y a rien à
   choisir. */
.chart-page {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px 12px 12px;
  min-height: calc(100dvh - var(--topbar-h) - var(--safe-t) - var(--safe-b));
}
/* ---- en-tête du graphe ---- */
.chart-head {
  display: flex;
  align-items: center;
  gap: 8px 14px;
  flex-wrap: wrap;
}
.chart-id { display: flex; align-items: baseline; gap: 8px; flex: 0 1 auto; min-width: 0; }
.chart-id b { font-size: 14px; color: var(--cyan); letter-spacing: .08em; }
.chart-id .nm {
  font-size: 10.5px; color: var(--txt-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chart-id .src {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 10px; letter-spacing: .1em; text-transform: uppercase; color: var(--txt-faint);
}
.chart-id .src .dot { width: 5px; height: 5px; border-radius: 50%; }

/* Lecture OHLC — chiffres tabulaires, sinon la ligne danse au survol. */
.chart-readout {
  display: flex; flex-wrap: wrap; gap: 4px 10px;
  font-size: 10.5px; font-variant-numeric: tabular-nums; color: var(--txt);
  flex: 1 1 200px; min-width: 0;
}
.chart-readout .ro-t { color: var(--txt-dim); }
.chart-readout .ro i { color: var(--txt-faint); font-style: normal; margin-right: 3px; }
.chart-readout .gr { color: var(--green); }
.chart-readout .rd { color: var(--red); }
.chart-readout .dim { color: var(--txt-dim); }

.seg { display: flex; border: 1px solid var(--line); flex: 0 0 auto; margin-left: auto; }
.seg-b {
  background: transparent; border: 0; border-right: 1px solid var(--line);
  color: var(--txt-dim); font-family: var(--mono); font-size: 10.5px;
  letter-spacing: .06em; padding: 5px 10px; cursor: pointer;
}
.seg-b:last-child { border-right: 0; }
.seg-b:hover { color: var(--txt); background: var(--panel-2); }
.seg-b.on { color: var(--bg); background: var(--cyan); }

.chart-warn {
  margin: 0; padding: 7px 10px;
  border: 1px solid #4a3a12; background: #140f04;
  color: var(--amber); font-size: 10.5px; line-height: 1.6;
}
.chart-warn code { color: var(--txt); font-size: 10px; }

.chart-box {
  position: relative;
  flex: 1;
  min-height: 260px;
  border: 1px solid var(--line);
  background: var(--panel);
}
/* Positionné en absolu, et pas `height: 100%` : la hauteur en pourcentage d'un
   élément flex à hauteur indéfinie est mal définie, et le canvas se retrouvait à
   n'occuper qu'un tiers de son cadre sur téléphone. */
.chart-box canvas { position: absolute; inset: 0; display: block; width: 100%; height: 100%; touch-action: none; }
.chart-status {
  position: absolute; inset: 0; margin: 0;
  display: flex; align-items: center; justify-content: center; text-align: center;
  padding: 20px; font-size: 11px; line-height: 1.7; color: var(--txt-dim);
}
.chart-foot { margin: 0; font-size: 10px; letter-spacing: .04em; color: var(--txt-faint);
  line-height: 1.6; }
.chart-foot .wr { color: var(--amber); font-weight: 400; }

/* Sur téléphone, la lecture OHLC passe sur sa propre ligne : coincée entre le
   nom de l'instrument et les unités de temps, elle s'empilait en colonne et
   mangeait la moitié de l'écran. */
@media (max-width: 720px) {
  .chart-readout { flex-basis: 100%; order: 1; }
  .chart-page { padding: 8px 10px 10px; }
  /* Le nom complet ne tient pas à côté du symbole ; le symbole, lui, suffit à
     savoir ce qu'on regarde. */
  .chart-id .nm { display: none; }
}

/* ---- bureau : le graphe prend toute la place que la grille lui laisse ---- */
@media (min-width: 1024px) {
  /* `height: 100%` et pas un calcul en 100dvh : le bandeau d'authentification
     coupée et la bannière de mise à jour sont des lignes de la grille, et un
     calcul qui les ignore pousse le pied de page sous l'écran. */
  .chart-page { height: 100%; min-height: 0; padding: 10px 14px 14px; }
}

/* ================================================================ formulaires
   Champ générique : libellé au-dessus, saisie sur une ligne avec son unité à
   droite. Les pages Réglages et StratMaker s'en servent ; les champs y sont
   GÉNÉRÉS depuis les schémas Pydantic, il faut donc qu'un champ ressemble à un
   champ sans style inline. */
.field { margin-bottom: 10px; }
.field label { display: block; font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase;
               color: var(--txt-dim); margin-bottom: 4px; }
.input { display: flex; align-items: center; gap: 8px;
         background: var(--panel-2); border: 1px solid var(--line); padding: 6px 9px; }
.input:focus-within { border-color: var(--cyan); }
.input input, .input select {
  flex: 1; min-width: 0; background: none; border: 0; color: var(--txt);
  font-family: var(--mono); font-size: 12px; padding: 0; outline: none;
}
.input select { appearance: none; -webkit-appearance: none; cursor: pointer; }
.input input::placeholder { color: var(--txt-faint); }
.input input[type="date"], .input input[type="time"] { color-scheme: dark; }
.input .unit { font-size: 9.5px; letter-spacing: .08em; color: var(--txt-faint); flex: none; }
.note { margin: 10px 0 0; font-size: 10.5px; color: var(--txt-dim); line-height: 1.55; }
.note b { color: var(--txt); font-weight: 500; }
.note.am { color: var(--amber); }
.note.rd { color: var(--red); }
.btn[disabled] { opacity: .4; cursor: not-allowed; }

/* ============================================================== indicateurs
   Tout ce qui suit est de l'AFFICHAGE : les indicateurs se calculent dans la
   page, sur les barres déjà chargées. Rien n'est écrit en base, rien n'en
   dépend côté serveur.

   ---- les outils, posés sur le canvas en haut à gauche ---- */
.chart-tools {
  position: absolute; z-index: 5;
  top: 7px; left: 7px; right: 64px;   /* 64px : l'échelle de prix, à droite */
  display: flex; align-items: flex-start; gap: 7px; flex-wrap: wrap;
  /* Le conteneur ne prend PAS les clics : sinon il volerait le glisser du
     graphe sur toute sa bande. Seuls ses enfants les prennent. */
  pointer-events: none;
}
.chart-tools > * { pointer-events: auto; }

.tool-menu { position: relative; flex: none; }
.tool-b {
  width: 24px; height: 24px; line-height: 1; padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--line-hot); background: rgba(7,12,18,.92); color: var(--txt-dim);
  font-family: var(--mono); font-size: 15px; cursor: pointer;
}
.tool-b svg { display: block; }
.tool-b:hover, .tool-b[aria-expanded="true"] { color: var(--cyan); border-color: var(--cyan); }

.tool-pop {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 10;
  min-width: 178px;
  border: 1px solid var(--line-hot); background: var(--panel);
  box-shadow: 0 8px 24px rgba(0,0,0,.7);
}
.tool-pop button {
  display: block; width: 100%; text-align: left;
  border: 0; background: none; color: var(--txt);
  font-family: var(--mono); font-size: 11px; letter-spacing: .06em;
  padding: 9px 12px; cursor: pointer; white-space: nowrap;
}
.tool-pop button:hover { background: var(--panel-2); color: var(--cyan); }

/* ---- la légende : un indicateur par pastille, avec sa valeur et son retrait */
.ind-legend { display: flex; flex-wrap: wrap; gap: 5px; min-width: 0; }
.ind-chip {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--line); background: rgba(7,12,18,.92);
  padding: 3px 4px 3px 7px; font-size: 10px; letter-spacing: .04em;
}
/* Configuré sur d'AUTRES unités de temps : la pastille reste, en retrait. La
   faire disparaître laisserait croire que l'indicateur a été perdu. */
.ind-chip.off { opacity: .45; }
.ind-chip .sw { width: 7px; height: 7px; flex: none; border-radius: 1px; }
.ind-chip .nm { color: var(--txt); }
.ind-chip .val { color: var(--txt); font-variant-numeric: tabular-nums; }
.ind-chip .tfs { color: var(--txt-faint); letter-spacing: .08em; }
.ind-chip .x {
  border: 0; background: none; color: var(--txt-faint); cursor: pointer;
  font-family: var(--mono); font-size: 12px; line-height: 1; padding: 0 3px;
}
.ind-chip .x:hover { color: var(--red); }

/* ---- la fenêtre modale ----
   `position: fixed` + marge automatique plutôt que le centrage natif de
   <dialog> : la fenêtre doit s'afficher pareil sur les navigateurs où
   `showModal()` manque et où l'on retombe sur l'attribut `open`. */
.modal {
  position: fixed; inset: 0; margin: auto;
  width: min(400px, calc(100vw - 28px)); max-height: calc(100dvh - 40px);
  border: 1px solid var(--line-hot); background: var(--panel);
  color: var(--txt); padding: 0; overflow: auto;
  box-shadow: 0 18px 60px rgba(0,0,0,.8);
}
.modal::backdrop { background: rgba(2,5,9,.72); }
.modal-card { padding: 16px 16px 14px; }
.modal-title {
  margin: 0 0 14px; font-size: 11px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--cyan); font-weight: 500;
}

/* Cases des unités de temps — même grammaire que le sélecteur du graphe (.seg),
   pour qu'un « 5m » coché se lise comme un « 5m » actif. */
.tf-pick { border: 0; margin: 0 0 12px; padding: 0; }
.tf-pick legend { padding: 0; font-size: 9.5px; letter-spacing: .12em;
                  text-transform: uppercase; color: var(--txt-dim); margin-bottom: 6px; }
.tf-pick .ticks { display: flex; flex-wrap: wrap; gap: 6px; }
/* Écrit `.tf-pick .tick` et pas `.tick` : une case est un <label> dans un
   `.field`, et `.field label` (0,1,1) l'emporterait — « 5m » s'afficherait
   « 5M », qui n'est pas le mot écrit sur le bouton d'unité de temps au-dessus
   du graphe. */
.tf-pick .tick { display: inline-flex; align-items: center; gap: 6px; margin: 0;
                 text-transform: none; letter-spacing: normal;
                 border: 1px solid var(--line); padding: 5px 9px; cursor: pointer; }
.tf-pick .tick input { accent-color: var(--cyan); margin: 0; cursor: pointer; }
.tf-pick .tick span { font-size: 11px; color: var(--txt-dim); }
.tf-pick .tick:has(input:checked) { border-color: var(--cyan); background: #071820; }
.tf-pick .tick:has(input:checked) span { color: var(--cyan); }

.modal-acts { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; }
.modal-acts .btn { padding: 9px 16px; }
.btn.cy { border-color: var(--cyan); color: var(--cyan); }
.btn.cy:hover { background: #071820; }

/* Au doigt, un bouton de 24 px se rate. L'app est installée sur iPhone : on
   grossit les cibles là où le pointeur est grossier, et nulle part ailleurs —
   la même marge sur un écran de bureau mangerait le graphe pour rien. */
@media (pointer: coarse) {
  .tool-b { width: 30px; height: 30px; font-size: 17px; }
  .ind-chip { padding: 2px 2px 2px 8px; }
  .ind-chip .x { padding: 5px 7px; font-size: 13px; }
}

/* ---------------------------------------------------- calendrier économique
   Le détail d'une échéance, au survol de son trait. Posé sur le canvas, il ne
   prend AUCUN clic : sans `pointer-events: none`, il volerait le glisser du
   graphe à l'endroit exact où l'œil s'est arrêté. */
.ev-tip {
  position: absolute; z-index: 6; top: 36px;
  max-width: min(280px, 72%);
  padding: 7px 9px;
  border: 1px solid var(--line-hot); border-left-width: 2px;
  background: rgba(7,12,18,.97);
  box-shadow: 0 8px 22px rgba(0,0,0,.7);
  font-size: 10.5px; line-height: 1.5;
  pointer-events: none;
}
/* La bordure gauche porte l'importance : c'est un état, pas une décoration. */
.ev-tip.high    { border-left-color: var(--amber); }
.ev-tip.medium  { border-left-color: var(--txt-dim); }
.ev-tip.low     { border-left-color: var(--txt-faint); }
.ev-tip.holiday { border-left-color: var(--txt-dim); }

.ev-tip .ev { display: block; }
.ev-tip .ev + .ev { margin-top: 7px; padding-top: 6px; border-top: 1px dashed #0e1d26; }
.ev-tip .h { display: flex; gap: 7px; align-items: baseline; color: var(--txt-faint);
             font-size: 9.5px; letter-spacing: .08em; text-transform: uppercase; }
.ev-tip .h .t { color: var(--cyan); letter-spacing: .04em; }
/* `display: block` et pas l'inline par défaut : sans ça l'intitulé et la ligne
   « attendu / précédent » se collent bout à bout, et « Federal Funds
   Rateattendu 4,00 % » ne se lit plus comme deux informations. */
.ev-tip .ti { display: block; color: var(--txt); }
/* Attendu et précédent — des chiffres, donc tabulaires, donc alignés. */
.ev-tip .fp { display: block; margin-top: 2px; color: var(--txt-dim);
              font-variant-numeric: tabular-nums; }
.ev-tip .fp i { color: var(--txt-faint); font-style: normal; }

/* ==================================================================== ordres
   La section qui engage de l'argent. Elle vit À CÔTÉ du graphe (bureau) ou
   AU-DESSUS (téléphone), jamais dessus : le canvas se balaie du doigt pour
   défiler, et un bouton d'ordre posé dans cette zone se déclencherait tout
   seul. D'où `.chart-main`, dont c'est l'unique raison d'être.

   La couleur porte un ÉTAT — vert = acheter, rouge = vendre, et rien d'autre
   n'est vert ou rouge ici. Les chiffres, eux, restent en clair et tabulaires :
   ce qu'on va engager se lit, il ne se devine pas. */
.chart-main {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1;
  min-height: 0;
}

/* Le rail : le compte, puis les ordres. Deux panneaux distincts et pas un seul,
   parce qu'ils ne se lisent pas au même moment — on regarde ce qu'on a, PUIS on
   décide d'engager. Sur écran large, c'est ce conteneur qui porte la largeur
   fixe du rail (cf. la requête média plus bas), pas les panneaux eux-mêmes. */
.rail {
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* Sans quoi un enfant flex refuse de descendre sous sa taille de contenu :
     un montant un peu long pousserait le graphe hors de l'écran. */
  min-width: 0;
}

.trade, .acct {
  position: relative;
  border: 1px solid var(--line);
  background: var(--panel);
  padding: 10px 12px 12px;
  display: flex;
  flex-direction: column;
  gap: 9px;
}
/* Les mêmes équerres que `.panel` — le décor de l'app, pas une exception. */
.trade::before, .trade::after, .acct::before, .acct::after {
  content: ""; position: absolute; width: 9px; height: 9px;
  border-color: var(--cyan); border-style: solid; opacity: .7;
}
.trade::before, .acct::before { top: -1px; left: -1px; border-width: 1px 0 0 1px; }
.trade::after,  .acct::after  { bottom: -1px; right: -1px; border-width: 0 1px 1px 0; }

.trade-t, .acct-t {
  display: flex; align-items: center; gap: 8px; margin: 0;
  font-size: 10px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--cyan); font-weight: 500;
}
/* Démo ou réel. Le réel n'est pas une information de plus : c'est la seule qui
   dit si un appui coûte quelque chose. Il passe donc en ambre, pendant que la
   démo reste effacée. */
.trade-env {
  margin-left: auto; padding: 1px 6px;
  border: 1px solid var(--line-hot); color: var(--txt-dim);
  font-size: 9px; letter-spacing: .12em;
}
.trade-env.live { border-color: var(--amber); color: var(--amber); }

/* ---- le compte : ce qu'on a, avant ce qu'on engage ----------------------
   Deux nombres et rien d'autre. Ils sont les plus GROS du rail, et les seuls
   qui ne soient pas en capitales : c'est ce qu'on lit d'un coup d'œil avant de
   cliquer, et un chiffre de pilotage ne se déchiffre pas. */
.acct-n {
  margin: 0; display: flex; flex-wrap: wrap; gap: 4px 16px;
}
.acct-n > div { display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px; min-width: 0; }
.acct-n dt {
  font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--txt-dim);
}
.acct-n dd {
  margin: 0; font-size: 13px; font-variant-numeric: tabular-nums;
  color: var(--txt); overflow-wrap: anywhere;
}
/* La couleur porte un ÉTAT : ici le SIGNE du P&L, et rien d'autre. Un P&L nul
   ou illisible reste en gris — le vert et le rouge disent qu'il y a quelque
   chose d'ouvert. */
.acct-n dd.gr { color: var(--green); }
.acct-n dd.rd { color: var(--red); }
.acct-n dd.dim { color: var(--txt-dim); }
/* Le pourcentage est la CONSÉQUENCE du montant, pas une seconde mesure. */
.acct-n dd i { font-style: normal; font-size: 10.5px; color: var(--txt-dim); }

/* L'heure du relevé. Un P&L latent bouge en permanence : sans elle, un nombre
   figé par une lecture qui échoue ressemble à un marché calme. */
.acct-age {
  margin-left: auto; font-size: 9px; letter-spacing: .1em;
  text-transform: none; color: var(--txt-faint);
}
.acct-age.rd { color: var(--red); }

.acct-err {
  margin: 0; padding: 6px 8px;
  border: 1px solid #4a3a12; background: var(--panel-2);
  font-size: 10px; line-height: 1.5; color: var(--amber); overflow-wrap: anywhere;
}

.trade-rules {
  margin: 0; display: flex; flex-wrap: wrap; gap: 4px 16px;
  font-size: 10.5px;
}
.trade-rules > div { display: flex; align-items: baseline; gap: 6px; min-width: 0; }
.trade-rules dt {
  font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--txt-dim);
}
.trade-rules dd { margin: 0; font-variant-numeric: tabular-nums; color: var(--txt); }
.trade-rules dd.gr { color: var(--green); }
.trade-rules dd.rd { color: var(--red); }
/* Le coût du point est le chiffre qu'on cherche des yeux avant d'appuyer : il
   porte la couleur d'attention de l'app, pas celle d'un gain ou d'une perte. */
.trade-rules dd.cy { color: var(--cyan); }
/* Le pourcentage est la CONSÉQUENCE de la distance, pas une seconde mesure :
   il se lit en second, en retrait. */
.trade-rules dd i { font-style: normal; color: var(--txt-dim); }

.trade-acts { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.trade-b {
  border: 1px solid; background: #061017;
  font-family: var(--mono); font-size: 12px; letter-spacing: .16em;
  text-transform: uppercase; padding: 14px 8px; cursor: pointer;
  clip-path: polygon(7px 0, 100% 0, 100% calc(100% - 7px), calc(100% - 7px) 100%, 0 100%, 0 7px);
}
.trade-b.buy  { border-color: var(--green); color: var(--green); }
.trade-b.sell { border-color: var(--red);   color: var(--red); }
.trade-b.buy:hover  { background: #04180f; }
.trade-b.sell:hover { background: #1a0510; }
.trade-b.buy:active  { background: var(--green); color: #02140c; }
.trade-b.sell:active { background: var(--red);   color: #14020a; }
/* Pendant l'aller-retour avec le courtier. Ce n'est pas une confirmation —
   c'est ce qui empêche un double appui d'ouvrir deux positions. */
.trade-b[disabled] { opacity: .35; cursor: progress; }

.trade-warn {
  margin: 0; font-size: 9.5px; line-height: 1.5; letter-spacing: .04em;
  color: var(--txt-faint);
}

.trade-out {
  margin: 0; padding: 7px 9px;
  border: 1px solid var(--line); background: var(--panel-2);
  font-size: 10.5px; line-height: 1.6; font-variant-numeric: tabular-nums;
  color: var(--txt); overflow-wrap: anywhere;
}
.trade-out.ok { border-color: #0c4a33; color: var(--green); }
.trade-out.rd { border-color: #4a1224; color: var(--red); }
.trade-out.am { border-color: #4a3a12; color: var(--amber); }
.trade-out b { font-weight: 700; }
.trade-out .dim { color: var(--txt-dim); }

/* ---- bureau : les ordres passent à gauche, en rail ---- */
@media (min-width: 1024px) {
  .chart-main { flex-direction: row; align-items: stretch; }
  /* Une largeur fixe, et pas un pourcentage : ce rail porte des chiffres de
     longueur connue, et le graphe doit prendre TOUT le reste. */
  .rail { flex: 0 0 218px; }
  .trade-rules { flex-direction: column; gap: 5px; }
  .acct-n { flex-direction: column; gap: 5px; }
  /* `min-width: 0` sans quoi un enfant flex refuse de descendre sous sa taille
     de contenu, et le canvas déborde du rail vers la droite. */
  .chart-box { min-width: 0; }
}

/* Au doigt, les deux boutons méritent plus de hauteur que partout ailleurs :
   ce sont les seuls de l'app dont un appui raté coûte de l'argent. */
@media (pointer: coarse) {
  .trade-b { padding: 17px 8px; }
}

/* ------------------------------------------------------------- positions
   Une LECTURE, sous les boutons. Elle n'ouvre ni ne ferme rien : ce panneau
   existe pour qu'une exposition ne puisse pas être oubliée, pas pour agir
   dessus. Les chiffres y sont tabulaires — un P&L qui saute d'un rafraîchis-
   sement à l'autre se lit mal. */
.trade-count {
  margin-left: auto; color: var(--txt-dim);
  font-size: 9.5px; letter-spacing: .12em;
}
.pos-list { display: flex; flex-direction: column; gap: 7px; }
.pos-empty { margin: 0; font-size: 10.5px; color: var(--txt-faint); }

.pos {
  border: 1px solid var(--line); background: var(--panel-2);
  padding: 6px 8px 7px;
  font-variant-numeric: tabular-nums;
}
.pos-h {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  font-size: 11px;
}
.pos-h .gr { color: var(--green); }
.pos-h .rd { color: var(--red); }
.pos-h .dim { color: var(--txt-dim); }
.pos-d {
  font-size: 9.5px; line-height: 1.6; color: var(--txt-dim);
  overflow-wrap: anywhere;
}
/* « hors graphe », « garanti » : des qualificatifs, pas des mesures. Ils
   s'effacent devant les chiffres. */
.pos-d em { font-style: normal; color: var(--amber); }

/* ------------------------------------------------------------ contexte
   Le régime porte un ÉTAT : « agité » en ambre parce qu'il change ce que
   valent les distances, « calme » effacé parce qu'il ne menace rien. Le
   garde-fou calendrier est ambre aussi — c'est un « pas maintenant », pas une
   erreur. */
.trade-rules dd.am { color: var(--amber); }
.trade-rules dd.dim { color: var(--txt-dim); }
.trade-block {
  margin: 0; padding: 7px 9px;
  border: 1px solid #4a3a12; background: #140f04;
  color: var(--amber); font-size: 10.5px; line-height: 1.55;
}
.trade-block b { color: var(--txt); font-weight: 500; }

/* ------------------------------------------------------------- candidates
   Les composantes directionnelles se lisent comme des AVIS, pas comme des
   ordres : la couleur dit le sens (vert/rouge), le taux à côté dit ce qu'il
   vaut — et tant qu'il n'y a pas assez de lectures, il n'y a pas de taux. */
.trade-rules.bias { border-top: 1px dashed #0e1d26; padding-top: 7px; }
.trade-rules.bias dd.gr { color: var(--green); }
.trade-rules.bias dd.rd { color: var(--red); }
.trade-rules.bias dd.dim { color: var(--txt-dim); }
.trade-rules.bias dd i { font-style: normal; color: var(--txt-faint); }

/* ----------------------------------------------------------- la journée
   Le règlement se lit en une ligne : trades, points, phase. Quand il ferme
   la journée, il le dit en ambre, avec la règle qui a parlé. */
.trade-rules.day dd i { font-style: normal; color: var(--txt-dim); }
.trade-rules.day dd.ok { color: var(--txt); }
