/* Le thème — voir docs/specs/07-palette-and-colour-semantics/SPEC.md.
 *
 * Deux couches. La **palette** est le relevé du thème, transcrit tel quel ;
 * les **rôles** en dessous nomment ce qu'on en fait. Une teinte ne s'écrit
 * qu'ici : toute couleur littérale ailleurs dans cette feuille est un bug,
 * c'est comme cela que cinq couleurs hors palette avaient fini par vivre dans
 * les types d'opération et les zones de la réglette.
 *
 * Les rôles se rangent en trois registres, et la règle tient en une phrase :
 * **le vert et le rouge ne sortent que du registre 3.**
 *
 *   1. la matière — de quoi l'écran est fait
 *   2. les états  — deux choses qui diffèrent sans que l'une vaille mieux que
 *                   l'autre ; elles se distinguent sur un axe froid ↔ chaud
 *   3. les verdicts — là où il y a vraiment bien et mal
 *
 * Un titre cher n'est pas un titre en faute : quand on le détient, c'est même
 * la bonne nouvelle. Il est chaud — l'œil le trouve, personne ne le blâme.
 */
:root {
  /* --- Palette : le relevé du thème --------------------------------------
     Transcrit sans retouche, y compris ses doublons (brown-lighter est
     gold-lighter, les deux cyans sont le même bleu) : c'est un relevé, pas une
     synthèse, et le corriger ici le ferait diverger de sa source. Toutes les
     entrées ne servent pas — une palette porte aussi ce qu'on n'a pas encore
     eu besoin de dire. */
  --gold-lighter: #eccfa3;
  --gold-darker: #d6ba7b;
  --white-darker: #ffeacc;
  --white-lighter: #ffffff;
  --grey-darker: #8b8b8b;
  --grey-lighter: #bab9ba;
  --black-darker: #050705;
  --black-lighter: #151515;
  --red-lighter: #ff1f19;
  --red-darker: #c26665;
  --purple-lighter: #c2a2ff;
  --purple-darker: #a559cb;
  --blue-lighter: #a6c8ff;
  --blue-darker: #234c87;
  --yellow-lighter: #e4b335;
  --yellow-darker: #e2db7f;
  --green-lighter: #1aff73;
  --green-darker: #7fa965;
  --cyan-lighter: #87f6f8;
  --cyan-darker: #87f6f8;
  --orange-lighter: #f4a05b;
  --orange-darker: #e65100;
  --brown-lighter: #eccfa3;
  --brown-darker: #a88d69;

  /* --- 1. La matière -----------------------------------------------------
     Le relevé donne deux noirs ; l'écran en demande quatre — le fond, les
     lignes paires, les barres et en-têtes, la ligne sous le curseur. Les deux
     manquants sont *dérivés* des deux autres plutôt qu'inventés : un soupçon
     de brun sur le noir haut, ce qui donne un peu de chaleur aux surfaces
     posées et laisse le fond froid dessous. */
  --bg: var(--black-darker);
  --bg-alt: var(--black-lighter);
  --header-bg: color-mix(
    in srgb,
    var(--brown-darker) 12%,
    var(--black-lighter)
  );
  --hover: color-mix(in srgb, var(--brown-darker) 20%, var(--black-lighter));
  --border: color-mix(in srgb, var(--brown-darker) 20%, var(--black-lighter));

  /* L'or est le texte courant, le blanc chaud est ce qui compte, le gris est
     ce qui recule. L'or clair est réservé à la structure active — onglet
     retenu, colonne de tri, en-tête de groupe : ce que l'œil doit trouver. */
  --fg: var(--gold-darker);
  --fg-dim: var(--grey-darker);
  --accent: var(--white-darker);
  --tab-active: var(--gold-lighter);
  --focus: var(--white-lighter);
  /* Le neutre franc, sans température : ce qui n'a rien à dire. */
  --neutral: var(--grey-lighter);

  /* --- 2. Les états ------------------------------------------------------
     Un cours sous son prix d'achat, un cours au-dessus de son prix de vente.
     Froid et chaud, parce qu'aucun des deux n'est une note : c'est la même
     réglette qu'on lit avant d'acheter et une fois qu'on détient, et les deux
     lectures sont inverses. Les variantes sombres remplissent les zones,
     les claires écrivent les chiffres.
     Les deux alphas ne sont pas les mêmes : #e65100 est bien plus saturé que
     #234c87, et à opacité égale la zone chaude écrasait la froide. Ce sont des
     fonds, pas des barres — la réglette doit se lire comme un rail teinté à ses
     extrémités, pas comme une jauge remplie. */
  --cheap: var(--blue-lighter);
  --rich: var(--orange-lighter);
  --cheap-zone: color-mix(in srgb, var(--blue-darker) 30%, transparent);
  --rich-zone: color-mix(in srgb, var(--orange-darker) 15%, transparent);

  /* --- 3. Les verdicts ---------------------------------------------------
     Le relevé donne deux verts et deux rouges, et c'est exactement la
     distinction qui manquait :

       le **signe** d'un résultat — muet, parce qu'une colonne entière en est
       faite et qu'un écran qui crie à chaque ligne n'est plus lu ;
       un **événement** — vif, parce qu'il est bref et qu'il doit arrêter la
       main : la saisie est passée, la saisie est bloquée, le flux est tombé. */
  --gain: var(--green-darker);
  --loss: var(--red-darker);
  --ok: var(--green-lighter);
  --ko: var(--red-lighter);
  --warn: var(--yellow-lighter);
  /* Les zones de la réglette sur une ligne détenue. Sous son prix de revient,
     une ligne perd vraiment de l'argent : c'est un verdict, et le registre 2
     n'a rien pour le dire (SPEC 08). Ce sont les verts et rouges du *signe*,
     pas ceux de l'événement — une table entière en est faite. Même alpha pour
     les deux : #7FA965 et #C26665 sont deux mi-tons de saturation voisine,
     contrairement au couple bleu/orange du registre 2. */
  --gain-zone: color-mix(in srgb, var(--green-darker) 22%, transparent);
  --loss-zone: color-mix(in srgb, var(--red-darker) 22%, transparent);
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--fg);
  font-family:
    ui-monospace, "JetBrains Mono", "IBM Plex Mono", Menlo, Consolas,
    "DejaVu Sans Mono", monospace;
  font-size: 12px;
  line-height: 1.25;
  min-height: 100vh;
}

a {
  color: var(--fg);
  text-decoration: none;
}

main {
  padding: 0;
}

/* Status bar */
status-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 12px;
}
status-bar .left,
status-bar .right {
  display: flex;
  gap: 14px;
  align-items: center;
}
status-bar .last-update {
  text-transform: uppercase;
}
status-bar .app-title {
  padding: 2px;
  background-color: var(--accent);
  color: var(--bg);
  /* Une pastille, pas un paragraphe : quand la barre manque de place, c'est
     elle qui pousse le pli, ce n'est pas le nom qui se coupe en deux. */
  white-space: nowrap;
}
status-bar .feed {
  display: flex;
  gap: 6px;
  align-items: center;
}
status-bar .dot {
  font-size: 14px;
  line-height: 1;
}
/* Le titre, les quatre onglets et l'horodatage demandent environ mille pixels.
   En dessous, la ligne unique ne se serre pas : elle se disloque — le nom se
   coupe en deux, les onglets tombent en lignes inégales, l'heure passe à la
   ligne au milieu d'elle-même. Alors la barre se plie franchement en deux :
   en haut ce qu'on lit — le titre à un bord, l'état du flux à l'autre ; en
   dessous ce qu'on touche — le menu, d'un bord à l'autre.

   Les moitiés `left` et `right` groupent pour la ligne unique du grand écran ;
   ici c'est la barre elle-même qui range, donc `left` s'efface en
   `display: contents` et rend ses deux enfants au flex parent. Les onglets
   passent en dernier (`order`) et réclament la largeur entière, ce qui les
   renvoie seuls à la ligne suivante. */
@media (max-width: 1000px) {
  status-bar {
    flex-wrap: wrap;
    row-gap: 4px;
  }
  status-bar .left {
    display: contents;
  }
  status-bar nav-tabs {
    order: 1;
    flex: 1 0 100%;
  }
}
/* Sur téléphone, même repliée, la ligne du haut ne tient pas avec les deux
   moitiés de l'horodatage : l'âge relatif part, l'heure des données dit la
   même chose. */
@media (max-width: 640px) {
  status-bar {
    padding: 4px 8px;
  }
  status-bar .right {
    gap: 10px;
  }
  status-bar .ago {
    display: none;
  }
}
/* Le seul feu tricolore de l'application, et c'en est un vrai : le flux est
   là, il se rattrape, il est tombé. Les verts et rouges *vifs*, pas ceux du
   signe — une pastille est un événement, pas une colonne de chiffres. */
status-bar .dot.live {
  color: var(--ok);
}
status-bar .dot.reconn {
  color: var(--warn);
}
status-bar .dot.off {
  color: var(--ko);
}

/* Le panneau « Compte » — deux gestes, ancrés au bouton de la barre.
   Il flotte plutôt qu'il ne pousse : la barre est déjà pliée en deux sur
   téléphone, et un panneau qui s'y insère déplacerait les onglets sous le
   doigt qui vient de les viser. */
account-panel {
  position: relative;
}
account-panel .account-toggle {
  background: transparent;
  color: var(--fg-dim);
  border: none;
  padding: 2px 4px;
  font: inherit;
  text-transform: uppercase;
  cursor: pointer;
}
account-panel .account-toggle:hover,
account-panel .account-toggle[aria-expanded="true"] {
  color: var(--tab-active);
}
account-panel .account-menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 34ch;
  max-width: min(46ch, calc(100vw - 16px));
  padding: 6px;
  border: 1px solid var(--border);
  background: var(--bg-alt);
}
/* Le lien et le label sont deux éléments différents — l'un télécharge, l'autre
   ouvre un sélecteur de fichiers — et ils doivent se présenter pareil : c'est
   le même rang de gestes. */
account-panel .account-action {
  display: block;
  padding: 6px 8px;
  color: var(--fg);
  text-decoration: none;
  cursor: pointer;
}
account-panel .account-action:hover {
  background: var(--hover);
  color: var(--tab-active);
}
/* Qui est connecté, en tête du panneau : l'adresse, et le rôle en retrait.
   Ce n'est pas un geste, donc ni survol ni curseur. */
account-panel .account-identity {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0 0 4px;
  padding: 6px 8px;
  border-bottom: 1px solid var(--border);
  color: var(--fg);
}
account-panel .account-role {
  color: var(--fg-dim);
  text-transform: uppercase;
}
/* Le bouton de déconnexion est un `<button>` dans un `<form>` — une
   navigation, pas un `fetch` — et il doit se présenter comme les autres
   gestes du panneau, pas comme un bouton. */
account-panel .logout {
  margin: 4px 0 0;
  padding-top: 4px;
  border-top: 1px solid var(--border);
}
account-panel .logout .account-action {
  width: 100%;
  border: none;
  background: transparent;
  font: inherit;
  text-align: left;
}
/* La confirmation dit ce qu'elle écrase avant de proposer de le faire. Chaude
   plutôt que rouge : remplacer ses données est un geste légitime, ce n'est pas
   une faute — le rouge est réservé aux verdicts. */
account-panel .account-confirm {
  margin-top: 4px;
  padding: 8px;
  border-left: 2px solid var(--warn);
  background: var(--bg);
  line-height: 1.5;
}
account-panel .account-confirm p {
  margin: 0 0 8px;
}
account-panel .account-confirm strong {
  color: var(--accent);
  font-weight: normal;
}
account-panel .account-confirm-actions {
  display: flex;
  gap: 8px;
}
account-panel .account-confirm-actions button {
  padding: 4px 10px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--fg);
  font: inherit;
  text-transform: uppercase;
  cursor: pointer;
}
account-panel .restore-confirm {
  border-color: var(--warn);
  color: var(--warn);
}
account-panel .account-confirm-actions button:hover {
  background: var(--hover);
}
account-panel .account-confirm-actions button:disabled {
  color: var(--fg-dim);
  cursor: progress;
}
account-panel .account-message {
  margin: 4px 0 0;
  padding: 0 8px;
  line-height: 1.5;
}
account-panel .account-message.ok {
  color: var(--ok);
}
account-panel .account-message.ko {
  color: var(--ko);
}

/* Fermer le compte : le dernier geste du panneau, sous un trait, en rouge
   parce que c'est un verdict — contrairement à la restauration, qui est
   chaude. Le lien de l'export dans le texte de confirmation est le seul
   endroit du panneau où un lien vit dans une phrase. Le trait est sur le
   bouton lui-même : `border: none` plus bas ne retire que les autres côtés. */
account-panel .close-open {
  width: 100%;
  border: none;
  border-top: 1px solid var(--border);
  margin-top: 4px;
  padding-top: 8px;
  background: transparent;
  font: inherit;
  text-align: left;
  color: var(--ko);
}
account-panel .close-confirm {
  border-left-color: var(--ko);
}
account-panel .close-confirm a {
  color: var(--accent);
}
account-panel .close-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
account-panel .close-form input {
  padding: 4px 6px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--fg);
  font: inherit;
}
account-panel .close-confirm-button {
  border-color: var(--ko);
  color: var(--ko);
}

/* Le volet des invitations, dans le panneau « Compte » du propriétaire. */
account-panel .invite-panel {
  margin-top: 4px;
  padding: 8px;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
account-panel .invite-form,
account-panel .invite-link {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
account-panel .invite-panel input {
  flex: 1 1 18ch;
  min-width: 0;
  padding: 4px 6px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--fg);
  font: inherit;
}
account-panel .invite-panel button {
  padding: 4px 10px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--fg);
  font: inherit;
  text-transform: uppercase;
  cursor: pointer;
}
account-panel .invite-panel button:hover {
  background: var(--hover);
}
account-panel .invite-link p {
  flex-basis: 100%;
  margin: 0;
  line-height: 1.5;
}
account-panel .invite-link strong {
  color: var(--accent);
  font-weight: normal;
}
account-panel .invite-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
account-panel .invite-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
}
account-panel .invite-email {
  color: var(--accent);
}
account-panel .invite-revoke {
  margin-left: auto;
  padding: 2px 8px;
}
account-panel .invite-panel .dim {
  margin: 0;
}

/* Les premiers pas — au-dessus des onglets, tant que le compte n'a rien.
   Trois boutons de même rang : ce sont trois débuts possibles, pas un
   chemin recommandé et deux alternatives. */
first-steps .first-steps {
  margin: 12px 12px 0;
  padding: 12px;
  border: 1px solid var(--border);
  border-left: 2px solid var(--accent);
  background: var(--bg-alt);
}
first-steps .first-steps-lead {
  margin: 0 0 10px;
  color: var(--fg);
  line-height: 1.5;
}
first-steps .first-steps-choices {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
first-steps .first-steps-choices button {
  padding: 6px 12px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--fg);
  font: inherit;
  text-transform: uppercase;
  cursor: pointer;
}
first-steps .first-steps-choices button:hover {
  background: var(--hover);
  color: var(--tab-active);
}

/* Nav tabs */
nav-tabs {
  display: flex;
  /* Les onglets ne tiennent pas toujours sur une ligne : sans passage à la
     ligne, la barre déborde et le navigateur dézoome la page entière pour la
     faire tenir. */
  flex-wrap: wrap;
  gap: 0;
}
nav-tabs button {
  background: transparent;
  color: var(--fg-dim);
  border: none;
  border-bottom: 2px solid transparent;
  padding: 6px 16px;
  font: inherit;
  text-transform: uppercase;
  cursor: pointer;
  letter-spacing: 0.05em;
}
/* Au doigt, les quatre onglets se rangent en deux colonnes plutôt que de
   couler en lignes inégales : les libellés s'alignent, et chaque bouton fait la
   moitié de la largeur — une cible tactile qui se vise sans viser. */
@media (max-width: 640px) {
  nav-tabs {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
  nav-tabs button {
    /* Le bouton occupe toute sa cellule : la cible tactile vient de la
       colonne, pas du rembourrage, et le libellé peut donc s'aligner sur le
       texte du titre au-dessus de lui. */
    padding: 12px 2px;
    text-align: left;
  }
}
nav-tabs button[aria-selected="true"] {
  color: var(--tab-active);
  border-bottom-color: var(--tab-active);
}
nav-tabs button:hover {
  color: var(--fg);
}

/* Le suivi, dans les tables d'analyse et de la Home : une étoile qui bascule.
   Pleine quand le code est suivi, creuse sinon — l'état est aussi porté par
   aria-pressed, que le sélecteur lit plutôt qu'une seconde classe libre de
   diverger.

   Plus grande que le texte de la table : c'est le seul élément cliquable d'une
   ligne, et au corps du texte sa cible tactile était sous ce qu'un doigt vise
   sans effort. Le `line-height: 1` garde la ligne à sa hauteur. */
data-table button.follow {
  background: transparent;
  border: none;
  color: var(--fg-dim);
  font: inherit;
  font-size: 1.4em;
  line-height: 1;
  cursor: pointer;
  padding: 0 4px;
}
data-table button.follow[aria-pressed="true"] {
  color: var(--tab-active);
}
data-table button.follow:hover {
  color: var(--fg);
}

/* Replay views (Lots, Positions) — strategy switcher and shared lot rows.
   The two tabs serve the same LotDTO through the same lot-row.js, so the row
   rules are written once for both rather than duplicated per element. */
:is(lots-view, portfolio-view, trade-form, trades-view) button.strategy {
  background: transparent;
  color: var(--fg-dim);
  border: 1px solid var(--fg-dim);
  padding: 2px 8px;
  font: inherit;
  cursor: pointer;
}
:is(lots-view, portfolio-view, trade-form, trades-view)
  button.strategy[aria-selected="true"] {
  color: var(--tab-active);
  border-color: var(--tab-active);
}
:is(lots-view, portfolio-view, trade-form, trades-view) button.strategy:hover {
  color: var(--fg);
}
:is(lots-view, portfolio-view) .lot {
  border: 1px solid var(--border);
  margin-bottom: 4px;
  background: var(--bg-alt);
}
:is(lots-view, portfolio-view) details.lot summary,
:is(lots-view, portfolio-view) .lot-flat {
  display: flex;
  gap: 16px;
  align-items: baseline;
  flex-wrap: wrap;
  padding: 4px 8px;
  background: var(--header-bg);
}
:is(lots-view, portfolio-view) details.lot summary {
  cursor: pointer;
  user-select: none;
}
/* non-openable bar: align with summaries that carry a disclosure marker */
:is(lots-view, portfolio-view) .lot-flat {
  padding-left: 28px;
}
:is(lots-view, portfolio-view) details.lot summary::marker {
  color: var(--tab-active);
}
:is(lots-view, portfolio-view) details.lot summary:hover {
  background: var(--hover);
}
:is(lots-view, portfolio-view) .lot-date {
  color: var(--fg-dim);
}
:is(lots-view, portfolio-view) .lot-qty,
:is(lots-view, portfolio-view) .lot-pru {
  font-variant-numeric: tabular-nums;
}
:is(lots-view, portfolio-view) .lot-body {
  padding: 4px 8px 8px 24px;
}

/* Positions view — a portfolio line, expandable into its lots */
portfolio-view .position {
  border: 1px solid var(--border);
  margin-bottom: 6px;
  background: var(--bg-alt);
}
portfolio-view details.position > summary {
  display: flex;
  gap: 16px;
  align-items: baseline;
  flex-wrap: wrap;
  padding: 6px 8px;
  background: var(--header-bg);
  cursor: pointer;
  user-select: none;
}
portfolio-view details.position > summary::marker {
  color: var(--tab-active);
}
portfolio-view details.position > summary:hover {
  background: var(--hover);
}
portfolio-view .pos-code {
  color: var(--fg);
}
portfolio-view .pos-qty,
portfolio-view .pos-pru,
portfolio-view .pos-basis,
portfolio-view .pos-pnl,
portfolio-view .pos-price,
portfolio-view .pos-value,
portfolio-view .pos-latent,
portfolio-view .pos-weight {
  font-variant-numeric: tabular-nums;
}
/* The market half of a line, set apart from the book half: everything after
   this rule moves with a quote. */
portfolio-view .pos-market {
  padding-left: 12px;
  border-left: 1px dotted var(--fg-dim);
}
/* the lots are the audit trail, one indent below the line they belong to */
portfolio-view .position-body {
  padding: 6px 8px 8px 24px;
}
/* Open / closed separator — a labelled rule between the two groups */
portfolio-view .position-group {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 14px 0 6px;
  padding-bottom: 2px;
  border-bottom: 1px solid var(--border);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
portfolio-view .position-group:first-child {
  margin-top: 0;
}
portfolio-view .position-group-label {
  color: var(--tab-active);
}

/* Strategy box — the switcher, what the selected strategy does (in French,
   since it describes a French fiscal method) and the figures it produced.
   Framed together because the figures are a function of the strategy above
   them; scoped to every view that serves a strategy-dependent figure — the two
   replay tabs and the cession preview in the entry form — so the box looks the
   same wherever the same question is asked. */
:is(lots-view, portfolio-view, trade-form, trades-view) .strategy-box {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-width: 760px;
  margin-bottom: 12px;
  padding: 6px 8px;
  border: 1px solid var(--fg-dim);
  background: var(--bg-alt);
}
:is(lots-view, portfolio-view, trade-form, trades-view) .strategy-switcher {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
}
:is(lots-view, portfolio-view, trade-form, trades-view) .strategy-label {
  color: var(--fg-dim);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-right: 4px;
}
/* One note at a time — the others stay in the DOM, hidden. */
:is(lots-view, portfolio-view, trade-form, trades-view) .strategy-note {
  margin: 0;
  color: var(--fg-dim);
  line-height: 1.45;
  max-width: 72ch;
}
:is(lots-view, portfolio-view, trade-form, trades-view) .strategy-note[hidden] {
  display: none;
}
:is(lots-view, portfolio-view) .stats {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 20px;
  padding-top: 6px;
  border-top: 1px dotted var(--border);
}
:is(lots-view, portfolio-view) .stats .k {
  color: var(--fg-dim);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-right: 4px;
}
:is(lots-view, portfolio-view) .stats .v {
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
/* A heading inside the figures: breaks the row (flex-basis: 100%) and names
   the layer the figures under it come from. The market ones move with a quote
   and the book ones do not, which is a distinction the box has to carry. */
:is(lots-view, portfolio-view) .stats .stat-group {
  flex-basis: 100%;
  margin-top: 4px;
  color: var(--tab-active);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
/* a figure whose label does not define it says so: dotted key, help cursor */
:is(lots-view, portfolio-view) .stats .stat[data-tip] .k {
  border-bottom: 1px dotted var(--fg-dim);
}
/* a signed figure keeps its sign colour: .gain/.loss alone lose to the rule
   above, which is the more specific one */
:is(lots-view, portfolio-view) .stats .v.gain {
  color: var(--gain);
}
:is(lots-view, portfolio-view) .stats .v.loss {
  color: var(--loss);
}
/* idem pour les deux extrémités de la bande de régression : `Cours/σ`, dans le
   détail d'une ligne, est le nombre que la réglette dessine */
:is(lots-view, portfolio-view) .stats .v.cheap {
  color: var(--cheap);
}
:is(lots-view, portfolio-view) .stats .v.rich {
  color: var(--rich);
}

/* The figures panel inside an unfolded line: the sell targets and the
   analysis, above the lots. Same grid as the strategy box — a figure reads the
   same at either scale — set apart from the lots below it by a rule, since it
   is a decision about the line and they are its history. */
portfolio-view .position-detail {
  margin-bottom: 10px;
  padding: 0 0 8px;
  border-top: 0;
  border-bottom: 1px dotted var(--border);
  max-width: 900px;
}
portfolio-view .position-detail .stat-group:first-child {
  margin-top: 0;
}

/* Tables */
data-table {
  display: block;
  width: 100%;
  overflow: auto;
}
data-table table {
  border-collapse: collapse;
  width: 100%;
  table-layout: auto;
}
/* A grouped column: no single value to order by, so the header does not
   pretend to offer one. */
data-table th.unsortable {
  cursor: default;
  color: var(--fg-dim);
}
data-table th {
  background: var(--header-bg);
  color: var(--fg);
  text-transform: uppercase;
  text-align: left;
  padding: 3px 8px;
  border-bottom: 1px solid var(--fg-dim);
  position: sticky;
  top: 0;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
data-table th.num {
  text-align: right;
}
data-table th[aria-sort="ascending"]::after {
  content: " ▲";
  color: var(--tab-active);
}
data-table th[aria-sort="descending"]::after {
  content: " ▼";
  color: var(--tab-active);
}
data-table td {
  padding: 2px 8px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
data-table td.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
data-table tr:nth-child(even) td {
  background: var(--bg-alt);
}
data-table tr:hover td {
  background: var(--hover);
}

/* Registre 3 — les verdicts, en deux intensités.
   `.gain` / `.loss` disent le **signe** d'un résultat : sourds, parce qu'une
   colonne entière en est faite. `.ok` / `.ko` disent un **événement** —
   enregistré, bloqué : vifs, parce qu'ils sont brefs et doivent arrêter la
   main. Les quatre ont désormais leur propre couleur ; c'est le nom partagé
   qui avait laissé `open` devenir vert. */
.gain {
  color: var(--gain);
}
.loss {
  color: var(--loss);
}
.ok {
  color: var(--ok);
}
.ko {
  color: var(--ko);
}

.dim {
  color: var(--fg-dim);
}
.warn {
  color: var(--warn);
}
.accent {
  color: var(--accent);
}

/* Registre 2 — les états. Un cours face à sa bande de régression : froid sous
   le prix d'achat, chaud au-dessus du prix de vente. Le seuil est ±1σ et il
   s'écrit dans `sigma-gauge.js` (`zoneOf`), qui est ce que la réglette, la
   colonne P/σ et le détail d'une ligne lisent tous les trois. Entre les deux
   il n'y a rien à décider, donc pas de classe : `fair` ne peint pas. */
.cheap {
  color: var(--cheap);
}
.rich {
  color: var(--rich);
}

/* Ouvert / clos — un état, pas un résultat. Ce qui court encore est éclairé,
   ce qui est soldé recule : le contraste fait ici tout le travail que le vert
   faisait à tort. */
.state-open {
  color: var(--accent);
}
.state-closed {
  color: var(--fg-dim);
}

/* Operation type tags — distinct from gain/loss so the Type column
   doesn't conflate cash-flow direction with P&L. */
.op-buy {
  color: var(--blue-lighter);
}
.op-sell {
  color: var(--purple-lighter);
}
.op-div {
  color: var(--yellow-lighter);
}
.op-deposit {
  color: var(--accent);
}
.op-withdrawal {
  color: var(--fg-dim);
}

/* Views */
market-view,
portfolio-view,
trades-view {
  display: block;
  padding: 0;
}
market-view[hidden],
portfolio-view[hidden],
trades-view[hidden],
first-steps[hidden] {
  display: none;
}
first-steps {
  display: block;
}

.section {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
}
.section h2 {
  margin: 0 0 6px 0;
  font-size: 11px;
  font-weight: bold;
  color: var(--fg-dim);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.summary-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 6px 20px;
}
.summary-grid .kv {
  display: flex;
  justify-content: space-between;
  border-bottom: 1px dotted var(--border);
  padding: 2px 0;
}
.summary-grid .kv .k {
  color: var(--fg-dim);
  text-transform: uppercase;
  font-size: 11px;
}
.summary-grid .kv .v {
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

.empty,
.error {
  padding: 20px;
  color: var(--fg-dim);
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

/* Une liste qui s'affiche amputée le dit en jaune : c'est un événement — une
   réponse manquante — et non l'état normal d'un écran vide. Sans cette règle,
   `.empty` gagnerait sur `.warn`, qui est déclarée plus haut. */
.empty.warn {
  color: var(--warn);
}
.error {
  color: var(--ko);
}

/* Operation entry form */
.op-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 8px 14px;
}
.op-form label {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 11px;
  color: var(--fg-dim);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.op-form input,
.op-form select {
  background: var(--bg-alt);
  border: 1px solid var(--border);
  color: var(--fg);
  font-family: inherit;
  font-size: 12px;
  padding: 3px 6px;
  min-width: 90px;
}
.op-form input:focus,
.op-form select:focus {
  outline: none;
  border-color: var(--focus);
}
.op-form label[hidden] {
  display: none;
}
/* A field that blocks the entry. Marked only once the reader has touched it —
   an untouched field is not wrong, it is unreached, and a form that opens all
   red has told them nothing. The disabled button is what says "not yet". */
.op-form label.invalid {
  color: var(--ko);
}
.op-form label.invalid input {
  border-color: var(--ko);
}
/* What is blocking, in one line under the button. Dim: it is an instruction,
   not an error — the reader has not done anything wrong by not being finished. */
.op-form-hint {
  flex-basis: 100%;
  font-size: 11px;
  color: var(--fg-dim);
}
.op-form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 12px;
  flex-basis: 100%;
}
.op-form button {
  background: var(--header-bg);
  border: 1px solid var(--fg-dim);
  color: var(--fg);
  font-family: inherit;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding: 4px 12px;
  cursor: pointer;
}
.op-form button:hover:not(:disabled) {
  background: var(--fg-dim);
  color: var(--bg);
}
.op-form button:disabled {
  opacity: 0.5;
  cursor: default;
}
.op-form-feedback {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
/* Enregistré, bloqué, ou rien encore. `.ok` / `.ko` plutôt que `.gain` /
   `.loss` : ce n'est pas le signe d'un montant, c'est le sort de la saisie. */
.op-form-feedback.ok {
  color: var(--ok);
}
.op-form-feedback.ko {
  color: var(--ko);
}
.op-form-feedback.dim {
  color: var(--fg-dim);
}

/* Cession impact preview — a movement, so most figures come in pairs. */
.op-impact {
  flex-basis: 100%;
  margin-top: 4px;
  padding-top: 6px;
  border-top: 1px dotted var(--border);
  font-size: 11px;
}
.op-impact-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 20px;
  margin: 4px 0;
}
.op-impact-grid .k {
  color: var(--fg-dim);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-right: 4px;
}
.op-impact-warn {
  margin-top: 4px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.op-impact .dim {
  color: var(--fg-dim);
}
/* The result of the cession, set apart from the two states it sits between. */
.op-impact-result {
  border-top: 1px dotted var(--border);
  padding-top: 4px;
}
.op-impact-none {
  margin: 4px 0;
}
/* The drawdown, oldest lot first. Wide on a phone, so it scrolls in its own
   box rather than widening the form. */
.op-lots {
  display: block;
  overflow-x: auto;
  width: 100%;
  border-collapse: collapse;
  margin: 4px 0;
  white-space: nowrap;
}
.op-lots th,
.op-lots td {
  padding: 2px 10px 2px 0;
  text-align: left;
}
.op-lots th {
  color: var(--fg-dim);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: normal;
}
.op-lots .num {
  text-align: right;
}
/* A lot the cession touches. The untouched ones stay legible but recede —
   they are what is left, not what is moving. */
.op-lots tbody tr:not(.op-lot-taken) {
  color: var(--fg-dim);
}
/* Same box, denser: the form is already a wall of fields, and here it carries
   no figures — the movement below is the figures. */
trade-form .strategy-box {
  border: none;
  padding: 0;
  margin: 0 0 2px;
  background: none;
  gap: 3px;
}
trade-form .strategy-note {
  font-size: 10px;
}
/* Neither the entry form nor the Trades table fills the figures slot: the
   movement below one and the Result column of the other are the figures. */
:is(trade-form, trades-view) .strategy-stats:empty {
  display: none;
}

/* Tip — our own tooltip, since the native one only answers a hover and half
   the readers of this app are on a phone. Anything carrying `data-tip` opens
   it: `tip.js` moves this single box around rather than rendering one per
   figure, because the texts are paragraphs and the screens are full of them. */
[data-tip] {
  cursor: help;
}
#tip {
  position: fixed;
  z-index: 50;
  max-width: min(46ch, calc(100vw - 16px));
  padding: 6px 8px;
  border: 1px solid var(--fg-dim);
  background: var(--bg-alt);
  color: var(--fg);
  line-height: 1.5;
  /* the ring keeps the border legible over a header of the same warm black */
  box-shadow: 0 0 0 1px var(--bg);
  /* anchored, it must never eat the hover that opened it */
  pointer-events: none;
}
#tip[hidden] {
  display: none;
}
/* On a narrow screen the box is docked to the bottom edge instead of being
   floated over the figure — a 46ch box is the whole width there, and the
   finger that opened it is exactly where it must not be. Detached from its
   label, it names the figure it explains. */
#tip.tip-docked {
  right: 0;
  bottom: 0;
  left: 0;
  top: auto;
  max-width: none;
  max-height: 50vh;
  overflow-y: auto;
  padding: 10px 12px 12px;
  border-width: 1px 0 0;
  /* docked, it is long enough to be scrolled */
  pointer-events: auto;
}
#tip .tip-label {
  display: block;
  margin-bottom: 4px;
  color: var(--tab-active);
  font-weight: normal;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
#tip.tip-docked::after {
  content: "Toucher pour fermer";
  display: block;
  margin-top: 8px;
  color: var(--fg-dim);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* Réglette σ — la position d'un cours dans sa bande de régression.
   Le domaine est figé à ±3σ pour toutes les instances : c'est ce qui rend deux
   lignes de la table comparables, et c'est pour cela que la largeur est fixe
   plutôt que fluide. Tout est positionné en absolu par-dessus le rail, d'où le
   `font-size: 0` sur l'hôte — sans lui, les blancs du gabarit ouvriraient une
   ligne de texte sous le dessin. */
sigma-gauge {
  position: relative;
  display: inline-block;
  width: 280px;
  height: 32px;
  vertical-align: middle;
  font-size: 0;
}
sigma-gauge .gauge-track {
  position: absolute;
  inset: 0;
}
/* Les deux extrémités. Ni vert ni rouge — ce ne sont pas des verdicts. La même
   réglette se lit dans les deux sens selon qu'on détient ou non le titre : bon
   marché est une occasion d'entrer *et* une moins-value latente, cher est le
   contraire des deux. Le froid et le chaud disent où l'on est sans dire si
   c'est bien.

   Leur `left` et leur `width` sont écrits en ligne par `sigma-gauge.js`, parce
   qu'ils dépendent de la ligne : sur une ligne suivie les zones se ferment sur
   les prix d'achat et de vente (∓1σ, un tiers de rail chacune), sur une ligne
   détenue sur le prix de revient et son majoré de 10 %. Une feuille de style
   ne peut pas connaître ces bornes-là. */
sigma-gauge .gauge-zone {
  position: absolute;
  top: 11px;
  bottom: 11px;
}
/* Deux registres, parce que la réglette a deux lectures. Une ligne suivie se
   lit en température — ni bien ni mal. Une ligne détenue se lit contre son prix
   de revient, et là il y a vraiment perte et gain : c'est `sigma-gauge.js` qui
   choisit la paire, la feuille de style ne fait que les tenir toutes les
   deux. */
sigma-gauge .gauge-zone.cheap {
  background: var(--cheap-zone);
}
sigma-gauge .gauge-zone.rich {
  background: var(--rich-zone);
}
sigma-gauge .gauge-zone.loss {
  background: var(--loss-zone);
}
sigma-gauge .gauge-zone.gain {
  background: var(--gain-zone);
}
sigma-gauge .gauge-rail {
  position: absolute;
  top: 50%;
  right: 0;
  left: 0;
  height: 1px;
  background: var(--border);
}
/* Trois hauteurs pour trois rôles : le centre est la valeur estimée, les ±1σ
   sont les prix d'achat et de vente — les seuils sur lesquels on décide — et les
   ±2σ ne sont qu'une échelle. */
sigma-gauge .gauge-tick {
  position: absolute;
  width: 1px;
  transform: translateX(-50%);
}
sigma-gauge .gauge-tick.est {
  top: 5px;
  height: 22px;
  background: var(--tab-active);
}
sigma-gauge .gauge-tick.band {
  top: 7px;
  height: 18px;
  background: var(--fg);
}
sigma-gauge .gauge-tick.outer {
  top: 11px;
  height: 10px;
  background: var(--fg-dim);
}
/* Les repères de coût d'une ligne détenue, sous le rail, du même côté que le
   `▲` du PRU qu'ils prolongent. Deux hauteurs pour deux rôles, comme les
   graduations σ au-dessus du rail distinguent les ±1σ des ±2σ : `+10 %` ferme
   la zone chaude, `+5 %` n'est qu'un jalon entre le prix de revient et lui. */
sigma-gauge .gauge-cost {
  position: absolute;
  width: 1px;
  transform: translateX(-50%);
}
sigma-gauge .gauge-cost.step {
  top: 18px;
  height: 6px;
  background: var(--fg-dim);
}
sigma-gauge .gauge-cost.target {
  top: 17px;
  height: 11px;
  background: var(--fg);
}
/* Le cours au-dessus du rail, le PRU en dessous : ils se croisent au moment
   précis où on les regarde, et deux marqueurs superposés ne diraient plus rien. */
sigma-gauge .gauge-price,
sigma-gauge .gauge-pru {
  position: absolute;
  transform: translateX(-50%);
  font-size: 13px;
  line-height: 13px;
}
sigma-gauge .gauge-price {
  top: 0;
}
sigma-gauge .gauge-pru {
  bottom: 0;
  font-size: 12px;
  line-height: 12px;
  color: var(--tab-active);
}
sigma-gauge .gauge-price.cheap {
  color: var(--cheap);
}
/* Entre les deux bornes : le neutre franc, sans température — il n'y a rien à
   décider, et l'or du texte courant le ferait quand même un peu briller. */
sigma-gauge .gauge-price.fair {
  color: var(--neutral);
}
sigma-gauge .gauge-price.rich {
  color: var(--rich);
}
sigma-gauge .gauge-price.loss {
  color: var(--loss);
}
sigma-gauge .gauge-price.gain {
  color: var(--gain);
}
/* Écart-type nul : l'historique était trop court pour une régression, il n'y a
   pas d'échelle. Un tiret, pas une réglette qui dessinerait une position que
   personne n'a calculée. */
sigma-gauge .gauge-void {
  font-size: 14px;
  line-height: 32px;
  color: var(--fg-dim);
}
/* La cellule de la colonne Position — la réglette, et à sa droite les montants
   qu'elle dessine. Le dessin dit *où*, il ne dit pas *combien*, et les montants
   étaient jusqu'ici derrière un `data-tip`, c'est-à-dire à un geste par ligne :
   on ne compare pas dix lignes en dix gestes (SPEC 12).

   Aucun air pris par la cellule : les cases le prennent elles-mêmes, et c'est
   ce qui permet à celle du cours de le peindre. */
data-table .position-cell {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 0;
}
/* La frise reste un dessin à part, à gauche, et les valeurs se rangent derrière
   elle en **grille** : des cases toutes de la même largeur, celle du plus long
   texte de la table, posée par la vue en `--fig-col`. Une même case tombe alors
   au même endroit d'une ligne à l'autre, et la table se lit en colonnes sans en
   avoir — sept repères, sept pas d'égale longueur (SPEC 14). C'est la forme des
   trois tables de la page Marché depuis la 16, et la seule : il n'y a plus de
   classe `grid` pour la distinguer d'une autre.

   Les cases s'étirent toutes à la hauteur de la plus haute pour que le filet
   qui les sépare soit le même partout. Leur contenu, lui, reste rangé par le
   haut : ce qui suit entre parenthèses descend sur une troisième ligne, et
   cette ligne-là n'existe pas dans toutes les cases. Alignées par le bas, les
   noms et les montants auraient sauté d'une case à l'autre. */
data-table .position-figures {
  display: flex;
  align-items: stretch;
  gap: 0;
  font-size: 11px;
  line-height: 14px;
}
/* L'air est pris **dans** la case, de part et d'autre de son texte, et non
   entre deux cases : le filet tombe alors sur la limite exacte de la case, et
   deux cases voisines se partagent le même écart. C'est ce qui fait une grille
   et non une liste espacée.

   En haut et en bas pour la même raison, et pour une de plus : cet air-là
   était celui de la cellule (`padding` d'un `td`), donc au-dehors des cases.
   La case du cours s'arrêtait deux pixels avant le bord de la ligne, et son
   fond avec elle — une pastille posée dans la ligne, exactement ce qu'il ne
   fallait pas. Pris ici, il appartient à la case et se peint avec elle.

   Quatre pixels et non les deux que la cellule prenait : une case pleine a
   besoin de respirer autour de son texte, ce dont un `td` transparent n'avait
   pas besoin. C'est le seul endroit de la table où la hauteur se règle. */
data-table .position-figures .figure {
  display: flex;
  align-items: stretch;
  padding: 4px 8px;
}
/* Un seul séparateur, le même entre toutes les cases : le filet pointillé des
   lignes de la table, assez pour séparer deux nombres, pas assez pour se voir.
   Chaque case portait autrefois la graduation qu'elle nommait, et c'est elle
   qui la séparait de la précédente — trait haut pour la valeur estimée, trait
   bas pour un palier, or pour le prix de revient. Cela faisait sept
   séparateurs différents entre sept cases identiques, et le trait se lisait
   avant le nom. Les graduations sont restées là où elles sont justes au pixel
   près : sur la frise. */
data-table .position-figures .figure + .figure {
  border-left: 1px dotted var(--border);
}
data-table .position-figures .figure-body {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0;
}
/* La largeur d'une case de l'échelle : celle du plus long texte de la table, la
   même pour toutes. L'air autour d'elle est celui de la case, pas du texte — il
   est pris dans le `padding` ci-dessus, donc il appartient à la case et se
   peint avec elle. */
data-table .position-figures .figure:not(.fact) .figure-body {
  box-sizing: border-box;
  width: var(--fig-col, 11ch);
}
/* Le dividende et la période ne sont pas de l'échelle : ils gardent la largeur
   de leur plus longue valeur dans la table, mesurée par la vue — le seul
   endroit qui voit toutes les lignes à la fois. Une ligne à deux détachements
   ne déborde donc pas sur sa voisine et ne décale rien ; la table défile vers
   la droite, et c'est ce qui permet de ne rien serrer. */
data-table .position-figures .figure.apart .figure-body {
  min-width: var(--div-col, 25ch);
}
data-table .position-figures > .figure:last-child .figure-body {
  min-width: var(--period-col, 9ch);
}
/* Plus de filet entre les lignes : la grille en a déjà sept verticaux, et un
   quadrillage complet ferait un tableur. Ce qui sépare deux lignes est ce qui
   les séparait déjà ailleurs dans l'application — une rangée sur deux, un fond
   plus clair. Et plus d'air au-dessus ni en dessous : il est repris par les
   cases, qui le peignent. */
data-table tr:has(.position-figures) td {
  border-bottom: none;
  padding-top: 0;
  padding-bottom: 0;
}
/* Trois lignes tiennent dans la hauteur qu'en occupaient deux : un cran de
   moins sur le nom, un autre sur la parenthèse, et plus d'interligne entre les
   trois — c'est un bloc, pas une liste. La hauteur de ligne reste celle des
   trois étages de la colonne Valeur, comme elle était celle de la frise. */
data-table .position-figures .figure-label {
  color: var(--fg-dim);
  line-height: 11px;
}
data-table .position-figures .figure-value {
  font-variant-numeric: tabular-nums;
}
/* La troisième ligne — l'écart réduit sous le cours. Plus petite et grise :
   c'est le même fait que la ligne du dessus, dit dans une autre unité, et il ne
   doit pas se lire avant lui. */
data-table .position-figures .figure-note {
  font-size: 10px;
  line-height: 10px;
  color: var(--fg-dim);
  font-variant-numeric: tabular-nums;
}
/* La case du cours : **remplie** de la zone où le cours tombe — celle de la
   bande qu'il occupe sur la frise, à gauche, et la même teinte exactement.
   C'est la seule case qui bouge d'un jour à l'autre, et dans une grille
   régulière il faut pouvoir la trouver sans la lire. Un fond se voit plus loin
   qu'un cadre et n'ajoute aucun trait à une table qui en a déjà sept.

   Le fond prend la case entière, d'un filet à l'autre et sur toute la hauteur :
   une case pleine dans une grille de cases vides, et non une pastille posée
   dans l'une d'elles.

   Sans zone — entre les deux bornes, ou sans échelle du tout — un gris franc :
   il n'y a rien à décider, mais il y a toujours une case à trouver.

   Les autres cases ne sont ni bonnes ni mauvaises : ce sont des repères, et un
   repère ne se peint pas. */
data-table .position-figures .figure.filled {
  background: color-mix(in srgb, var(--neutral) 14%, transparent);
}
data-table .position-figures .figure.filled.zone-cheap {
  background: var(--cheap-zone);
}
data-table .position-figures .figure.filled.zone-rich {
  background: var(--rich-zone);
}
data-table .position-figures .figure.filled.zone-loss {
  background: var(--loss-zone);
}
data-table .position-figures .figure.filled.zone-gain {
  background: var(--gain-zone);
}
/* La case du dividende est un **texte**, pas un champ : pas de nom au-dessus
   d'elle, mais trois lignes qui s'énoncent —

       1,13 € div. annuels
       6,01 % du cours
       ~26/05

   un fait par ligne, dans l'ordre où on les demande : combien, quelle part du
   cours, et quand.

   Deux typographies, et deux seulement. Les nombres gardent celle des autres
   valeurs du bloc, le taux compris : c'est un chiffre qu'on compare d'une
   ligne à l'autre de la table, et le rapetisser le ferait lire après le
   montant alors qu'on le cherche autant. Ce qui les glose descend d'un cran et
   prend le gris des noms — `div. annuels` et `du cours` disent ce qu'on lit,
   ils ne sont pas ce qu'on lit. C'est le partage que cette feuille connaît
   déjà entre une valeur et un nom ; ici il tombe au milieu d'une ligne au lieu
   d'entre deux.

   Trois lignes à 12 px font les 36 px de la cellule Position, exactement comme
   le bloc code / nom / valeur de la colonne Valeur : la hauteur de ligne ne
   bouge pas. */
data-table .position-figures .dividend {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  line-height: 12px;
}
data-table .position-figures .dividend-gloss {
  font-size: 10px;
  color: var(--fg-dim);
}
/* Une case sans nom ne peut pas s'aligner sur une rangée de noms qu'elle
   n'occupe pas : son contenu se centre dans la hauteur de la case, la case
   elle-même restant pleine hauteur pour que le filet qui l'ouvre le soit
   aussi. */
data-table .position-figures .figure.labelless .figure-body {
  justify-content: center;
}

/* La cellule de la colonne Valeur : le code, son nom, et — dans la seule table
   des détenues — ce que la ligne pèse. Une seule case pour ce qui répond à une
   seule question : *de quelle ligne parle-t-on*, et combien j'en ai.

   Trois lignes à 12 px font exactement les 36 px de la cellule Position, donc
   la hauteur de ligne ne bouge pas : c'est toujours la réglette qui la donne. */
data-table .instrument {
  display: flex;
  flex-direction: column;
  line-height: 12px;
}
data-table .instrument-name {
  font-size: 11px;
  color: var(--fg-dim);
}
data-table .instrument-value {
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

/* Les légendes — la même réglette, en plus grand, ses traits nommés. Elles ne
   représentent aucun titre : leurs marqueurs y sont posés à des écarts
   d'illustration, pour dire la convention (le cours au-dessus du rail, les
   repères de coût en dessous) et non une position. Tout est positionné en
   pourcentage comme dans une cellule, donc la légende et les lignes qu'elle
   explique partagent exactement la même géométrie.

   Elles sont deux — ligne suivie, ligne détenue — parce que les zones se
   ferment sur deux repères différents et qu'une seule légende ne pourrait pas
   montrer les deux sans en inventer une troisième. Chacune porte son titre,
   c'est lui qui dit à quelle lecture appartiennent les zones dessinées juste
   en dessous. */
sigma-gauge[legend] {
  display: block;
  width: min(440px, 100%);
  height: 94px;
  margin-bottom: 10px;
}
sigma-gauge[legend] .gauge-rail {
  top: 42px;
}
sigma-gauge[legend] .gauge-zone {
  top: 36px;
  bottom: 46px;
}
sigma-gauge[legend] .gauge-tick.est {
  top: 34px;
  height: 16px;
}
sigma-gauge[legend] .gauge-tick.band {
  top: 36px;
  height: 12px;
}
sigma-gauge[legend] .gauge-tick.outer {
  top: 38px;
  height: 8px;
}
sigma-gauge[legend] .gauge-cost.step {
  top: 48px;
  height: 6px;
}
sigma-gauge[legend] .gauge-cost.target {
  top: 48px;
  height: 10px;
}
sigma-gauge[legend] .gauge-price {
  top: 20px;
  font-size: 10px;
  line-height: 10px;
}
sigma-gauge[legend] .gauge-pru {
  top: 52px;
  bottom: auto;
  font-size: 10px;
  line-height: 10px;
}
/* Le nom du marqueur se pose à sa droite plutôt qu'en dessous : centré, il
   tomberait sur la ligne des noms de graduations. */
sigma-gauge[legend] .gauge-mark-label {
  position: absolute;
  transform: translateX(7px);
  font-size: 10px;
  line-height: 10px;
  color: var(--fg-dim);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  white-space: nowrap;
}
sigma-gauge[legend] .gauge-mark-label.price {
  top: 20px;
}
/* La légende détenue nomme deux rangs de graduations, et son marqueur de cours
   remonte pour leur faire place : les σ au-dessus du rail, les repères de coût
   dessous, chacun du côté où il est dessiné. */
sigma-gauge[legend][held] .gauge-price,
sigma-gauge[legend][held] .gauge-mark-label.price {
  top: 6px;
}
/* Les cotes σ : l'échelle, pas le sujet. Grises, elles passent derrière les
   trois repères de coût, qui sont ce que cette légende-là explique. */
sigma-gauge[legend] .gauge-tick-label.sigma {
  top: 22px;
  color: var(--fg-dim);
}
/* Une ligne de noms sous le rail : les graduations σ pour la légende suivie,
   les repères de coût pour la légende détenue. */
sigma-gauge[legend] .gauge-tick-label {
  position: absolute;
  top: 68px;
  transform: translateX(-50%);
  font-size: 10px;
  line-height: 10px;
  color: var(--fg);
  white-space: nowrap;
}
/* Les deux extrémités, nommées au centre de leur zone — c'est la seule chose
   que les couleurs seules ne disent pas. Le centre est écrit en ligne par
   `sigma-gauge.js`, comme la zone elle-même : un nom ne peut pas se détacher de
   la bande qu'il nomme. */
sigma-gauge[legend] .gauge-zone-label {
  position: absolute;
  top: 82px;
  transform: translateX(-50%);
  font-size: 10px;
  line-height: 10px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  white-space: nowrap;
}
sigma-gauge[legend] .gauge-zone-label.cheap {
  color: var(--cheap);
}
sigma-gauge[legend] .gauge-zone-label.rich {
  color: var(--rich);
}
sigma-gauge[legend] .gauge-zone-label.loss {
  color: var(--loss);
}
sigma-gauge[legend] .gauge-zone-label.gain {
  color: var(--gain);
}

/* Sur téléphone la table défile déjà horizontalement ; la réglette y perd de la
   largeur plutôt que de la lui prendre. La légende, elle, n'est pas dans la
   table : elles suivent la largeur de l'écran. */
@media (max-width: 640px) {
  sigma-gauge:not([legend]) {
    width: 210px;
  }
}
