/* v0.10.0 : la page d'accueil (login/register + Rules + About) remplace
   l'ancienne modale superposée à la carte — c'est maintenant une vraie page,
   pas une fenêtre par-dessus le jeu. */
.home-page{min-height:100vh;display:grid;place-items:center;padding:20px;background:radial-gradient(circle at 50% 30%,#151a21 0,#090c10 40%,var(--bg) 75%)}
.home-card{width:min(440px,94vw);padding:34px 30px;border:1px solid #3b4552;background:#10151b;text-align:left;box-shadow:0 30px 100px #000;max-height:92vh;overflow-y:auto}
.home-brand{display:flex;justify-content:center;align-items:center;margin-bottom:22px}
.home-tabs{margin:0 0 20px}
.home-tab-content{display:none}
.home-tab-content.active{display:block}
.home-tab-content .quiet{text-align:center}

/* v0.7.0 : comptes joueurs — onglets Connexion / Créer un compte */
.auth-tabs{margin:6px 0 20px}
.auth-form{display:grid;gap:14px}
.auth-form label{display:grid;gap:6px;font-size:11px;color:var(--muted);letter-spacing:.03em}
.auth-form label small{color:#657081;font-weight:400;letter-spacing:0}
.auth-form input[type=text],.auth-form input[type=password],.auth-form input[type=email],.auth-form input[type=file]{background:#161c24;border:1px solid var(--line);color:var(--text);padding:11px 12px;font-size:13px}
.auth-form button[type=submit]{width:100%;border:1px solid #245b47;background:#123d2d;color:#72e3ae;font-weight:900;font-size:12px;letter-spacing:.06em;padding:13px;cursor:pointer;margin-top:4px}
.auth-form .error{color:#ff7a7a;font-size:11px;margin:0}
/* v0.26.0 — "Forgot password?" / "Back to log in", styled as plain text links
   rather than full buttons (secondary actions, not competing with the main
   submit button above them). */
.link-button{background:none;border:0;color:var(--muted);font-size:11px;text-decoration:underline;cursor:pointer;padding:0;justify-self:center;margin-top:-4px}
.link-button:hover{color:var(--text)}
.faction-choice{border:1px solid var(--line);padding:12px;display:flex;gap:16px;justify-content:center}
.faction-choice legend{font-size:10px;color:var(--muted);letter-spacing:.04em;padding:0 6px;text-align:center}
.faction-choice label{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--text);letter-spacing:.04em;cursor:pointer}

/* v0.7.0 : avatar encerclé par la couleur du gang, sur la carte et dans la
   liste des gangsters — voir setAvatarDisplay()/markerHtml().
   v0.16.0 : coins carrés plutôt que ronds (demande explicite de Cédric,
   avatars partout dans le jeu) ; le wrap de case contient désormais un
   marqueur PAR occupant (plus de badge "+N" qui n'en montrait qu'un).
   v0.16.1 : correctif — les marqueurs s'empilaient exactement les uns sur
   les autres au lieu de se répartir côte à côte/en grille. En cause : le
   wrap était en `position:absolute` SANS largeur définie (juste `left`/
   `top` + `transform`), et un conteneur flex sans largeur connue ne peut
   pas calculer correctement son passage à la ligne (`flex-wrap`). Revenu à
   `inset:0` (taille exacte de la case, donc calculable) — le débordement
   visuel voulu par Cédric ("même si ça l'aggrandit, c'est pas grave") reste
   possible puisque rien ne coupe ce qui dépasse (`overflow` par défaut).
   `.marker-avatar` (nouveau) isole l'avatar + son badge véhicule dans son
   propre repère de positionnement, pour que le badge d'un occupant ne se
   retrouve plus ancré sur le wrap partagé (donc au même endroit que celui
   d'un autre occupant) une fois qu'il y a plus d'un joueur sur la case. */
.player-marker-wrap{position:absolute;inset:0;display:flex;flex-wrap:wrap;justify-content:center;align-items:center;align-content:center;gap:2px 4px;z-index:3;pointer-events:none}
/* v0.17.0 — the wrap stays pointer-events:none (so empty parts of a crowded
   cell still pass clicks through to the cell underneath for movement), but
   each marker opts back into pointer-events so the map can tell which
   player is under the cursor for the hover card (app.js, updatePlayerHoverAt) —
   a click on a marker still reaches the cell's own onclick via normal
   bubbling, pointer-events:none on an ancestor doesn't stop that. */
.marker-single{display:flex;flex-direction:column;align-items:center;gap:1px;pointer-events:auto}
.marker-avatar{position:relative;display:block}
/* v0.24.0 — "les carré avatar des joueurs et NPC soit un peu plus gros" :
   26px -> 32px (et le variant réduit .has-building ci-dessous, 16px -> 20px,
   dans les mêmes proportions). */
.player-marker{width:32px;height:32px;border:2px solid;display:grid;place-items:center;overflow:hidden;font-size:.65em;font-weight:900}
.player-marker img{width:100%;height:100%;object-fit:cover}

/* v0.17.0 — hover card for a player marker (Name/Gang/Rank/Transport, see
   app.js updateHoverCardAt/playerHoverCardHtml). Replaces the always-on
   name label that used to sit under each marker (.marker-name, retired this
   version — "enlever le nom des joueurs sous leurs avatar dans la map").
   Fixed positioning (not relative to the map) since #playerHoverCard lives
   outside the scrollable #mapViewport in the DOM and is placed in JS from
   viewport coordinates; pointer-events:none so it can never itself become
   the element the cursor is "over" (see elementFromPoint in updateHoverCardAt).
   v0.25.0 — generalized to 4 marker types (player/vehicle/building/NPC, see
   resolveHoverTarget() in app.js) ; same single card element and
   position/hide logic for all of them, only the inner content differs. */
.player-hover-card{position:fixed;z-index:30;pointer-events:none;min-width:150px;border:1px solid #3d4652;background:#12161cf2;box-shadow:0 12px 40px #0008;padding:12px 14px}
.hover-card-name{font-weight:900;font-size:13px;margin-bottom:8px;text-align:center}
.hover-card-facts{margin:0;display:grid;gap:5px}
.hover-card-facts div{display:flex;justify-content:space-between;gap:16px}
.hover-card-facts dt{color:var(--muted);font-size:10px;letter-spacing:.08em;margin:0}
.hover-card-facts dd{margin:0;font-size:11px;font-weight:800}
/* v0.25.0 — "je veux voir l'avatar du joueur en plus gros" (the card had no
   photo at all before this) + photo for the 3 new card types below. The
   player variant reuses the existing .red/.blue/.police classes (already the
   border/background/color used by .player-marker/.mini-avatar elsewhere) by
   just adding the player's faction as a 2nd class in playerHoverCardHtml();
   the other 3 types have no faction, so each gets its own neutral variant. */
.hover-card-photo{width:64px;height:64px;display:grid;place-items:center;overflow:hidden;font-size:26px;font-weight:900;margin:0 auto 10px;border:2px solid;border-radius:4px}
.hover-card-photo img{width:100%;height:100%;object-fit:cover;display:block}
.hover-card-photo.building{border-color:#3a4250;background:#0b0e12;color:#ffd166}
.hover-card-photo.vehicle{border-color:var(--line);background:#0b0e12}
.hover-card-photo.npc{border-color:#9aa5b1;background:#0b0e12}
/* NPC card is photo-only ("sans leurs nom et sans indiquer ce qu'il achete,
   juste la photo") — bigger since nothing else fills the card, and no
   bottom margin since nothing follows it. */
.hover-card-photo-only{width:84px;height:84px;margin-bottom:0;font-size:34px}

.avatar-ring{width:68px;height:68px;border:3px solid;display:grid;place-items:center;font-size:26px;font-weight:900;overflow:hidden;position:relative;margin:0 auto 16px}
.avatar-ring img{width:100%;height:100%;object-fit:cover}
.avatar-ring.big{width:120px;height:120px;font-size:46px}

.gangsters-list{display:grid;gap:10px;margin-top:18px}
.gangster-row{display:flex;align-items:center;gap:12px;border:1px solid var(--line);background:#12161c;padding:12px 14px;cursor:pointer;color:var(--text);text-align:left;width:100%;font-family:inherit}
.gangster-row:hover{border-color:var(--amber)}
.gangster-row .player-marker{position:static;width:34px;height:34px;font-size:14px}
.gangster-row span{flex:1;font-weight:700;font-size:13px}
.gangster-row small{color:var(--muted);font-size:10px;letter-spacing:.06em}

.gangster-card{text-align:center}
.gangster-card h2{margin:0 0 4px}

/* --- v0.3 additions ------------------------------------------------- */
.vehicle-picker{display:grid;grid-template-columns:1fr 1fr;gap:6px;margin:8px 0}
.vehicle-btn{border:1px solid var(--line);background:#161c24;color:var(--muted);font-size:10px;font-weight:800;letter-spacing:.04em;padding:8px 4px;cursor:pointer}
.vehicle-btn.active{border-color:var(--amber);color:var(--text);background:#231d10}
.vehicle-btn:disabled{opacity:.4;cursor:not-allowed}
.person button:disabled,.hit-card button:disabled{opacity:.35;cursor:not-allowed}
.quiet-inline{margin-left:auto;color:var(--muted);font-size:10px;text-align:right;max-width:120px}

/* v0.18.0 — avatar+name roster inside a Gang Hits list card (attackers/
   defenders/crew), replacing the plain comma-separated name text that used
   to be all a card showed before opening it. Small enough that several fit
   per row inside the ~280-300px card width, wraps to more rows if crowded
   — same "let it wrap rather than hide someone" spirit as the map markers
   (v0.16.0/v0.17.0). */
.hit-roster-label{font-size:9px;letter-spacing:.1em;color:var(--muted);text-transform:uppercase}
.hit-roster{display:flex;flex-wrap:wrap;gap:8px 10px;margin-top:-6px}
.hit-roster-item{display:flex;flex-direction:column;align-items:center;gap:3px;width:46px}
.hit-roster-item .mini-avatar{width:30px;height:30px;font-size:12px}
.hit-roster-item span{font-size:9px;color:var(--muted);text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:46px}

.hits-toolbar{display:flex;gap:8px;margin-bottom:14px}
.pill{flex:1;border:1px solid var(--line);background:#151a21;color:var(--muted);font-size:10px;font-weight:800;letter-spacing:.06em;padding:9px 6px;cursor:pointer}
.pill.active{border-color:var(--amber);color:var(--text)}
#hitsList{display:grid;gap:12px}
.hit-card button.join{border-color:#245b47;background:#123d2d;color:#72e3ae}
/* v0.15.0 — full-width Gang Hits page (#page-hits): same list, wider grid
   since it isn't squeezed into the side panel's 300px column. */
.hits-list-page{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px}
.van-hit-card{border-color:#6e5725}
.van-hit-card p{color:var(--amber)}
.page-title-count{font-style:normal;font-size:14px;background:var(--red);color:#fff;border-radius:12px;padding:3px 10px;margin-left:10px;vertical-align:middle}
.completed-hits{margin-top:18px;border-top:1px solid var(--line);padding-top:12px}
.completed-hits summary{cursor:pointer;font-size:11px;color:var(--muted);letter-spacing:.08em}
.completed-row{display:flex;flex-direction:column;gap:2px;padding:10px 0;border-bottom:1px solid #212832;font-size:11px}
.completed-row span{color:var(--text)}
.completed-row small{color:var(--muted)}

.combat-card{width:min(920px,96vw)}
.combat-body{display:grid;grid-template-columns:1fr minmax(260px,340px) 1fr;gap:16px;margin-top:20px;align-items:start}
.side-panel{border:1px solid #2a313b;background:#0e1319;padding:14px;max-height:340px;overflow-y:auto}
.side-label{font-size:10px;letter-spacing:.14em;color:var(--muted);margin:0 0 10px}
.side-list{display:grid;gap:8px}
.combat-row{display:flex;align-items:center;gap:9px;padding:8px;border:1px solid transparent;cursor:default}
.combat-row[data-select]{cursor:pointer}
.combat-row[data-select]:hover{border-color:#3d4652}
.combat-row.selected{border-color:var(--red);background:#1c1013}
.combat-row.left{opacity:.45}
.combat-row div:nth-child(2){display:grid;gap:3px;flex:1;min-width:0}
.combat-row strong{font-size:12px}
.combat-row span{font-size:10px;color:var(--muted)}
.combat-row-meter{height:4px;background:#282e36;width:100%}
.combat-row-meter b{display:block;height:100%;background:var(--red)}
.combat-row .dmg{color:var(--amber);font-size:10px}
.target-stage{margin-top:0}
.target-stage .enemy-portrait{inset:18px 22px;font-size:0}
.target-stage .enemy-portrait span{font-size:26px;display:block}
.target-stage .enemy-portrait small{font-size:10px}
.combat-ready{display:none}
.combat-ready:not(.hidden){display:flex}
#strikeButton:disabled{opacity:.4;cursor:not-allowed}
.combat-ended-note{margin-top:18px;padding:16px;border:1px solid var(--line);background:#12161c;color:var(--muted);text-align:center;font-size:12px}
.combat-log{margin-top:18px;border:1px solid var(--line);background:#0c1015;padding:12px 14px;max-height:130px;overflow-y:auto;display:grid;gap:6px}
.log-row{font-size:11px;color:#c3cad4;display:flex;gap:8px}
.log-row time{color:var(--muted);font-variant-numeric:tabular-nums;flex-shrink:0}
.log-row.quiet{color:var(--muted)}
.combat-controls{display:flex;gap:10px;margin-top:16px;justify-content:flex-end}
.combat-controls button{border:1px solid #803038;background:#3a151a;color:#ff7a7a;font-size:11px;font-weight:900;padding:10px 16px;cursor:pointer}
#joinCombatButton{border-color:#245b47;background:#123d2d;color:#72e3ae}
@media(max-width:900px){.combat-body{grid-template-columns:1fr}.side-panel{max-height:180px}}

/* --- v0.3.1 additions: stats / weapons / territory -------------------- */

/* v0.3.4 : barres de stats (remplace l'ancien tableau dt/dd) */
.stats-bars{display:grid;gap:9px;margin:14px 0 6px;max-height:220px;overflow-y:auto;padding-right:4px}
.stat-row{display:grid;grid-template-columns:72px 1fr 46px;align-items:center;gap:8px}
.stat-label{color:var(--muted);font-size:11px}
.stat-bar{height:7px;background:#282e36;border-radius:4px;overflow:hidden}
.stat-bar b{display:block;height:100%;background:var(--green);border-radius:4px}
.stat-value{color:var(--text);text-align:right;font-variant-numeric:tabular-nums;font-size:10px}

/* v0.8.0 : Rang (remplace la barre XP + bouton d'allocation de v0.4.0) —
   simple note "X pts / seuil suivant" à côté du libellé du rang. */
.xp-label{color:var(--muted);font-weight:600;font-size:9px;margin-left:6px}

/* v0.8.0 : bouton vol de voiture, panneau joueur — style "illicite" comme
   #robButton (bordure/texte rouges), en plus petit. */
.small-action{width:100%;padding:9px;font-size:11px;font-weight:800;letter-spacing:.04em;margin-top:4px;border:1px solid #803038;background:#3a151a;color:#ff7a7a;cursor:pointer}
.small-action:disabled{opacity:.4;cursor:not-allowed}

.weapon-picker{grid-template-columns:1fr 1fr;max-height:260px;overflow-y:auto;padding-right:2px}
.weapon-btn{display:flex;flex-direction:column;align-items:center;gap:2px;line-height:1.3}
.weapon-btn small{color:var(--muted);font-weight:600;font-size:9px}
.weapon-btn.active small{color:var(--amber)}

.cell.owned-red{border-color:#5a2323;background:linear-gradient(135deg,#241213,#171d24)}
.cell.owned-blue{border-color:#233a5a;background:linear-gradient(135deg,#121a24,#171d24)}
.cell.contested:not(.current):before{content:"⚑";position:absolute;left:8%;bottom:6%;font-size:.8em;color:var(--amber)}
.cell.current.owned-red,.cell.current.owned-blue{border-color:var(--red)}
.legend .owned-red{background:#5a2323;border:1px solid #8a3535}
.legend .owned-blue{background:#233a5a;border:1px solid #355a8a}

/* Cases où le joueur actif peut se déplacer (orthogonal + diagonale) —
   surbrillance pâle plutôt qu'un indicateur de destination. */
.cell.reachable{box-shadow:inset 0 0 0 1000px rgba(255,255,255,.07);border-color:#4a5560}
.cell.reachable:hover{box-shadow:inset 0 0 0 1000px rgba(255,255,255,.12)}
.legend .reachable{background:rgba(255,255,255,.15);border:1px solid #4a5560}

/* v0.3.4 : la carte 15x15 n'affiche plus qu'une fenêtre ~10x10 à la fois,
   avec des cases nettement plus grandes ; #map est dimensionné en JS
   (sizeMap()) pour remplir #mapViewport, qui lui remplit l'écran disponible
   dans le panneau. Le défilement révèle le reste de la grille. */
.map-viewport::-webkit-scrollbar{width:10px;height:10px}
.map-viewport::-webkit-scrollbar-thumb{background:#2a313b}
.map-viewport::-webkit-scrollbar-track{background:#0c1015}

/* Magasins sur la carte */
.shop-icon{position:absolute;right:6%;top:50%;transform:translateY(-50%);font-size:1.2em;line-height:1;filter:drop-shadow(0 0 2px #000)}
.cell.shop-weapon{border-color:#6e5725}
.cell.shop-vehicle{border-color:#245b47}
.cell.shop-hideout{border-color:#7a2f8c}
/* v0.8.0 : hôpital (icône partage l'emplacement des magasins/hideout) */
.cell.shop-hospital{border-color:#2f7a6e}
/* v0.21.0 : prison (case fixe unique, voir CONFIG.prisonBlock) */
.cell.shop-prison{border-color:#4a5568}

/* v0.8.0 : banques (fixes) et fourgons (mobiles) — coin haut-gauche, pour ne
   jamais chevaucher shop-icon (droite) ni business-icon (bas-gauche). */
.heist-icon{position:absolute;left:6%;top:6%;font-size:1.1em;line-height:1;filter:drop-shadow(0 0 2px #000)}

/* v0.6.0 : plus d'icône proxénète sur la carte — elles sont volontairement
   invisibles (voir personalizePimps côté serveur) ; règles .pimp-icon /
   .cell.has-pimp de v0.5.0 retirées avec le rendu correspondant dans app.js. */

/* v0.4.0 : commerce par case (icône distincte des magasins fixes, coin
   opposé pour ne jamais chevaucher l'icône de magasin) */
.business-icon{position:absolute;left:6%;bottom:6%;font-size:1.1em;line-height:1;filter:drop-shadow(0 0 2px #000)}

/* v0.22.0 : prison avec avatar custom (uploadé depuis /admin) — .shop-icon
   reste positionné pareil, mais en <img> plutôt qu'en <i> emoji, il faut lui
   donner une taille explicite (le "font-size" de la règle .shop-icon
   ci-dessus ne dimensionne pas une image). */
img.shop-icon{width:1.5em;height:1.5em;object-fit:cover;border-radius:3px}

/* v0.22.0 : bâtiments à posséder — "un avatar carré assez gros pour qu'on
   reconnaisse c'est quoi le batiment", toujours visible comme les banques.
   v0.22.0-v0.24.0 : pointer-events:none pour ne jamais intercepter le clic
   sur la case (onCellClick gère déjà l'ouverture de la page Buildings quand
   on est sur son bloc).
   v0.25.0 : repassé à pointer-events:auto pour que la fenêtre contextuelle
   (survol, voir buildingHoverCardHtml() dans app.js) puisse détecter ce
   marqueur — sans ça elementFromPoint() l'ignore entièrement, comme le reste
   de sa case en dessous. Le clic continue d'atteindre le `.cell` normalement
   par bubbling (le marqueur est un enfant DOM du `.cell`, `onCellClick` ne
   lit jamais `event.target`) — même principe déjà en place pour
   `.marker-single` plus haut, qui est lui aussi cliquable sans intercepter
   le déplacement.
   v0.22.1 : corrigé sur retour de Cédric — l'avatar occupait tout le centre
   de la case, exactement là où se dessine aussi l'avatar du joueur présent,
   rendant illisible "qui est sur la case" (les deux se superposaient). Le
   marqueur occupe la partie BASSE de la case (le haut reste libre pour
   `.player-marker-wrap`, repositionné plus haut ci-dessous). z-index:2 reste
   sous .player-marker-wrap (z-index:3), donc un joueur présent reste visible
   par-dessus le HAUT du marqueur.
   v0.22.2 : le débordement volontaire sous la case (bottom négatif, accepté
   une première fois par Cédric le temps du correctif précédent) est retiré
   — Cédric est revenu dessus dès qu'il l'a vu en vrai ("c'est pas bon,
   l'image déborde sur le bas"). Les cases étant maintenant nettement plus
   grandes (la carte remplit tout le panneau central plutôt qu'une petite
   fenêtre 10x10), il y a largement la place de loger avatar joueur + image
   + nom ENTIÈREMENT à l'intérieur de la case — `bottom` repasse donc à une
   valeur positive, plus aucun débordement. */
.building-marker{position:absolute;left:6%;right:6%;top:24%;bottom:4%;z-index:2;pointer-events:auto;display:flex;flex-direction:column;align-items:center;gap:2px}
.building-marker-img{flex:1;width:100%;min-height:0;overflow:hidden;border-radius:4px;background:#000a;border:1px solid #3a4250;display:flex;align-items:center;justify-content:center}
.building-marker-img img{width:100%;height:100%;object-fit:cover;display:block}
.building-marker-img span{font-size:1.4em;font-weight:900;color:#ffd166;filter:drop-shadow(0 0 2px #000)}
.building-marker-name{flex-shrink:0;font-size:.6em;font-weight:800;color:#f2f4f7;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%;text-shadow:0 0 3px #000,0 0 4px #000}
/* v0.23.0 — contour de la couleur du camp propriétaire ("essayer d'évité
   qu'un membre de même gang l'achète, même si c'est permis") : la bordure/
   ombre de `.building-marker-img` change de couleur selon `ownedBuilding.
   ownerFaction`, posé côté client comme classe `owner-red`/`owner-blue`/
   `owner-police` sur `.building-marker`. Sans propriétaire (jamais acheté),
   la bordure grise par défaut ci-dessus reste inchangée. */
.building-marker.owner-red .building-marker-img{border-color:var(--red);box-shadow:0 0 8px #e3424280}
.building-marker.owner-blue .building-marker-img{border-color:var(--blue);box-shadow:0 0 8px #3b82f680}
.building-marker.owner-police .building-marker-img{border-color:#9aa5b1;box-shadow:0 0 8px #9aa5b180}

/* v0.24.0 — NPC client de drogue ("qu'on voit sur la carte... le contour des
   avatar NPC est gris"). Coin supérieur-droit de la case pour ne jamais se
   superposer au marqueur de bâtiment (ancré en bas) ni aux avatars de
   joueurs (centrés) ; toujours gris, jamais coloré par un camp — contraire à
   `.building-marker` ci-dessus — puisqu'un NPC n'appartient à aucun gang
   ("ils sont neutre, juste des clients").
   v0.25.0 — repassé à pointer-events:auto (même raison que `.building-marker`
   ci-dessus) pour que la fenêtre contextuelle au survol (npcHoverCardHtml()
   dans app.js, photo seule, sans nom ni drogue voulue) puisse détecter ce
   marqueur. Le clic continue de traverser jusqu'au `.cell` par bubbling. */
.npc-marker{position:absolute;top:3%;right:3%;width:30px;height:30px;z-index:2;pointer-events:auto}
.npc-marker-img{width:100%;height:100%;border-radius:50%;overflow:hidden;background:#000a;border:2px solid #9aa5b1;box-shadow:0 0 6px #9aa5b180;display:grid;place-items:center;font-size:16px}
.npc-marker-img img{width:100%;height:100%;object-fit:cover;display:block}

/* v0.23.0 — écran de prison affiché à la connexion si le joueur purge une
   peine ("s'il se connecte, il doit avoir un écran avec une photo de prison
   et un texte disant combien de temps il lui reste à purger sa peine"). */
.prison-login-card{text-align:center}
.prison-login-avatar{width:160px;height:160px;margin:0 auto 16px;border-radius:6px;overflow:hidden;background:#000a;border:1px solid #3a4250;display:grid;place-items:center;font-size:56px}
.prison-login-avatar img{width:100%;height:100%;object-fit:cover}

/* v0.22.1 : quand un joueur se trouve sur la case d'un bâtiment, ses
   marqueurs se recroquevillent en haut (au lieu de rester centrés, ce qui
   les faisait chevaucher pile l'avatar du bâtiment juste en dessous) —
   "j'aimerais que le gangster soit en haut du batiment". */
.cell.has-building .player-marker-wrap{align-items:flex-start;align-content:flex-start;padding-top:3%}
.cell.has-building .player-marker{width:20px;height:20px;font-size:.48em;border-width:1px}
.cell.has-building .vehicle-badge{width:9px;height:9px;font-size:6px;left:-2px;bottom:-2px}

/* Statut véhicule en lecture seule (achat/équipement au magasin) */
.loadout-status{color:var(--text);font-size:13px;font-weight:700}

/* v0.20.0 — sélecteur d'arme dans le menu de gauche ("je veux pouvoir
   changer d'arme" + voir le nombre de munitions), à côté du statut véhicule
   en lecture seule ci-dessus. Ne liste que les armes possédées (achat non
   inclus, ça reste réservé au magasin d'armes) ; le serveur garde la même
   règle qu'avant ("il faut être physiquement au magasin pour changer
   d'arme") — voir socket.on('setWeapon') côté serveur, inchangé. */
.loadout-select{width:100%;background:#12181f;color:var(--text);border:1px solid #2b333d;font-size:12px;font-weight:700;padding:7px 8px;cursor:pointer}
.loadout-select:focus{outline:1px solid var(--amber)}
.ammo-note{color:var(--amber);font-size:11px;font-weight:700;letter-spacing:.04em}

/* Business/Gangster popup (weapon/car shop popup removed in v0.9.0 — buying
   now happens inline in Buildings, see .shop-list/.shop-row below) */
.shop-card{width:min(420px,92vw);border:1px solid #3d4652;background:#10151b;padding:26px;position:relative;box-shadow:0 30px 100px #000}
.shop-card h2{font-size:22px;margin:0 0 18px}

/* v0.9.0 : liste d'achat en ligne (magasin d'armes/concessionnaire), dans
   l'onglet Buildings — remplace le popup #shopModal de v0.3.3 */
.shop-list{display:grid}
.shop-row{display:flex;align-items:center;gap:12px;border-top:1px solid #212832;padding:11px 0}
.shop-row:first-child{border-top:0}
.shop-row-head{flex:1;display:flex;align-items:baseline;gap:8px}
.shop-row-head small{color:var(--green);font-size:10px;letter-spacing:.06em}
.shop-row-price{color:var(--amber);font-weight:800;font-size:12px;min-width:70px;text-align:right}
.shop-row button{border:1px solid #245b47;background:#123d2d;color:#72e3ae;font-weight:800;font-size:11px;letter-spacing:.04em;padding:9px 14px;cursor:pointer}
.shop-row button:disabled{opacity:.4;cursor:not-allowed}
/* v0.19.0 — ammo rows add a quantity input before the BUY button (see
   renderAmmoSection); weapon/vehicle rows never had one before this. */
.shop-row input[type=number]{width:60px;background:#161c24;border:1px solid var(--line);color:var(--text);padding:9px 8px;font-size:12px}
.shop-row input[type=number]:disabled{opacity:.4;cursor:not-allowed}

/* v0.4.0 : commerce (bouton unique, réutilise le style du bouton de magasin) */
#businessActionButton,#pimpActionButton{width:100%;border:1px solid #245b47;background:#123d2d;color:#72e3ae;font-weight:900;font-size:12px;letter-spacing:.06em;padding:13px;cursor:pointer;margin-top:6px}
#businessActionButton:disabled,#pimpActionButton:disabled{opacity:.4;cursor:not-allowed}

/* --- v0.5.0 : onglet Business (banque, drogue, proxénètes, commerces) --- */
.biz-section{border:1px solid var(--line);background:linear-gradient(180deg,#12161c,#0d1116);padding:22px;margin-bottom:16px}
.biz-section h3{font-size:15px;margin:0 0 10px}
.bank-row{display:flex;gap:24px;margin:14px 0}
.bank-figure{display:flex;flex-direction:column;gap:4px}
.bank-figure span{font-size:11px;color:var(--muted);letter-spacing:.06em}
.bank-figure strong{font-size:20px}
.bank-actions{display:grid;grid-template-columns:1fr auto auto;gap:10px}
.bank-actions input{background:#161c24;border:1px solid var(--line);color:var(--text);padding:10px 11px;font-size:13px}
.bank-actions button{border:1px solid #245b47;background:#123d2d;color:#72e3ae;font-weight:900;font-size:12px;letter-spacing:.04em;padding:0 16px;cursor:pointer}
.bank-actions button.ghost{border-color:var(--line);background:transparent;color:var(--muted)}
.bank-actions button:disabled{opacity:.4;cursor:not-allowed}

.drug-row,.pimp-row{border-top:1px solid #212832;padding:12px 0}
.drug-row:first-child,.pimp-row:first-child{border-top:0}
.drug-head,.pimp-head{display:flex;align-items:baseline;gap:8px;margin-bottom:6px}
.drug-head small,.pimp-head small{color:var(--muted);font-size:10px}
.drug-figures,.pimp-figures{display:flex;flex-wrap:wrap;gap:16px;font-size:11px;color:var(--muted);margin-bottom:10px}
.drug-figures b,.pimp-figures b{color:var(--text)}
.drug-actions-row,.pimp-actions-row{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.drug-actions-row input,.pimp-actions-row input{width:96px;background:#161c24;border:1px solid var(--line);color:var(--text);padding:9px 10px;font-size:12px}
.drug-actions-row button,.pimp-actions-row button{border:1px solid #245b47;background:#123d2d;color:#72e3ae;font-weight:800;font-size:11px;letter-spacing:.04em;padding:9px 14px;cursor:pointer}
.drug-actions-row button:disabled,.drug-actions-row input:disabled{opacity:.4;cursor:not-allowed}
.pimp-services{margin-left:auto}
.save-confirm{color:#72e3ae;font-weight:800;font-size:11px;letter-spacing:.03em}
.save-confirm.hidden{display:none}

/* v0.6.0 : bouton de braquage (onglet Buildings) */
#robButton{width:100%;border:1px solid #803038;background:#3a151a;color:#ff7a7a;font-weight:900;font-size:12px;letter-spacing:.06em;padding:13px;cursor:pointer;margin-top:6px}
#robButton:disabled{opacity:.4;cursor:not-allowed}

.building-row{display:flex;justify-content:space-between;border-top:1px solid #212832;padding:10px 0;font-size:12px}
.building-row:first-child{border-top:0}

/* v0.22.0 : "Buildings You Own" (bâtiments à posséder) — délibérément
   distinct de .building-row ci-dessus (commerce par case, page Business,
   fonctionnalité sans rapport) pour éviter toute collision de nom. */
.owned-buildings-list{display:block}
.owned-building-row{display:flex;align-items:center;gap:10px;border-top:1px solid #212832;padding:10px 0;font-size:12px}
.owned-building-row:first-child{border-top:0}
/* v0.24.0 — "j'aimerais voir l'image du building que j'ai uploadé" : small
   square thumbnail leading each row, same avatar/fallback-letter pattern as
   the map marker (.building-marker-img). */
.owned-building-thumb{width:32px;height:32px;flex-shrink:0;border-radius:4px;overflow:hidden;background:#000a;border:1px solid #3a4250;display:grid;place-items:center;font-size:14px;font-weight:900;color:#ffd166}
.owned-building-thumb img{width:100%;height:100%;object-fit:cover}
.owned-building-info{display:flex;justify-content:space-between;flex:1;min-width:0;gap:10px}

/* v0.8.0 : hôpital (bouton "repos", même style que robButton — action
   engageante plutôt qu'un simple achat) */
#hospitalRestButton{width:100%;border:1px solid #245b47;background:#123d2d;color:#72e3ae;font-weight:900;font-size:12px;letter-spacing:.06em;padding:13px;cursor:pointer;margin-top:6px}
#hospitalRestButton:disabled{opacity:.4;cursor:not-allowed}

/* v0.8.0 : braquages de banque/fourgon — réutilise la structure des lignes
   drogue/proxénète (.drug-row/.pimp-row) */
.heist-table{display:grid}
.heist-row{border-top:1px solid #212832;padding:12px 0}
.heist-row:first-child{border-top:0}
.heist-head{display:flex;align-items:baseline;gap:8px;margin-bottom:6px}
.heist-head small{color:var(--muted);font-size:10px}
.heist-figures{display:flex;flex-wrap:wrap;gap:16px;font-size:11px;color:var(--muted);margin-bottom:10px}
.heist-figures b{color:var(--text)}
.heist-actions-row{display:flex;justify-content:space-between;align-items:center;gap:10px}
.heist-actions-row.centered{justify-content:center}
.heist-actions-row button{border:1px solid #803038;background:#3a151a;color:#ff7a7a;font-weight:800;font-size:11px;letter-spacing:.04em;padding:9px 14px;cursor:pointer}
.heist-actions-row button:disabled{opacity:.4;cursor:not-allowed}

/* v0.9.0 : cartes de rencontre dynamique sur le bloc courant, panneau
   "ON THIS BLOCK" à côté de la carte — hustler (persuasion par mot-clé) et
   fourgon (braquage), visibles uniquement tant que l'un des deux est là. */
.block-encounter-card{border:1px solid #3d4652;background:#151a21;padding:14px;margin-bottom:14px}
.block-encounter-eyebrow{font-size:10px;letter-spacing:.14em;color:var(--amber);margin:0 0 8px}
.block-encounter-card>p:not(.block-encounter-eyebrow):not(.quiet){font-size:12px;color:var(--muted);margin:0 0 10px;line-height:1.5}
.block-encounter-row{display:flex;gap:8px;align-items:center}
.block-encounter-row input{flex:1;background:#161c24;border:1px solid var(--line);color:var(--text);padding:9px 10px;font-size:12px}
.block-encounter-row button{border:1px solid #245b47;background:#123d2d;color:#72e3ae;font-weight:800;font-size:11px;letter-spacing:.04em;padding:9px 12px;cursor:pointer;white-space:nowrap}
#blockVanCard .heist-row{border-top:0;padding:0}
#pimpStatus:empty{display:none}

/* v0.11.0 : avatar de hustler (admin-managed, /admin → Hustlers) — pas de
   camp, donc une teinte neutre plutôt que le rouge/bleu de .mini-avatar. Sert
   à la fois sur la carte de rencontre (bloc courant) et la liste "Hustlers
   on Your Payroll". */
.mini-avatar.hustler{background:#2b1a2b;color:#e691dd;border-color:#6d2f66}
.block-encounter-head{display:flex;align-items:center;gap:10px;margin-bottom:8px}
.block-encounter-head strong{font-size:13px}
.pimp-head .mini-avatar{width:30px;height:30px;font-size:13px}
/* v0.10.0 : voiture volable trouvée sur le bloc courant — même carte que
   hustler/fourgon ci-dessus. */
#blockCarCard .block-encounter-row strong{flex:1;font-weight:700;font-size:12px}

/* v0.10.0 : bouton Hide (déconnexion) dans la barre du haut, à côté du
   statut serveur. */
.topbar-actions{display:flex;align-items:center;gap:16px}
.hide-button{border:1px solid #803038;background:#3a151a;color:#ff7a7a;font-weight:800;font-size:11px;letter-spacing:.06em;padding:8px 16px;cursor:pointer}
.hide-button:hover{background:#4a1c22}

/* v0.10.0 : icône véhicule sur le marqueur d'un joueur sur la carte (voiture
   volable, voiture de magasin...) — image admin si personnalisée, sinon un
   emoji générique par véhicule (voir VEHICLE_EMOJI côté client). */
.vehicle-badge{position:absolute;left:-4px;bottom:-4px;width:16px;height:16px;display:grid;place-items:center;font-size:11px;background:#0b0e12;border:1px solid var(--line);border-radius:50%;overflow:hidden;line-height:1}
.vehicle-badge img{width:100%;height:100%;object-fit:cover}

/* v0.10.0 : vignette véhicule dans la liste du concessionnaire (Buildings),
   quand l'admin a personnalisé une image pour ce véhicule. */
.shop-row-thumb{width:34px;height:34px;object-fit:cover;border:1px solid var(--line);flex-shrink:0}

/* --- v0.5.0 : onglet News Paper (flux global) --- */
.feed-list{display:grid;gap:2px}
.feed-row{display:grid;grid-template-columns:60px 60px 1fr;gap:10px;align-items:baseline;padding:8px 0;border-bottom:1px solid #212832;font-size:12px}
.feed-row time{color:var(--muted);font-variant-numeric:tabular-nums;font-size:11px}
.feed-block{color:var(--amber);font-size:10px;letter-spacing:.04em}
.feed-row p{margin:0;color:#c3cad4}

/* v0.13.0 — protection bar under a vehicle's map badge (mapMarkerHtml),
   scaled to a max of 300 ("un score équivalent à 300"). Positioned right
   below the small circular vehicle-badge icon. */
.vehicle-protection-bar{position:absolute;left:-4px;bottom:-9px;width:16px;height:3px;background:#0b0e12;border:1px solid var(--line);overflow:hidden}
.vehicle-protection-bar i{display:block;height:100%;background:var(--amber)}

/* v0.13.0 — van heist card (block side panel): truck avatar (admin-supplied
   image, see /van-avatar.png) + a strength bar with NO number ("sans
   nombre, juste comme une barre force"), unlike the numeric stat bars
   elsewhere. */
.van-heist-row{padding-top:2px}
.van-heist-head{align-items:center;gap:10px;margin-bottom:10px}
.van-avatar{width:44px;height:44px;object-fit:cover;border:1px solid var(--line);background:#161c24;flex-shrink:0}
/* v0.24.0 — emoji fallback for an NPC without an uploaded avatar, reusing
   .van-avatar's sizing (see npcCardHtml() in app.js) but as a centered emoji
   rather than an <img>, since object-fit/width/height need `display:grid`
   on a <span> to actually take effect. */
.npc-avatar-fallback{display:grid;place-items:center;font-size:20px}
.van-heist-head small{display:block;color:var(--muted);font-size:10px;margin-top:2px}
.van-strength-bar{height:8px;background:#282e36;border-radius:4px;overflow:hidden;margin-bottom:10px}
.van-strength-bar i{display:block;height:100%;background:var(--red)}

/* v0.14.0 — reusable green→amber→red protection meter, replaces plain-text
   eligibility hints on the street-car and bank-heist cards. The fill itself
   carries the full gradient clipped to its width, so a low protection value
   reads as green and a high one reads as red without a number anywhere. */
.protection-meter{height:8px;background:#282e36;border-radius:4px;overflow:hidden;margin:8px 0}
.protection-meter i{display:block;height:100%;background:linear-gradient(90deg,var(--green),var(--amber),var(--red))}

/* v0.21.0 — snitch/prime & prison (occupant list + Buildings > Prison). Le
   bandeau "WANTED" et le bouton snitch s'affichent sous n'importe quel
   occupant primé (pas seulement les ennemis, voir renderPeople) ; le tag
   "Behind bars" remplace le bouton TARGET pour une cible emprisonnée. */
.bounty-row{grid-column:1/-1;display:grid;gap:6px;margin-top:8px;padding-top:8px;border-top:1px dashed #3a2a1a}
.bounty-tag{display:inline-block;color:var(--amber);font-size:10px;font-weight:900;letter-spacing:.1em;background:#2a1f0e;border:1px solid #5c471f;padding:3px 7px;width:fit-content}
.snitch-btn,.arrest-btn{width:100%;border:1px solid #803038;background:#3a151a;color:#ff7a7a;font-size:10px;font-weight:900;padding:9px 11px;cursor:pointer;text-align:center}
.arrest-btn{border-color:#3a4b5c;background:#131c26;color:#9fc4e8}
.snitch-btn:disabled,.arrest-btn:disabled{opacity:.35;cursor:not-allowed}
.jail-tag{display:inline-block;color:#c4ccd6;font-size:10px;font-weight:800;letter-spacing:.08em;background:#1c1f24;border:1px solid #4a5568;padding:2px 7px;width:fit-content}

.prison-row{display:flex;align-items:center;gap:11px;padding:13px 0;border-bottom:1px solid #252b33}
.prison-row div:nth-child(2){display:grid;gap:4px}
.prison-row span{color:var(--muted);font-size:11px}
.prison-row button{margin-left:auto;border:1px solid #287151;background:#123d2d;color:#72e3ae;font-size:10px;font-weight:900;padding:9px 11px;cursor:pointer}
.prison-row button:disabled{opacity:.35;cursor:not-allowed}
.prison-rival{margin-left:auto;color:var(--muted);font-size:11px;font-style:italic}
#prisonSelfCard{border:1px solid #4a5568;background:#1c1f24;padding:14px;margin-bottom:16px}
#prisonSelfCard #prisonSelfStatus{color:#c4ccd6;font-weight:800}
