:root {
  --fond: #f5f4f1;
  --carte: #ffffff;
  --texte: #1c1c1a;
  --texte-att: #6b6a66;
  --bordure: #e2e0da;
  /* Or du logo (23/09/2026), assombri pour rester lisible sur un fond clair :
     #d4af37 tel quel ne rend que 1,95:1 sur #f5f4f1, tres sous le seuil AA. Cette
     teinte-ci reste dans la meme famille (H=45, un or franc) a 5,05:1. */
  --accent: #856300;
  --positif: #1e7a4a;
  --negatif: #b8412f;
  --alerte-fond: #fbf0dc;
  --alerte-bordure: #e3b04b;
  /* Bleu-gris des icones d'action et des sous-titres. #6b7f8a ne donnait que
     4,18:1 sur blanc, sous le seuil AA de 4,5. Meme teinte, assombrie : 5,16:1
     sur une carte et 4,69:1 sur le fond. */
  --action: #5e7079;
  --sur-accent: #ffffff;
  --sous-total: #fafaf7;
  --entete: #ecebe6;
  --erreur-fond: #fbe6e2;
  --voile: rgba(128, 128, 128, 0.08);
  --voile-accent: rgba(133, 99, 0, 0.09);
  --grille: rgba(28, 28, 26, 0.10);
  --courbe-valeur: #856300;
  --courbe-performance: #8a5fb0;
  --point-flux: #c98a3a;
  --point-flux-nc: #c0392b;
  --courbe-moyenne: #8a8f7a;
  /* Effet de verre des encadres (24/09/2026) : translucide sur `--carte`, jamais une
     couleur en dur, pour suivre le theme sans etre redeclare a chaque bascule. */
  --verre: color-mix(in srgb, var(--carte) 78%, transparent);
  --verre-fond: color-mix(in srgb, var(--fond) 82%, transparent);
  color-scheme: light;
}

/* --- Theme sombre -----------------------------------------------------------
   Structure reprise de la palette « Financial Dashboard » du skill ui-ux-pro-max.
   L'accent a d'abord ete un vert (#2f5d50 puis #6b9e8f, choisi pour ses 6,64:1 sur
   ce fond) avant de devenir l'or du logo le 23/09/2026 : #d4af37 rend 9,59:1 ici,
   large marge au-dessus du seuil AA — l'or clair passe tres facilement sur un fond
   sombre, contrairement au fond clair ou il faut l'assombrir (voir plus haut).

   Trois etats, et l'ordre compte : le systeme d'abord, puis le choix explicite qui
   le supplante dans les deux sens. `:not([data-theme="clair"])` permet de forcer le
   clair sur une machine reglee en sombre. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="clair"]) {
    --fond: #020617;
    --carte: #0e1223;
    --texte: #f8fafc;
    --texte-att: #94a3b8;
    --bordure: #334155;
    --accent: #d4af37;
    --positif: #22c55e;
    --negatif: #f87171;
    --action: #94a3b8;
    --alerte-fond: #2a2110;
    --alerte-bordure: #e3b04b;
    --sur-accent: #051014;
    --sous-total: #131a30;
    --entete: #161d33;
    --erreur-fond: #3a1a1a;
    --voile: rgba(148, 163, 184, 0.10);
    --voile-accent: rgba(212, 175, 55, 0.16);
    --grille: rgba(248, 250, 252, 0.10);
    --courbe-valeur: #d4af37;
    --courbe-performance: #b794e6;
    --point-flux: #e0a355;
    --point-flux-nc: #f87171;
    --courbe-moyenne: #a3a99a;
    color-scheme: dark;
  }
}

:root[data-theme="sombre"] {
  --fond: #020617;
  --carte: #0e1223;
  --texte: #f8fafc;
  --texte-att: #94a3b8;
  --bordure: #334155;
  --accent: #d4af37;
  --positif: #22c55e;
  --negatif: #f87171;
  --action: #94a3b8;
  --alerte-fond: #2a2110;
  --alerte-bordure: #e3b04b;
  --sur-accent: #051014;
  --sous-total: #131a30;
  --entete: #161d33;
  --erreur-fond: #3a1a1a;
  --voile: rgba(148, 163, 184, 0.10);
  --voile-accent: rgba(212, 175, 55, 0.16);
  --grille: rgba(248, 250, 252, 0.10);
  --courbe-valeur: #d4af37;
  --courbe-performance: #b794e6;
  --point-flux: #e0a355;
  --point-flux-nc: #f87171;
  --courbe-moyenne: #a3a99a;
  color-scheme: dark;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  background: var(--fond);
  color: var(--texte);
}

/* Le theme « fenetre en verre » de la connexion (24/09/2026), etendu a tout le
   site : ces encadres flottent sur le halo de `.fond-logo` plutot que de le
   couvrir d'un aplat. Les tableaux et les controles de formulaire restent
   opaques — l'audit d'accessibilite du 31/08/2026 a deja etabli qu'une donnee
   dense ne doit rien perdre en contraste, et un `<select>` ou une case a cocher
   de quelques pixels n'a rien a gagner d'un flou qu'on n'y verrait pas. */
.nav-principale,
.carte,
.statistiques .tuile,
.carte-reglage,
.dialogue-carte,
.ajout-carte form {
  background: var(--verre);
  backdrop-filter: blur(20px) saturate(1.3);
  -webkit-backdrop-filter: blur(20px) saturate(1.3);
}

.nav-principale {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  padding: 0.9rem 1.5rem;
  border-bottom: 1px solid var(--bordure);
}

.nav-titre {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 700;
  margin-right: 1rem;
  color: var(--accent);
}
/* Le fond noir du rendu d'origine a ete detoure (23/09/2026) : le sigle est
   maintenant sur fond transparent, et se pose directement sur la barre, claire ou
   sombre, sans vignette ni pastille autour. */
.logo-marque { display: block; height: 34px; width: auto; }

.nav-principale a {
  color: var(--texte-att);
  text-decoration: none;
  font-size: 0.95rem;
  padding: 0.3rem 0;
  border-bottom: 2px solid transparent;
}

.nav-principale a.actif,
.nav-principale a:hover {
  color: var(--texte);
  border-bottom-color: var(--accent);
}

main {
  max-width: 1100px;
  margin: 0 auto;
  padding: 1.5rem;
}

h1 { font-size: 1.4rem; margin-bottom: 0.2rem; }
.titre-profil { display: flex; align-items: center; gap: 0.6rem; }
.logo-profil { display: block; border-radius: 7px; }
h2 { font-size: 1.1rem; margin-top: 2rem; }

.cartes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 0.9rem;
  margin: 1rem 0;
}

.carte {
  border: 1px solid var(--bordure);
  border-radius: 8px;
  padding: 0.9rem 1rem;
}

.carte .libelle { font-size: 0.8rem; color: var(--texte-att); }
.carte .valeur { font-size: 1.3rem; font-weight: 600; }
.carte .lien-bouton { display: block; margin-top: 0.3rem; font-size: 0.8rem; }

/* La tuile « Salaire net » en edition (25/09/2026) : meme carte, un champ et deux
   boutons a la place du chiffre et du lien. */
.carte-edition-salaire input[name="mensuel"] {
  display: block;
  width: 100%;
  font-size: 1.1rem;
  font-variant-numeric: tabular-nums;
  margin: 0.2rem 0 0.5rem;
}
.carte-edition-salaire .actions-carte { display: flex; gap: 0.5rem; flex-wrap: wrap; }

.bandeau-alerte {
  background: var(--alerte-fond);
  border: 1px solid var(--alerte-bordure);
  border-radius: 6px;
  padding: 0.6rem 0.9rem;
  margin: 1rem 0;
  font-size: 0.9rem;
}

table {
  width: 100%;
  border-collapse: collapse;
  background: var(--carte);
  font-size: 0.9rem;
}

th, td {
  padding: 0.5rem 0.6rem;
  border-bottom: 1px solid var(--bordure);
  text-align: right;
}

th:first-child, td:first-child,
th.gauche, td.gauche { text-align: left; }

th {
  color: var(--texte-att);
  font-weight: 600;
  font-size: 0.78rem;
  text-transform: uppercase;
  cursor: pointer;
  white-space: nowrap;
}

/* Les en-tetes triables sont des boutons depuis le 31/08/2026 : un `<a href="#">`
   ne mene nulle part et s'annonce comme un lien vers le haut de page. */
th a, th button {
  color: inherit;
  text-decoration: none;
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  cursor: pointer;
}
th.tri-actif { color: var(--accent); }

tr.sous-total td {
  font-weight: 600;
  background: var(--sous-total);
}

tr.total td {
  font-weight: 700;
  border-top: 2px solid var(--bordure);
}

.positif { color: var(--positif); }
.negatif { color: var(--negatif); }
.att { color: var(--texte-att); font-style: italic; }

.filtres {
  display: flex;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin: 1rem 0;
}

.filtres select {
  padding: 0.3rem 0.5rem;
  border: 1px solid var(--bordure);
  border-radius: 6px;
  background: var(--carte);
}

.legende {
  font-size: 0.8rem;
  color: var(--texte-att);
  margin: 0.4rem 0 1rem;
}

.badge-flux {
  background: var(--alerte-fond);
  border: 1px solid var(--alerte-bordure);
  border-radius: 4px;
  padding: 0 0.3rem;
  font-size: 0.75rem;
}

.actions { white-space: nowrap; font-size: 0.85rem; }
.actions a, .actions button {
  color: var(--accent);
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  cursor: pointer;
  text-decoration: none;
}
.actions a:hover, .actions button:hover { text-decoration: underline; }

tr.inactif td { color: var(--texte-att); font-style: italic; }

/* --- Collection Pokemon : possedee / non possedee ------------------------------
   Demande le 08/09/2026 : « grise quand pas possede, pas grise quand possede ».
   Le gris est celui des lignes inactives — un jeton deja verifie a 4,5:1 dans les
   deux themes — et non une opacite, qui abaisserait le contraste sans le dire. */
tr.non-possedee td { color: var(--texte-att); }

.coche-cellule { text-align: center; white-space: nowrap; }

/* La coche « possedee », rendue cliquable le 09/09/2026.

   C'est une CASE DESSINEE, pas un glyphe : « ☑ » et « ☐ » n'ont ni la meme chasse ni
   le meme dessin d'une police a l'autre, et la colonne ondulait. Un carre en CSS se
   pose au pixel, garde la meme taille cochee ou non, et prend la couleur d'accent
   sans dependre du rendu des emoji.

   La cible fait 30 px, 44 sur un ecran tactile : c'est la regle du 31/08/2026 sur les
   actions de ligne, et elle vaut d'autant plus ici qu'on parcourt neuf cents lignes
   au doigt. */
.coche {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: none;
  background: none;
  border-radius: 6px;
  cursor: pointer;
}
.coche .case {
  display: block;
  width: 17px;
  height: 17px;
  border: 2px solid var(--texte-att);
  border-radius: 4px;
  background: var(--carte);
  transition: background-color 0.12s ease, border-color 0.12s ease;
}
/* Cochee : la case se remplit d'accent et porte une vraie coche, tracee avec deux
   bords d'un rectangle vide qu'on fait pivoter. Pas de glyphe, donc rien qui depende
   de la police installee. */
.coche.oui .case {
  background: var(--accent);
  border-color: var(--accent);
  position: relative;
}
.coche.oui .case::after {
  content: "";
  position: absolute;
  left: 4px;
  top: 0;
  width: 5px;
  height: 10px;
  border: solid var(--sur-accent);
  border-width: 0 2.5px 2.5px 0;
  transform: rotate(42deg);
}
.coche:hover { background: var(--voile-accent); }
.coche:hover .case { border-color: var(--accent); }
.coche:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Le survol d'une ligne fait ressortir sa case : on suit des yeux la ligne qu'on
   s'apprete a cocher, pas la colonne entiere. */
tr:hover .coche.non .case { border-color: var(--action); }

/* Diamant & Perle, une ligne par carte : trois cases de tirage empilees dans la
   meme cellule plutot qu'une ligne par tirage. Demande le 23/09/2026. */
.tirages-carte { min-width: 13rem; }
.etat-carte { min-width: 6rem; }

/* La miniature d'une carte, ajoutee le 23/09/2026 pour le bloc Diamant & Perle
   seul. Taille uniforme et `object-fit: contain` : les cartes n'ont pas toutes
   le meme cadrage source, et une image etiree serait pire qu'une absente. */
.miniature-carte { width: 4.5rem; }
.miniature-bouton {
  display: block;
  width: 60px;
  height: 84px;
  padding: 0;
  border: none;
  border-radius: 8px;
  background: var(--fond-alt, var(--fond));
  cursor: zoom-in;
  overflow: hidden;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.miniature-bouton:hover, .miniature-bouton:focus-visible {
  transform: scale(1.05);
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.22);
}
.miniature-bouton:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.miniature-bouton img { display: block; width: 100%; height: 100%; object-fit: contain; }
.miniature-manquante {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 60px;
  height: 84px;
}

/* L'agrandissement au clic : un <dialog> natif et unique, partage par les neuf
   cents miniatures du bloc — il porte deja la fermeture au clavier (Echap) et le
   focus-trap, sans rien a ecrire pour ca. Meme image que la miniature : elle est
   deja en haute resolution, l'agrandir ne la degrade pas. */
.dialogue-carte {
  position: relative;
  border: none;
  border-radius: 12px;
  padding: 1rem;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
  max-width: min(90vw, 420px);
}
.dialogue-carte::backdrop { background: rgba(0, 0, 0, 0.55); }
.dialogue-carte img { display: block; width: 100%; height: auto; border-radius: 8px; }
.dialogue-carte .fermer-dialogue {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  width: 32px;
  height: 32px;
  border: none;
  border-radius: 6px;
  background: var(--fond-alt, var(--fond));
  cursor: pointer;
}
.dialogue-carte .fermer-dialogue:hover { background: var(--voile-accent); }

/* La fenetre de modification d'une carte (16/10/2026) : un <dialog> natif, unique pour
   les trois blocs. L'image de la carte a gauche, les champs a droite — on voit ce qu'on
   corrige pendant qu'on le corrige. Fond OPAQUE (`--carte`) : une fenetre de saisie ne
   gagne rien a la transparence, et le contraste d'un formulaire passe avant le style. */
.dialogue-edition {
  border: 1px solid var(--bordure);
  border-radius: 12px;
  padding: 0;
  color: var(--texte);
  background: var(--carte);
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.45);
  width: min(52rem, 94vw);
  max-height: 92vh;
  overflow: auto;
}
.dialogue-edition::backdrop { background: rgba(0, 0, 0, 0.6); }
.dialogue-edition-interieur { position: relative; padding: 1.2rem 1.4rem 1.3rem; }
.dialogue-edition .fermer-dialogue {
  position: absolute;
  top: 0.6rem;
  right: 0.6rem;
  width: 32px;
  height: 32px;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--texte-att);
  cursor: pointer;
}
.dialogue-edition .fermer-dialogue:hover { background: var(--voile-accent); color: var(--texte); }
.dialogue-edition .fermer-dialogue:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.edition-corps { display: flex; gap: 1.4rem; align-items: flex-start; }
.edition-miniature { flex: none; width: 240px; }
.edition-miniature img { display: block; width: 100%; height: auto; border-radius: 10px; }
.edition-miniature img[hidden], .edition-sans-image[hidden] { display: none; }
/* Le bouton qui ouvre la fenetre d'ajout, dans l'en-tete de chaque bloc a la main. */
.barre-ajout { margin: 0.9rem 0; }
.bouton-ajout { font-weight: 600; }
.edition-sans-image {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 5 / 7;
  text-align: center;
  padding: 1rem;
  border: 1px dashed var(--bordure);
  border-radius: 10px;
}
.edition-champs { flex: 1 1 auto; min-width: 0; padding-right: 1.6rem; }
.edition-champs .titre-panneau { font-size: 1.05rem; }
#dialogue-edition-erreur:empty { display: none; }
#dialogue-edition-erreur { margin-top: 0.6rem; }
/* Sur un ecran etroit l'image passe AU-DESSUS, plus petite : les champs gardent toute la
   largeur, et la carte reste visible sans manger la fenetre. */
@media (max-width: 700px) {
  .edition-corps { flex-direction: column; align-items: stretch; }
  .edition-miniature { width: 140px; align-self: center; }
  .edition-champs { padding-right: 0; }
}
/* ITEMS SCELLES (09/11/2026). Une photo de produit n'a pas le format d'une carte : en
   miniature elle est CARREE et recadree (`cover`) pour que la colonne reste alignee ; dans
   la fenetre elle est montree ENTIERE (`contain`), puisque c'est la qu'on verifie qu'on a
   la bonne. */
.miniature-bouton:has(.photo-scelle) { height: 60px; }
.photo-scelle { width: 60px; height: 60px; object-fit: cover; display: block; }
.edition-miniature .apercu-scelle { aspect-ratio: 1; object-fit: contain;
                                    background: var(--fond-alt, var(--fond)); }
#formulaire-scelle .edition-sans-image { aspect-ratio: 1; }
.choix-photo { display: block; margin-top: 0.7rem; font-weight: 600; }
.choix-photo input { display: block; margin-top: 0.3rem; max-width: 100%; font-weight: normal; }
.etat-photo { margin: 0.3rem 0; font-size: 0.85rem; }
.etat-photo:empty { display: none; }
.ligne-tirage {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.1rem 0;
  white-space: nowrap;
}
.ligne-tirage .nom-tirage { min-width: 4.2rem; }

/* Visible des lecteurs d'ecran, invisible a l'oeil. Le glyphe seul se prononce
   « ballot box with check », ce qui n'apprend rien. */
.lecteur-ecran {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

tr.ligne-erreur td {
  background: var(--erreur-fond);
  color: var(--negatif);
  font-size: 0.85rem;
  text-align: left;
}

td input, td select {
  width: 100%;
  padding: 0.2rem 0.3rem;
  border: 1px solid var(--bordure);
  border-radius: 4px;
  font: inherit;
}

/* Rafraichissement des cotations (jalon 4) */
button.rafraichir { margin-left: auto; }
.htmx-indicator { opacity: 0; transition: opacity 0.2s; }
.htmx-request .htmx-indicator, .htmx-request.htmx-indicator { opacity: 1; }
.rapport-cotations {
  margin: 0.6rem 0;
  padding: 0.5rem 0.8rem;
  border-left: 3px solid var(--texte-att);
  background: var(--voile);
  font-size: 0.9em;
}
.rapport-cotations ul { margin: 0.2rem 0 0.4rem 1.2rem; }
.rapport-cotations details summary { cursor: pointer; }

/* Historique : bascule entre les deux courbes (jalon 5) */
.bascule-courbes { display: flex; gap: 0.4rem; margin: 0.8rem 0 0.4rem; }
.bascule-courbes button.actif { background: var(--accent); color: var(--sur-accent); }
.bascule-courbes button[disabled] { opacity: 0.45; cursor: not-allowed; }
.avertissement {
  margin: 0.6rem 0;
  padding: 0.5rem 0.8rem;
  border-left: 3px solid #c98a3a;
  background: rgba(201, 138, 58, 0.09);
  font-size: 0.9em;
}

/* Saisie rapide dans une cellule (prix de revient) */
.cellule-saisie { white-space: nowrap; }
/* Les actions de ligne. Elles etaient a `opacity: 0`, revelees au survol : sur un
   telephone, ou le survol n'existe pas, elles devenaient introuvables. Elles sont
   desormais toujours visibles, discretes, et se renforcent au survol.

   Taille : 24x24 est le minimum WCAG 2.5.8 (AA) pour un pointeur ; les appareils
   tactiles passent a 44x44 plus bas. Trois icones voisines dont une desactive une
   position, la cible ne peut pas rester a 20x16. */
button.icone {
  border: none;
  background: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  min-height: 24px;
  padding: 0 0.15rem;
  font-size: 0.95em;
  color: var(--action);
  opacity: 0.65;
  border-radius: 4px;
  transition: opacity 0.12s, background 0.12s;
}
tr:hover button.icone, button.icone:focus { opacity: 1; }
button.icone:hover { color: var(--accent); background: var(--voile-accent); }

/* Aucun survol : appareil tactile. Les actions sont pleinement visibles et la cible
   passe a 44x44, la taille recommandee pour le doigt. */
@media (hover: none) {
  button.icone { opacity: 1; min-width: 44px; min-height: 44px; }
  /* La coche suit la meme regle, et elle y a d'autant plus droit qu'on parcourt neuf
     cents lignes au doigt. */
  .coche { width: 44px; height: 44px; }
}
.cellule-saisie input { width: 6rem; }
/* Seconde ligne du formulaire d'edition : zone, secteur, compte */
tr.ligne-detail > td { border-top: none; padding-top: 0; }
tr.ligne-detail label { margin-right: 1rem; font-size: 0.9em; color: var(--action); }

/* ---- Tableau des investissements, mise en page compacte (27/08/2026) ---- */
.tableau-positions { font-size: 0.92rem; }
.tableau-positions th.chiffre, .tableau-positions td:not(.gauche) { text-align: right; }
.tableau-positions td { vertical-align: middle; padding: 0.45rem 0.6rem; }

/* Deux informations dans une cellule : la seconde en retrait */
.sous-titre {
  display: block;
  font-size: 0.8em;
  color: var(--texte-att);
  font-weight: 400;
  margin-top: 0.1rem;
}
.cellule-position { min-width: 15rem; }
.titre-position { font-weight: 600; }
.fort { font-weight: 600; }
.discret {
  text-decoration: none;
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
}

/* Pastille de classe d'actif */
.pastille {
  display: inline-block;
  width: 0.55rem; height: 0.55rem;
  border-radius: 50%;
  margin-right: 0.45rem;
  vertical-align: baseline;
}
.pastille-action { background: var(--accent); }
.pastille-fonds  { background: #4a7fb5; }
.pastille-or     { background: #c98a3a; }
.pastille-crypto { background: #8a5fb0; }

/* Allocation : une barre plutot qu'un nombre isole */
.cellule-allocation { white-space: nowrap; min-width: 7rem; }
.barre {
  display: inline-block;
  width: 3.2rem; height: 0.45rem;
  background: var(--bordure);
  border-radius: 3px;
  overflow: hidden;
  vertical-align: middle;
  margin-right: 0.4rem;
}
.barre-remplie { display: block; height: 100%; background: var(--accent); }
.part { font-variant-numeric: tabular-nums; }

/* En-tete de groupe : le sous-total au-dessus des lignes qu'il resume */
tr.entete-groupe td {
  background: var(--entete);
  border-top: 1px solid var(--bordure);
  font-weight: 600;
  padding-top: 0.55rem;
  padding-bottom: 0.55rem;
}
tr.entete-groupe td:first-child { font-weight: 700; }

/* L'en-tete d'une extension : logo, nom, poids, completion, sur une seule ligne qui
   se replie proprement si la fenetre est etroite. Un filet d'accent a gauche pour
   qu'on retrouve les debuts de section en faisant defiler neuf cents lignes. */
.titre-extension {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  border-left: 3px solid var(--accent);
  padding-left: 0.7rem;
  min-height: 2.4rem;
}
.titre-extension .nom-extension { font-size: 1.02rem; letter-spacing: 0.01em; }
.titre-extension .att { font-weight: 400; }

/* La completion, en pastille : la jauge donne l'ordre de grandeur d'un coup d'oeil,
   le chiffre donne la reponse exacte. Les deux, parce qu'une barre seule ne se lit
   pas au dixieme et qu'un rapport seul ne se compare pas d'une section a l'autre. */
.completion {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.15rem 0.5rem;
  border: 1px solid var(--bordure);
  border-radius: 999px;
  background: var(--carte);
}
.jauge-completion {
  display: block;
  width: 3.5rem;
  height: 6px;
  border-radius: 999px;
  background: var(--voile);
  overflow: hidden;
}
.jauge-completion > span {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--accent);
}
.completion-chiffre {
  font-size: 0.8rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--texte-att);
}

/* Panneau d'edition */
tr.ligne-edition > td { background: var(--carte); padding: 0.9rem 1rem; }
.panneau-edition {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem 1.1rem;
}
.panneau-edition label {
  display: flex;
  flex-direction: column;
  font-size: 0.8rem;
  color: var(--texte-att);
  gap: 0.2rem;
}
.panneau-edition label.large { flex: 1 1 18rem; }
.panneau-edition input, .panneau-edition select { font-size: 0.92rem; padding: 0.25rem 0.4rem; }
/* Un menu se dimensionne sur son option la plus longue, jamais sur la colonne qui
   l'accueille. C'est le defaut signale le 09/09/2026 : « Near Mint » etait coupe par
   une cellule reglee sur la largeur du mot « État », fleche du menu deduite. Dans un
   panneau il n'y a plus de colonne, mais `width: auto` le dit explicitement — la
   regle globale `td select { width: 100% }` s'applique encore ici. */
.panneau-edition select { width: auto; max-width: 100%; }

/* Les deux champs de gradation (societe, note) voyagent par paire — le nom ou la
   note personnalises juste a cote du menu qui les revele. Ajoute le 24/09/2026.
   `.panneau-edition label` (une classe + un type) l'emporterait sur le `[hidden]`
   de l'UA sans la regle explicite ci-dessous, plus specifique. */
.groupe-gradation { display: flex; gap: 0.7rem; flex-wrap: wrap; }
.panneau-edition label.champ-gradation-autre[hidden] { display: none; }

/* En-tete du panneau : de quelle carte on parle. Sans lui, un panneau sur toute la
   largeur perd le seul reperage que les cellules donnaient. */
.titre-panneau {
  margin: 0 0 0.7rem;
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  flex-wrap: wrap;
}
/* ---- Bandeau de statistiques de la collection (10/09/2026) ----------------
   Il y avait trois cartes de meme poids, qui se lisaient comme une liste sans dire
   laquelle repondait a quelle question. La grille est maintenant hierarchisee : deux
   tuiles larges portent ce qu'on vient chercher — combien ca vaut, ou j'en suis — et
   les deux petites completent. Motif « bento » du skill ui-ux-pro-max, tenu avec les
   jetons du projet : aucun ton importe, et pas d'agrandissement au survol qui jurerait
   avec la sobriete des autres pages. */
.statistiques {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.9rem;
  margin: 1.1rem 0;
}
.statistiques .tuile {
  border: 1px solid var(--bordure);
  border-radius: 10px;
  padding: 0.95rem 1.1rem;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
}
.statistiques .tuile-large { grid-column: span 2; }
.tuile-libelle {
  margin: 0;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--texte-att);
}
.tuile-valeur {
  margin: 0;
  font-size: 1.6rem;
  font-weight: 700;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
  /* Un chiffre long ne doit pas casser la tuile : il retrecit avant de deborder. */
  overflow-wrap: anywhere;
}
.tuile-large .tuile-valeur { font-size: 2rem; }
.tuile-sur { font-size: 1.1rem; font-weight: 600; color: var(--texte-att); }
.tuile-pourcent {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--accent);
  margin-left: 0.5rem;
}
.tuile-note { margin: 0; font-size: 0.82rem; color: var(--texte-att); }
.jauge-completion.large { width: 100%; height: 9px; margin: 0.35rem 0 0.15rem; }

.statistiques .tuile-pleine { grid-column: 1 / -1; gap: 0.55rem; }

/* Le top 5, dans la synthese. Une liste ordonnee et non un tableau : cinq lignes de
   meme forme n'ont pas besoin d'en-tetes, et `<ol>` porte le classement. La grille
   tient les quatre colonnes alignees d'une ligne a l'autre — rang, carte, barre,
   montant — ce qu'une suite de `flex` ne ferait pas. */
.podium {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.15rem;
}
.podium li {
  display: grid;
  grid-template-columns: 1.6rem minmax(0, 1fr) minmax(3rem, 8rem) auto;
  align-items: center;
  gap: 0.7rem;
  padding: 0.4rem 0.3rem;
  border-radius: 6px;
}
.podium li:hover { background: var(--voile); }

/* Le rang. Le premier est plein, les autres en retrait : le classement se voit avant
   d'etre lu, sans qu'aucune information ne tienne a la seule couleur — le chiffre est
   ecrit dans la pastille. */
.podium .rang {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 50%;
  font-size: 0.78rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  background: var(--voile);
  color: var(--texte-att);
}
.podium li:first-child .rang { background: var(--accent); color: var(--sur-accent); }

.podium-carte { display: flex; flex-direction: column; min-width: 0; }
/* Le nom se REPLIE plutot que de se couper. C'est la regle « compact label overflow »
   du skill : on ne cache pas un libelle derriere une info-bulle de survol, qui
   n'existe ni au doigt ni au clavier. Sur cinq lignes, une deuxieme ligne de temps en
   temps coute moins qu'un nom tronque. Le detail, lui, est secondaire et se coupe. */
.podium-nom { font-weight: 600; overflow-wrap: anywhere; }
.podium-detail {
  font-size: 0.78rem;
  color: var(--texte-att);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.podium-detail .numero-carte { color: inherit; }

.podium-barre {
  height: 7px;
  border-radius: 999px;
  background: var(--voile);
  overflow: hidden;
}
.podium-barre > span {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--accent);
}
.podium-valeur {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Sous 700 px la barre cede la place : le nom et le montant sont l'essentiel, et une
   barre de deux centimetres ne compare plus rien. */
@media (max-width: 700px) {
  .podium li { grid-template-columns: 1.6rem minmax(0, 1fr) auto; }
  .podium-barre { display: none; }
}

/* La repartition par societe de gradation (24/09/2026), dans son propre bloc de
   statistiques. Meme grille que le podium (nom, barre, valeur) mais sans rang : ce
   n'est pas un classement de cartes individuelles, seulement une repartition —
   `.podium-nom`/`.podium-barre`/`.podium-valeur` sont reprises telles quelles pour la
   typographie, sans le style `.podium`, pense pour quatre colonnes. */
.repartition-societes {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.15rem;
}
.repartition-societes li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(3rem, 8rem) auto;
  align-items: center;
  gap: 0.7rem;
  padding: 0.3rem;
}
@media (max-width: 700px) {
  .repartition-societes li { grid-template-columns: minmax(0, 1fr) auto; }
  .repartition-societes .podium-barre { display: none; }
}

/* L'infobulle sur « Prix moyen » (24/09/2026) : un `title` natif, comme celui deja
   pose sur la jauge de completion — pas de bibliotheque de tooltip, le projet ne
   charge que des statiques deja presents. `tabindex="0"` la rend atteignable au
   clavier, ce que la jauge de completion n'a pas besoin d'etre (elle est deja
   doublee d'un chiffre ecrit en clair juste a cote). */
.aide {
  cursor: help;
  border-bottom: 1px dotted var(--texte-att);
}
.aide:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* La repartition entre les deux blocs : une lecture secondaire, donc une ligne et non
   des tuiles — lui donner le meme poids qu'a la valeur totale brouillerait la
   hierarchie qu'on vient d'etablir. */
.repartition-blocs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.8rem;
  margin: 0 0 1.1rem;
  font-size: 0.88rem;
  color: var(--texte-att);
}
.repartition-blocs strong { color: var(--texte); margin-right: 0.4rem; }

@media (max-width: 900px) {
  .statistiques { grid-template-columns: repeat(2, 1fr); }
  .statistiques .tuile-large { grid-column: span 2; }
}
@media (max-width: 520px) {
  .statistiques { grid-template-columns: 1fr; }
  .statistiques .tuile-large { grid-column: span 1; }
  .tuile-large .tuile-valeur { font-size: 1.6rem; }
}

/* ---- Les deux blocs de la collection (10/09/2026) -------------------------
   Ils ne se lisent pas de la meme facon — l'un a un catalogue derriere lui, l'autre
   est tenu a la main — donc ils ne partagent plus un tableau. Le filet superieur et
   l'espace qui les separe disent qu'on change de sujet, pas de page. */
.bloc-collection {
  margin: 1.6rem 0;
  padding-top: 1.1rem;
  border-top: 2px solid var(--bordure);
}
.bloc-collection > .entete-bloc {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.entete-bloc h2 { margin: 0 0 0.15rem; }
.entete-bloc .legende { margin: 0; max-width: 60ch; }
.entete-bloc .actions-bloc { margin: 0; }

/* Le bouton qui replie la section « Autres » (24/09/2026), dans `.actions-bloc` —
   meme emplacement que « Tout déplier »/« Tout plier » du bloc precedent. */
.chevron-icone { font-size: 0.85em; }

/* La rangee de boutons d'une page : ils vivaient chacun dans un `<form class="filtres">`
   empile, ce qui les mettait sur trois lignes separees par des blancs. */
.barre-actions {
  display: flex;
  gap: 0.6rem;
  flex-wrap: wrap;
  align-items: center;
  margin: 0.9rem 0;
}
.barre-actions form { margin: 0; }

/* Le formulaire d'ajout d'une carte, replie par defaut : on ajoute de temps en temps,
   on consulte tous les jours. */
.ajout-carte { margin: 0.9rem 0; }
.ajout-carte summary {
  cursor: pointer;
  color: var(--accent);
  font-weight: 600;
  padding: 0.2rem 0;
}
.ajout-carte summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.ajout-carte form {
  border: 1px solid var(--bordure);
  border-radius: 6px;
  padding: 0.9rem 1rem;
  margin-top: 0.5rem;
}

/* La recherche interactive du formulaire d'ajout (16/10/2026) : les cartes que le
   catalogue connait, sous les champs Carte / Extension / Numero. Un element de la grille
   du panneau, sur toute la largeur ; vide, il disparait avec son espacement. */
.suggestions { flex: 1 0 100%; }
.suggestions:empty { display: none; }
.suggestions-liste {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
  gap: 0.4rem;
}
.suggestion {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  text-align: left;
  padding: 0.35rem 0.5rem;
  font-size: 0.85rem;
  color: var(--texte);
  background: var(--carte);
  border: 1px solid var(--bordure);
  border-radius: 6px;
}
button.suggestion { cursor: pointer; }
button.suggestion:hover { border-color: var(--accent); }
button.suggestion:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.suggestion-suivie { opacity: 0.6; }
.suggestion img { object-fit: contain; border-radius: 3px; flex: none; }
.suggestion-vide {
  flex: none;
  width: 40px;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--texte-att);
  border: 1px dashed var(--bordure);
  border-radius: 3px;
}
.suggestion-texte { display: flex; flex-direction: column; min-width: 0; }
.suggestions-note { margin: 0.3rem 0 0; font-size: 0.85rem; }

/* L'annonce d'un retrait porte son annulation : le bouton vit dans la phrase, a
   hauteur de texte, pas en dessous. */
.annonce-retrait {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  flex-wrap: wrap;
}

.actions-panneau {
  margin: 0.8rem 0 0;
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

/* Choix des colonnes */
.choix-colonnes { margin: 0.6rem 0; font-size: 0.9rem; }
.choix-colonnes summary { cursor: pointer; color: var(--texte-att); }
.choix-colonnes form { display: flex; flex-wrap: wrap; gap: 0.3rem 1rem; padding: 0.5rem 0 0.2rem; }
label.case { display: inline-flex; align-items: center; gap: 0.3rem; white-space: nowrap; }

@media (max-width: 800px) {
  .tableau-positions { font-size: 0.85rem; }
  .cellule-position { min-width: 10rem; }
  .barre { display: none; }
}

/* Bascule de devise de la Synthese. Reprend le style des boutons de courbes. */
.bouton-devise {
  padding: 0.25rem 0.7rem;
  border: 1px solid var(--bordure);
  border-radius: 4px;
  text-decoration: none;
  color: inherit;
  font-size: 0.9rem;
}
.bouton-devise.actif { background: var(--accent); color: var(--sur-accent); border-color: var(--accent); }


/* Focus clavier. Il n'y avait aucune regle : on s'en remettait au contour par defaut
   du navigateur, peu visible sur ces fonds clairs. `:focus-visible` ne se declenche
   qu'au clavier, donc le clic a la souris ne dessine pas de halo. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

/* Un tableau plus large que l'ecran doit defiler DANS son cadre. Sans ce conteneur,
   c'est la page entiere qui part en travers sur telephone — le tableau des
   investissements peut monter a douze colonnes. */
.tableau-defilant {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* Bascule de theme, a droite de la navigation. Un formulaire POST plutot qu'un
   lien : changer un reglage n'est pas une navigation, et cela evite qu'un
   prechargement de navigateur modifie la preference au passage. */
.choix-theme {
  display: flex;
  gap: 0.15rem;
}
.choix-theme button {
  background: none;
  border: 1px solid transparent;
  border-radius: 4px;
  color: var(--texte-att);
  cursor: pointer;
  font-size: 0.95rem;
  min-width: 28px;
  min-height: 28px;
  line-height: 1;
}
.choix-theme button:hover { color: var(--texte); background: var(--voile); }
.choix-theme button.actif { color: var(--accent); border-color: var(--bordure); }
@media (hover: none) {
  .choix-theme button { min-width: 40px; min-height: 40px; }
}


/* --- Tableaux de donnees --------------------------------------------------
   Style « data-dense-dashboard » : en-tetes collants, lignes qui se distinguent au
   survol, et surtout des chiffres alignes. */

/* `tabular-nums` donne a chaque chiffre la meme largeur : les unites, dizaines et
   centaines se superposent d'une ligne a l'autre, et une colonne de montants se lit
   d'un coup d'oeil. Sans cela, « 1 111 » est plus etroit que « 8 888 » et la colonne
   ondule. C'est le gain le plus net sur un tableau financier, pour une ligne de CSS. */
td, th, .valeur, .carte .valeur {
  font-variant-numeric: tabular-nums;
}

/* L'en-tete reste visible quand on fait defiler 21 positions groupees par classe.
   Il lui faut un fond opaque, sinon les lignes defilent au travers. */
thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--entete);
}

tbody tr:hover > td { background: var(--voile); }
/* Une ligne en cours d'edition ne doit pas reagir au survol : elle est deja
   distinguee, et le fond changerait sous les champs de saisie. */
tbody tr.ligne-edition:hover > td { background: none; }

/* Le camembert de la page Liquidite et son resume textuel, cote a cote quand la
   place le permet, empiles sinon. */
.camembert-cadre { width: 100%; max-width: 238px; }   /* 340 - 30 % */


/* Visible des lecteurs d'ecran, absent de l'ecran.
   La technique standard : l'element garde une taille d'un pixel et un rectangle de
   decoupe, au lieu de `display: none` ou `visibility: hidden` — qui le retireraient
   aussi de l'arbre d'accessibilite, donc de tout. */
.hors-ecran {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Barre d'avancement d'un credit. Doublee d'un texte chiffre juste dessous : une
   information portee par une seule barre coloree n'est pas lisible par tout le
   monde. */
.progression {
  height: 10px;
  background: var(--voile);
  border-radius: 5px;
  overflow: hidden;
  max-width: 420px;
  margin: 0.4rem 0;
}
.progression-barre {
  height: 100%;
  background: var(--accent);
}

/* Le graphique en barres des trois poches. Hauteur fixe : trois barres n'ont pas
   besoin de plus, et un canvas sans contrainte grandit indefiniment. */
.graphique-barres {
  max-width: 560px;
  height: 160px;
}

/* Les deux graphiques de la Synthese, cote a cote. Ils s'empilent d'eux-memes sous
   820 px : deux graphiques serres dans une colonne de telephone ne se lisent ni l'un
   ni l'autre. */
.graphiques-cote-a-cote {
  display: flex;
  flex-wrap: wrap;
  gap: 2rem;
  align-items: flex-start;
}
.graphiques-cote-a-cote > section { flex: 1 1 340px; min-width: 0; }
/* Le titre du premier bloc ne doit pas creuser au-dessus des deux : la marge du h2
   servait a separer des sections empilees. */
.graphiques-cote-a-cote h2 { margin-top: 0; }
.graphiques-cote-a-cote .camembert-cadre { max-width: 238px; }

/* --- Mode discret ---------------------------------------------------------
   Masque les montants pour consulter son patrimoine en public. Le flou plutot que
   des asterisques : la mise en page ne bouge pas d'un pixel, et on garde la forme
   des graphiques — assez pour se reperer, pas assez pour lire.

   Le flou ne se leve PAS au survol : ce serait rendre au premier regard par-dessus
   l'epaule ce qu'on vient de cacher. Le bouton est la pour ca. */
[data-discret] .carte .valeur,
[data-discret] .carte .legende,
[data-discret] td:not(.gauche),
[data-discret] tfoot td,
[data-discret] canvas,
[data-discret] .montant {
  filter: blur(7px);
  user-select: none;
}

/* Le bouton lui-meme ne doit pas se flouter, ni ce qui sert a le retrouver. */
[data-discret] .nav-principale,
[data-discret] .nav-principale * { filter: none; }

.choix-discret button {
  background: none;
  border: 1px solid transparent;
  border-radius: 4px;
  color: var(--texte-att);
  cursor: pointer;
  font-size: 0.95rem;
  min-width: 28px;
  min-height: 28px;
  line-height: 1;
  margin-left: auto;
}
.choix-discret button:hover { color: var(--texte); background: var(--voile); }
.choix-discret button.actif { color: var(--accent); border-color: var(--bordure); }
/* Quand l'oeil est la, c'est lui qui pousse la barre a droite, plus le theme. */
.choix-discret + .choix-theme { margin-left: 0.25rem; }
@media (hover: none) {
  .choix-discret button { min-width: 40px; min-height: 40px; }
}

/* Sous-onglets d'une page. Distincts de la navigation principale : plus discrets,
   soulignes plutot qu'encadres, pour qu'on voie tout de suite lequel des deux
   niveaux on parcourt. */
.sous-onglets {
  display: flex;
  gap: 0.25rem;
  border-bottom: 1px solid var(--bordure);
  margin: 0.8rem 0 1.2rem;
}
.sous-onglets a {
  padding: 0.45rem 0.9rem;
  text-decoration: none;
  color: var(--texte-att);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.sous-onglets a:hover { color: var(--texte); }
.sous-onglets a.actif {
  color: var(--accent);
  border-bottom-color: var(--accent);
  font-weight: 600;
}

/* Les quatre camemberts d'allocation des Investissements, DEUX PAR DEUX.
   `repeat(2, 1fr)` et non l'`auto-fit` de la premiere version : celui-ci dependait
   de la largeur reelle du conteneur, et retombait a une colonne des que la page
   etait un peu etroite — Lorenzo les a vus empiles. Deux colonnes ecrites en clair
   font ce qu'elles disent, et le seul cas ou une colonne unique se justifie est le
   telephone, ou elle est demandee explicitement plus bas. */
.grille-camemberts {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.8rem 2rem;
  margin-bottom: 1.4rem;
}
.grille-camemberts > section {
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.grille-camemberts h3 {
  margin: 0 0 0.6rem;
  font-size: 0.95rem;
  color: var(--texte-att);
}
/* Plus grands que ceux de la premiere version : la legende ayant disparu sous le
   graphique, la place qu'elle prenait revient au camembert — et les libelles ecrits
   dans les parts ont besoin de ce diametre pour tenir. */
.grille-camemberts .camembert-cadre { max-width: 300px; }

@media (max-width: 700px) {
  /* Deux camemberts de 150 px cote a cote sur un telephone ne se lisent ni l'un ni
     l'autre : mieux vaut faire defiler. */
  .grille-camemberts { grid-template-columns: 1fr; }
}

/* La carte du monde des Investissements. Elle remplace le camembert des zones, et
   prend toute la largeur : une carte de la taille d'un camembert ne se lit pas — les
   pays d'Europe y feraient quelques pixels. */
.bloc-carte { margin-bottom: 1.6rem; }
.bloc-carte h3 {
  margin: 0 0 0.6rem;
  font-size: 0.95rem;
  color: var(--texte-att);
}
.carte-monde {
  /* Une hauteur explicite : un <canvas> sans hauteur imposee s'effondre a zero, et
     `maintainAspectRatio: false` laisse justement Chart.js suivre le conteneur. */
  height: 380px;
  width: 100%;
  background: var(--fond-carte, transparent);
  border: 1px solid var(--bordure);
  border-radius: 6px;
  /* `pan-y` et non `none` : le doigt fait defiler la page verticalement, la carte ne
     capte que le glissement horizontal. Retire avec le zoom a la molette le
     02/09/2026 — un graphique ne doit pas retenir le geste de lecture. */
  touch-action: pan-y;
}
.carte-monde canvas { cursor: grab; }
.carte-monde canvas:active { cursor: grabbing; }

@media (max-width: 700px) {
  .carte-monde { height: 260px; }
}
/* La legende de la carte : une pastille et un libelle par zone. En HTML et non
   dessinee dans le canvas, pour qu'elle se copie, se lise au clavier et suive la
   taille de texte du navigateur. */
.legende-carte {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.2rem;
  margin: 0.6rem 0 0.4rem;
  font-size: 0.85rem;
}
.legende-zone { display: inline-flex; align-items: center; gap: 0.4rem; }
.legende-zone i {
  width: 0.85rem;
  height: 0.85rem;
  border-radius: 3px;
  border: 1px solid var(--bordure);
  flex: none;
}

/* Connexion et profil. Le formulaire est etroit et centre : une colonne de 26rem se
   lit d'un coup d'oeil, la ou un champ pleine largeur oblige a balayer l'ecran. */

/* Le logo en arriere-plan flou, façon menu Apple. Ne au 24/09/2026 pour la seule
   page de connexion, etendu le meme jour a tout le site (bloc `fond` de base.html) :
   Lorenzo a demande ce theme partout apres l'avoir vu sur la connexion. Position
   fixe et z-index negatif, pour rester derriere le contenu SANS toucher a
   l'empilement des encadres : la nav et les cartes, desormais en verre elles
   aussi (voir plus haut), le laissent transparaitre au lieu de le masquer.
   `pointer-events: none` l'exclut de tout clic, `aria-hidden` de toute lecture
   d'ecran — c'est une ambiance, pas un contenu.

   Discret par defaut : une page de tableaux denses (Investissements, la collection
   Pokemon) n'a pas a rivaliser avec un halo pour rester lisible — l'audit
   d'accessibilite du 31/08/2026 a deja etabli ce seuil. `.fond-logo--marque`
   reprend l'intensite d'origine, gardee sur la connexion et son code 2FA : deux
   pages presque vides, ou la marque peut se permettre d'occuper la place. */
.fond-logo {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}
.fond-logo img {
  position: absolute;
  top: 15%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(75vw, 950px);
  max-width: none;
  filter: blur(70px) saturate(1.7) brightness(1.4);
  opacity: 0.35;
}
:root[data-theme="sombre"] .fond-logo img { opacity: 0.5; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="clair"]) .fond-logo img { opacity: 0.5; }
}

.fond-logo--marque img {
  top: 33%;
  width: min(90vw, 1100px);
  filter: blur(60px) saturate(1.8) brightness(1.5);
  opacity: 0.55;
}
:root[data-theme="sombre"] .fond-logo--marque img { opacity: 0.8; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="clair"]) .fond-logo--marque img { opacity: 0.8; }
}

/* La carte se veut translucide, en verre depoli, pour laisser deviner le flou
   derriere elle plutot que de le couvrir d'un fond plein. */
.bloc-connexion {
  position: relative;
  max-width: 26rem;
  margin: 3rem auto;
  padding: 2rem;
  background: color-mix(in srgb, var(--carte) 78%, transparent);
  backdrop-filter: blur(24px) saturate(1.3);
  -webkit-backdrop-filter: blur(24px) saturate(1.3);
  border: 1px solid var(--bordure);
  border-radius: 16px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
}
.formulaire-connexion {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  max-width: 26rem;
  margin-bottom: 0.8rem;
}
.formulaire-connexion label {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.9rem;
  color: var(--texte-att);
}
.formulaire-connexion input { padding: 0.5rem 0.6rem; font-size: 1rem; }
.formulaire-connexion button {
  align-self: flex-start;
  padding: 0.55rem 1.2rem;
  font-size: 0.95rem;
}
/* La pastille du profil : un mot de passe temporaire doit se voir de n'importe
   quelle page, pas seulement quand on pense a aller voir son compte. */
.pastille {
  display: inline-block;
  min-width: 1.1em;
  padding: 0 0.25em;
  border-radius: 999px;
  background: var(--negatif, #b3261e);
  color: #fff;
  font-size: 0.72em;
  font-weight: 700;
  text-align: center;
  line-height: 1.5;
}

/* --- Menu du compte -------------------------------------------------------
   En tete de barre. `<details>` natif : il s'ouvre au clavier comme a la souris sans
   une ligne de script, et la page reste utilisable si le JavaScript ne charge pas. */
.menu-profil { position: relative; }
.menu-profil > summary {
  list-style: none;          /* pas de triangle */
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.25rem 0.5rem;
  border-radius: 6px;
  user-select: none;
}
.menu-profil > summary::-webkit-details-marker { display: none; }
.menu-profil > summary:hover,
.menu-profil[open] > summary { background: var(--fond-alt); }
.menu-profil > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Roue crantee + libelle, ajoutes le 24/09/2026 pour que ce bouton s'annonce
   clairement comme les reglages : le logo seul ne le disait pas. Meme habillage que
   les autres liens de la barre (couleur, taille), pour rester coherent avec eux.
   Le logo « GP » et la pastille d'alerte ont ete retires le 24/09/2026 (capture a
   l'appui) : trop peu lisibles sur le fond sombre. La roue et le libelle passent en
   `var(--texte)` — blanc en theme sombre, lisible dans les deux themes — au lieu du
   gris attenue `--texte-att` d'origine, et le libelle en gras pour se voir d'un coup
   d'oeil. */
/* `fill: currentColor` est ce qui manquait : un `<svg>` sans `fill` explicite sur ses
   formes vaut noir par defaut, quoi que dise `color` — la roue restait donc noire
   malgre le changement ci-dessus, signale par Lorenzo le 24/09/2026 apres redemarrage
   de l'application (donc pas un probleme de cache des statiques, un vrai oubli). */
.menu-profil .icone-roue { display: block; color: var(--texte); fill: currentColor; flex: none; }
.menu-profil:hover .icone-roue,
.menu-profil[open] .icone-roue { color: var(--accent); }
.menu-profil .libelle-parametres { font-size: 0.95rem; font-weight: 700; color: var(--texte); }
.menu-profil:hover .libelle-parametres,
.menu-profil[open] .libelle-parametres { color: var(--accent); }
/* Le libelle s'efface le premier quand la place manque : l'icone et le logo suffisent
   a retrouver le bouton, comme sur telephone ou la barre defile deja horizontalement. */
@media (max-width: 700px) {
  .menu-profil .libelle-parametres { display: none; }
}

.menu-profil-contenu {
  position: absolute;
  top: calc(100% + 0.4rem);
  left: 0;
  z-index: 50;
  min-width: 13.5rem;
  padding: 0.4rem;
  /* `--verre-fond`, pas `--verre` : ce menu flotte sur la barre (deja en verre
     elle-meme), et une meme teinte translucide sur les deux l'aurait fait s'y
     fondre. `--fond` tranche deja avec `--carte` sans le concours du flou. */
  background: var(--verre-fond);
  backdrop-filter: blur(20px) saturate(1.3);
  -webkit-backdrop-filter: blur(20px) saturate(1.3);
  border: 1px solid var(--bordure);
  border-radius: 8px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.menu-profil-contenu .menu-titre {
  margin: 0.3rem 0 0.1rem;
  padding: 0 0.5rem;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--texte-att);
}
/* Une entree de menu est tantot un lien, tantot un bouton de formulaire : les deux
   doivent se ressembler au pixel pres, sinon la liste parait bancale. */
.menu-profil-contenu .menu-entree {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.45rem 0.5rem;
  border: none;
  border-radius: 6px;
  background: none;
  color: var(--texte);
  font: inherit;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}
.menu-profil-contenu .menu-entree:hover { background: var(--fond-alt); }
.menu-profil-contenu form { margin: 0; }
.menu-couleurs { display: flex; gap: 0.2rem; padding: 0 0.2rem 0.2rem; }
.menu-couleurs button {
  flex: 1;
  padding: 0.35rem 0.2rem;
  border: 1px solid var(--bordure);
  border-radius: 6px;
  background: none;
  color: var(--texte-att);
  font-size: 0.78rem;
  cursor: pointer;
}
.menu-couleurs button:hover { background: var(--fond-alt); color: var(--texte); }
.menu-couleurs button.actif {
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 600;
}
/* Le menu du compte est passe en bout de barre le 02/09/2026. `margin-left: auto`
   dans un flex : il occupe l'espace restant et se colle a droite, sans qu'aucune
   largeur ne soit a tenir a jour quand un onglet s'ajoute. Le panneau s'ouvre alors
   vers la gauche, sinon il deborderait de l'ecran. */
.menu-profil.menu-a-droite { margin-left: auto; }
.menu-profil.menu-a-droite .menu-profil-contenu { left: auto; right: 0; }

/* La jauge de cotation. Une barre et un compteur : sur une tache de plus d'une
   minute, savoir qu'il reste 300 cartes vaut mieux qu'un sablier. */
.jauge {
  height: 0.6rem;
  background: var(--fond-alt);
  border: 1px solid var(--bordure);
  border-radius: 999px;
  overflow: hidden;
  max-width: 32rem;
  margin-bottom: 1rem;
}
.jauge-remplissage {
  height: 100%;
  background: var(--accent);
  transition: width 0.4s ease;
}

/* Extensions pliables de la collection Pokemon. Le `tbody` porte l'etat : ses lignes
   disparaissent, son en-tete reste. Sans JavaScript, aucun `data-plie` n'est pose et
   tout s'affiche — la page reste lisible, simplement plus longue. */
tbody[data-plie] tr:not(.entete-groupe) { display: none; }
.chevron {
  border: none;
  background: none;
  color: var(--texte-att);
  cursor: pointer;
  font-size: 0.8rem;
  padding: 0 0.3rem 0 0;
  line-height: 1;
}
.chevron:hover { color: var(--texte); }
.chevron:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Un bouton qui a l'air d'un lien : « Tout déplier » n'est pas une action assez
   lourde pour mériter un bouton plein, mais c'en est une — donc pas un <a href="#">. */
.lien-bouton {
  border: none;
  background: none;
  padding: 0;
  color: var(--accent);
  font: inherit;
  text-decoration: underline;
  cursor: pointer;
}
/* Le numero imprime, « 004/130 » : a chasse fixe pour que les colonnes s'alignent,
   comme les montants. */
.numero-carte {
  font-variant-numeric: tabular-nums;
  color: var(--texte-att);
  white-space: nowrap;
}
/* Le logo d'une extension, dans son en-tete de groupe. Hauteur fixe et largeur libre :
   les logos Pokemon ont des proportions tres differentes, et les forcer a une largeur
   commune les ecraserait. */
.logo-extension {
  height: 2.3rem;
  width: auto;
  max-width: 8rem;
  vertical-align: middle;
  object-fit: contain;
  flex: none;
}
/* Sous 700 px le logo cede la place au nom : c'est le nom qu'on lit pour choisir,
   le logo ne fait que le reconnaitre plus vite. */
@media (max-width: 700px) {
  .logo-extension { height: 1.6rem; max-width: 5rem; }
}
/* Sur fond sombre, les logos noirs disparaissent : un fond clair discret les rattrape
   sans les encadrer. */
:root[data-theme="sombre"] .logo-extension {
  background: rgba(255, 255, 255, 0.88);
  border-radius: 5px;
  padding: 2px 5px;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="clair"]) .logo-extension {
    background: rgba(255, 255, 255, 0.88);
    border-radius: 5px;
    padding: 2px 5px;
  }
}

/* --- Page Securite (24/09/2026) -----------------------------------------------
   Un menu dedie, cote a cote avec le profil : deconnexion automatique et double
   authentification n'avaient nulle part ou vivre sans se perdre au milieu du
   changement de mot de passe. */
.cartes-securite {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1rem;
  margin-top: 1rem;
}
.carte-reglage {
  border: 1px solid var(--bordure);
  border-radius: 8px;
  padding: 1.1rem 1.2rem;
}
.carte-reglage h2 {
  margin-top: 0;
  font-size: 1.05rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.pastille-etat {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  background: var(--voile);
  color: var(--texte-att);
}
.pastille-etat.pastille-active { background: var(--voile-accent); color: var(--accent); }

.totp-configuration {
  display: flex;
  gap: 1.2rem;
  flex-wrap: wrap;
  align-items: flex-start;
}
.totp-qr {
  flex: 0 0 auto;
  background: #ffffff;
  padding: 0.6rem;
  border-radius: 8px;
  line-height: 0;
}
.totp-qr svg { display: block; width: 9rem; height: 9rem; }
.totp-details { flex: 1 1 16rem; min-width: 14rem; }
.totp-cle code {
  display: inline-block;
  background: var(--entete);
  border-radius: 5px;
  padding: 0.3rem 0.5rem;
  font-size: 0.95rem;
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
}

/* --- Page Controle du logiciel (25/09/2026) ------------------------------------
   Arreter / redemarrer, avec un bandeau d'etat et un journal en direct. Meme jeton
   `.pastille-etat` que la double authentification, complete de trois variantes de
   couleur — la couleur renforce le libelle deja ecrit en toutes lettres, elle ne le
   remplace jamais (meme regle que le reste du site depuis l'audit du 31/08/2026). */
.pastille-etat.etat-ok {
  background: color-mix(in srgb, var(--positif) 16%, transparent);
  color: var(--positif);
}
.pastille-etat.etat-cours {
  background: rgba(201, 138, 58, 0.16);
  color: #c98a3a;
}
.pastille-etat.etat-erreur {
  background: color-mix(in srgb, var(--negatif) 16%, transparent);
  color: var(--negatif);
}

.details-controle {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.3rem 1rem;
  margin: 0.6rem 0 1rem;
}
.details-controle dt { color: var(--texte-att); font-size: 0.85rem; }
.details-controle dd { margin: 0; }

.icone-bouton { vertical-align: -3px; margin-right: 0.3rem; }

.bouton-danger { border-color: var(--negatif); color: var(--negatif); }
.bouton-danger:hover:not([disabled]) {
  background: color-mix(in srgb, var(--negatif) 12%, transparent);
}

.journal-controle {
  list-style: none;
  margin: 0.4rem 0 0;
  padding: 0;
  max-height: 22rem;
  overflow-y: auto;
  border: 1px solid var(--bordure);
  border-radius: 8px;
  font-family: ui-monospace, "Cascadia Code", "Consolas", monospace;
  font-size: 0.82rem;
}
.ligne-journal {
  display: grid;
  grid-template-columns: 9rem 5.5rem 10rem 1fr;
  gap: 0.2rem 0.6rem;
  padding: 0.3rem 0.6rem;
  border-bottom: 1px solid var(--bordure);
  white-space: pre-wrap;
  word-break: break-word;
}
.ligne-journal:last-child { border-bottom: none; }
.ligne-journal:hover { background: var(--voile); }
.journal-heure, .journal-origine { color: var(--texte-att); }
.ligne-journal.niveau-warning .journal-niveau { color: #c98a3a; font-weight: 700; }
.ligne-journal.niveau-error .journal-niveau,
.ligne-journal.niveau-critical .journal-niveau { color: var(--negatif); font-weight: 700; }

@media (max-width: 700px) {
  .ligne-journal { grid-template-columns: 1fr; }
}

/* --- Page Comptes (06/10/2026) -------------------------------------------------
   Gestion des comptes, reservee aux administrateurs. Memes jetons que la page
   Securite : `.carte-reglage` pour les blocs, `.pastille-etat` pour les etats — un
   badge « Administrateur » ou « Mot de passe temporaire » est un libelle ecrit, la
   couleur ne fait que le renforcer. Pas de tableau : une liste de lignes qui
   s'empilent, donc lisible tel quel sur un telephone. */
.carte-comptes { margin-top: 1rem; max-width: 46rem; }
.liste-comptes { list-style: none; margin: 0; padding: 0; }
.ligne-compte { padding: 0.9rem 0; border-bottom: 1px solid var(--bordure); }
.ligne-compte:last-child { border-bottom: none; }
.entete-compte { display: flex; align-items: center; flex-wrap: wrap; gap: 0.45rem; }
.identifiant-compte { font-weight: 600; font-size: 1rem; overflow-wrap: anywhere; }
.meta-compte { margin: 0.3rem 0 0.6rem; font-size: 0.85rem; color: var(--texte-att); }
.actions-compte { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 1.2rem; }
.forme-inline { margin: 0; }
/* Un bouton qui se lit comme un lien : c'est une action (POST), jamais un `<a href="#">`
   — CLAUDE.md, « Faux liens ». Cible de 44 px au doigt, comme les actions de ligne. */
.bouton-lien {
  background: none;
  border: none;
  padding: 0.25rem 0;
  color: var(--accent);
  font: inherit;
  font-size: 0.9rem;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.bouton-lien:hover { text-decoration-thickness: 2px; }
.bouton-danger { color: var(--negatif); }
details.reinit-mdp { font-size: 0.9rem; }
details.reinit-mdp summary { cursor: pointer; color: var(--accent); text-decoration: underline;
  text-underline-offset: 2px; }
.formulaire-inline-mdp { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem;
  margin-top: 0.5rem; }
.formulaire-inline-mdp input { flex: 1 1 11rem; min-width: 0; padding: 0.4rem 0.5rem; }
.actions-formulaire { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 1.2rem; }
@media (hover: none) {
  .bouton-lien, details.reinit-mdp summary { min-height: 44px; display: inline-flex;
    align-items: center; }
}
@media (max-width: 700px) {
  .carte-comptes { max-width: none; }
  .actions-compte { flex-direction: column; align-items: flex-start; }
}

/* La page de connexion propose les comptes deja utilises sur CE navigateur. */
.comptes-memorises { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 0.9rem; }
.comptes-memorises-titre { margin: 0; font-size: 0.9rem; color: var(--texte-att); }
.compte-memorise { display: flex; align-items: stretch; border: 1px solid var(--bordure);
  border-radius: 8px; overflow: hidden; }
.compte-memorise-choix { flex: 1; text-align: left; background: none; border: none;
  padding: 0.6rem 0.8rem; font: inherit; font-size: 1rem; cursor: pointer;
  overflow-wrap: anywhere; }
.compte-memorise-choix:hover, .compte-memorise-choix:focus-visible { background: var(--voile-accent); }
.compte-memorise-oublier { background: none; border: none; border-left: 1px solid var(--bordure);
  padding: 0 0.8rem; min-width: 2.75rem; font-size: 1.1rem; cursor: pointer;
  color: var(--texte-att); }
.compte-memorise-oublier:hover, .compte-memorise-oublier:focus-visible { color: var(--negatif);
  background: var(--voile); }
.compte-choisi { margin: 0 0 0.9rem; font-size: 0.95rem; display: flex; flex-wrap: wrap;
  align-items: center; gap: 0.3rem 0.8rem; }
/* Un `display` d'auteur l'emporte sur le `[hidden]` du navigateur : sans ces regles, le
   bloc des comptes, « Compte : … » et le champ Identifiant resteraient visibles tous
   ensemble, et les boutons « Generer » (caches tant que le script ne les a pas
   reveles) apparaitraient morts sur un appareil tactile. Meme piege que les champs de
   gradation des cartes (24/09/2026). */
.comptes-memorises[hidden],
.compte-choisi[hidden],
.formulaire-connexion label[hidden],
.bouton-lien[hidden] { display: none; }
