/* ============================================================================
   HAULITH — la couche COMPOSANTS, transcrite de `haulith-app.html`.

   POURQUOI UNE FEUILLE GLOBALE ET PAS QUINZE BLOCS `<style>`. La maquette est
   du CSS natif à classes, et le brief impose « mêmes noms de classes ». Un
   `.btn` recopié dans quinze composants Svelte, ce sont quinze occasions de
   diverger — c'est exactement le mode de panne que le système de jetons
   existe pour fermer. Les composants portent la CLASSE ; le style vit ici.

   Ce qui reste dans un bloc `<style>` de composant : ce qui n'appartient qu'à
   lui — la grille d'un écran, la position d'un élément unique. Rien de ce qui
   se répète.

   AUCUNE VALEUR BRUTE. Les trente couleurs littérales de la maquette (seize
   hex, quatorze rgba) sont devenues des jetons ; ses cinq z-index en dur
   sont devenus l'échelle d'empilement. Ce fichier ne contient que des
   longueurs et des jetons.
   ========================================================================= */

/* ============================================================ ossature === */
.app {
  display: grid;
  grid-template-columns: var(--rail) 1fr;
  height: 100vh;
}

.rail {
  background: var(--surface-sunken);
  border-right: 1px solid var(--border-subtle);
  display: flex;
  flex-direction: column;
  padding: var(--s3) var(--s2);
  gap: 2px;
  overflow: hidden;
}
.brand {
  display: flex;
  align-items: center;
  gap: var(--s2);
  padding: var(--s2) var(--s3) var(--s5);
  font-weight: var(--gras-fort);
  letter-spacing: -0.01em;
}
/* LA PUCE DE MARQUE EST LE LOGO, plus un disque qui lui ressemble. D-006
   décidait déjà que le bloc de marque « réutilise `logo-icon.png` (déjà servi)
   + le mot en texte » ; le CSS, lui, dessinait un dégradé radial. Le fichier
   est le même que la favicon et que l'écran de connexion — une seule image en
   cache pour les trois.

   UNE BALISE `img`, PAS UN `background`. La règle des jetons couvre
   `background` et descend dans ses sous-propriétés : elle refuse `url(…)`
   comme elle refuserait un hex, et elle a raison de ne pas savoir distinguer.
   L'écran de connexion sert déjà ce fichier en `img` — même geste ici, aucune
   barrière à desserrer.

   NI RAYON NI ANNEAU : le logo porte son propre cercle, et le `border-radius`
   d'avant lui rognerait ses quatre pointes. L'ambre du fichier (#ffca3d) et
   `--ambre-4` (#fac131) sont la même couleur à ΔE près — la marque reste dans
   la palette sans qu'on la reteinte. */
.brand .mark {
  width: 22px;
  height: 22px;
  flex: none;
}
.rail a {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: var(--s2) var(--s3);
  border-radius: var(--r2);
  color: var(--text-secondary);
  text-decoration: none;
  font-size: var(--t3);
  transition:
    background var(--dur-fast),
    color var(--dur-fast);
}
.rail a:hover {
  background: var(--surface-hover);
  color: var(--text-primary);
}
.rail a.on {
  background: var(--surface-raised);
  color: var(--text-primary);
  font-weight: var(--gras-titre);
}
/* LE REPÈRE DE L'ENTRÉE COURANTE EST UNE MARQUE, PLUS UN LISERÉ PLEINE
   HAUTEUR. C'était un `box-shadow: inset 2px 0 0` : il court d'un bord à
   l'autre du bouton et passe donc DERRIÈRE les deux coins arrondis, où il se
   fait rogner en biseau. À l'écran, un trait qui s'amincit en haut et en bas
   sans que rien ne l'explique. Une marque courte, centrée, arrondie du côté
   ouvert : elle ne rencontre aucun coin. */
.rail a.on::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 3px;
  height: 16px;
  margin-top: -8px;
  border-radius: 0 var(--r1) var(--r1) 0;
  background: var(--accent);
}
/* Les icônes sont des TRACÉS : elles prennent la couleur de la ligne, se
   décalent d'un cran vers le discret au repos, et reviennent à l'accent quand
   l'entrée est celle où l'on est. */
.rail a .ic,
.rail .lien .ic,
.rail .outil .ic {
  width: 17px;
  height: 17px;
  flex: none;
  color: var(--text-muted);
}
.rail a:hover .ic,
.rail .lien:hover .ic {
  color: var(--text-secondary);
}
.rail a.on .ic {
  color: var(--accent);
}
.rail .flowcap {
  font-size: var(--t0);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: var(--gras-titre);
  padding: var(--s4) var(--s3) 6px;
}
.rail .step {
  font-size: var(--t0);
  color: var(--text-muted);
  margin-left: auto;
}
.rail .spacer {
  flex: 1;
}
.rail .kbd {
  margin: var(--s2) var(--s3);
  font-size: var(--t0);
  color: var(--text-muted);
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
}
.rail .kbd b {
  border: 1px solid var(--border-default);
  border-radius: var(--r1);
  padding: 1px 5px;
  font-weight: 500;
  color: var(--text-secondary);
}

.main {
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow: hidden;
}

.topbar {
  height: var(--top);
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: 0 var(--s4);
  border-bottom: 1px solid var(--border-subtle);
  font-size: var(--t2);
  color: var(--text-secondary);
  background: var(--surface-base);
}
.topbar .pick {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px;
  border: 1px solid var(--border-control);
  border-radius: var(--r1);
  color: var(--text-primary);
  background: var(--surface);
  cursor: pointer;
  font-size: var(--t2);
}
.topbar .pick:hover {
  border-color: var(--border-control-hover);
}
.topbar .dv {
  width: 1px;
  height: 16px;
  background: var(--border-subtle);
}
.topbar b {
  color: var(--text-primary);
  font-weight: var(--gras-titre);
}
/* PLUS DE `margin-left: auto` ICI. Il poussait ce bloc à droite du temps où
   il fermait la barre ; il ouvre désormais celle-ci, contre le nom du pilote,
   et l'auto le repoussait donc vers le centre — avec tout ce qui le suit.
   Relevé à l'écran : la barre entière flottait au milieu. C'est le menu du
   compte, en fin de barre, qui porte l'auto maintenant. */
.topbar .live {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: var(--t1);
}
/* « RELEVER MAINTENANT » — discret au repos, lisible au survol. Il vit dans
   la barre de VOUS parce que ce qu'il relit est vous : position, soute,
   portefeuille. Le même glyphe que le relevé du marché, pour que le geste
   se reconnaisse d'un écran à l'autre. */
.topbar .relever {
  background: none;
  border: 1px solid var(--border-control);
  color: var(--text-secondary);
  border-radius: var(--r1);
  padding: 0 var(--s2);
  height: 22px;
  cursor: pointer;
  font-size: var(--t1);
  line-height: 1;
}
.topbar .relever:hover:not(:disabled) {
  color: var(--text-primary);
  border-color: var(--border-control-hover);
}
.topbar .relever:disabled {
  opacity: 0.5;
  cursor: default;
}

/* LA SEULE ANIMATION PERMANENTE TOLÉRÉE, parce qu'elle PORTE une
   information : elle s'arrête quand le flux tombe, et c'est ainsi qu'on
   l'apprend. `prefers-reduced-motion` la coupe — voir tokens.css. */
.topbar .live i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--status-good);
  animation: pouls 2.4s var(--ease) infinite;
}
@keyframes pouls {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.35;
  }
}

.scroll {
  flex: 1;
  overflow: auto;
  min-height: 0;
}
.wrap {
  max-width: 2560px;
  margin: 0 auto;
  padding: var(--s5) var(--s5) var(--s7);
}
.wrap.flush {
  padding: 0;
}

/* LA BARRE DE MISSION CÈDE SA LARGEUR AU VOLET DE DÉTAIL.
   Sous 1 280 px le volet du Marché quitte sa colonne et se pose EN FIXE à
   droite, sur toute la hauteur (voir Tiroir.svelte, même frontière). La barre
   du bas, elle, est collée en bas de `.scroll` et fait toute sa largeur : son
   coin droit passait donc sous le volet, avec le gain total et « Vider »
   dessous. Elle garde son fond d'un bord à l'autre — c'est une barre, pas une
   carte — et retire son CONTENU de la bande occupée.

   CE BLOC VIT ICI ET NON DANS `Dock.svelte` parce qu'il énonce une relation
   entre TROIS propriétaires : la coquille qui défile, l'écran qui ouvre son
   volet, et la barre. Un composant ne peut la dire qu'en perçant sa portée
   avec `:global`, ce que ce projet refuse. Les tiroirs de l'Industrie sont des
   modales centrées avec voile : ils n'amputent rien, et `.avec-tiroir` ne
   nomme que le volet du Marché. */
@media (width <= 1279px) {
  .scroll:has(.avec-tiroir) .dock {
    padding-right: var(--panneau-etroit);
  }
}

/* ============================================================ primitives = */
.h-screen {
  font-size: var(--t6);
}
.cap {
  font-size: var(--t0);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: var(--gras-fort);
}
.muted {
  color: var(--text-muted);
}
.sec2 {
  color: var(--text-secondary);
}
.tiny {
  font-size: var(--t0);
}
.sm {
  font-size: var(--t1);
}
/* La précision qui accompagne un chiffre ou un nom. Cinq composants la
   redéclaraient à l'identique et deux écrans la POSAIENT sans qu'aucune règle
   ne la définisse — la Carte et Mes ordres rendaient donc leurs précisions à
   la taille et à l'encre du corps de page. */
.b {
  color: var(--text-muted);
  font-size: var(--t1);
}

.card {
  background: var(--surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r3);
  padding: var(--s4);
}
.card.pad0 {
  padding: 0;
}
.card h3 {
  font-size: var(--t3);
  margin-bottom: var(--s3);
}

/* ============================================================== contrôles = */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  background: var(--surface);
  border: 1px solid var(--border-control);
  color: var(--text-secondary);
  padding: 7px 13px;
  border-radius: var(--r2);
  font-size: var(--t2);
  cursor: pointer;
  white-space: nowrap;
  transition:
    border-color var(--dur-fast),
    color var(--dur-fast),
    background var(--dur-fast);
}
.btn:hover {
  color: var(--text-primary);
  border-color: var(--border-control-hover);
  background: var(--surface-raised);
}
.btn.ghost {
  background: none;
  border-color: transparent;
  color: var(--text-muted);
}
.btn.ghost:hover {
  color: var(--text-primary);
  background: var(--surface-hover);
}
.btn.primary {
  background: var(--accent);
  border-color: transparent;
  color: var(--accent-contrast);
  font-weight: var(--gras-fort);
}
.btn.primary:hover {
  background: var(--accent-strong);
}
.btn.lg {
  padding: 11px 20px;
  font-size: var(--t4);
  border-radius: var(--r2);
}
.btn.sm {
  padding: 4px 10px;
  font-size: var(--t1);
}
.btn[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}
.btn.danger {
  border-color: var(--status-critical-border);
  color: var(--status-critical-soft);
}
.btn.danger:hover {
  background: var(--status-critical-bg);
  border-color: var(--status-critical);
}

.field {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--s2);
  background: var(--surface);
  border: 1px solid var(--border-control);
  border-radius: var(--r2);
  padding: 0 var(--s3);
  height: 34px;
  transition:
    border-color var(--dur-fast),
    background var(--dur-fast);
}
.field:hover {
  border-color: var(--border-control-hover);
}
.field:focus-within {
  border-color: var(--accent);
  background: var(--surface-raised);
}
.field input {
  background: none;
  border: none;
  outline: none;
  width: 100%;
  min-width: 0;
  font-size: var(--t3);
  padding: 0;
}
.field input::placeholder {
  color: var(--text-muted);
}
.field .unit,
.field .op {
  font-size: var(--t1);
  color: var(--text-muted);
  white-space: nowrap;
}
.field .op {
  font-size: var(--t3);
}
.lbl {
  display: block;
  font-size: var(--t0);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: var(--gras-fort);
  margin-bottom: 6px;
}

/* Onglets SOULIGNÉS. Le segmenté en pilule reste réservé aux options
   exclusives — deux formes, deux sens, et on ne les échange pas. */
.tabs {
  display: flex;
  gap: 2px;
  border-bottom: 1px solid var(--border-subtle);
  padding: 0 var(--s5);
}
.tabs button {
  background: none;
  border: none;
  padding: 11px 15px 12px;
  font-size: var(--t3);
  font-weight: var(--gras-titre);
  color: var(--text-muted);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  cursor: pointer;
  transition: color var(--dur-fast);
}
.tabs button:hover {
  color: var(--text-primary);
}
.tabs button.on {
  color: var(--accent-strong);
  border-bottom-color: var(--accent);
}
.tabs .n {
  font-weight: 400;
  font-size: var(--t1);
  color: var(--text-muted);
  margin-left: 6px;
}

.chk {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: var(--t2);
  color: var(--text-secondary);
  cursor: pointer;
  user-select: none;
}
.chk input {
  appearance: none;
  width: 15px;
  height: 15px;
  border-radius: var(--r1);
  flex: none;
  border: 1px solid var(--border-control-hover);
  background: var(--surface);
  cursor: pointer;
  display: grid;
  place-content: center;
  transition:
    background var(--dur-fast),
    border-color var(--dur-fast);
}
.chk input:checked {
  background: var(--accent);
  border-color: var(--accent);
}
.chk input:checked::after {
  content: "✓";
  font-size: 10px;
  color: var(--accent-contrast);
  font-weight: 900;
}
.chk:hover {
  color: var(--text-primary);
}
.chk.sw input {
  width: 32px;
  height: 18px;
  border-radius: var(--r-pill);
  position: relative;
}
.chk.sw input::after {
  content: "";
  position: absolute;
  left: 2px;
  top: 2px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--text-muted);
  transition:
    transform var(--dur) var(--ease),
    background var(--dur-fast);
}
.chk.sw input:checked::after {
  transform: translateX(14px);
  background: var(--accent-contrast);
}

/* ======================================== pastilles de statut / sécurité = */
.sec {
  display: inline-block;
  font-size: var(--t0);
  border-radius: var(--r-pill);
  padding: 0 6px;
  border: 1px solid var(--border-default);
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
.sec.hi {
  color: var(--status-good-soft);
  border-color: var(--status-good-border);
}
.sec.lo {
  color: var(--amber-soft);
  border-color: var(--status-warning-border);
}
.sec.null {
  color: var(--status-critical-soft);
  border-color: var(--status-critical-border);
}
.tagb {
  font-size: var(--t0);
  letter-spacing: 0.05em;
  color: var(--text-muted);
  border: 1px solid var(--border-default);
  border-radius: var(--r1);
  padding: 0 5px;
  white-space: nowrap;
}
.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--t1);
  border: 1px solid var(--border-default);
  border-radius: var(--r-pill);
  padding: 1px 9px;
  color: var(--text-secondary);
}
.pill.acc {
  border-color: var(--accent-border);
  background: var(--accent-bg);
  color: var(--accent-soft);
}
.pill.warn {
  border-color: var(--amber-border);
  background: var(--amber-bg);
  color: var(--amber-soft);
}
/* La hausse et la baisse d'un PRIX, qui ne sont pas un péril — d'où deux
   teintes à part du danger. La maquette les peignait avec `--status-good` et
   `--status-critical` ; c'est l'inverse de la règle du produit. */
.up {
  color: var(--hausse);
}
.down {
  color: var(--baisse);
}

/* ============================== ligne de vol (élément signature) ========= */
.rline {
  display: flex;
  align-items: center;
  gap: 0;
  min-width: 0;
}
.rline .node {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex: none;
  background: var(--status-good);
  box-shadow: 0 0 0 3px var(--surface-base);
}
.rline .node.lo {
  background: var(--status-warning);
}
.rline .node.null {
  background: var(--status-critical);
}
/* SÉCURITÉ NON RELEVÉE. La maquette n'a pas ce cas — ses données étaient
   choisies. Un système jamais relevé ne se peint ni en vert ni en rouge : il
   se peint en neutre, parce que « non relevé » se dit et ne se comble pas. */
.rline .node.inconnu {
  background: var(--border-control);
}
.rline .node.black {
  background: var(--status-critical);
  box-shadow:
    0 0 0 2px var(--surface-base),
    0 0 0 4px var(--status-critical);
}
.rline .seg {
  height: 2px;
  flex: 1;
  min-width: 10px;
  background: var(--status-good);
  opacity: 0.5;
}
.rline .seg.lo {
  background: var(--status-warning);
}
.rline .seg.null {
  background: var(--status-critical);
}
.rline .seg.inconnu {
  background: var(--border-control);
}
/* Un point CLIQUABLE reste le même point : le bouton n'apporte que la cible
   et le focus, jamais une apparence de plus. La cible dépasse le disque —
   9 px ne se clique pas — sans écarter les points les uns des autres. */
button.node {
  position: relative;
  border: 0;
  padding: 0;
  cursor: pointer;
  outline-offset: 3px;
}
/* LA CIBLE DÉPASSE LE DISQUE, sans l'écarter de ses voisins : 9 px ne se
   clique pas, et agrandir le point casserait la ligne. Le pseudo est
   invisible et ne prend aucune place dans le flux. */
button.node::after {
  content: "";
  position: absolute;
  inset: -5px;
}
.rline.mini .node {
  width: 6px;
  height: 6px;
}
.rline.mini .seg {
  height: 1.5px;
  min-width: 5px;
}

/* ============================== tables =================================== */
table {
  width: 100%;
  border-collapse: collapse;
}
thead th {
  position: sticky;
  top: 0;
  z-index: var(--z-fond);
  background: var(--surface-base);
  text-align: right;
  font-size: var(--t0);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: var(--gras-fort);
  padding: var(--s3);
  white-space: nowrap;
  border-bottom: 1px solid var(--border-default);
  cursor: pointer;
  user-select: none;
}
thead th.l {
  text-align: left;
}
thead th.plain {
  cursor: default;
}
thead th:hover:not(.plain) {
  color: var(--text-secondary);
}
thead th.sorted {
  color: var(--accent-strong);
}
/* L'INDICATEUR DE TRI EST UN BOUTON, et il vit ici parce que deux écrans le
   posent — le Marché et l'Industrie. L'Industrie écrivait ` ▴`/` ▾` dans le
   TEXTE d'un `<th>` cliquable : la flèche se lisait, mais la colonne ne se
   triait qu'à la souris et aucun lecteur d'écran n'annonçait l'ordre.
   `aria-sort` appartient à la cellule, le bouton à son contenu. */
.tri {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  text-transform: inherit;
  letter-spacing: inherit;
}
.tri:hover {
  color: var(--text-primary);
}
.tri.actif {
  color: var(--accent-strong);
}
.fleche-tri {
  margin-left: 4px;
  font-size: 9px;
}
/* Le bouton prend toute la cellule pour que son texte se pose là où la
   colonne l'aligne : un bouton au gabarit de son libellé resterait collé à
   gauche dans une colonne de nombres. */
thead th:not(.l) .tri {
  width: 100%;
  text-align: right;
}
tbody td {
  padding: var(--s3);
  border-bottom: 1px solid var(--border-subtle);
  text-align: right;
  vertical-align: top;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
tbody td.l {
  text-align: left;
  white-space: normal;
}
tbody tr:hover {
  background: var(--surface);
}
tbody tr.sel {
  background: var(--accent-bg);
}
.big {
  font-size: var(--t4);
  font-weight: var(--gras-titre);
  white-space: nowrap;
}
.sub {
  font-size: var(--t0);
  color: var(--text-muted);
  margin-top: 3px;
  white-space: normal;
}
/* LES ACTIONS DE LIGNE NE SONT PAS CACHÉES AU CLAVIER. `opacity: 0` les rend
   invisibles à la souris mais elles restent focusables : sans le
   `:focus-within`, une tabulation emmène le focus sur un bouton qu'on ne voit
   pas. La maquette ne pose que le survol. */
.rowact {
  display: flex;
  gap: 4px;
  justify-content: flex-end;
  opacity: 0;
  transition: opacity var(--dur-fast);
}
tbody tr:hover .rowact,
.rowact:focus-within {
  opacity: 1;
}
.iconbtn {
  width: 26px;
  height: 26px;
  border-radius: var(--r1);
  border: 1px solid var(--border-default);
  background: var(--surface-raised);
  color: var(--text-secondary);
  cursor: pointer;
  display: grid;
  place-content: center;
  font-size: var(--t2);
}
.iconbtn:hover {
  border-color: var(--accent-border);
  color: var(--accent-strong);
}

/* ============================== grilles ================================== */
.g {
  display: grid;
  gap: var(--s4);
}
.g-kpi {
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
}
.kpi {
  background: var(--surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r3);
  padding: var(--s4) var(--s4) var(--s3);
}
.kpi .cap {
  display: block;
  margin-bottom: var(--s2);
}
/* UN CHIFFRE DE TUILE NE SE COUPE JAMAIS. Vu à l'écran sur l'accueil :
   « 194.7 k » passait à la ligne entre le nombre et son unité, « 91,3 % »
   entre le nombre et le signe. C'est la tuile qui doit se replier, pas la
   valeur qui doit se casser. */
.kpi .v {
  white-space: nowrap;
  font-size: var(--t8);
  font-weight: var(--gras-fort);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.kpi .n {
  font-size: var(--t1);
  color: var(--text-muted);
  margin-top: 4px;
}
/* La tuile MISE EN AVANT — « le prochain gain », « pour vous, maintenant ». */
.kpi.acc {
  border-color: var(--accent-border);
  background: linear-gradient(180deg, var(--accent-bg), transparent 70%);
}

/* ============================== états ==================================== */
.empty {
  border: 1px dashed var(--border-default);
  border-radius: var(--r3);
  padding: var(--s6);
  text-align: center;
  color: var(--text-muted);
  background: var(--surface);
}
/* Le titre d'un état vide se pose au NIVEAU que la page lui donne : le
   Portefeuille et le Personnage ouvrent leur section en `h2`, l'accueil en
   `h3` sous le titre de sa carte. Le style est celui du rôle, pas du rang. */
.empty :is(h2, h3) {
  color: var(--text-primary);
  margin-bottom: var(--s2);
}
.empty p {
  margin: 0 auto var(--s4);
  max-width: 56ch;
  font-size: var(--t2);
}
.skels {
  display: grid;
  gap: 6px;
}
.skel {
  background: linear-gradient(
    90deg,
    var(--surface) 25%,
    var(--surface-hover) 37%,
    var(--surface) 63%
  );
  background-size: 400% 100%;
  animation: chatoiement 1.4s linear infinite;
  border-radius: var(--r1);
  height: 12px;
}
@keyframes chatoiement {
  0% {
    background-position: 100% 0;
  }
  100% {
    background-position: 0 0;
  }
}

/* ============================== surcouches =============================== */
.scrim {
  position: fixed;
  inset: 0;
  background: var(--voile);
  backdrop-filter: blur(3px);
  z-index: var(--z-voile);
}
.palette {
  position: fixed;
  z-index: var(--z-palette);
  top: 14vh;
  left: 50%;
  transform: translateX(-50%);
  width: min(640px, 92vw);
  background: var(--surface-overlay);
  border: 1px solid var(--border-control);
  border-radius: var(--r3);
  box-shadow: var(--elev-3);
  overflow: hidden;
}
.palette .q {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s4);
  border-bottom: 1px solid var(--border-subtle);
}
.palette .q input {
  flex: 1;
  background: none;
  border: none;
  outline: none;
  font-size: var(--t5);
}
.palette ul {
  list-style: none;
  margin: 0;
  padding: var(--s2);
  max-height: 52vh;
  overflow: auto;
}
.palette li {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: 9px var(--s3);
  border-radius: var(--r2);
  cursor: pointer;
  font-size: var(--t3);
}
.palette li .ic {
  width: 18px;
  color: var(--text-muted);
  text-align: center;
}
.palette li .hint {
  margin-left: auto;
  font-size: var(--t0);
  color: var(--text-muted);
}
.palette li.on,
.palette li:hover {
  background: var(--accent-bg);
  color: var(--text-primary);
}
.palette .grp {
  padding: var(--s3) var(--s3) 4px;
  font-size: var(--t0);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: var(--gras-fort);
}

.maplayer {
  position: fixed;
  z-index: var(--z-panneau);
  top: 9vh;
  left: 50%;
  transform: translateX(-50%);
  width: min(1480px, 92vw);
  max-height: 82vh;
  background: var(--surface-overlay);
  border: 1px solid var(--border-control);
  border-radius: var(--r3);
  box-shadow: var(--elev-4);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.maplayer header {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s3) var(--s4);
  border-bottom: 1px solid var(--border-subtle);
}
.maplayer .body {
  flex: 1;
  position: relative;
  background:
    radial-gradient(
      900px 500px at 30% 20%,
      color-mix(in oklch, var(--accent) 5%, transparent),
      transparent 60%
    ),
    var(--surface-sunken);
}

/* ============================== barre de filtres ========================= */
/* UNE CARTE POSÉE, PLUS UN BANDEAU TRAVERSANT. Le liseré courait d'un bord à
   l'autre et faisait paraître la barre solidaire de l'en-tête au-dessus ; ce
   qu'elle règle est le TABLEAU en dessous. */
.filterbar {
  display: flex;
  align-items: center;
  gap: var(--s2);
  flex-wrap: wrap;
  position: relative;
  /* AUCUNE MARGE HORIZONTALE : la rangée vit dans `.ecran`, qui porte déjà
     `padding: var(--s4) var(--s5)`. En ajouter une la rentrait DEUX fois, et
     elle finissait plus étroite que le tableau qu'elle filtre — décalée d'un
     `--s5` de chaque côté. */
  margin: var(--s2) 0 var(--s4);
  padding: var(--s2);
  background: var(--surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--r3);
}
/* LE CHAMP CÈDE, LES CRITÈRES NON. `flex:1 / min-width:320px` disait
   l'inverse : la recherche prenait tout l'espace libre et refusait de
   descendre sous 320 px, donc c'étaient les critères — dont ceux qu'on a
   posés — qui passaient à la ligne pour laisser de la place à un champ vide. */
.fsearch {
  flex: 0 1 320px;
  min-width: 170px;
  height: 32px;
  background: var(--surface-base);
}
/* Le rappel du raccourci n'a plus rien à rappeler une fois le champ pris. */
.fsearch:focus-within .kbdhint {
  opacity: 0;
}
.kbdhint {
  font-size: var(--t0);
  color: var(--text-muted);
  border: 1px solid var(--border-default);
  border-radius: var(--r1);
  padding: 1px 5px;
}
.fsep {
  width: 1px;
  height: 20px;
  background: var(--border-subtle);
  margin: 0 var(--s1);
}
/* Le DÉCLENCHEUR de filtre : repos, survol, ouvert, actif portant sa valeur,
   focus clavier. Un critère réglé devient une pastille pleine qui PORTE sa
   valeur — jamais le nom du critère en double. */
.trig {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 30px;
  padding: 0 10px;
  background: none;
  border: 1px solid var(--border-control);
  border-radius: var(--r-pill);
  color: var(--text-secondary);
  font-size: var(--t2);
  cursor: pointer;
  white-space: nowrap;
  transition:
    border-color var(--dur-fast),
    color var(--dur-fast),
    background var(--dur-fast);
}
.trig:hover {
  color: var(--text-primary);
  border-color: var(--border-control-hover);
  background: var(--surface);
}
.trig .car {
  font-size: 9px;
  color: var(--text-muted);
  transform: translateY(1px);
}
.trig[aria-expanded="true"] {
  border-color: var(--accent);
  color: var(--text-primary);
  background: var(--surface-raised);
}
.trig.active {
  background: var(--accent-bg);
  border-color: var(--accent-border);
  color: var(--accent-strong);
  font-weight: var(--gras-titre);
}
.trig.active .val {
  color: var(--accent-soft);
}
/* Le nom du critère quand la valeur ne suffit pas à le désigner — les deux
   lieux. Il s'efface derrière elle : c'est le lieu qu'on relit, pas le mot
   « Acheter à ». */
.trig.active .nom {
  font-weight: var(--gras-moyen);
  opacity: 0.72;
}
.trig.toggle.active {
  background: var(--amber-bg);
  border-color: var(--amber-border);
  color: var(--amber-soft);
}

/* UNE RÈGLE POSÉE ET SA CROIX FORMENT UN OBJET, et il ne se coupe pas en deux
   quand la rangée passe à la ligne — d'où `inline-flex` et `flex:none` sur la
   paire. Les deux styles manquaient : `.trigduo` et `.trigx` étaient écrits
   dans le balisage depuis la refonte de la barre et n'existaient dans aucune
   feuille, ce qui rendait la croix en bouton nu du navigateur — gris clair,
   carré, à la police du système. */
.trigduo {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  flex: none;
}
.trigx {
  height: 30px;
  padding: 0 7px;
  /* Le voile clair : `--overlay-soft` est déclaré pour cet usage exact, « la
     croix d'un filtre actif, posée sur une pastille déjà teintée ». */
  background: var(--overlay-soft);
  border: 0;
  border-radius: var(--r-pill);
  color: var(--accent-strong);
  font-size: var(--t2);
  line-height: 1;
  cursor: pointer;
}
.trigx:hover {
  background: var(--overlay-soft-hover);
  color: var(--text-primary);
}

/* LE BILAN À DROITE DE LA RANGÉE, jamais entre deux critères : c'est le seul
   contrôle qui agit sur tous les autres. `margin-left:auto` le décolle du
   dernier critère quelle que soit la largeur restante. */
.fbilan {
  margin-left: auto;
  flex: none;
}
/* `fcompte` ET NON `pastille` : `.pastille` est DÉJÀ, dans les styles portés
   par l'écran Marché, le point cyan de huit pixels qui pulse en tête du
   bandeau des changements. Une classe scopée par Svelte gagne à égalité de
   spécificité — le compte s'affichait donc en pastille pleine indigo, chiffre
   indigo sur fond indigo. Mesuré : `oklch(.845…)` sur `oklch(.805…)`. */
.fcompte {
  display: inline-flex;
  align-items: center;
  min-width: 18px;
  justify-content: center;
  margin-left: var(--s2);
  padding: 1px var(--s2);
  border: 1px solid var(--accent-border);
  border-radius: var(--r-pill);
  background: var(--accent-bg);
  color: var(--accent-strong);
  font-size: var(--t1);
  font-variant-numeric: tabular-nums;
}

/* LA BARRE DE PROPORTION SUIT SON COMPTE. Elle vivait sous la ligne de retour
   des filtres ; le compte des retenues est descendu au pied du tableau et la
   barre l'a suivi. Cette ligne de retour a disparu à son tour — la rangée
   unique montre l'état des filtres sans avoir à l'écrire. */
.compteur-lignes .bar {
  flex: 0 0 120px;
  height: 3px;
  border-radius: 2px;
  background: var(--border-subtle);
  overflow: hidden;
}
.compteur-lignes .bar i {
  display: block;
  height: 100%;
  background: var(--accent);
  transition: width var(--dur) var(--ease);
}

.pop {
  position: absolute;
  z-index: var(--z-popover);
  min-width: 280px;
  background: var(--surface-overlay);
  border: 1px solid var(--border-control);
  border-radius: var(--r3);
  padding: var(--s4);
  box-shadow: var(--elev-2);
  display: none;
}
.pop.open {
  display: block;
}
.pop h4 {
  font-size: var(--t2);
  margin-bottom: var(--s3);
  display: flex;
  gap: var(--s2);
  align-items: center;
}
.pop h4 em {
  margin-left: auto;
  font-style: normal;
  font-size: var(--t0);
  color: var(--text-muted);
  font-weight: 400;
}
.pop .two {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s2);
}
.pop .foot {
  display: flex;
  align-items: center;
  gap: var(--s2);
  margin-top: var(--s3);
  padding-top: var(--s3);
  border-top: 1px solid var(--border-subtle);
}
.pop .foot .hint {
  font-size: var(--t0);
  color: var(--text-muted);
  margin-right: auto;
}
.quick {
  display: flex;
  gap: 6px;
  margin-top: var(--s2);
  flex-wrap: wrap;
}
.quick button {
  background: var(--surface);
  border: 1px solid var(--border-control);
  color: var(--text-secondary);
  font-size: var(--t0);
  padding: 3px 9px;
  border-radius: var(--r-pill);
  cursor: pointer;
}
.quick button:hover {
  border-color: var(--accent-border);
  color: var(--accent-strong);
}

/* Le curseur de SEUIL ORDINAL à crans cumulatifs : « Prudence » inclut
   « Sûr ». Ce n'est pas un choix exclusif, et la forme le dit — les crans en
   deçà du choisi restent allumés. */
.thresh {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.thresh .track {
  display: flex;
  gap: 3px;
}
.thresh .track button {
  flex: 1;
  height: 30px;
  background: var(--surface);
  border: 1px solid var(--border-control);
  color: var(--text-muted);
  font-size: var(--t1);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  transition:
    background var(--dur-fast),
    color var(--dur-fast);
}
.thresh .track button:first-child {
  border-radius: var(--r2) 0 0 var(--r2);
}
.thresh .track button:last-child {
  border-radius: 0 var(--r2) var(--r2) 0;
}
.thresh .track button.inc {
  background: var(--surface-raised);
  color: var(--text-primary);
  border-color: var(--border-control-hover);
}
.thresh .track button.edge {
  border-color: var(--accent-border);
  background: var(--accent-bg);
  color: var(--text-primary);
  font-weight: var(--gras-fort);
}
.thresh .cur {
  font-size: var(--t1);
  color: var(--text-secondary);
}

/* ============================== arbre marché ============================= */
.treewrap {
  border-right: 1px solid var(--border-subtle);
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.tree {
  overflow: auto;
  flex: 1;
  padding: var(--s2) var(--s2) var(--s5);
  font-size: var(--t2);
}
/* Troncature par ellipse, jamais de débordement : un nom de marchandise
   d'EVE dépasse toujours la colonne qu'on lui a prévue. */
.tree .n {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px var(--s2);
  border-radius: var(--r1);
  cursor: pointer;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tree .n .car {
  flex: none;
  width: 10px;
  font-size: 9px;
  color: var(--text-muted);
}
.tree .n:hover {
  background: var(--surface-hover);
  color: var(--text-primary);
}
.tree .n.on {
  background: var(--accent-bg);
  color: var(--accent-strong);
  font-weight: var(--gras-titre);
}
.tree .lvl1 {
  padding-left: var(--s2);
}
.tree .lvl2 {
  padding-left: 22px;
}
.tree .lvl3 {
  padding-left: 36px;
}
.tree .lvl4 {
  padding-left: 50px;
}

/* ============================== graphe =================================== */
.chart {
  width: 100%;
  height: 260px;
  display: block;
}
.chart .grid {
  stroke: var(--border-subtle);
  stroke-width: 1;
}
/* LES BARRES DE VOLUME MONTENT DE #39414d À `--border-control`, et ce n'est
   pas un goût : la valeur de la maquette rend 1,66:1 sur `--surface`, quand
   WCAG 1.4.11 demande 3:1 pour un objet graphique porteur d'information —
   une barre de volume en est un. `--border-control` tient 3,61:1. L'opacité
   de 0,75 part avec : elle rabaissait le contraste sous le seuil qu'on vient
   d'atteindre. La subordination à la ligne de prix reste portée par la
   TEINTE — un neutre contre l'accent — et par l'empilement. */
.chart .vol {
  fill: var(--border-control);
}
.chart .line {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2;
  stroke-linejoin: round;
}

/* ============================== encarts ================================== */
.note {
  border-left: 2px solid var(--accent);
  background: var(--accent-bg);
  padding: var(--s3) var(--s4);
  border-radius: 0 var(--r2) var(--r2) 0;
  font-size: var(--t2);
  color: var(--accent-soft);
}
.note b {
  color: var(--text-primary);
}
.warnbox {
  border-left: 2px solid var(--status-warning);
  background: var(--amber-bg);
  padding: var(--s3) var(--s4);
  border-radius: 0 var(--r2) var(--r2) 0;
  font-size: var(--t2);
  color: var(--amber-soft);
}
.warnbox b {
  color: var(--text-primary);
}
/* `.avis` — la mention sous un tableau ou une carte, et rien d'autre. Elle
   avait trois définitions : celle-ci, une copie mot pour mot dans le Marché,
   une quatrième propriété près dans les relevés, et `MarcheComplet` qui en
   faisait une BOÎTE — fond, bordure, padding — pour deux messages qui sont
   des encarts et portent maintenant `.note` et `.warnbox`. Une seule reste,
   sans `:where()` : il n'y a plus de règle locale à laisser gagner. */
.avis {
  font-size: var(--t1);
  color: var(--text-muted);
  margin-top: var(--s4);
  max-width: 80ch;
}
.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s4);
}
.rows {
  display: flex;
  flex-direction: column;
}
.kv {
  display: flex;
  align-items: baseline;
  gap: var(--s3);
  padding: 9px 0;
  border-bottom: 1px solid var(--border-subtle);
  font-size: var(--t2);
}
.kv:last-child {
  border-bottom: none;
}
.kv .k {
  color: var(--text-muted);
  flex: 1;
}
.kv .v {
  font-weight: var(--gras-titre);
  font-variant-numeric: tabular-nums;
}
.kv .x {
  color: var(--text-muted);
  font-size: var(--t1);
  min-width: 92px;
  text-align: right;
}
.dots {
  display: inline-flex;
  gap: 3px;
}
.dots i {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 1px solid var(--border-control-hover);
  display: block;
}
.dots i.f {
  background: var(--accent);
  border-color: var(--accent);
}
.acc {
  border: 1px solid var(--border-subtle);
  border-radius: var(--r2);
  margin-bottom: 6px;
  background: var(--surface);
  overflow: hidden;
}
.acc summary {
  padding: 10px var(--s4);
  cursor: pointer;
  font-size: var(--t3);
  list-style: none;
  display: flex;
  align-items: center;
  gap: var(--s2);
}
.acc summary::-webkit-details-marker {
  display: none;
}
.acc summary::before {
  content: "▸";
  color: var(--text-muted);
  font-size: 10px;
  transition: transform var(--dur-fast);
}
.acc[open] summary::before {
  transform: rotate(90deg);
}
.acc summary:hover {
  background: var(--surface-hover);
}
.acc .in {
  padding: 0 var(--s4) var(--s3);
  font-size: var(--t2);
  color: var(--text-secondary);
}

/* ============================================================== relevés = */
/* Ce qui reste en propre aux écrans de relevé — Portefeuille et Personnage :
   le titre de section et la table dense à en-tête calme. Le reste de ce bloc
   était une seconde peau pour des rôles qui en avaient déjà une : `.vide`
   doublait `.empty`, `.squel` doublait `.skel` avec sa propre animation,
   `.avis` et `.b` recopiaient la règle globale, et `.btn` redessinait le
   bouton. Portée par `.releve` pour ne rien changer aux tables des autres
   écrans. */
.releve .sect {
  font-size: var(--t0);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-secondary);
  font-weight: var(--gras-moyen);
  margin: var(--s5) 0 var(--s2);
}
.releve th {
  font-size: var(--t0);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-secondary);
  font-weight: var(--gras-moyen);
  padding: var(--s2) var(--s3);
  border-bottom: 1px solid var(--border-default);
}
.releve td {
  padding: var(--ligne-pad) var(--s3);
  border-bottom: 1px solid var(--border-subtle);
}
.releve tbody tr {
  transition: background var(--dur-fast) var(--ease);
}
.releve tbody tr:hover {
  background: var(--surface-raised);
}
/* La ligne d'un relevé est haute : son squelette l'est aussi. C'est la seule
   chose que ces écrans avaient encore à dire d'un squelette. */
.releve .skel {
  height: 34px;
}

/* LES ONGLETS D'UNE FICHE — barre raccordée au contenu, filet d'accent de
   2 px sous l'actif. Elle vivait recopiée dans deux composants : le `Tiroir`
   d'« Acheter et revendre » et le volet de « Vendre et attendre ». Trente et
   une lignes identiques, que jscpd a refusées — à raison : deux barres
   d'onglets qui divergent d'un composant à l'autre, c'est le même écran qui
   se contredit.

   CE QUI RESTE AUX COMPOSANTS : le NOMBRE de colonnes et la marge, qui
   dépendent de ce que la barre coiffe. Tout le reste est une décision de
   design, et sa place est ici. */
.onglets-fiche {
  display: grid;
  background: var(--surface-base);
  border-bottom: 1px solid var(--border-default);
}
.onglets-fiche button {
  all: unset;
  box-sizing: border-box;
  cursor: pointer;
  text-align: center;
  padding: var(--s3) var(--s2);
  font-size: var(--t2);
  color: var(--text-muted);
  border-bottom: 2px solid transparent;
  white-space: nowrap;
}
.onglets-fiche button:hover {
  color: var(--text-secondary);
  background: var(--surface);
}
.onglets-fiche button[aria-selected="true"] {
  color: var(--text-primary);
  font-weight: var(--gras-titre);
  background: var(--surface);
  border-bottom-color: var(--accent);
}
.onglets-fiche button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
