/* MISE-EN-PAGE — colonnes, barre laterale, onglets, selecteur de scenario
 *
 * Tranche 02 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.
 */
/* Pas de `padding-bottom` ici : `.app-shell` fait deja `min-height: 100vh`, donc la moindre
   marge basse portait la page a `100vh + marge` et le navigateur affichait une barre de
   defilement verticale sur TOUS les ecrans, meme vides (constate le 2026-08-26). Le contenu
   a deja sa propre respiration par `.app-content`. */
body {
  margin: 0;
  background: var(--bg); color: var(--text);
  transition: background-color 0.15s ease, color 0.15s ease;
}
.app-shell { display: flex; align-items: stretch; min-height: 100vh; }

/* La marge de gauche prend la couleur de la page et n a plus de trait de separation : les
   onglets flottent sur le meme fond que le contenu, la seule chose qui les distingue est la
   pastille de l onglet actif. */
.sidebar {
  flex: 0 0 var(--sidebar-width);
  position: sticky; top: 0; align-self: flex-start; height: 100vh; overflow-y: auto;
  background: var(--bg);
  display: flex; flex-direction: column;
  padding: var(--space-4) var(--space-3);
}
.sidebar-brand { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-2) var(--space-4); }
.sidebar-logo {
  width: 2.1rem; height: 2.1rem; border-radius: var(--radius-input);
  background: linear-gradient(155deg, var(--gold) 0%, var(--gold-strong) 100%);
  /* Encre fixe (pas var(--text)) : ce badge garde le meme dore dans les deux themes, le texte
     doit donc rester lisible independamment de l'un ou l'autre — cf. contraste calcule dans
     la spec Bloc 8 (le dore ne porte du texte lisible qu'en sombre, jamais en clair). */
  color: #1E293B; font-weight: 700; font-size: 0.76rem; letter-spacing: 0.01em;
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
  box-shadow: 0 2px 10px color-mix(in srgb, var(--gold) 40%, transparent);
}
.sidebar-title { font-size: 1.05rem; font-weight: 600; letter-spacing: -0.015em; color: var(--text-strong); }

/* La zone « Scénario » a été ramenée à ce qui ne fait pas doublon (2026-08-26). Elle portait
   six éléments empilés : intitulé, liste déroulante, ligne « Actif : … », pastilles, deux
   boutons et la plage d'années. Or « Modifier » ne faisait qu'ouvrir l'onglet Événements,
   présent trois centimètres plus haut ; « Actif : … » répétait le nom déjà lisible dans la
   liste ; la plage d'années ne parlait pas du scénario choisi. Reste : la liste, une icône de
   réglages, les pastilles, et une ligne d'état qui n'apparaît QUE pendant une bascule ou en
   cas d'échec de chargement. */
.sidebar-scenario {
  display: flex; flex-direction: column; gap: var(--space-2);
  padding: var(--space-3) var(--space-2); margin-top: var(--space-5);
  border-top: 1px solid var(--border);
}
.sidebar-scenario-label { font-size: 0.68rem; color: var(--muted); font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; }
/* La liste et l'icône de réglages sur une seule ligne, à la MÊME hauteur.
   `height: 2rem` sur les deux, et pas seulement `align-items: center` : la liste n'avait
   aucun habillage (elle restait au dessin brut du navigateur, 19 px de haut) tandis que
   l'icône en faisait 30, ce qui donnait deux boîtes visiblement inégales côte à côte.
   Une hauteur explicite les rend identiques quelle que soit la police du système.
   `min-width: 0` sur la liste : sans lui, un nom de scénario long élargit la barre latérale
   au lieu d'être tronqué. */
.sidebar-scenario-row { display: flex; align-items: center; gap: 0.35rem; }
.sidebar-scenario-row select {
  flex: 1 1 auto; min-width: 0; height: 2rem;
  background: var(--bg-inset); border: 1px solid var(--border); color: var(--text-strong);
  border-radius: var(--radius-btn); padding: 0 0.4rem; font-size: 0.82rem;
}
.sidebar-scenario-reglages {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem; padding: 0;
  background: transparent; border: 1px solid var(--border); border-radius: var(--radius-btn);
  color: var(--muted); cursor: pointer;
  transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
}
.sidebar-scenario-reglages:hover { color: var(--text-strong); background: var(--bg-hover); border-color: var(--border-strong); }
.sidebar-scenario-reglages:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
/* Ligne d'ÉTAT, pas d'identité : « Activation… » pendant la bascule (qui refait un
   aller-retour serveur complet, d'où l'accusé de réception) ou le message d'échec de
   chargement. Vide le reste du temps, et alors invisible — sinon elle laisserait un blanc
   permanent sous la liste. */
.sidebar-scenario-actif {
  margin: 0.1rem 0 0; font-size: 0.72rem; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sidebar-scenario-actif:empty { display: none; }
/* Pastilles « trajectoire réelle » / « isolé » sous le sélecteur — visibles sans ouvrir
   la fenêtre de gestion, pour qu'on sache toujours quel scénario alimente la file « À
   confirmer » sans avoir à s'en souvenir. */
.sidebar-scenario-badges { display: flex; flex-wrap: wrap; gap: 0.3rem; margin: -0.2rem 0 0.3rem; }
.scenario-badge {
  font-size: 0.65rem; font-weight: 600; letter-spacing: 0.02em;
  padding: 0.12rem 0.5rem; border-radius: 999px; white-space: nowrap;
}
.scenario-badge.is-reference { color: var(--gold-text, var(--text-strong)); background: var(--gold-soft); }
.scenario-badge.is-isole { color: var(--muted); background: var(--bg-inset); }
/* --- L'INDICATEUR D'ENREGISTREMENT (socle/indicateur-enregistrement.js) ------------
   DANS LA LIGNE, a cote de ce qu'on vient de modifier : le bandeau flottant du bas est
   reserve aux erreurs qu'il faut lire puis fermer.

   SANS `data-etat`, IL N'EXISTE PAS. Les quatre <span> qu'il remplace occupaient leur place
   en permanence pour un message de trois secondes, et `.params-autosave` allait jusqu'a
   s'imposer un `min-height: 1.2em` : une bande vide reservee au vide. */
.enregistrement { display: none; }
.enregistrement[data-etat] {
  display: inline-flex; align-items: center; gap: 0.35rem;
  /* `.modal-actions` et `.params-actions` sont des rangees flex SANS `align-items` : sans
     cette ligne la pastille s'etirait a la hauteur du bouton voisin. */
  align-self: center;
  padding: 0.15rem 0.55rem; border-radius: 999px;
  background: var(--bg-inset); color: var(--muted);
  font-size: 0.75rem; font-weight: 500; line-height: 1.5;
}
/* La pastille dit l'etat avant qu'on ait lu le mot. */
.enregistrement[data-etat]::before {
  content: ''; flex: none; width: 6px; height: 6px; border-radius: 50%; background: currentColor;
}
.enregistrement[data-etat="cours"]::before { animation: enregistrement-pouls 1.1s ease-in-out infinite; }
.enregistrement[data-etat="ok"] { color: var(--accent-text); background: color-mix(in srgb, var(--accent) 14%, transparent); }
.enregistrement[data-etat="echec"] { color: var(--red-text); background: color-mix(in srgb, var(--red) 14%, transparent); }
@keyframes enregistrement-pouls { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }
@media (prefers-reduced-motion: reduce) {
  .enregistrement[data-etat="cours"]::before { animation: none; }
}
/* Parametres : l'indicateur y est seul, sans bouton a cote. Il porte donc lui-meme sa marge
   haute, plutot qu'un conteneur qui dessinerait une bande meme au repos.
   `flex-start` et non `center` : le panneau est une colonne flex, ou l'axe transversal est
   l'horizontale — la valeur heritee ci-dessus y aurait centre la pastille dans la page, et
   sans elle la pastille s'etirait sur toute la largeur (vu a l'ecran). */
.enregistrement-bloc[data-etat] { margin-top: 1rem; align-self: flex-start; }

.sidebar-nav { display: flex; flex-direction: column; gap: var(--space-1); }
.sidebar-footer {
  margin-top: auto; padding-top: var(--space-4);
  display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
}

/* Rappelle sur quel compte on travaille — utile dès qu'on jongle entre deux comptes.
   `min-width: 0` + `break-all` : une adresse longue doit se couper, pas élargir la barre. */
.compte-connecte {
  flex: 1 1 100%; min-width: 0;
  font-size: 0.7rem; color: var(--muted);
  overflow-wrap: break-word; word-break: break-all;
  margin-bottom: var(--space-1);
}

.tab {
  position: relative;
  display: flex; align-items: center; gap: var(--space-3);
  width: 100%; text-align: left; background: transparent; border: none;
  color: var(--muted); padding: 0.55rem var(--space-3); cursor: pointer;
  font-size: 0.85rem; font-weight: 500; letter-spacing: 0.01em;
  border-radius: var(--radius-btn);
  transition: color 0.15s ease, background-color 0.15s ease;
}
.tab-icon { width: 18px; height: 18px; flex: 0 0 auto; }
.tab:hover { color: var(--text-strong); background: var(--bg-hover); }
.tab.active {
  color: var(--text-strong); font-weight: 600;
  background: var(--gold-soft);
}
.tab.active::before {
  content: ''; position: absolute; left: -0.75rem; top: 20%; bottom: 20%;
  width: 3px; border-radius: 0 3px 3px 0; background: var(--gold);
}

.theme-toggle {
  background: var(--bg-inset); border: none; color: var(--text);
  width: 2.1rem; height: 2.1rem; border-radius: 999px; cursor: pointer;
  font-size: 1rem; display: inline-flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow-btn); transition: box-shadow 0.15s ease, transform 0.15s ease;
}
.theme-toggle:hover { box-shadow: var(--shadow-btn-hover); transform: translateY(-1px); }

.app-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }

.app-content { flex: 1 1 auto; width: 100%; padding: var(--space-6) var(--space-6) var(--space-6); }
.panel { display: none; }
.panel.active { display: flex; flex-direction: column; gap: var(--space-5); }
/* Les cartes apparaissent en fondu, légèrement décalées, à chaque bascule d'onglet — pas
   à chaque recalcul du tableau de bord : le passage display:none -> flex ci-dessus est ce
   qui rejoue l'animation, une seule fois par bascule (chantier 2 - animations, 2026-08-30).
   nth-of-type compte par groupe de frères, pas dans tout le panneau : l'effet de décalage
   porte surtout sur les cartes voisines d'une même rangée, ce qui reste le cas le plus vu. */
@keyframes carte-apparait {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}
.panel.active .card { animation: carte-apparait 0.4s ease both; }
.panel.active .card:nth-of-type(2) { animation-delay: 0.05s; }
.panel.active .card:nth-of-type(3) { animation-delay: 0.1s; }
.panel.active .card:nth-of-type(4) { animation-delay: 0.15s; }
.panel.active .card:nth-of-type(5) { animation-delay: 0.2s; }
.panel.active .card:nth-of-type(6) { animation-delay: 0.25s; }
.event-modal-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: 12px; }
.event-modal-tab { padding: 8px 12px; border: none; background: none; color: var(--muted); cursor: pointer; }
.event-modal-tab[disabled] { opacity: 0.35; cursor: not-allowed; }
.event-modal-tab.active { color: var(--text-strong); border-bottom: 2px solid var(--gold); font-weight: 600; }
.event-modal-panel[hidden] { display: none; }
h2 { font-size: 1.05rem; font-weight: 600; letter-spacing: -0.005em; margin: 0 0 0.5rem; color: var(--text-strong); }
.hint { font-size: 0.75rem; color: var(--muted); line-height: 1.45; margin: 0 0 0.5rem; }
.section-head-row .info-tip { margin-left: 0.35rem; }
.info-tip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; border-radius: 50%; flex: 0 0 auto;
  background: var(--bg-inset); color: var(--muted);
  font-size: 0.62rem; font-style: normal; font-weight: 700; line-height: 1;
  cursor: help; position: relative; vertical-align: middle;
}
.info-tip:hover, .info-tip:focus { color: var(--accent-text); outline: none; }
.info-tip .info-tip-bubble {
  display: none; position: absolute; z-index: 20; top: 135%; left: 0;
  width: max-content; max-width: 240px; background: var(--card); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius-input);
  box-shadow: var(--shadow-card); padding: 0.5rem 0.65rem;
  font-size: 0.72rem; font-weight: 400; font-style: normal; line-height: 1.4; white-space: normal;
  cursor: default;
}
.info-tip:hover .info-tip-bubble, .info-tip:focus .info-tip-bubble { display: block; }
.card {
  background: var(--card); box-shadow: var(--shadow-card);
  border-radius: var(--radius-card); padding: 1rem;
}
.card.inner { background: var(--card-inner); box-shadow: none; }
.kpi-row {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  background: var(--card); box-shadow: var(--shadow-card-sm); border-radius: var(--radius-card);
  padding: 0.3rem 0; margin-bottom: 1.1rem; overflow: hidden;
}
/* display:grid l'emporte sur la règle UA [hidden] — même piège que .subtabs[hidden] /
   .modal-overlay[hidden] : sans ce !important, une kpi-row vide reste visible comme un
   bloc carte vide. */
.kpi-row[hidden] { display: none !important; }


/* === UNE BANDE VIDE NE SE DESSINE PAS =============================================
   Le defaut est toujours le meme : un conteneur porte son trait de separation, sa marge ou
   son fond DANS SA REGLE DE BASE, et les dessine donc meme quand il n'a rien a montrer. Le
   pied du graphique Patrimoine laissait ainsi un trait et une bande de vide des que la sante
   de tresorerie manquait ; la barre collante d'Evenements reservait 4,5 rem pour un message
   de trois secondes (traitee au Bloc 1, `.scenario-sticky-bar`).

   La convention, en un seul endroit : le conteneur disparait quand il est vide. `:empty`
   ajoute une classe de specificite, donc cette regle l'emporte sur la regle de base meme
   quand celle-ci vit dans une feuille chargee plus tard.

   ATTENTION : `:empty` compte les espaces comme du contenu. Un rendu qui vide un conteneur
   doit ecrire `innerHTML = ''`, jamais un gabarit reduit a un saut de ligne. */
.hint:empty,
.chart-footnote:empty,
.endettement-mini:empty,
.alertes:empty,
.hyp-legend:empty,
.kpi-row:empty,
.catalog-segments:empty,
.catalog-wizard-fields:empty,
.comparer-grid:empty,
.flux-dated-list:empty,
.flux-liste:empty,
.revenu-cards:empty,
.computed-net:empty,
.structure-titre:empty,
.sidebar-scenario-badges:empty { display: none; }
