/* VUE-ENSEMBLE — indicateurs, graphiques, legendes, tableaux de synthese
 *
 * Tranche 03 de public/styles.css, decoupe le 2026-08-24. Les fichiers sont
 * NUMEROTES parce que l'ordre de chargement compte : une regle plus bas l'emporte sur une
 * regle de meme portee plus haut. Ne pas reordonner les <link> de index.html.
 */
.kpi-row:empty { display: none; }
.kpi {
  position: relative;
  display: flex; align-items: baseline; justify-content: space-between; gap: 0.75rem;
  padding: 0.55rem 1.1rem 0.55rem 1.65rem;
  border-bottom: 1px solid var(--border);
  transition: background-color 0.12s ease;
}
.kpi:hover { background: var(--bg-inset); }
.kpi::before {
  content: ''; position: absolute; left: 1.1rem; top: 50%; transform: translateY(-50%);
  width: 6px; height: 6px; border-radius: 50%; background: var(--border-strong);
}
.kpi .label {
  font-size: 0.76rem; color: var(--muted); font-weight: 500;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.kpi .value {
  font-size: 0.92rem; font-weight: 700; line-height: 1.2; text-align: right;
  font-variant-numeric: tabular-nums; letter-spacing: -0.01em; white-space: nowrap;
}
.kpi.positive::before { background: var(--accent); }
.kpi.negative::before { background: var(--red); }
.kpi.positive .value { color: var(--accent); }
.kpi.negative .value { color: var(--red); }
.kpi-txt { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.chart-headline {
  display: block; font-size: 1.15rem; font-weight: 700; color: var(--text-strong);
  font-variant-numeric: tabular-nums; letter-spacing: -0.01em; white-space: nowrap;
  margin-bottom: 0.5rem;
}
.section-head-row .chart-headline { display: inline; margin-bottom: 0; }
/* Titre de page (revu le 2026-09-22) : affiché deux fois à l'écran (ici ET dans la topbar,
   qui lit ce même h1 — `onglets.js`). Seul celui de la topbar se voit, sans trait dessous
   (retiré le 2026-10-13, jugé inutile par Nicolas). Le h1 reste dans le DOM, invisible (`clip`, pas `display:none`) :
   `onglets.js` continue de lire son texte pour remplir la topbar, et un lecteur d'écran
   garde un vrai titre de page par onglet. L'aide « i » suit son titre : elle se lit ici et
   s'affiche dans la topbar, sans quoi elle occupait seule une ligne vide en haut de l'onglet.
   C'est l'en-tête entier qui sort du flux, pas seulement son h1 : même vide, il restait une
   rangée du panneau et lui coûtait un écart (`gap`) au-dessus du premier contenu. */
.page-head .info-tip { display: none; }
.page-head {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
.hero-metric {
  display: block; font-size: 2rem; font-weight: 600; color: var(--text-strong);
  font-variant-numeric: tabular-nums; letter-spacing: -0.025em; line-height: 1.15;
}
/* Le mode (net/brut/liquide/d'épargne) suit le montant, en plus petit : sans cette règle il
   héritait des 2rem/600 du montant lui-même. C'est la liste qui le choisit : le mot lu après
   le montant est celui qu'on change, il n'y a pas d'onglets ailleurs.
   Encre de champ, pas `--muted` : grisée, la liste se lisait comme désactivée à côté des
   listes « Horizon : ». Pas plus grande que 1rem : la flèche native ne grandit pas avec le
   texte, et au-delà elle paraissait minuscule et décrochée du mot. */
.hero-metric-mode {
  font-size: 1rem; font-weight: 500; letter-spacing: normal;
  min-height: 0; padding: 0.1rem 0.15rem; vertical-align: baseline; cursor: pointer;
  /* Large comme le mot choisi, pas comme le plus long (« d'épargne ») : sinon un vide
     sépare « net » de sa flèche. Ignoré par les navigateurs qui ne le connaissent pas. */
  field-sizing: content;
}
/* LA CARTE QU'ON MONTRE (captures, page d'accueil) : fond crème léger, petit libellé gris, le
   montant, puis la pastille de ce qu'il devient à l'horizon choisi. */
.carte-vitrine { background: var(--carte-vitrine-fond); }
.hero-libelle { font-family: var(--font-sans); font-size: 0.85rem; font-weight: 500; color: var(--muted); margin: 0 0 var(--space-1); }
.hero-tete { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--space-3); flex-wrap: wrap; }
.hero-actions { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.hero-horizon {
  display: inline-flex; margin-top: var(--space-2); padding: 0.15rem 0.6rem; border-radius: 999px;
  background: var(--accent-soft); color: var(--accent-text); font-size: 0.85rem; font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.hero-horizon[hidden] { display: none !important; }
/* Le chiffre AU-DESSUS du graphique, sur le même fond, jamais par-dessus : posé dans le
   graphique (essayé le 2026-10-13), il passait sous la bande d'alerte du matelas, son triangle
   et les lignes de fond. Pas de coupure pour autant : même carte, même fond, aucun trait. */
.hero-scene .patrimoine-chart-wrap { margin-top: var(--space-3); }
.hero-metric { font-size: 3rem; font-weight: 700; letter-spacing: -0.035em; }
/* L'or du « à faire » : ce montant n'existe que tant qu'un événement attend sa confirmation. */
.hero-a-venir {
  display: inline-block; margin-left: var(--space-2); padding: 0.1rem 0.55rem; border-radius: 999px;
  font-size: 0.9rem; font-weight: 600; letter-spacing: normal; vertical-align: middle;
  background: var(--gold-soft); color: var(--gold-strong); white-space: nowrap;
}
.hero-a-venir[hidden] { display: none !important; }
/* Les autres blocs suivent le même dessin que « Votre patrimoine » (petite ligne grise, grand
   chiffre, pastille), un cran plus petit : le patrimoine reste le chiffre de la page. */
.hero-metric.bloc-metric { font-size: 2rem; }
.hero-metric.bloc-metric:empty { display: none; }
/* Une pastille qui signale un manque prend l'or du « à faire », pas le vert du « fait ». */
.hero-horizon.alerte { background: var(--gold-soft); color: var(--gold-strong); }
.hero-horizon + .choix-affichage, .hero-metric + .choix-affichage { display: block; margin-top: var(--space-3); }
/* Synthèse annuelle : le patrimoine net se lit d'abord, les taux restent en retrait. */
#table-overview td:nth-child(3) { font-weight: 700; color: var(--text-strong); }
#table-overview td:nth-child(5), #table-overview td:nth-child(6) { color: var(--muted); }
.chart-footnote {
  margin-top: 0.6rem; padding-top: 0.6rem; border-top: 1px solid var(--border);
  font-size: 0.78rem; color: var(--muted);
}
/* Le panneau qui remplace l'infobulle flottante de Chart.js (socle/chart-temporel.js,
   renderInfobulleExterne). Il est POSÉ PAR-DESSUS le graphique, hors du flux : dans le flux
   (essayé le 2026-09-06) son apparition et sa disparition au survol poussaient le graphique
   vers le bas puis le remontaient, à chaque entrée et sortie du curseur — le graphique
   n'arrêtait plus de sauter. Son référentiel est `.patrimoine-chart-wrap`, qui porte déjà
   `position: relative` : ne jamais le rattacher à la carte, dont l'animation d'entrée laisse
   un `transform` figé (cf. CLAUDE.md).
   Il suit le curseur en se posant au-dessus du sommet de la pile (`placerInfobulle`,
   socle/chart-temporel.js) : la seule zone du cadre vide par construction. D'où `top`/`left`
   à zéro — la position vient d'un `transform`, que la transition ci-dessous fait glisser d'un
   mois au suivant. `pointer-events: none` l'empêche de couper le survol quand le curseur
   passe dessous. Aucun `display` d'auteur ici : la garde `[hidden]` du navigateur suffit,
   cf. CLAUDE.md. */
.chart-infobulle-externe {
  position: absolute; top: 0; left: 0; z-index: 2;
  max-width: calc(100% - 0.8rem); pointer-events: none;
  transform: translate(0, 0); transition: transform 0.12s ease-out;
  padding: 0.5rem 0.6rem;
  background: var(--bg-inset); border: 1px solid var(--border);
  border-radius: var(--radius-input); box-shadow: var(--shadow-card-sm);
  font-size: 0.78rem; line-height: 1.4;
}
@media (prefers-reduced-motion: reduce) { .chart-infobulle-externe { transition: none; } }
.chart-infobulle-titre { font-weight: 600; color: var(--text-strong); margin-bottom: 0.25rem; }
/* Une couche par ligne. En colonnes qui se replient, deux couches voisines se retrouvaient
   côte à côte et le panneau changeait de forme d'un mois à l'autre. */
.chart-infobulle-corps { display: flex; flex-direction: column; gap: 0.15rem; }
.chart-infobulle-ligne { display: flex; align-items: center; gap: 0.3rem; white-space: nowrap; }
.chart-infobulle-ligne i { width: 8px; height: 8px; border-radius: 50%; display: inline-block; flex: none; }
.chart-infobulle-detail { padding-left: 1.1rem; color: var(--muted); white-space: nowrap; }
/* Nom du projet du mois survolé, alerte de matelas d'épargne (cf. `afterBody` dans
   renderInfobulleExterne, socle/chart-temporel.js) : séparé du corps, sans pastille de
   couleur puisqu'aucune couche ne s'y rattache. */
.chart-infobulle-evenements { display: flex; flex-direction: column; gap: 0.15rem; margin-top: 0.3rem; white-space: nowrap; }
.chart-infobulle-pied { margin-top: 0.3rem; font-weight: 700; font-size: 0.85rem; color: var(--text-strong); }

/* Sur mobile, la légende cède sa place au bouton « Gérer l'affichage »
   (fenêtre plutôt qu'inline, pour économiser la place) : cf. #patrimoine-affichage-overlay et
   son câblage dans ecrans/vue-ensemble.js. Rien ne change au-dessus de 900px. */
/* `.btn.gerer-affichage`, pas `.gerer-affichage` seul : ce bouton porte
   aussi `.btn`, dont le `display: inline-flex` (04-formulaires.css, charge apres ce fichier)
   l'aurait sinon emporte a specificite egale — meme piege que `.hero-row` plus haut ce soir. */
.btn.gerer-affichage { display: none; }
@media (max-width: 900px) {
  .btn.gerer-affichage { display: inline-flex; }
  /* Comparer reste a un clic (l'onglet Comparer, dans le tiroir) : ce bouton-ci ne fait que
     gagner de la place pour que "Gerer l'affichage" s'aligne avec le montant, seul a droite. */
  .btn.hero-btn-comparer { display: none; }
  /* Même raison pour « Modifier manuellement » (l'onglet Flux, dans le menu) : sur téléphone il
     s'intercalait entre la ligne grise et le chiffre qu'elle annonce. */
  .btn.remuneration-modifier { display: none; }
  /* Police resserrée pour laisser plus de hauteur au graphique lui-même, le vrai contenu
     de la carte. */
  .hero-metric { font-size: 2.1rem; }
}
/* .remuneration-legend-item partage exactement le style de .patrimoine-legend-item (même
   légende drag & drop + pastille couleur, cf. renderRemunerationLegend) — mêmes règles,
   sélecteur ajouté plutôt que dupliqué. */
.patrimoine-legend, .remuneration-legend { display: flex; flex-wrap: wrap; gap: 0.4rem; }
/* Le chevron d'une famille de couches (socle/legende-reordonnable.js) : tourné vers le bas
   quand elle est dépliée ; ses couches dépliées se distinguent par un contour pointillé. */
.legende-deplier { display: inline-flex; padding: 0.1rem; border: 0; background: none; color: var(--muted); cursor: pointer; }
.legende-deplier svg { transition: transform 0.12s ease; }
.legende-deplier[aria-expanded="true"] svg { transform: rotate(90deg); }
.patrimoine-legend-item.legende-membre { background: transparent; outline: 1px dashed var(--border); }
.patrimoine-legend-item, .remuneration-legend-item {
  display: flex; align-items: center; gap: 0.35rem;
  background: var(--bg-inset); border-radius: 999px; padding: 0.28rem 0.6rem 0.28rem 0.5rem;
  font-size: 0.76rem; cursor: grab; user-select: none;
  transition: box-shadow 0.12s ease, opacity 0.12s ease;
}
.patrimoine-legend-item:active, .remuneration-legend-item:active { cursor: grabbing; }
.patrimoine-legend-item.dragging, .remuneration-legend-item.dragging { opacity: 0.4; box-shadow: var(--shadow-btn-hover); }
.patrimoine-legend-item .drag-handle, .remuneration-legend-item .drag-handle { display: inline-flex; color: var(--muted); line-height: 1; }
.patrimoine-legend-item i, .remuneration-legend-item i { width: 8px; height: 8px; border-radius: 50%; display: inline-block; flex: none; }
/* Une couche masquée du graphique reste dans la légende (c'est par elle qu'on la fait
   revenir) mais se distingue au premier coup d'œil, sans dépendre du seul état de l'œil. */
.patrimoine-legend-item.legende-cachee, .remuneration-legend-item.legende-cachee { opacity: 0.5; }
.legende-visibilite {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 1.1rem; height: 1.1rem; padding: 0; margin-left: 0.1rem;
  background: transparent; border: none; color: var(--muted); cursor: pointer;
}
.legende-visibilite:hover { color: var(--text-strong); }
/* Légende « tableau » du patrimoine (Enveloppe | Couleur | Affiché), cf.
   renderLegendeReordonnable({colonnes}) — même mécanisme de glisser-déposer que les
   pastilles ci-dessus (la ligne porte donc AUSSI `.patrimoine-legend-item`, requis par
   `brancherDeplacement`), seul le balisage change. D'où les resets `background`/
   `border-radius` : sans eux la ligne pleine largeur héritait du fond pilule des pastilles.
   4 colonnes alignées : poignée, nom (élastique), couleur, œil ; l'en-tête reprend
   la même grille avec une 1re cellule vide pour rester aligné sur la poignée. */
.legende-en-tableau { display: block; }
.legende-table-header, .legende-table-row {
  display: grid; grid-template-columns: 20px 1fr 52px 46px; align-items: center; gap: 0.6rem;
}
.legende-table-header {
  padding: 0.2rem 0.4rem 0.4rem; font-size: 0.72rem; font-weight: 600; color: var(--muted);
  border-bottom: 1px solid var(--border); white-space: nowrap;
}
.legende-table-header span:nth-child(3) { text-align: center; }
.legende-table-header span:nth-child(4) { text-align: right; }
.legende-table-row {
  background: transparent; border-radius: 0; padding: 0.55rem 0.4rem;
  border-bottom: 1px solid var(--border);
  cursor: grab; user-select: none; transition: box-shadow 0.12s ease, opacity 0.12s ease;
}
.legende-table-row:last-child { border-bottom: none; }
.legende-table-row:active { cursor: grabbing; }
.legende-table-row.dragging { opacity: 0.4; box-shadow: var(--shadow-btn-hover); }
.legende-table-nom { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.85rem; }
.legende-table-couleur-inerte { width: 14px; height: 14px; border-radius: 50%; display: inline-block; justify-self: center; }
.legende-table-row .pastille-couleur { width: 16px; height: 16px; justify-self: center; }
/* Colonne « Affiché » : le MÊME œil que la légende en pastilles (cf. `boutonOeil`,
   socle/legende-reordonnable.js), poussé au bout de sa colonne. La cible est agrandie par la
   BOÎTE, pas par un `padding` : `.legende-visibilite` pose une largeur fixe, et un padding
   viendrait rogner l'icône au lieu d'élargir le bouton. */
.legende-table-oeil { justify-self: end; width: 1.75rem; height: 1.75rem; margin-left: 0; }
/* Le point de couleur cliquable (socle/pastille-couleur.js). Un peu plus grand que le point
   inerte voisin : il faut pouvoir le viser. Les neuf règles qui habillaient le champ natif
   (`::-webkit-color-swatch`, `::-moz-color-swatch`) sont parties avec lui. */
.pastille-couleur {
  width: 12px; height: 12px; padding: 0; border: none; border-radius: 50%;
  cursor: pointer; flex: none;
}
.pastille-couleur:hover { outline: 2px solid var(--accent); outline-offset: 1px; }
td .pastille-couleur { margin-right: 0.35rem; vertical-align: middle; }
.table-color-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; margin-right: 0.35rem; vertical-align: middle; }
.chart-footnote strong { color: var(--text-strong); font-weight: 700; font-variant-numeric: tabular-nums; }
.chart-footnote strong.negative { color: var(--red); }
.endettement-mini {
  display: flex; flex-wrap: wrap; gap: 0.5rem 1.25rem;
  margin-top: 0.7rem; padding-top: 0.65rem; border-top: 1px solid var(--border);
}
.endettement-mini-item { display: flex; align-items: baseline; gap: 0.4rem; font-size: 0.78rem; }
.endettement-mini-item .label { color: var(--muted); }
.endettement-mini-item .value { font-weight: 700; color: var(--text-strong); font-variant-numeric: tabular-nums; }
.chart-grid {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--ecart-blocs);
}
/* Deux vraies moitiés d'écran : minmax(0, 1fr) force le partage 50/50 même quand le
   contenu de gauche (lignes dépenses à colonnes fixes) a un min-content plus large que
   sa part — sans ça, "1fr" seul laisse ce min-content déborder sur la colonne de droite. */
.budget-flux-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: start; }
.budget-flux-grid .flux-dated-list { overflow-x: auto; }
@media (max-width: 900px) { .budget-flux-grid { grid-template-columns: 1fr; } }
/* Grille 2×2 (pas 2 colonnes indépendantes) : chart-total/chart-flux forment la 1ʳᵉ rangée,
   table-total/table-flux la 2ᵉ — align-items:stretch (défaut) aligne chaque rangée sur sa
   propre carte la plus haute, donc chart contre chart et tableau contre tableau, même si
   les colonnes ont un total de hauteur différent (legende qui wrap, nombre de lignes...). */
@media (max-width: 900px) { .env-macro-grid { grid-template-columns: 1fr; } }
.chart-card canvas { max-height: 260px; }
/* `maintainAspectRatio: false` (ecrans/vue-ensemble.js) : sans lui Chart.js fixe la hauteur a
   largeur/2. Chart.js (responsive) mesure le PARENT du canvas puis pose lui-meme la taille du
   <canvas> - attribut ET style, en pixels physiques. Poser la hauteur en CSS `!important`
   DIRECTEMENT sur le <canvas> (essaye le 2026-09-05) ne change que la boite affichee, jamais
   la resolution du bitmap dessine par Chart.js : mesure sur telephone, canvas.style.height a
   560px (la valeur que Chart.js avait calculee a un tour precedent) contre une boite
   reellement affichee de 446px (55vh) - tout le graphique, texte des axes compris, se
   retrouvait ecrase verticalement. D'ou l'enveloppe dediee `.patrimoine-chart-wrap`, dont
   Chart.js mesure la hauteur sans jamais la lui disputer ensuite, et `max-height: none` sur
   le canvas pour annuler le plafond generique ci-dessus (260px, pense pour un graphique
   carre). */
/* Jamais plus haut que large (demande de Nicolas, 2026-10-14) : sur un téléphone tenu droit,
   une hauteur prise sur l'écran faisait une colonne étirée. `aspect-ratio: 1` donne la
   largeur pour hauteur, `max-height` la hauteur voulue sur un écran large ; la carte suit,
   puisque l'enveloppe est sa seule hauteur. `min-height: 0` : sans lui, une boîte à
   proportion grandit avec son contenu, et le canevas de Chart.js la pousserait en boucle.
   `width: 100%` : sans largeur posée, la proportion reporte le plafond de hauteur sur la
   largeur, et le graphique devenait carré sur ordinateur aussi (405 px dans une carte large).
   Même règle pour toute enveloppe de graphique dont la hauteur n'est pas fixée par Chart.js. */
.patrimoine-chart-wrap { position: relative; width: 100%; aspect-ratio: 1; min-height: 0; max-height: min(45vh, 480px); }
/* `display: block` : en `inline` le canevas garde une marge de ligne de base sous lui, et les
   pixels de Chart.js ne coincideraient plus avec le repere de l'enveloppe — ce dont depend le
   placement de l'infobulle. */
#chart-patrimoine, #chart-remuneration, #chart-roc { max-height: none; display: block; }
/* Même enveloppe pour la rémunération : sans elle, Chart.js la dessinait deux fois plus large
   que haute, une bande plate sur un téléphone (Nicolas, 2026-10-12). Le rendement, à côté,
   la partage : plafonné à 260 px, il paraissait plus petit que son voisin de rangée. */
.remuneration-chart-wrap { position: relative; width: 100%; aspect-ratio: 1; min-height: 0; max-height: min(34vh, 380px); }
@media (max-width: 900px) {
  /* Le graphique est le vrai contenu de la carte : sur un telephone, tout le reste (titre,
     onglets, boutons) a deja ete resserre pour lui laisser cette hauteur. */
  .patrimoine-chart-wrap { max-height: min(55vh, 560px); }
  .remuneration-chart-wrap { max-height: min(42vh, 440px); }
}
.env-charts canvas { max-height: 260px; max-width: 260px; margin: 0 auto; display: block; }
/* Resserré seulement DANS une carte (camemberts côte à côte) : entre deux cartes de la page,
   c'est l'écart commun. */
.env-detail-composition .chart-grid { gap: 0.5rem; }
/* Le bilan est COLLÉ sous les Revenus : il partage une colonne en flex avec eux
   (.budget-flux-col) au lieu d'être un 3ᵉ enfant de la grille — il reste une carte à
   part entière (cf. retour Nicolas), simplement empilée. En 3ᵉ enfant, il démarrait à la
   2ᵉ rangée, dont le haut est fixé par la PLUS HAUTE des deux sections : dès que Dépenses
   dépassait Revenus, un trou s'ouvrait entre les Revenus et le Bilan. */
.budget-flux-col { display: flex; flex-direction: column; gap: var(--ecart-blocs); min-width: 0; }
/* min-height fixe : évite qu'un canvas créé pendant que son onglet est masqué (Chart.js
   mesure alors 0×0) ne fige la carte à une hauteur nulle en boucle (cf. resizeEnvCharts
   dans app.js — le resize() seul ne suffit pas si le conteneur lui-même s'est effondré). */
.env-charts .card.inner { padding: 0.65rem; min-height: 290px; }
#env-panel-macro canvas { max-height: 360px; max-width: 360px; }
/* Camemberts enveloppes : canvas + légende détaillée (couleur/label/valeur/%) à droite,
   plus lisible que la légende empilée en bas de Chart.js (retour utilisateur 2026-07-20). */
.env-chart-row { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }
.env-chart-row canvas { flex: 1 1 auto; margin: 0 !important; }
/* UNE SEULE hauteur, calée sur celle du camembert (260px, cf. `.env-charts canvas`), qu'elle
   soit à côté ou sous lui (2026-09-17) — plus de second réglage propre au mode colonne : une
   légende longue (crypto, vingt lignes) défile au-delà dans les deux cas, sans jamais dicter
   la hauteur de la carte ni de sa voisine dans la même rangée. */
/* Une GRILLE, pas une pile de lignes : le % et le montant ont chacun leur colonne, alignée
   d'une ligne à l'autre. Collés en « 2 138 € · 36,4 % », ils ne se lisaient pas de loin
   (retour du 2026-09-24). Le % vient d'abord, c'est lui qu'on cherche. */
.env-chart-legend {
  flex: 1 1 170px; min-width: 150px; max-width: 280px; max-height: 260px; overflow-y: auto;
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto;
  column-gap: 0.5rem; row-gap: 0.32rem; align-content: start; align-items: center;
}
.env-chart-legend-item { display: contents; font-size: 0.78rem; }
.env-chart-legend-item i { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }
.env-chart-legend-item .pct, .env-chart-legend-item .val {
  text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap;
}
.env-chart-legend-item .pct { font-weight: 600; }
.env-chart-legend-item .val { color: var(--muted); padding-left: 0.25rem; }
/* `flex: 1 1 170px` donne une largeur minimale de 170px à la légende quand elle est À CÔTÉ
   du camembert (ligne). Une fois la ligne repliée en colonne, ce même 170px devient une
   HAUTEUR — sans rapport avec le contenu. `flex-basis: auto` évite qu'elle réserve 170px de
   boîte vide ; `max-height` (ci-dessus) reste la seule limite, dans les deux dispositions. */
@media (max-width: 640px) {
  .env-chart-row { flex-direction: column; }
  .env-chart-row canvas { max-width: 260px !important; }
  .env-chart-legend { flex: 0 1 auto; }
}
.computed-net {
  margin-top: 0.5rem; padding: 0.5rem 0.65rem; border-radius: var(--radius-input);
  background: var(--bg-hover); font-size: 0.9rem; font-weight: 600; color: var(--accent);
}
.span-2 { grid-column: span 2; }
@media (max-width: 900px) {
  /* minmax(0, 1fr), pas "1fr" seul : sans le plancher a 0, la piste garde son
     "min-width: auto" par defaut, et un contenu au min-content large (le canevas du
     graphique Patrimoine, une fois haut de 55vh et sans rapport largeur/hauteur fixe)
     poussait la carte ENTIERE a 910px sur un ecran de 375px (meme piege que
     .budget-flux-grid/.env-macro-grid ci-dessus, deja corrige, et que le CLAUDE.md decrit
     pour une grille de champs). */
  .chart-grid { grid-template-columns: minmax(0, 1fr); }
  .span-2 { grid-column: span 1; }
}
table { width: 100%; border-collapse: collapse; font-size: 0.8rem; }
th, td { text-align: right; padding: 0.4rem 0.45rem; border-bottom: 1px solid var(--border); }
th { color: var(--muted); font-weight: 600; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.03em; }
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover td { background: var(--bg-hover); }
/* « Où est mon argent » : sept colonnes dont une seule porte du texte long. Sans largeurs,
   l'auto-layout coupe le nom de l'enveloppe pour donner de la place à des nombres courts.
   (Les largeurs des deux tableaux fusionnés dans celui-ci ont disparu avec eux.) */
#table-macro { table-layout: fixed; }
#table-macro th:nth-child(1), #table-macro td:nth-child(1) { width: 24%; }
#table-macro th:nth-child(2), #table-macro td:nth-child(2) { width: 13%; }
#table-macro th:nth-child(3), #table-macro td:nth-child(3) { width: 16%; }
#table-macro th:nth-child(4), #table-macro td:nth-child(4) { width: 11%; }
#table-macro th:nth-child(5), #table-macro td:nth-child(5) { width: 13%; }
#table-macro th:nth-child(6), #table-macro td:nth-child(6) { width: 11%; }
#table-macro th:nth-child(7), #table-macro td:nth-child(7) { width: 12%; }
th:first-child, td:first-child { text-align: left; }
tr.highlight { background: var(--bg-hover); }
.table-wrap { overflow-x: auto; }
/* Un tableau trop large glisse dans sa carte (c'est ce qui rend « Exposition par actif »
   lisible sur un téléphone) : un chiffre ou un libellé de colonne coupé sur deux lignes
   rendait « Où est mon argent » illisible, et le nom de la ligne, lui, partait avec les
   colonnes. Il reste en place, sur le fond opaque de la carte, pour que rien ne passe
   dessous (Nicolas, 2026-10-12). */
.table-wrap th:not(:first-child), .table-wrap td:not(:first-child) { white-space: nowrap; }
.table-wrap th:first-child, .table-wrap td:first-child { position: sticky; left: 0; z-index: 1; background: var(--card); }
.table-wrap tbody tr:hover td:first-child, .table-wrap tr.highlight td:first-child { background: var(--bg-hover); }
@media (max-width: 900px) {
  /* Les largeurs en pourcentage serraient sept colonnes dans la largeur d'un téléphone. */
  #table-macro { table-layout: auto; width: max-content; min-width: 100%; }
  #table-macro th:first-child, #table-macro td:first-child { min-width: 7rem; }
  .table-wrap th:first-child, .table-wrap td:first-child { box-shadow: 1px 0 0 var(--border); }
}
.sliders { display: grid; gap: 0.5rem; }
/* « Couleurs par défaut », sous la légende des familles : discret, il ne sert qu'une fois. */
.btn-link.patrimoine-couleurs-defaut { display: inline-block; margin-top: var(--space-2); font-size: 0.8rem; }
.btn-link.patrimoine-couleurs-defaut[hidden] { display: none !important; }
