  /* ---------- Toasts de succès (bas à droite) ---------- */
  #achToasts{ position:fixed; right:16px; bottom:16px; z-index:60;
              display:flex; flex-direction:column; gap:10px; align-items:flex-end;
              pointer-events:none; max-width:min(340px, 84vw) }
  .ach-toast{ display:flex; align-items:center; gap:12px; pointer-events:auto;
              background:linear-gradient(135deg,#2c2338,#181322);
              border:1px solid var(--accent,#e0a83c); border-left:4px solid var(--accent,#e0a83c);
              border-radius:12px; padding:11px 15px; color:var(--ink,#efe7f5);
              box-shadow:0 10px 30px rgba(0,0,0,.55), 0 0 0 1px rgba(224,168,60,.15);
              opacity:1; transform:none;
              /* PAS de fill-mode `both` (corrige 2026-08-20). Avec `both`, l'etat
                 de DEPART du keyframe (opacity:0) s'applique AVANT que l'animation
                 ne demarre : si celle-ci ne tourne pas — onglet en arriere-plan,
                 economie d'energie mobile, "reduire les animations" du systeme —
                 le toast reste invisible POUR TOUJOURS alors qu'il est bien dans
                 le DOM. La visibilite ne doit jamais dependre d'une animation :
                 l'etat de repos est desormais VISIBLE, l'animation ne fait que
                 l'amener en glissant. */
              animation:achIn .45s cubic-bezier(.2,1.3,.4,1); }
  /* Systeme regle sur "reduire les animations" : on affiche sans glissement. */
  @media (prefers-reduced-motion: reduce){
    .ach-toast{ animation:none }
    .ach-toast.out{ animation:none; opacity:0 }
  }
  .ach-toast.out{ animation:achOut .4s ease-in forwards }
  .ach-toast .ach-ico{ font-size:1.9rem; line-height:1; flex:0 0 auto }
  .ach-toast .ach-txt{ display:flex; flex-direction:column; gap:1px; min-width:0 }
  .ach-toast .ach-lbl{ font-size:.62rem; letter-spacing:.14em; text-transform:uppercase;
                       color:var(--accent,#e0a83c); font-weight:700 }
  .ach-toast .ach-name{ font-weight:700; font-size:.92rem; line-height:1.15 }
  .ach-toast .ach-desc{ font-size:.7rem; color:var(--ink-dim,#b7abc8); line-height:1.25 }
  .ach-toast .ach-pts{ margin-left:auto; align-self:flex-start; flex:0 0 auto;
                       color:#ffd860; font-weight:700; font-size:.82rem; white-space:nowrap }
  @keyframes achIn{ from{ transform:translateX(40px) scale(.9); opacity:0 } to{ transform:none; opacity:1 } }
  /* `achOut` garde `forwards` : la disparition, elle, DOIT rester acquise. */
  @keyframes achOut{ to{ transform:translateX(60px); opacity:0 } }
  /* toast "objet équipable ramassé" : même carte que les succès + un bouton
     dédié pour ouvrir l'inventaire directement (voir showLootEquipToast, js/18) */
  .loot-toast{ align-items:center }
  .loot-toast .loot-toast-equip{
    flex:0 0 auto; align-self:center; margin-left:4px;
    padding:7px 10px; border-radius:8px; font-size:.72rem; white-space:nowrap;
    background:var(--accent-dim,#5c4a78); border-color:var(--accent,#e0a83c); color:var(--ink,#efe7f5);
  }
  .loot-toast .loot-toast-equip:hover{ background:var(--accent,#e0a83c); color:#181322 }
  #inventory{ position:absolute; inset:0; display:none; align-items:center; justify-content:center;
              background:rgba(8,6,12,.82); z-index:15 }   /* au-dessus de la boutique (14) */
  #inventory.show{ display:flex }
  #inventory .card{ background:var(--panel); border:1px solid var(--accent-dim); border-radius:12px;
               padding:24px 30px; text-align:center; box-shadow:0 12px 40px rgba(0,0,0,.6); animation:pop .3s ease-out;
               max-width:calc(100vw - 24px); max-height:calc(100vh - 24px); overflow:auto }
  #inventory h2{ color:var(--accent); font-size:1.3rem; letter-spacing:.08em; margin-bottom:6px }
  .inv-layout{ display:flex; gap:18px; flex-wrap:wrap; text-align:left; margin-top:10px;
    align-items:flex-start; justify-content:center }

  /* ---------- SILHOUETTE ÉQUIPÉE (renderInventoryCore, js/50) ----------
     Le sprite du héros au centre, ses emplacements de part et d'autre, DANS
     L'ORDRE DU CORPS (tête en haut, bottes en bas) — on voit son personnage au
     lieu de lire une liste d'étiquettes. */
  .inv-doll{ display:flex; gap:8px; align-items:stretch; flex:0 0 auto }
  .inv-doll-col{ display:flex; flex-direction:column; gap:5px; justify-content:center; width:132px }
  .inv-doll-mid{ display:flex; flex-direction:column; align-items:center; justify-content:center; gap:4px }
  #invHeroCanvas{ width:150px; height:150px; image-rendering:pixelated;
    background:radial-gradient(circle at 50% 42%, #2a2338 0%, #17131f 70%);
    border:1px solid var(--panel-edge,#3a3050); border-radius:12px }
  .inv-doll-name{ font-size:.72rem; color:var(--ink-dim); text-align:center }
  .doll-slot{ display:flex; align-items:center; gap:6px; padding:4px 6px; border-radius:8px;
    border:1px solid var(--panel-edge,#3a3050); background:#1b1626; min-height:34px; cursor:default }
  .doll-slot.filled{ cursor:pointer; border-color:#5a4a78 }
  .doll-slot.filled:hover{ background:#241d33 }
  .doll-slot.empty{ opacity:.5 }
  .doll-slot.side-r{ flex-direction:row-reverse; text-align:right }
  .doll-ic{ font-size:1.15rem; line-height:1; flex:0 0 auto }
  .doll-lbl{ font-size:.66rem; line-height:1.15; overflow:hidden; flex:1 }

  /* ---------- COLONNE SAC : jauge, puis DEUX grilles bien distinctes ---------- */
  .inv-bagcol{ flex:1 1 300px; min-width:280px; max-width:380px;
    display:flex; flex-direction:column; gap:8px }
  .inv-bagline{ font-size:.78rem; margin:2px 0 4px }
  .inv-grid-sect{ display:flex; flex-direction:column; gap:4px }
  /* Pastilles compactes : c'est ce qui permet de tenir SANS ASCENSEUR — le
     détail d'un objet s'ouvre dans le bandeau dédié, pas dans la liste. */
  .inv-grid{ display:flex; flex-wrap:wrap; gap:5px }
  .inv-chip{ display:flex; align-items:center; gap:5px; padding:4px 8px; border-radius:14px;
    border:1px solid var(--panel-edge,#3a3050); background:#1b1626; cursor:pointer;
    font-size:.68rem; max-width:100%; color:var(--ink) }
  .inv-chip:hover{ background:#241d33 }
  .inv-chip.sel{ border-color:#8a7ab0; background:#2a2340; box-shadow:0 0 0 1px #8a7ab066 }
  .chip-ic{ font-size:1rem; line-height:1 }
  .chip-qty{ font-weight:700; color:var(--ink-dim) }
  .chip-nm{ white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:150px }
  .inv-empty-mini{ font-size:.7rem; color:var(--ink-dim); font-style:italic }

  /* ---------- SAC EN CASES (renderBagCases, js/50) ----------
     Une case = une place. Le CONTOUR de chaque objet dit sa RARETÉ (--rar, posé
     par buildBagCell(), js/50) et un badge en coin dit sa famille ; une case
     PARTAGÉE est découpée en autant de sous-cases que d'occupants, ce qui montre
     sans un mot que ces objets-là ne prennent pas une case entière (pelles ×5,
     sacs à compartiments…). */
  .bag-grid{ display:grid; grid-template-columns:repeat(auto-fill, minmax(46px, 1fr));
    gap:5px; }
  .bag-cell{ position:relative; aspect-ratio:1/1; border-radius:9px;
    border:2px solid #332c46; background:#171320;
    display:flex; align-items:stretch; overflow:hidden }
  .bag-cell-empty{ border-style:dashed; border-color:#2c2740; background:#13101b }
  /* Fond seulement : la couleur de FAMILLE ne porte plus le contour, elle reste
     juste en teinte de fond très sourde sous les objets. */
  .bag-cell-g{ background:#1f1a22 }   /* équipement */
  .bag-cell-c{ background:#161d1a }   /* consommables */
  .bag-cell-m{ background:#1a1726 }   /* case mixte */
  /* Sous-cases d'une case partagée : séparateur net entre occupants. */
  .bag-cell.split .bag-sub + .bag-sub{ border-left:1px dashed #ffffff33 }
  /* LISERÉ DE RARETÉ : posé en ombre INTERNE plutôt qu'en bordure — deux
     sous-cases voisines colleraient sinon leurs bordures (4px au milieu d'une
     case partagée), et la sélection ci-dessous peut se superposer sans
     l'effacer. --rar vient de buildBagCell() (js/50). */
  .bag-sub{ position:relative; flex:1 1 0; min-width:0; display:flex; flex-direction:column;
    align-items:center; justify-content:center; gap:1px; border-radius:7px;
    background:transparent; border:0; cursor:pointer; color:var(--ink); padding:0;
    box-shadow:inset 0 0 0 2px var(--rar, #332c46) }
  .bag-sub:hover{ background:#ffffff12 }
  .bag-sub.sel{ background:#8a7ab033; outline:2px dashed #cfc2ff; outline-offset:-5px }
  /* BADGE DE FAMILLE : pastille en coin, ronde pour un consommable, carrée pour
     un équipement — la FORME reste lisible là où l'emoji, à cette taille, ne
     l'est plus toujours (petits écrans, case partagée à trois). */
  .bag-badge{ position:absolute; top:1px; right:1px; width:13px; height:13px;
    display:flex; align-items:center; justify-content:center;
    font-size:.52rem; line-height:1; border:1px solid #0009; pointer-events:none }
  /* L'emoji est rendu en SILHOUETTE sombre — et sur l'ENFANT, pas sur la
     pastille : un filtre posé sur le badge lui-même noircissait aussi son fond,
     c'est-à-dire justement la couleur qu'on veut montrer. À cette taille, les
     couleurs propres de l'emoji (le 👕 est bleu vif) recouvraient la pastille ;
     réduit à une forme noire, il la précise au lieu de la masquer. */
  .bag-badge i{ font-style:normal; filter:grayscale(1) brightness(.1) }
  .bag-badge-c{ background:#4f9d6a; border-radius:50% }              /* consommable */
  .bag-badge-g{ background:#c08a3c; border-radius:3px }              /* équipement */
  .bag-cell.split .bag-badge{ width:11px; height:11px; font-size:.44rem }
  .bag-sub-ic{ font-size:1.25rem; line-height:1 }
  .bag-cell.split .bag-sub-ic{ font-size:.95rem }
  .bag-sub-qty{ font-size:.58rem; font-weight:700; color:var(--ink-dim); line-height:1 }
  /* Cases BONUS : mêmes règles, fond légèrement teinté pour dire « à part ». */
  .bag-grid-bonus .bag-cell{ border-style:solid }
  .bag-grid-bonus .bag-cell-empty{ border-style:dashed; background:#121a16 }
  /* Petite légende dans le titre. */
  .lg-g{ color:#c08a3c } .lg-c{ color:#4f9d6a } .lg-r{ color:#9aa0aa }

  /* Bandeau de détail de l'objet sélectionné : description + actions. */
  .inv-detail{ border:1px solid var(--panel-edge,#3a3050); border-radius:10px;
    padding:8px 10px; background:#17131f; min-height:56px; font-size:.74rem }
  .inv-detail.muted{ color:var(--ink-dim); font-style:italic; display:flex; align-items:center }
  .inv-detail-head{ display:flex; align-items:center; gap:6px; margin-bottom:3px }
  .dt-ic{ font-size:1.2rem }
  .inv-detail-sub{ color:var(--ink-dim); font-size:.7rem; line-height:1.35 }
  .inv-detail-acts{ display:flex; gap:6px; flex-wrap:wrap; margin-top:7px }
  .inv-detail-acts button{ padding:5px 10px; font-size:.7rem }
  .inv-keys{ display:flex; gap:6px; flex-wrap:wrap }
  .inv-keychip{ font-size:.72rem; padding:2px 8px; border-radius:12px;
    border:1px solid var(--panel-edge,#3a3050); background:#1b1626 }
  /* Cran VIDE du trousseau (2026-09-08, avis #12 de Pixel) : présent mais
     manifestement inoccupé — c'est ce contraste qui apprend au joueur quelles
     serrures existent et ce qu'il lui reste à trouver. */
  .inv-keychip.vide{ color:var(--ink-dim,#b7abc8); opacity:.45;
    border-style:dashed; font-style:italic; }
  .inv-slots{ display:grid; grid-template-columns:1fr 1fr; gap:8px; min-width:260px; align-content:start }
  .inv-slot{ background:#2a2436; border:1px solid var(--panel-edge); border-radius:10px;
             padding:10px 12px; min-height:52px }
  .inv-slot.filled{ cursor:pointer }
  .inv-slot.filled:hover{ border-color:var(--target); box-shadow:0 0 8px rgba(92,200,216,.4) }
  .inv-slot.empty{ opacity:.5 }
  .inv-slot b{ font-size:.9rem }
  .inv-slot small{ color:var(--ink-dim); font-size:.72rem; line-height:1.3 }
  .inv-slot .inv-action{ display:block; margin-top:4px; font-size:.7rem; color:var(--accent-dim) }
  .inv-list{ flex:1; min-width:280px; max-width:420px; max-height:400px; overflow-y:auto;
             display:flex; flex-direction:column; gap:6px; padding-right:4px }
  .inv-item{ display:flex; align-items:center; gap:10px; background:#2a2436;
             border:1px solid var(--panel-edge); border-radius:8px; padding:8px 10px }
  .inv-item .meta{ flex:1; min-width:0 }
  .inv-item .meta b{ font-size:.88rem }
  .inv-item .meta small{ color:var(--ink-dim); font-size:.7rem; display:block }
  .inv-item button{ padding:5px 10px; font-size:.72rem; white-space:nowrap }
  .inv-item button:disabled{ opacity:.4; cursor:not-allowed }
  .inv-empty{ color:var(--ink-dim); font-size:.82rem; max-width:280px }
  .inv-cat{ font-size:.66rem; font-weight:bold; text-transform:uppercase; letter-spacing:.06em;
    color:var(--accent-dim,#8a7ab0); margin:8px 0 2px }
  .inv-cat:first-child{ margin-top:0 }
  /* Sous-titre d'une categorie : total de places occupees par le groupe — voir
     renderInventoryCore(), js/50. Ton attenue, il complete le titre sans le
     concurrencer. */
  .inv-cat-sub{ text-transform:none; letter-spacing:0; font-weight:600;
    color:var(--ink-dim); margin-left:6px }

  /* ---------- JAUGE DE REMPLISSAGE DU SAC (bagGaugeHTML, js/50) ----------
     Une barre vaut mieux qu'un compteur seul : on voit d'un coup d'oeil s'il
     reste de la marge, et la part qu'un objet en attente viendrait prendre. */
  .bag-gauge{ margin-top:6px }
  .bag-gauge-bar{ position:relative; height:8px; border-radius:5px; overflow:hidden;
    background:#221c2c; border:1px solid var(--panel-edge,#3a3050) }
  .bag-gauge-fill{ position:absolute; left:0; top:0; bottom:0; border-radius:5px 0 0 5px;
    transition:width .18s ease }
  .bag-gauge-fill.ok{   background:linear-gradient(90deg,#4f9d6a,#6fc48a) }
  .bag-gauge-fill.warn{ background:linear-gradient(90deg,#b8862f,#e0aa46) }
  .bag-gauge-fill.crit{ background:linear-gradient(90deg,#a83c3c,#d45a52) }
  /* Part de l'objet EN ATTENTE de decision, hachuree par-dessus le remplissage. */
  .bag-gauge-pending{ position:absolute; top:0; bottom:0;
    background:repeating-linear-gradient(45deg,#7fd0ff44,#7fd0ff44 3px,#7fd0ff22 3px,#7fd0ff22 6px);
    border-left:1px solid #7fd0ff88 }
  .bag-gauge-pending.over{
    background:repeating-linear-gradient(45deg,#ff707044,#ff707044 3px,#ff707022 3px,#ff707022 6px);
    border-left-color:#ff8a8a }
  .bag-gauge-txt{ font-size:.7rem; color:var(--ink-dim); margin-top:3px }
  .bag-rest-none{ color:#e59a9a }
  .bag-fit{ color:#8ce0a8 }
  .bag-nofit{ color:#e59a9a; font-weight:700 }
  /* Le sac dans le bloc "Sac a dos" : legerement mis en avant, il porte la jauge. */
  .inv-bagslot{ border-color:#5a4a78 }
  .bag-gauge-inf .bag-gauge-txt{ color:#8ce0a8 }
  #invClose{ margin-top:16px; padding:10px 26px; border-radius:10px }
  #invCapacity{ font-size:.78rem; color:var(--accent-dim,#8a7ab0) }
  /* BOURSE (score de la run) + ÉCLATS (monnaie permanente, js/75) : deux petits
     badges en tête de l'inventaire, pour savoir d'un coup d'œil ce qu'on a en
     poche sans rouvrir la boutique (demande Pixel 2026-08-19). */
  #invCurrency{ display:flex; gap:10px; flex-wrap:wrap; margin:2px 0 8px }
  .inv-currency-badge{ display:inline-flex; align-items:center; gap:5px; font-size:.8rem;
    background:#221c2e; border:1px solid var(--panel-edge); border-radius:999px; padding:4px 12px;
    color:var(--ink,#efe7f5) }
  .inv-currency-badge b{ color:var(--accent,#e0a83c) }
  .inv-item .inv-discard{ background:#3a2230; border-color:#7a3a44; color:#e59a9a }
  .inv-item .inv-discard:hover{ background:#4a2836; border-color:#c05050 }
  /* ---------- Fenêtre "sac plein" (échange au ramassage) ---------- */
  #bagFullModal{ position:absolute; inset:0; display:none; align-items:center; justify-content:center;
              background:rgba(8,6,12,.85); z-index:20 }   /* au-dessus de tout : inventaire, boutique */
  #bagFullModal.show{ display:flex }
  #bagFullModal .card{ background:var(--panel); border:1px solid var(--accent-dim); border-radius:12px;
               padding:24px 30px; text-align:center; box-shadow:0 12px 40px rgba(0,0,0,.6); animation:pop .3s ease-out;
               max-width:calc(100vw - 24px); max-height:calc(100vh - 24px); overflow:auto; width:440px }
  #bagFullModal h2{ color:#e59a9a; font-size:1.3rem; letter-spacing:.08em; margin-bottom:6px }
  #bagFullCapacity{ font-size:.78rem; color:var(--accent-dim,#8a7ab0); margin-bottom:8px }
  #bagFullNewCard{ background:#2a2436; border:2px solid var(--target,#5cc8d8); border-radius:10px;
    padding:10px 12px; text-align:left; display:flex; gap:10px; align-items:flex-start;
    box-shadow:0 0 14px rgba(92,200,216,.25) }
  #bagFullNewCard .bagfull-icon{ font-size:1.7rem; line-height:1 }
  #bagFullNewCard .meta{ flex:1; min-width:0 }
  #bagFullNewCard .meta b{ font-size:.95rem }
  /* ---------- Petite boîte de confirmation générique (remplace confirm() natif —
     la popup du navigateur casse le style du jeu et ferme sans prévenir les
     fenêtres déjà ouvertes ; celle-ci reste DANS l'univers visuel du jeu, et
     peut s'ouvrir PAR-DESSUS #bagFullModal ou #inventory) ---------- */
  /* z-index 30 : AU-DESSUS DE TOUT (corrigé 2026-08-20). Il valait 22, comme
     #charPick — or à z-index ÉGAL c'est l'ordre du DOM qui départage, et
     #charPick est déclaré plus bas dans index.html : il recouvrait donc
     entièrement la confirmation. Concrètement, cliquer le ✕ d'un personnage
     ouvrait bien la fenêtre… invisible, derrière la liste, et le clic sur
     « Confirmer » atterrissait sur le formulaire de création. D'où « la croix ne
     permet pas de supprimer le perso » (retour Pixel) : la suppression n'était
     jamais confirmée. Une confirmation doit toujours passer devant ce qui l'a
     déclenchée — d'où une valeur franchement supérieure, pas égale. */
  #confirmModal{ position:absolute; inset:0; display:none; align-items:center; justify-content:center;
              background:rgba(8,6,12,.88); z-index:30 }
  #confirmModal.show{ display:flex }
  #confirmModal .card{ background:var(--panel); border:1px solid var(--danger,#c05050); border-radius:12px;
               padding:22px 26px; text-align:center; box-shadow:0 12px 40px rgba(0,0,0,.6); animation:pop .3s ease-out;
               max-width:calc(100vw - 24px); max-height:calc(100vh - 24px); overflow:auto; width:380px }
  #confirmModal h2{ color:#e59a9a; font-size:1.1rem; letter-spacing:.06em; margin-bottom:10px }
  #confirmModal p{ font-size:.86rem; line-height:1.4; color:var(--ink,#efe7f5) }
  #confirmModal #confirmOk{ background:#3a2230; border-color:#7a3a44; color:#e59a9a }
  #confirmModal #confirmOk:hover{ background:#4a2836; border-color:#c05050 }
  #bagFullNewCard .meta small{ display:block; color:var(--ink-dim); font-size:.72rem; margin-top:2px }
  #bagFullNewCard .bagfull-cost{ color:var(--target,#5cc8d8); font-weight:bold }
  .bagfull-hint{ font-size:.74rem; color:var(--ink-dim); margin:8px 0 6px; text-align:left }
  /* ---------- Équiper directement depuis "sac plein" (2026-08-18) : l'équipement
     ne compte pas dans la capacité du sac, donc pas besoin de jeter quoi que ce
     soit pour équiper l'objet ramassé — encart dédié, même famille visuelle que
     .cmp-diff-box, juste sous la carte du nouvel objet. ---------- */
  .bagfull-equipnow{ margin-top:8px; padding:8px 12px; background:#20192a; border:1px solid var(--target,#5cc8d8);
              border-radius:8px; text-align:left }
  .bagfull-equipnow button{ margin-top:6px }
  /* ---------- Potion de second souffle (choix du % de score sacrifié) ---------- */
  #secondWindModal{ position:absolute; inset:0; display:none; align-items:center; justify-content:center;
              background:rgba(8,6,12,.9); z-index:24 }   /* au-dessus de tout, y compris la confirmation générique (22) */
  #secondWindModal.show{ display:flex }
  #secondWindModal .card{ background:var(--panel); border:1px solid #e0b050; border-radius:12px;
               padding:24px 30px; text-align:center; box-shadow:0 12px 50px rgba(0,0,0,.7), 0 0 30px rgba(224,176,80,.25);
               animation:pop .3s ease-out; max-width:calc(100vw - 24px); width:420px }
  #secondWindModal h2{ color:#e0b050; font-size:1.25rem; letter-spacing:.06em; margin-bottom:6px }
  .sw-slider-row{ display:flex; align-items:center; gap:12px; margin:16px 0 8px }
  .sw-slider-row input[type="range"]{ flex:1; accent-color:#e0b050 }
  .sw-slider-row span{ font-weight:bold; color:#e0b050; min-width:3.2em; text-align:right }
  .sw-preview{ font-size:.82rem; color:var(--ink,#efe7f5); line-height:1.5 }
  .sw-preview b{ color:#5fce6a }
  .sw-preview .sw-cost{ color:#e59a9a }
  #secondWindModal #secondWindOk{ background:#3a3020; border-color:#8a6a2a; color:#e0b050 }
  #secondWindModal #secondWindOk:hover{ background:#4a3d28; border-color:#e0b050 }
  /* ---------- Premiers soins (coop, choix du nombre de PA à sacrifier) ---------- */
  #firstAidModal{ position:absolute; inset:0; display:none; align-items:center; justify-content:center;
              background:rgba(8,6,12,.9); z-index:23 }   /* sous le Second Souffle (24, mort réelle), au-dessus du reste */
  #firstAidModal.show{ display:flex }
  #firstAidModal .card{ background:var(--panel); border:1px solid #5fb890; border-radius:12px;
               padding:24px 30px; text-align:center; box-shadow:0 12px 50px rgba(0,0,0,.7), 0 0 30px rgba(95,184,144,.25);
               animation:pop .3s ease-out; max-width:calc(100vw - 24px); width:420px }
  #firstAidModal h2{ color:#5fb890; font-size:1.25rem; letter-spacing:.06em; margin-bottom:6px }
  #firstAidModal .sw-slider-row input[type="range"]{ accent-color:#5fb890 }
  #firstAidModal .sw-slider-row span{ color:#5fb890 }
  #firstAidModal #firstAidOk{ background:#203a2c; border-color:#2a8a5a; color:#5fb890 }
  #firstAidModal #firstAidOk:hover{ background:#284a38; border-color:#5fb890 }
  #firstAidModal #firstAidCancel{ color:var(--ink-dim,#9a90a8); border-color:#4a4258 }
  #firstAidModal #firstAidCancel:hover{ color:var(--ink,#efe7f5); border-color:#6a6078 }
  /* ---------- Partage d'objets (coop, js/78) ---------- */
  #giveItemModal{ position:absolute; inset:0; display:none; align-items:center; justify-content:center;
              background:rgba(8,6,12,.9); z-index:23 }
  #giveItemModal.show{ display:flex }
  #giveItemModal .card{ background:var(--panel); border:1px solid #d0a850; border-radius:12px;
               padding:24px 30px; text-align:center; box-shadow:0 12px 50px rgba(0,0,0,.7), 0 0 30px rgba(208,168,80,.25);
               animation:pop .3s ease-out; max-width:calc(100vw - 24px); width:460px }
  #giveItemModal h2{ color:#d0a850; font-size:1.25rem; letter-spacing:.06em; margin-bottom:6px }
  #giveItemModal #giveItemCancel{ color:var(--ink-dim,#9a90a8); border-color:#4a4258 }
  #giveItemModal #giveItemCancel:hover{ color:var(--ink,#efe7f5); border-color:#6a6078 }
  /* ---------- Comparatif d'objets : styles COMMUNS aux 3 fenêtres (boutique au
     survol, sac plein, équipement rapide) — 2026-08-11, retour Pixel : « trop
     riche trop lourde, [...] bien visualiser l'objet nouveau et ancien et
     clairement voir ce que l'on gagne ou perd ». Règles non-scopées (au lieu de
     dupliquées par fenêtre comme avant) : un seul endroit à ajuster, cohérence
     garantie partout. ---------- */
  .cmp-up{ color:#7fd88f }
  .cmp-down{ color:#e59a9a }
  /* objets de même emplacement mais aux bonus identiques : l'information est
     utile (« ils se valent »), mais elle ne doit pas crier comme un écart */
  .cmp-same{ color:var(--ink-dim,#b7abc8); opacity:.85 }
  .cmp-line{ display:block; font-size:.7rem; line-height:1.4; font-weight:600 }
  /* liste verticale d'UNE ligne par bonus (▲/▼) — remplace l'ancien paragraphe
     unique façon "🆚 +1 Dégâts · -2 PV · …", jugé trop dense d'un coup d'œil */
  .cmp-list{ display:flex; flex-direction:column; gap:1px }
  /* petite étiquette "🆕 Nouveau" / "🔸 Actuel" posée au-dessus du nom de l'objet
     — lève toute ambiguïté sur QUI est comparé à QUOI, peu importe l'ordre
     d'affichage (avant : seule la position gauche/droite le suggérait) */
  .cmp-badge{ display:inline-block; font-size:.6rem; font-weight:700; letter-spacing:.04em;
    text-transform:uppercase; padding:1px 7px; border-radius:999px; margin-bottom:3px }
  .cmp-badge-new{ background:rgba(92,200,216,.18); color:var(--target,#5cc8d8); border:1px solid rgba(92,200,216,.5) }
  .cmp-badge-old{ background:rgba(138,122,176,.18); color:var(--accent-dim,#8a7ab0); border:1px solid rgba(138,122,176,.45) }
  /* ---------- Comparaison d'équipement (raccourci "Équiper" déjà occupé) ---------- */
  #equipCompareModal{ position:absolute; inset:0; display:none; align-items:center; justify-content:center;
              background:rgba(8,6,12,.85); z-index:20 }   /* même palier que #bagFullModal */
  #equipCompareModal.show{ display:flex }
  /* max-height + overflow OBLIGATOIRES (2026-08-19, audit) : sans eux, en paysage
     sur téléphone, les boutons "Équiper le nouveau" / "Garder l'actuel" tombaient
     sous le bord de #gameWrap (overflow:hidden) SANS défilement possible — et
     comme cette fenêtre n'a ni Échap ni fermeture au clic sur le fond, la partie
     était bloquée. Aligné sur #bagFullModal .card, qui les avait déjà. */
  #equipCompareModal .card{ background:var(--panel); border:1px solid var(--accent-dim); border-radius:12px;
               padding:22px 26px; text-align:center; box-shadow:0 12px 40px rgba(0,0,0,.6); animation:pop .3s ease-out;
               max-width:calc(100vw - 24px); max-height:calc(100vh - 24px); overflow:auto; width:440px }
  #equipCompareModal h2{ color:var(--accent); font-size:1.15rem; letter-spacing:.06em; margin-bottom:6px }
  .equip-cmp-row{ display:flex; align-items:center; gap:10px; margin-top:12px }
  .equip-cmp-card{ flex:1; min-width:0; background:#2a2436; border:1px solid var(--panel-edge); border-radius:10px;
              padding:10px 12px; display:flex; gap:10px; align-items:flex-start; text-align:left }
  .equip-cmp-card .bagfull-icon{ font-size:1.6rem; line-height:1; flex:0 0 auto }
  .equip-cmp-card .meta{ min-width:0 }
  .equip-cmp-card .meta small{ display:block; color:var(--ink-dim); font-size:.7rem; margin-top:2px }
  .equip-cmp-vs{ flex:0 0 auto; font-size:1.3rem; opacity:.6; color:var(--accent,#e0a83c) }
  /* encart dédié pour le delta (gain/perte) : détaché des cartes, bien visible,
     fond légèrement teinté au lieu d'un simple <p> perdu dans le reste du texte */
  .cmp-diff-box{ margin-top:12px; padding:8px 12px; background:#20192a; border:1px solid var(--panel-edge);
              border-radius:8px; text-align:left }
  .cmp-diff-box .cmp-same{ text-align:center; display:block }
  .equip-cmp-actions{ display:flex; gap:10px; justify-content:center; flex-wrap:wrap; margin-top:14px }
  .equip-cmp-actions button{ padding:9px 18px; border-radius:10px; font-size:.85rem }
  /* case à cocher UNIQUE pour le sort de l'objet non gardé (ranger par défaut,
     détruire si cochée) — remplace les 4 boutons précédents (2 choix "équiper" ×
     2 choix "ranger/jeter" affichés en permanence, quelle que soit la décision) */
  .equip-cmp-discard-toggle{ display:flex; align-items:center; gap:7px; justify-content:center;
              margin-top:12px; font-size:.74rem; color:var(--ink-dim,#b7abc8); cursor:pointer }
  .equip-cmp-discard-toggle input{ accent-color:#c05050 }
  /* choix de vente OBLIGATOIRE (sac plein) — voir #equipCmpSellRow, index.html */
  .equip-cmp-sell-row{ display:flex; align-items:center; gap:8px; justify-content:center;
              flex-wrap:wrap; margin-top:12px; font-size:.78rem; color:var(--ink-dim,#b7abc8) }
  .equip-cmp-sell-row select{ background:#2a2436; color:var(--ink,#efe7f5); font-size:.78rem;
              border:1px solid var(--panel-edge); border-radius:8px; padding:7px 10px;
              max-width:100%; min-height:34px }
  @media (max-width:520px){
    .equip-cmp-row{ flex-direction:column }
    .equip-cmp-vs{ transform:rotate(90deg) }
  }
  #bagFullList{ max-height:340px; margin:0 auto; text-align:left }
  #bagFullLeave{ padding:10px 22px; border-radius:10px }
  /* objet de MÊME TYPE que le ramassage en cours : mis en avant + bouton dédié */
  .inv-item.inv-sametype{ border-color:var(--target,#5cc8d8); background:#233238 }
  .inv-item .cmp-list{ margin-top:3px }
  .inv-item .inv-swap{ background:#1f3a40; border-color:var(--target,#5cc8d8); color:#bdeef5 }
  .inv-item .inv-swap:hover{ background:#264a52 }
  .inv-item .inv-space{ color:var(--ink-dim); font-size:.68rem }

  /* ---------- Bandeau d'avertissement (haut d'écran) ----------
     Distinct des toasts de succès (positifs, coin bas-droit) : celui-ci
     signale un événement vraiment notable — danger rare/imminent ("warn",
     orange) ou alerte de survie ("critical", rouge, pulse plus marqué). */
  /* PLACÉ DANS LE TIERS CENTRAL, ET PLUS GROS (2026-09-03, demande Pixel :
     « mets les toasts d'info plus gros et plus centrés au milieu de l'écran,
     là c'est trop haut »). À 14 px du bord, le bandeau se confondait avec
     l'en-tête et passait inaperçu — or c'est précisément le canal réservé aux
     événements qu'on ne DOIT pas manquer (alarme, boss, renforts…).
     38 % de la hauteur plutôt que 50 % : franchement dans le milieu de
     l'écran, mais toujours au-dessus du héros, qui est dessiné pile au centre
     et ne doit pas être masqué au moment où on l'avertit d'un danger. */
  /* COLLÉ EN HAUT, SOUS LA BARRE DE MENU (2026-09-04, demande Pixel). On
     réutilise `--hdr-h`, la hauteur MESURÉE de l'en-tête (syncHeaderHeightVar,
     js/44) : elle change avec la largeur de l'écran et la longueur du nom de
     niveau, donc toute valeur codée en dur finirait par chevaucher le menu —
     c'est exactement le bug déjà corrigé sur la barre de boss. */
  #warnBanner{ position:fixed; top:calc(var(--hdr-h, 80px) + 8px); left:50%; transform:translateX(-50%); z-index:65;
               display:flex; flex-direction:column; gap:10px; align-items:center;
               pointer-events:none; width:min(600px, 94vw) }
  .warn-toast{ display:flex; align-items:center; gap:14px; pointer-events:auto;
               background:linear-gradient(135deg,#3a2416,#241811);
               border:1px solid #e0a03c; border-left:6px solid #e0a03c;
               border-radius:12px; padding:14px 26px; color:#f5ece0;
               font-weight:700; font-size:1.15rem; line-height:1.35; text-align:center;
               max-width:100%;
               box-shadow:0 10px 34px rgba(0,0,0,.6), 0 0 26px rgba(224,160,60,.4);
               animation:warnIn .4s cubic-bezier(.2,1.3,.4,1) both; }
  .warn-toast.out{ animation:warnOut .35s ease-in forwards }
  .warn-toast .warn-ico{ font-size:2rem; line-height:1; flex:0 0 auto }
  .warn-toast.critical{ background:linear-gradient(135deg,#3a1620,#241016);
               border-color:#e0505a; border-left-color:#e0505a;
               box-shadow:0 8px 26px rgba(0,0,0,.6), 0 0 22px rgba(224,80,90,.5);
               animation:warnIn .4s cubic-bezier(.2,1.3,.4,1) both, warnPulse 1.1s ease-in-out .4s infinite; }
  @keyframes warnIn{ from{ transform:translateY(-24px) scale(.92); opacity:0 } to{ transform:none; opacity:1 } }
  @keyframes warnOut{ to{ transform:translateY(-16px); opacity:0 } }
  @keyframes warnPulse{ 0%,100%{ box-shadow:0 8px 26px rgba(0,0,0,.6), 0 0 22px rgba(224,80,90,.5) }
                         50%{ box-shadow:0 8px 26px rgba(0,0,0,.6), 0 0 34px rgba(224,80,90,.85) } }
  /* ---------- Barre de vie du BOSS engagé (js/69) ----------
     Sous le bandeau d'avertissement, centrée : nom + jauge + pastilles de
     phase (◆ atteintes / ◇ restantes). Passe en rouge pulsé en phase finale. */
  /* #bossBar : simple conteneur EMPILANT une carte .boss-bar-item par boss
     visible (BUG CORRIGÉ, retour Pixel : « quand il y a plusieurs boss seul
     une barre apparait » — avant, #bossBar ÉTAIT la carte unique, JS
     n'écrivait donc jamais que dans UN SEUL jeu d'éléments #bossBarName/
     #bossBarFill/#bossBarPips quel que soit le nombre de boss engagés).
     Chaque carte porte désormais sa propre mise en forme/classes
     (.phase3/.unknown) indépendamment des autres. */
  /* `--hdr-h` = hauteur MESURÉE de l'en-tête (syncHeaderHeightVar, js/44) : elle
     varie avec la largeur (l'en-tête passe à deux rangées sur petit écran) et
     avec la longueur du nom de niveau. Les 62 px codés en dur d'avant étaient
     une supposition, fausse dès que l'en-tête faisait 80 px — la barre de boss
     chevauchait alors le menu. */
  /* `--warn-h` = hauteur des toasts d'alerte actuellement affichés (0 sinon,
     voir syncWarnHeightVar, js/42) : la barre de boss se décale d'autant, les
     deux occupant désormais le même coin haut. */
  #bossBar{ position:fixed; top:calc(var(--hdr-h, 80px) + 8px + var(--warn-h, 0px)); left:50%; transform:translateX(-50%); z-index:62;
            display:none; flex-direction:column; gap:8px; pointer-events:none;
            width:min(420px, 88vw); align-items:stretch }
  #bossBar.show{ display:flex }
  .boss-bar-item{ display:flex; flex-direction:column; gap:5px;
            background:linear-gradient(135deg,rgba(32,22,40,.94),rgba(18,13,24,.94));
            border:1px solid var(--accent-dim,#8a7ab0); border-radius:10px; padding:8px 14px;
            box-shadow:0 8px 26px rgba(0,0,0,.6) }
  .boss-bar-head{ display:flex; align-items:baseline; justify-content:space-between; gap:10px }
  .bossBarName{ font-weight:700; font-size:.9rem; letter-spacing:.04em; color:var(--ink,#efe7f5) }
  .bossBarPips{ font-size:.8rem; color:var(--accent,#e0a83c); letter-spacing:.12em }
  .boss-bar-track{ height:9px; border-radius:5px; background:#1a1424;
                   border:1px solid var(--panel-edge,#3a3048); overflow:hidden }
  .bossBarFill{ height:100%; width:100%; border-radius:4px;
                background:linear-gradient(90deg,#e0a83c,#e05a3a); transition:width .25s ease-out }
  .boss-bar-item.phase3{ border-color:#e0505a; box-shadow:0 8px 26px rgba(0,0,0,.6), 0 0 22px rgba(224,80,90,.5);
                   animation:warnPulse 1.1s ease-in-out infinite }
  .boss-bar-item.phase3 .bossBarFill{ background:linear-gradient(90deg,#e0505a,#ff2a20) }
  .boss-bar-item.phase3 .bossBarPips{ color:#ff6a6a }
  .bossBarIcon{ display:none }
  /* ---------- PLUS DE DEUX BOSS : pastilles carrées (js/69) ----------
     Trois cartes pleines mangent le tiers de l'écran et repoussent le combat
     hors de vue. En pastilles, l'essentiel — qui est là, et dans quel état —
     tient sur une ligne ; le détail (nom, phase, jauge lisible) revient au
     SURVOL, une pastille à la fois. */
  #bossBar.compact{ flex-direction:row; justify-content:center; gap:6px;
            width:auto; pointer-events:none }
  #bossBar.compact .boss-bar-item{ position:relative; width:46px; height:46px;
            padding:4px; gap:3px; align-items:center; justify-content:center;
            pointer-events:auto; cursor:help }
  #bossBar.compact .bossBarIcon{ display:block; font-size:1.15rem; line-height:1 }
  #bossBar.compact .boss-bar-head{ display:none }
  #bossBar.compact .boss-bar-track{ width:100%; height:5px }
  /* Le détail au survol : la carte pleine, reconstruite au-dessus de la
     pastille — même contenu que le format normal, sans le dupliquer en DOM. */
  #bossBar.compact .boss-bar-item:hover{ width:auto; min-width:200px; height:auto;
            padding:8px 14px; z-index:2 }
  #bossBar.compact .boss-bar-item:hover .boss-bar-head{ display:flex }
  #bossBar.compact .boss-bar-item:hover .bossBarIcon{ display:none }
  #bossBar.compact .boss-bar-item:hover .boss-bar-track{ height:9px }
  @media (max-width:760px){ .boss-bar-item{ padding:6px 10px } .bossBarName{ font-size:.8rem }
            #bossBar.compact .boss-bar-item{ width:40px; height:40px } }

  /* ---------- Boss jamais vaincu (bestiaire, js/69 updateBossBar) ----------
     Même principe que la barre de vie des monstres normaux (masquée tant
     qu'ils ne sont pas vaincus, creatureKnown() js/02) — mais un boss ENGAGÉ
     ne peut pas juste disparaître du HUD en plein combat : sa jauge reste
     affichée, VISUELLEMENT CORROMPUE (capteur détraqué), jamais fiable, tant
     qu'on ne l'a pas déjà terrassé. Le pourcentage réel (fillEl.style.width)
     est déjà bruité côté JS ; le CSS ajoute le "signal cassé" — nom qui
     saute, remplissage strié, pastilles de phase illisibles. */
  .boss-bar-item.unknown{ border-color:#5a5a68; animation:bossGlitchShake 2.4s steps(1) infinite }
  .boss-bar-item.unknown .bossBarName{
    animation:bossGlitchText 2.4s steps(1) infinite;
    text-shadow:1px 0 #ff3050, -1px 0 #30d0ff;
  }
  .boss-bar-item.unknown .boss-bar-track{
    background:repeating-linear-gradient(90deg,#1a1424 0 3px,#241c30 3px 6px);
  }
  .boss-bar-item.unknown .bossBarFill{
    background:repeating-linear-gradient(45deg,#6a6a78 0 4px,#44445a 4px 8px);
    transition:width .12s steps(3);
  }
  .boss-bar-item.unknown .bossBarPips{ color:#7a7a88; font-family:monospace }
  /* phase 3 + inconnu : la couleur d'alerte prime, la corruption reste (nom/jauge) */
  .boss-bar-item.phase3.unknown{ border-color:#e0505a }
  /* chaque carte est maintenant un enfant EMPILÉ (plus de left:50%/translateX(-50%)
     individuel comme à l'époque de la carte unique) — le tremblement part donc
     d'une origine (0,0) simple plutôt que de "-50%". */
  @keyframes bossGlitchShake{
    0%,91%,100%{ transform:translate(0,0) }
    92%{ transform:translate(-3px, 1px) }
    93%{ transform:translate(2px, -1px) }
    94%{ transform:translate(0,0) }
    96%{ transform:translate(3px, 0) }
  }
  @keyframes bossGlitchText{
    0%,79%{ opacity:1; transform:none }
    80%{ opacity:.55; transform:translateX(-2px) }
    82%{ opacity:1; transform:translateX(1px) }
    84%{ opacity:.7; transform:none }
    86%{ opacity:1 }
  }

  @media (prefers-reduced-motion: reduce){
    .pip,.slot,#hpFill{transition:none}
    .warn-toast, .warn-toast.critical{ animation:none }
    .boss-bar-item.phase3{ animation:none }
    .boss-bar-item.unknown, .boss-bar-item.unknown .bossBarName{ animation:none }
  }
  @media (max-width:760px){
    header h1{width:100%}
    #hint{display:none}
    #log{max-width:200px}
  }

  /* Comparatif "objet du sac vs objet porté" dans le bandeau de détail
     (renderInvDetail, js/50) — même rendu ▲/▼ que la fenêtre de ramassage. */
  .inv-detail-cmp{ margin-top:6px; display:flex; flex-direction:column; gap:1px;
    border-top:1px solid var(--panel-edge,#3a3050); padding-top:6px }

/* ---------- ÉCRIN DES CŒURS DE GOLEM (2026-09-08, demande Pixel) ----------
   Placé après les éclats : ce sont des acquis de COMPTE, pas du contenu de sac.
   Autant d'alvéoles que d'éléments, les vides restant visibles — c'est la forme
   qui énonce l'objectif « un de chaque », sans une ligne de texte. */
  /* CENTRÉ (2026-09-08, demande Pixel). Le titre comme les alvéoles : un écrin
     s'expose, il ne s'aligne pas sur le bord comme une ligne de liste. */
  .inv-ecrin{ margin-top:8px; text-align:center }
  .inv-ecrin-slots{
    display:flex; gap:5px; flex-wrap:wrap; margin-top:4px;
    justify-content:center;
  }
  .ecrin-slot{
    width:30px; height:30px; flex:0 0 auto;
    display:flex; align-items:center; justify-content:center;
    background:#181322; border:1px dashed var(--panel-edge,#3a3050);
    border-radius:7px; box-shadow:inset 0 1px 3px rgba(0,0,0,.55);
  }
  /* alvéole PLEINE : trait continu, teinté de son élément (posé en style inline),
     et un fond légèrement relevé — la pièce est sertie, pas posée. */
  .ecrin-slot.rempli{
    border-style:solid; background:#241d33;
    box-shadow:inset 0 1px 3px rgba(0,0,0,.4), 0 0 6px rgba(255,255,255,.06);
  }
  .ecrin-slot img{ display:block; width:100%; height:100%; object-fit:contain; image-rendering:pixelated }
  .ecrin-emoji{ font-size:1rem; line-height:1 }
  /* COLLECTION COMPLÈTE : l'écrin entier s'allume — c'est ce moment-là qui
     ouvrira le bouton « Réunir » et le boss final. */
  .inv-ecrin.complet .inv-cat{ color:var(--accent,#e0a83c) }
  .inv-ecrin.complet .ecrin-slot.rempli{ box-shadow:0 0 8px rgba(224,168,60,.5) }
