Après avoir cliqué sur ACHETER, aucune indication ne montrait que l'achat
était pris en compte avant que la mini-carte définitive n'apparaisse à
côté de la main (à la résolution du tour, plusieurs secondes plus tard).
Le serveur exposait déjà pendingBuyItemId/pendingBuyBuildingId via
getStateFor(), mais rien côté client ne les utilisait.
- ItemBoardToken.js : nouveau paramètre `pending`. Quand actif, le jeton
compact affiche un halo doré pulsant (tween alpha 1<->0.25 en boucle) et
un texte "En attente..." sous l'icône, tant que l'achat n'est pas résolu.
Le bouton ACHETER de la carte détaillée passe alors sur un libellé
distinct "EN ATTENTE..." (au lieu de "INSUFFISANT", qui suggérerait à
tort un problème de jauge) et devient non-cliquable, cohérent avec le
refus déjà appliqué côté serveur pour une seconde tentative le même tour.
Le tween est proprement arrêté dans destroy() (les jetons sont détruits/
recréés à chaque game-state).
- GameScene.js : _buildItemTokens()/_buildBuildingTokens() déterminent
`pending` à partir de state.pendingBuyItemId/pendingBuyBuildingId (déjà
reçus du serveur, jamais consommés auparavant) et le passent au jeton
correspondant, désactivant aussi son affordabilité pendant l'attente.
shopChanged/buildingShopChanged comparent désormais aussi ces deux champs
pour déclencher la reconstruction dès le clic sur ACHETER (avant, seul
un changement de myItems/availableItems/jauges provoquait un rebuild).
- Nouveau test E2E (item-shop.spec.js) : après achat, vérifie que le jeton
correspondant a pending=true, affordable=false et un tween actif chez
l'acheteur, que l'ADVERSAIRE ne voit PAS cet état "pending" (propre au
joueur), et qu'après résolution du tour le jeton disparaît normalement
de la boutique (comportement de stock unique déjà existant, inchangé).
54 tests unitaires client + 166 tests unitaires serveur + suite
item-shop.spec.js (4 tests) au vert.