{"id":769,"date":"2025-10-08T14:08:21","date_gmt":"2025-10-08T14:08:21","guid":{"rendered":"https:\/\/staging.digitalisetapme.fr\/?page_id=769"},"modified":"2025-10-24T12:48:13","modified_gmt":"2025-10-24T12:48:13","slug":"page-jeux","status":"publish","type":"page","link":"https:\/\/staging.digitalisetapme.fr\/index.php\/page-jeux\/","title":{"rendered":"page Jeux"},"content":{"rendered":"<p>[et_pb_section fb_built=\u00a0\u00bb1&Prime; admin_label=\u00a0\u00bbServices\u00a0\u00bb _builder_version=\u00a0\u00bb4.27.4&Prime; _module_preset=\u00a0\u00bbdefault\u00a0\u00bb background_color=\u00a0\u00bb#FFFFFF\u00a0\u00bb global_colors_info=\u00a0\u00bb{}\u00a0\u00bb][et_pb_row use_custom_gutter=\u00a0\u00bbon\u00a0\u00bb gutter_width=\u00a0\u00bb4&Prime; make_equal=\u00a0\u00bbon\u00a0\u00bb _builder_version=\u00a0\u00bb4.27.4&Prime; _module_preset=\u00a0\u00bbdefault\u00a0\u00bb width=\u00a0\u00bb95%\u00a0\u00bb max_width=\u00a0\u00bb2347px\u00a0\u00bb min_height=\u00a0\u00bb283.6px\u00a0\u00bb custom_margin=\u00a0\u00bb|auto|-5px|auto|false|false\u00a0\u00bb custom_padding=\u00a0\u00bb0px||0px|||\u00a0\u00bb border_width_all=\u00a0\u00bb5px\u00a0\u00bb border_color_all=\u00a0\u00bb#0031d6&Prime; global_colors_info=\u00a0\u00bb{}\u00a0\u00bb][et_pb_column type=\u00a0\u00bb4_4&Prime; _builder_version=\u00a0\u00bb4.16&Prime; _module_preset=\u00a0\u00bbdefault\u00a0\u00bb global_colors_info=\u00a0\u00bb{}\u00a0\u00bb][et_pb_image src=\u00a0\u00bbhttps:\/\/staging.digitalisetapme.fr\/wp-content\/uploads\/2025\/03\/telehealth-29.png\u00a0\u00bb title_text=\u00a0\u00bbtelehealth-29&Prime; _builder_version=\u00a0\u00bb4.16&Prime; _module_preset=\u00a0\u00bbdefault\u00a0\u00bb positioning=\u00a0\u00bbabsolute\u00a0\u00bb position_origin_a=\u00a0\u00bbtop_right\u00a0\u00bb width=\u00a0\u00bb15%\u00a0\u00bb global_colors_info=\u00a0\u00bb{}\u00a0\u00bb][\/et_pb_image][et_pb_code _builder_version=\u00a0\u00bb4.27.4&Prime; _module_preset=\u00a0\u00bbdefault\u00a0\u00bb background_color=\u00a0\u00bbgcid-secondary-color\u00a0\u00bb hover_enabled=\u00a0\u00bb0&Prime; custom_css_free_form=\u00a0\u00bb\/* Corrige les blocs Code de Divi *\/||.et_pb_code_inner {||  background: transparent !important; \/* ou #fff si tu veux blanc *\/||  color: inherit !important;          \/* garde la couleur du texte normale *\/||  padding: 0 !important;              \/* enl\u00e8ve le padding noir autour *\/||}\u00a0\u00bb global_colors_info=\u00a0\u00bb{%22gcid-secondary-color%22:%91%22background_color%22%93}\u00a0\u00bb sticky_enabled=\u00a0\u00bb0&Prime;]<\/p>\n<div id=\"cyber-arcade\"><\/div>\n<p><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] --><!-- Firebase (requis pour le multijoueur en ligne) --><!-- [et_pb_line_break_holder] --><!-- === Configuration Firebase pour Arcade Cyber === --><!-- [et_pb_line_break_holder] --><!-- === Firebase: Config + Test de connexion (Compat) === --><!-- [et_pb_line_break_holder] --><\/p>\n<style><!-- [et_pb_line_break_holder] -->  #fb-badge{position:fixed;right:12px;bottom:12px;padding:10px 14px;border-radius:12px;<!-- [et_pb_line_break_holder] -->    font:600 14px\/1.2 system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;<!-- [et_pb_line_break_holder] -->    box-shadow:0 10px 30px rgba(0,0,0,.15);z-index:999999;display:none}<!-- [et_pb_line_break_holder] -->  #fb-badge.ok{background:#10b981;color:#fff;border:2px solid #059669}<!-- [et_pb_line_break_holder] -->  #fb-badge.err{background:#ef4444;color:#fff;border:2px solid #dc2626}<!-- [et_pb_line_break_holder] --><\/style>\n<p><!-- [et_pb_line_break_holder] --><\/p>\n<div id=\"fb-badge\"><\/div>\n<p><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] --><script><!-- [et_pb_line_break_holder] -->  \/\/ 1) Ta configuration Firebase (v\u00e9rifie bien databaseURL)<!-- [et_pb_line_break_holder] -->  window.CYBER_ARCADE_FIREBASE = {<!-- [et_pb_line_break_holder] -->    apiKey: \"AIzaSyCrqkQ2VlPS0odD83ZSjM5gqvt05DiCkBc\",<!-- [et_pb_line_break_holder] -->    authDomain: \"arcade-cyber.firebaseapp.com\",<!-- [et_pb_line_break_holder] -->    \/\/ \u26a0\ufe0f Mets ici l\u2019URL EXACTE de ta Realtime Database (copie depuis la console Firebase)<!-- [et_pb_line_break_holder] -->     databaseURL: \"https:\/\/arcade-cyber-default-rtdb.europe-west1.firebasedatabase.app\",<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    projectId: \"arcade-cyber\",<!-- [et_pb_line_break_holder] -->    storageBucket: \"arcade-cyber.appspot.com\",<!-- [et_pb_line_break_holder] -->    messagingSenderId: \"273148972313\",<!-- [et_pb_line_break_holder] -->    appId: \"1:273148972313:web:9f51fba4b8c092bebf8988\"<!-- [et_pb_line_break_holder] -->  };<!-- [et_pb_line_break_holder] --><\/script><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] --><!-- 2) Librairies compat (\u00e0 laisser tel quel) --><!-- [et_pb_line_break_holder] --><script src=\"https:\/\/www.gstatic.com\/firebasejs\/10.12.2\/firebase-app-compat.js\"><\/script><!-- [et_pb_line_break_holder] --><script src=\"https:\/\/www.gstatic.com\/firebasejs\/10.12.2\/firebase-database-compat.js\"><\/script><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] --><script><!-- [et_pb_line_break_holder] -->(function(){<!-- [et_pb_line_break_holder] -->  const badge = document.getElementById('fb-badge');<!-- [et_pb_line_break_holder] -->  function showBadge(ok, msg){<!-- [et_pb_line_break_holder] -->    badge.className = ok ? 'ok' : 'err';<!-- [et_pb_line_break_holder] -->    badge.textContent = ok ? ('' + msg) : ('Firebase ERREUR \u2014 ' + msg);<!-- [et_pb_line_break_holder] -->    badge.style.display = 'block';<!-- [et_pb_line_break_holder] -->  }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  \/\/ 3) Attendre que les scripts soient bien charg\u00e9s (Divi peut les diff\u00e9rer)<!-- [et_pb_line_break_holder] -->  function whenFirebaseLoaded(maxMs=6000){<!-- [et_pb_line_break_holder] -->    return new Promise((res, rej)=>{<!-- [et_pb_line_break_holder] -->      const start = Date.now();<!-- [et_pb_line_break_holder] -->      (function tick(){<!-- [et_pb_line_break_holder] -->        if (window.firebase && firebase.initializeApp) return res();<!-- [et_pb_line_break_holder] -->        if (Date.now()-start > maxMs) return rej(new Error(\"Firebase non charg\u00e9 (timeout)\"));<!-- [et_pb_line_break_holder] -->        setTimeout(tick, 120);<!-- [et_pb_line_break_holder] -->      })();<!-- [et_pb_line_break_holder] -->    });<!-- [et_pb_line_break_holder] -->  }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  \/\/ 4) Init + test d\u2019\u00e9criture\/lecture<!-- [et_pb_line_break_holder] -->  whenFirebaseLoaded().then(()=>{<!-- [et_pb_line_break_holder] -->    try{<!-- [et_pb_line_break_holder] -->      const cfg = window.CYBER_ARCADE_FIREBASE;<!-- [et_pb_line_break_holder] -->      const app = firebase.apps?.length ? firebase.app() : firebase.initializeApp(cfg);<!-- [et_pb_line_break_holder] -->      const db  = firebase.database();<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->      \/\/ Test: \u00e9criture puis suppression d\u2019une cl\u00e9 _ping<!-- [et_pb_line_break_holder] -->      const k = \"_ping\/\" + Math.random().toString(36).slice(2,8);<!-- [et_pb_line_break_holder] -->      db.ref(k).set({ts: Date.now()})<!-- [et_pb_line_break_holder] -->        .then(()=> db.ref(k).remove())<!-- [et_pb_line_break_holder] -->        .then(()=>{<!-- [et_pb_line_break_holder] -->          \/\/ Succ\u00e8s visible<!-- [et_pb_line_break_holder] -->          window.FB = { app, db }; \/\/ (optionnel) accessible globalement<!-- [et_pb_line_break_holder] -->          showBadge(true, \"\");<!-- [et_pb_line_break_holder] -->        })<!-- [et_pb_line_break_holder] -->        .catch((e)=>{<!-- [et_pb_line_break_holder] -->          showBadge(false, \"acc\u00e8s DB refus\u00e9 : \" + (e?.message || e));<!-- [et_pb_line_break_holder] -->        });<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    } catch(e){<!-- [et_pb_line_break_holder] -->      showBadge(false, \"init \u00e9chou\u00e9e : \" + (e?.message || e));<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] -->  }).catch((e)=>{<!-- [et_pb_line_break_holder] -->    showBadge(false, e?.message || e);<!-- [et_pb_line_break_holder] -->  });<!-- [et_pb_line_break_holder] -->})();<!-- [et_pb_line_break_holder] --><\/script><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] --><\/p>\n<style><!-- [et_pb_line_break_holder] -->\/* === Styles (identiques \u00e0 ta base, condens\u00e9s) === *\/<!-- [et_pb_line_break_holder] -->#cyber-arcade{--tile:90px;--gap:8px;--ring:#e5e7eb;--muted:#6b7280;--equip:#eaf2ff;--action:#f1e9ff;--hazard:#ffe9e9;--start:#e6fff4;--cardGrad1:#fff;--cardGrad2:#f9fafb;--glass:rgba(255,255,255,.88);background:#1760b3;color:#3537af;font-family:Inter,system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;padding:16px;padding-bottom:180px}<!-- [et_pb_line_break_holder] -->#cyber-arcade *{box-sizing:border-box}<!-- [et_pb_line_break_holder] -->.ca-btn{display:inline-flex;align-items:center;gap:.6rem;border-radius:14px;padding:.7rem 1rem;border:1px solid #111;background:#111;color:#fff;font-weight:800;cursor:pointer}<!-- [et_pb_line_break_holder] -->.ca-btn.ghost{background:#fff;color:#111;border-color:var(--ring)}<!-- [et_pb_line_break_holder] -->.ca-btnBar{display:inline-flex;align-items:center;gap:.5rem;padding:.65rem 1rem;border-radius:14px;border:1px solid #111;background:#fff;font-weight:800;cursor:pointer}<!-- [et_pb_line_break_holder] -->.ca-btnPri{background:#0f0f0f;color:#fff;border-color:#0f0f0f}<!-- [et_pb_line_break_holder] -->.ca-in{border:1px solid var(--ring);border-radius:12px;padding:.6rem .8rem;font-size:14px}<!-- [et_pb_line_break_holder] -->.ca-card{background:#fff;border:1px solid var(--ring);border-radius:22px;padding:18px;box-shadow:0 16px 32px rgba(0,0,0,.18);color:#111}<!-- [et_pb_line_break_holder] -->.ca-h{font-weight:900;letter-spacing:-.02em}<!-- [et_pb_line_break_holder] -->.ca-soft{color:var(--muted)}<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->#ca-home{max-width:1100px;margin:12px auto 0;color:#fff}<!-- [et_pb_line_break_holder] -->#ca-home h1{font-size:38px;margin:0 0 8px}<!-- [et_pb_line_break_holder] -->.ca-grid1{display:grid;grid-template-columns:1fr;gap:16px}<!-- [et_pb_line_break_holder] -->.ca-players{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin-top:10px}<!-- [et_pb_line_break_holder] -->.ca-swatchRow{display:flex;gap:8px;flex-wrap:wrap}<!-- [et_pb_line_break_holder] -->.ca-swatch{width:22px;height:22px;border-radius:999px;border:2px solid rgba(0,0,0,.7);outline:2px solid transparent;cursor:pointer}<!-- [et_pb_line_break_holder] -->.ca-swatch.selected{outline-color:#000}<!-- [et_pb_line_break_holder] -->.ca-dot{width:16px;height:16px;border-radius:999px;border:2px solid #000;display:inline-block;margin-right:6px}<!-- [et_pb_line_break_holder] -->.ca-row{display:flex;gap:10px;align-items:center;flex-wrap:wrap}<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->.ca-top{display:flex;justify-content:space-between;align-items:center;margin:12px 0;color:#fff}<!-- [et_pb_line_break_holder] -->.ca-box{background:#fff;border:1px solid var(--ring);border-radius:24px;box-shadow:0 20px 40px rgba(0,0,0,.18)}<!-- [et_pb_line_break_holder] -->.ca-score{max-width:1100px;margin:0 auto 12px;position:sticky;top:calc(8px + env(safe-area-inset-top));z-index:4}<!-- [et_pb_line_break_holder] -->.sb-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px}<!-- [et_pb_line_break_holder] -->.sb-list{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:10px}<!-- [et_pb_line_break_holder] -->.sb-row{display:flex;align-items:center;gap:8px;justify-content:space-between;border:1px solid var(--ring);border-radius:14px;padding:8px 10px;background:#fff}<!-- [et_pb_line_break_holder] -->.sb-left{display:flex;align-items:center;gap:8px}<!-- [et_pb_line_break_holder] -->.sb-badge{font-size:12px;border:1px solid var(--ring);border-radius:999px;padding:2px 8px;background:linear-gradient(180deg,#fff,#fafafa)}<!-- [et_pb_line_break_holder] -->.sb-turn{background:#111;color:#fff;border-color:#111}<!-- [et_pb_line_break_holder] -->.sb-toggle{display:none}<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->\/* ======== ZONE 3D ======== *\/<!-- [et_pb_line_break_holder] -->.ca-wrap{position:relative;padding:10px; margin-top: 10%;}<!-- [et_pb_line_break_holder] -->.ca-stage{perspective-origin:30% 10% !important;padding:0 !important;min-height:auto;}<!-- [et_pb_line_break_holder] -->.ca-iso{transform-style:preserve-3d;transform:translateY(calc(var(--tile)*-0.8)) rotateX(360deg) rotateZ(360deg) scale(1) !important;transform-origin:center;transition:none !important;}<!-- [et_pb_line_break_holder] -->.ca-iso:hover{transform:translateY(calc(var(--tile)*-0.8)) rotateX(360deg) rotateZ(360deg) scale(1) !important;}<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->.ca-grid{display:grid;grid-template-columns:repeat(11,1fr);gap:var(--gap);padding:14px}<!-- [et_pb_line_break_holder] -->.ca-tile{position:relative;height:var(--tile);background:#fff;border:1px solid var(--ring);border-radius:10px;display:flex;align-items:center;justify-content:center;padding:6px;box-shadow:0 16px 26px rgba(0,0,0,.25)}<!-- [et_pb_line_break_holder] -->.ca-tile::after{content:\"\";position:absolute;inset:-2px;z-index:-1;border-radius:12px;background:linear-gradient(180deg,rgba(0,0,0,.18),rgba(0,0,0,.34));transform:translateZ(-10px);filter:blur(6px);opacity:.35}<!-- [et_pb_line_break_holder] -->.ca-corner{height:calc(var(--tile)*1.7)}<!-- [et_pb_line_break_holder] -->.ca-equip{background:linear-gradient(180deg,#fff,#f3f7ff)}<!-- [et_pb_line_break_holder] -->.ca-action{background:linear-gradient(180deg,#fff,#f5f0ff)}<!-- [et_pb_line_break_holder] -->.ca-hazard{background:linear-gradient(180deg,#fff,#fff0f0)}<!-- [et_pb_line_break_holder] -->.ca-start{background:linear-gradient(180deg,#fff,#ecfff7)}<!-- [et_pb_line_break_holder] -->.ca-ico{position:absolute;top:6px;left:6px;font-size:10px;opacity:.5}<!-- [et_pb_line_break_holder] -->.ca-price{position:absolute;bottom:6px;right:6px;font-size:10px;padding:1px 6px;border-radius:999px;color:#fff;background:#111;font-weight:800;opacity:.92}<!-- [et_pb_line_break_holder] -->.ca-lab{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:calc(var(--tile)*.96);pointer-events:none}<!-- [et_pb_line_break_holder] -->.ca-corner .ca-lab{width:calc(var(--tile)*1.6)}<!-- [et_pb_line_break_holder] -->.ca-labIn{display:block;font-weight:900;line-height:1.1;text-align:center;font-size:clamp(8px, calc(var(--tile)\/6.8), 14px);word-break:break-word}<!-- [et_pb_line_break_holder] -->.ca-left .ca-labIn{transform:rotate(-90deg)} .ca-right .ca-labIn{transform:rotate(90deg)}<!-- [et_pb_line_break_holder] -->.ca-tokens{position:absolute;bottom:6px;left:0;right:0;display:flex;gap:4px;justify-content:center}<!-- [et_pb_line_break_holder] -->.ca-token{width:16px;height:16px;border-radius:999px;border:2px solid #111;box-shadow:0 1px 2px rgba(0,0,0,.25)}<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->.ca-strip{margin-top:10px;padding:12px}<!-- [et_pb_line_break_holder] -->.ca-hand{display:flex;gap:12px;overflow:auto}<!-- [et_pb_line_break_holder] -->.ca-cardTile{width:200px;min-width:200px;height:132px;border-radius:16px;border:1px solid var(--ring);padding:10px 12px;background:linear-gradient(180deg,var(--cardGrad1),var(--cardGrad2));box-shadow:0 6px 18px rgba(0,0,0,.05);display:flex;flex-direction:column;justify-content:space-between;cursor:pointer}<!-- [et_pb_line_break_holder] -->.ca-ctEquip{background:linear-gradient(180deg,#f6faff,#eef4ff)}<!-- [et_pb_line_break_holder] -->.ca-ctAction{background:linear-gradient(180deg,#f7f2ff,#f1e9ff)}<!-- [et_pb_line_break_holder] -->.ca-ctHead{font-weight:900}<!-- [et_pb_line_break_holder] -->.ca-ctHead .i{opacity:.8;margin-right:.35rem}<!-- [et_pb_line_break_holder] -->.ca-ctTag{font-size:10px;padding:2px 8px;border-radius:999px;background:#111;color:#fff;font-weight:800;align-self:flex-start}<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->.ca-hud{position:fixed;left:16px;right:16px;bottom:calc(16px + env(safe-area-inset-bottom));display:flex;gap:12px;justify-content:space-between;align-items:center;pointer-events:none;z-index:5}<!-- [et_pb_line_break_holder] -->.ca-hud>*{pointer-events:auto}<!-- [et_pb_line_break_holder] -->.ca-hudCard{background:var(--glass);backdrop-filter:blur(8px);border:1px solid var(--ring);border-radius:18px;padding:10px 14px;box-shadow:0 10px 30px rgba(0,0,0,.08)}<!-- [et_pb_line_break_holder] -->.ca-dice{width:90px;height:90px;border-radius:20px;background:#0f0f0f;color:#fff;display:flex;align-items:center;justify-content:center;font-size:36px;font-weight:900;box-shadow:0 16px 40px rgba(0,0,0,.25)}<!-- [et_pb_line_break_holder] -->.ca-dice[disabled]{opacity:.5;cursor:not-allowed}<!-- [et_pb_line_break_holder] -->.ca-modal{position:fixed;inset:0;background:rgba(0,0,0,.5);display:none;align-items:center;justify-content:center;padding:16px;z-index:50}<!-- [et_pb_line_break_holder] -->.ca-boxM{background:#fff;border:1px solid var(--ring);border-radius:20px;max-width:920px;width:100%;box-shadow:0 24px 60px rgba(0,0,0,.3)}<!-- [et_pb_line_break_holder] -->.ca-boxHead{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;border-bottom:1px solid var(--ring)}<!-- [et_pb_line_break_holder] -->.ca-boxBody{padding:16px}<!-- [et_pb_line_break_holder] -->.ca-locked .ca-boxHead button{display:none}<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->\/* Enlever l\u2019aspect cadre autour du plateau *\/<!-- [et_pb_line_break_holder] -->.ca-wrap.ca-box{background:transparent !important;border:0 !important;box-shadow:none !important;padding:0 10px 10px 10px !important;}<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->@media (max-width:900px){#cyber-arcade{--tile:84px}.ca-cardTile{width:180px;min-width:180px;height:126px}}<!-- [et_pb_line_break_holder] -->@media (max-width:720px){#cyber-arcade{--tile:78px}.ca-price{font-size:9px}.ca-ctHead{font-size:14px}.sb-toggle{display:inline-flex}.sb-list{grid-template-columns:1fr}}<!-- [et_pb_line_break_holder] -->@media (max-width:500px){#cyber-arcade{--tile:70px}.ca-labIn{font-size:clamp(8px, calc(var(--tile)\/7.2), 13px)}.ca-dice{width:78px;height:78px;font-size:30px}.ca-cardTile{width:168px;min-width:168px;height:120px}}<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->\/* D\u00e9 3D *\/<!-- [et_pb_line_break_holder] -->.ca-dice{ position:relative; perspective:900px; overflow:visible }<!-- [et_pb_line_break_holder] -->.ca-dice[aria-disabled=\"true\"]{ opacity:.5; cursor:not-allowed }<!-- [et_pb_line_break_holder] -->.dice3d{--size: 72px;width:var(--size); height:var(--size);transform-style:preserve-3d;transition:transform 900ms cubic-bezier(.22,.68,0,1.05);will-change: transform;position:relative;}<!-- [et_pb_line_break_holder] -->.dice3d .face{position:absolute; inset:0;display:flex; align-items:center; justify-content:center;background:#fff; border:2px solid #111; border-radius:12px;box-shadow:inset 0 2px 6px rgba(0,0,0,.08);}<!-- [et_pb_line_break_holder] -->.dice3d .pips{--dot: radial-gradient(circle at center, #111 45%, transparent 46%);width:100%; height:100%; background-repeat:no-repeat; filter:drop-shadow(0 1px 0 rgba(0,0,0,.2));}<!-- [et_pb_line_break_holder] -->.face.f1 .pips{ background-image:var(--dot); background-position:50% 50%; background-size:18% 18% }<!-- [et_pb_line_break_holder] -->.face.f2 .pips{ background-image:var(--dot),var(--dot); background-position:25% 25%, 75% 75%; background-size:18% 18% }<!-- [et_pb_line_break_holder] -->.face.f3 .pips{ background-image:var(--dot),var(--dot),var(--dot); background-position:25% 25%, 50% 50%, 75% 75%; background-size:18% 18% }<!-- [et_pb_line_break_holder] -->.face.f4 .pips{ background-image:var(--dot),var(--dot),var(--dot),var(--dot); background-position:25% 25%, 75% 25%, 25% 75%, 75% 75%; background-size:18% 18% }<!-- [et_pb_line_break_holder] -->.face.f5 .pips{ background-image:var(--dot),var(--dot),var(--dot),var(--dot),var(--dot); background-position:25% 25%, 75% 25%, 50% 50%, 25% 75%, 75% 75%; background-size:18% 18% }<!-- [et_pb_line_break_holder] -->.face.f6 .pips{ background-image:var(--dot),var(--dot),var(--dot),var(--dot),var(--dot),var(--dot);background-position:25% 20%, 75% 20%, 25% 50%, 75% 50%, 25% 80%, 75% 80%; background-size:18% 18% }<!-- [et_pb_line_break_holder] -->.dice3d .f1{ transform:translateZ(calc(var(--size)\/2)) }<!-- [et_pb_line_break_holder] -->.dice3d .f6{ transform:rotateY(180deg) translateZ(calc(var(--size)\/2)) }<!-- [et_pb_line_break_holder] -->.dice3d .f3{ transform:rotateY(90deg) translateZ(calc(var(--size)\/2)) }<!-- [et_pb_line_break_holder] -->.dice3d .f4{ transform:rotateY(-90deg) translateZ(calc(var(--size)\/2)) }<!-- [et_pb_line_break_holder] -->.dice3d .f5{ transform:rotateX(90deg) translateZ(calc(var(--size)\/2)) }<!-- [et_pb_line_break_holder] -->.dice3d .f2{ transform:rotateX(-90deg) translateZ(calc(var(--size)\/2)) }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->\/* Th\u00e8me *\/<!-- [et_pb_line_break_holder] -->:root{--glass: rgba(255,255,255,0.96);--ring: #D9D0FF;}<!-- [et_pb_line_break_holder] -->#cyber-arcade{<!-- [et_pb_line_break_holder] -->  background:<!-- [et_pb_line_break_holder] -->    radial-gradient(1200px 520px at 88% -8%, #d551c1 42%, transparent 61%),<!-- [et_pb_line_break_holder] -->    radial-gradient(900px 460px at 8% 108%, #6d9de4 24%, transparent 60%),<!-- [et_pb_line_break_holder] -->    radial-gradient(700px 380px at 70% 110%, #29D1FF 20%, transparent 55%),<!-- [et_pb_line_break_holder] -->    linear-gradient(180deg,#6a5498 0%, #d0c6ee 42%, #533192 100%);<!-- [et_pb_line_break_holder] -->}<!-- [et_pb_line_break_holder] -->.ca-card, .ca-box{background:#fff;border:2px solid var(--ring);box-shadow: 0 18px 44px rgba(16,10,24,.14), inset 0 1px 0 #ffffff;}<!-- [et_pb_line_break_holder] -->.ca-btn, .ca-btnBar{border:2px solid #7B5BFA;background:linear-gradient(180deg,#FFFFFF 0%, #2733b1 100%);}<!-- [et_pb_line_break_holder] -->.ca-btn.ca-btnPri{background:linear-gradient(180deg,#5E3EE6,#7B5BFA);color:#fff !important;border-color:#5E3EE6;}<!-- [et_pb_line_break_holder] -->.ca-btn:hover, .ca-btnBar:hover{transform: translateY(-1px);box-shadow: 0 18px 36px rgba(94,62,230,.24), 0 0 0 4px rgba(32,212,183,.28);}<!-- [et_pb_line_break_holder] -->.ca-score{background:#ffffff;border:2px solid var(--ring);box-shadow:0 24px 48px rgba(94,62,230,.16);}<!-- [et_pb_line_break_holder] -->.sb-badge{ background:linear-gradient(180deg,#fff,#F3EFFF); border:1px solid var(--ring) }<!-- [et_pb_line_break_holder] -->.sb-turn{ background:#5E3EE6; color:#fff; border-color:#5E3EE6 }<!-- [et_pb_line_break_holder] -->.ca-stage{background: linear-gradient(180deg,#F1E9FF 0%, #F3F0FF 60%, #EDE4FF 100%);border-radius:18px;box-shadow: inset 0 60px 120px rgba(94,62,230,.10), 0 24px 48px rgba(94,62,230,.12);}<!-- [et_pb_line_break_holder] -->.ca-tile{border-radius:16px;border:2px solid var(--ring);background:linear-gradient(180deg,#FFFFFF 0%, #F7F2FF 100%);box-shadow:0 18px 38px rgba(16,10,24,.12), 0 2px 0 #ffffff inset;}<!-- [et_pb_line_break_holder] -->.ca-tile:hover{transform:translateY(-2px);box-shadow: 0 24px 52px rgba(16,10,24,.16), 0 2px 0 #ffffff inset;}<!-- [et_pb_line_break_holder] -->.ca-equip { background:linear-gradient(180deg,#FFFFFF 0%, #E8F3FF 100%) }<!-- [et_pb_line_break_holder] -->.ca-action{ background:linear-gradient(180deg,#FFFFFF 0%, #FFE6F1 100%) }<!-- [et_pb_line_break_holder] -->.ca-hazard{ background:linear-gradient(180deg,#FFFFFF 0%, #E4FFF4 100%) }<!-- [et_pb_line_break_holder] -->.ca-start { background:linear-gradient(180deg,#FFFFFF 0%, #FFEAD6 100%) }<!-- [et_pb_line_break_holder] -->.ca-price{background: linear-gradient(180deg,#5E3EE6,#7B5BFA);color:#fff;border:none;box-shadow: 0 4px 12px rgba(94,62,230,.28);padding: 3px 8px;font-weight:800;border-radius:12px;font-size:10px !important;}<!-- [et_pb_line_break_holder] -->.ca-labIn{font-size:clamp(7px, calc(var(--tile)\/8.2), 10px) !important;font-weight:800; letter-spacing:-.01em; line-height:1.08;}<!-- [et_pb_line_break_holder] -->.ca-token{box-shadow:0 1px 3px rgba(0,0,0,.28),0 0 0 3px rgba(32,212,183,.35);}<!-- [et_pb_line_break_holder] -->.ca-cardTile{border:1px solid var(--ring);background:linear-gradient(180deg,#FFFFFF 0%, #bda4ed 100%);box-shadow:0 12px 28px rgba(16,10,24,.12);}<!-- [et_pb_line_break_holder] -->.ca-ctEquip{  background:linear-gradient(180deg,#E9F6FF,#DFF0FF) }<!-- [et_pb_line_break_holder] -->.ca-ctAction{ background:linear-gradient(180deg,#FFE6F2,#F7E3FF) }<!-- [et_pb_line_break_holder] -->.ca-ctTag{ background:#FF5C8A; color:#fff; }<!-- [et_pb_line_break_holder] -->.ca-hudCard{background: var(--glass);border:1px solid var(--ring);box-shadow:0 10px 30px rgba(94,62,230,.14);}<!-- [et_pb_line_break_holder] -->.ca-dice{background:linear-gradient(180deg,#5E3EE6,#7B5BFA);border:2px solid #5E3EE6;color:#fff;box-shadow:0 18px 44px rgba(94,62,230,.34), 0 0 0 6px rgba(32,212,183,.28) inset;}<!-- [et_pb_line_break_holder] -->.ca-dice:not([aria-disabled=\"true\"]):hover{box-shadow:0 22px 56px rgba(94,62,230,.42), 0 0 0 6px rgba(184,255,102,.28) inset;}<!-- [et_pb_line_break_holder] -->.dice3d .face{background:#fff;border:2px solid #5E3EE6;border-radius:14px;}<!-- [et_pb_line_break_holder] -->.ca-modal{ background: radial-gradient(60% 60% at 50% 50%, rgba(14,10,20,.70), rgba(14,10,20,.82)) }<!-- [et_pb_line_break_holder] -->.ca-boxM{ border:2px solid var(--ring); box-shadow:0 30px 70px rgba(16,10,24,.46) }<!-- [et_pb_line_break_holder] -->#boardSub,.ca-sub,.ca-soft { color: #1ada27 !important; opacity: 0.85; font-weight: 500;}<!-- [et_pb_line_break_holder] -->.ca-dot{<!-- [et_pb_line_break_holder] -->  width:16px;height:16px;border-radius:999px;<!-- [et_pb_line_break_holder] -->  border:2px solid #000;display:inline-block;margin-right:6px;<!-- [et_pb_line_break_holder] -->}<!-- [et_pb_line_break_holder] --><\/style>\n<p><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] --><script><!-- [et_pb_line_break_holder] -->(() => {<!-- [et_pb_line_break_holder] -->  try {<!-- [et_pb_line_break_holder] -->    \/* ======================== UTIL ======================== *\/<!-- [et_pb_line_break_holder] -->    const mount = document.getElementById(\"cyber-arcade\");<!-- [et_pb_line_break_holder] -->    const H = (html) => { const d = document.createElement(\"div\"); d.innerHTML = html; return d.firstElementChild; };<!-- [et_pb_line_break_holder] -->    const clamp = (n, a, b) => Math.min(Math.max(n, a), b);<!-- [et_pb_line_break_holder] -->    const rnd = (a, b) => Math.random() * (b - a) + a;<!-- [et_pb_line_break_holder] -->    const pick = (arr) => arr[Math.floor(Math.random() * arr.length)];<!-- [et_pb_line_break_holder] -->    const d6 = () => Math.floor(Math.random() * 6) + 1;<!-- [et_pb_line_break_holder] -->    const uid = () => Math.random().toString(36).slice(2, 9);<!-- [et_pb_line_break_holder] -->    const q = (sel, sc = mount) => sc.querySelector(sel);<!-- [et_pb_line_break_holder] -->    const PALETTE = [ \"#111827\", \/\/ noir<!-- [et_pb_line_break_holder] -->  \"#ef4444\", \/\/ rouge<!-- [et_pb_line_break_holder] -->  \"#2563eb\", \/\/ bleu<!-- [et_pb_line_break_holder] -->  \"#10b981\", \/\/ vert<!-- [et_pb_line_break_holder] -->  \"#f59e0b\", \/\/ orange<!-- [et_pb_line_break_holder] -->  \"#06b6d4\", \/\/ cyan<!-- [et_pb_line_break_holder] -->  \"#84cc16\", \/\/ lime<!-- [et_pb_line_break_holder] -->  \"#8b5cf6\", \/\/ violet (1 seul violet)<!-- [et_pb_line_break_holder] -->  \"#eab308\", \/\/ jaune\/amber<!-- [et_pb_line_break_holder] -->  \"#ec4899\" ];<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    \/* ======================== DATA ======================== *\/<!-- [et_pb_line_break_holder] -->    const HAZARDS_CORE = [<!-- [et_pb_line_break_holder] -->      {id:\"ransom\",icon:\"\ud83e\udde8\",name:\"Logiciel ran\u00e7on (ransomware)\",tef:[0.4,1.2],vuln:0.45,lm:[50000,250000],rep:12,explain:\"Un pirate chiffre les \u00e9quipements; activit\u00e9 \u00e0 l\u2019arr\u00eat.\"},<!-- [et_pb_line_break_holder] -->      {id:\"bec\",icon:\"\u2709\ufe0f\",name:\"Usurpation d\u2019email (fraude au virement)\",tef:[0.8,2.5],vuln:0.35,lm:[20000,120000],rep:6,explain:\"Usurpation d\u2019un dirigeant\/fournisseur pour obtenir un virement.\"},<!-- [et_pb_line_break_holder] -->      {id:\"cloud\",icon:\"\u2601\ufe0f\",name:\"Fuite de donn\u00e9es (cloud mal r\u00e9gl\u00e9)\",tef:[0.2,0.8],vuln:0.55,lm:[40000,200000],rep:10,explain:\"Partage public par erreur; documents expos\u00e9s.\"},<!-- [et_pb_line_break_holder] -->      {id:\"insider\",icon:\"\ud83d\udd75\ufe0f\",name:\"Acte interne (erreur\/malveillance)\",tef:[0.1,0.5],vuln:0.40,lm:[30000,150000],rep:8,explain:\"Suppression, fuite, sabotage par un collaborateur.\"},<!-- [et_pb_line_break_holder] -->      {id:\"ddos\",icon:\"\ud83c\udf0a\",name:\"D\u00e9ni de service (site indisponible)\",tef:[0.7,2.0],vuln:0.50,lm:[15000,80000],rep:5,explain:\"Vague de trafic bloque le e-commerce.\"},<!-- [et_pb_line_break_holder] -->      {id:\"zero\",icon:\"\ud83d\udea8\",name:\"Faille critique exploit\u00e9e\",tef:[0.3,1.0],vuln:0.50,lm:[60000,220000],rep:11,explain:\"Vuln\u00e9rabilit\u00e9 non corrig\u00e9e utilis\u00e9e comme porte d\u2019entr\u00e9e.\"}<!-- [et_pb_line_break_holder] -->    ];<!-- [et_pb_line_break_holder] -->    const HAZARDS_MOB = [<!-- [et_pb_line_break_holder] -->      {id:\"wifi\",icon:\"\ud83d\udcf6\",name:\"Wi-Fi public pi\u00e9g\u00e9\",tef:[0.5,1.6],vuln:0.50,lm:[15000,90000],rep:7,explain:\"\u00c9coute\/vol d\u2019identifiants sur hotspot public.\"},<!-- [et_pb_line_break_holder] -->      {id:\"usb\",icon:\"\ud83d\udd0c\",name:\"C\u00e2ble\/chargeur pi\u00e9g\u00e9\",tef:[0.3,1.1],vuln:0.45,lm:[12000,70000],rep:6,explain:\"Injection via p\u00e9riph\u00e9rique malveillant.\"},<!-- [et_pb_line_break_holder] -->      {id:\"spy\",icon:\"\ud83d\udd76\ufe0f\",name:\"Espionnage industriel\",tef:[0.2,0.6],vuln:0.35,lm:[80000,260000],rep:12,explain:\"Collecte cibl\u00e9e lors d\u2019un d\u00e9placement.\"}<!-- [et_pb_line_break_holder] -->    ];<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    const EQUIPS_CHALLENGE = [<!-- [et_pb_line_break_holder] -->      {id:\"mfa\",icon:\"\ud83d\udd10\",name:\"Authentification multi-facteur (MFA)\",price:120,covers:[\"bec\"],why:\"2\u1d49 \u00e9tape de connexion; m\u00eame si le mdp fuit, compte prot\u00e9g\u00e9.\"},<!-- [et_pb_line_break_holder] -->      {id:\"edr\",icon:\"\ud83d\udee1\ufe0f\",name:\"D\u00e9tection & r\u00e9ponse (EDR)\",price:150,covers:[\"ransom\",\"zero\"],why:\"Bloque comportements suspects (ransomware\u2026).\"},<!-- [et_pb_line_break_holder] -->      {id:\"backup\",icon:\"\ud83d\udcbe\",name:\"Sauvegardes + PRA\",price:200,covers:[\"ransom\"],why:\"Reprise d\u2019activit\u00e9 sans payer.\"},<!-- [et_pb_line_break_holder] -->      {id:\"patch\",icon:\"\ud83e\udde9\",name:\"Mises \u00e0 jour\",price:100,covers:[\"zero\"],why:\"Ferme les failles exploit\u00e9es.\"},<!-- [et_pb_line_break_holder] -->      {id:\"waf\",icon:\"\ud83e\uddf1\",name:\"WAF + CDN\",price:90,covers:[\"ddos\"],why:\"Filtre les requ\u00eates malveillantes.\"},<!-- [et_pb_line_break_holder] -->      {id:\"disk\",icon:\"\ud83d\udcbf\",name:\"Chiffrement des postes\",price:60,covers:[\"insider\"],why:\"Perte\/vol PC sans fuite exploitable.\"},<!-- [et_pb_line_break_holder] -->      {id:\"iam\",icon:\"\ud83e\udded\",name:\"Moindre privil\u00e8ge\",price:110,covers:[\"insider\",\"cloud\"],why:\"Limite l\u2019impact d\u2019erreurs\/compromissions.\"},<!-- [et_pb_line_break_holder] -->      {id:\"dmarc\",icon:\"\ud83d\udcec\",name:\"DMARC\/DKIM\/SPF\",price:70,covers:[\"bec\"],why:\"Anti-usurpation du domaine d\u2019email.\"},<!-- [et_pb_line_break_holder] -->      {id:\"seg\",icon:\"\ud83d\uddc2\ufe0f\",name:\"Segmentation r\u00e9seau\",price:130,covers:[\"ransom\",\"zero\"],why:\"R\u00e9duit la propagation interne.\"},<!-- [et_pb_line_break_holder] -->      {id:\"siem\",icon:\"\ud83d\udcc8\",name:\"Supervision s\u00e9curit\u00e9 (SIEM)\",price:140,covers:[\"insider\",\"ransom\"],why:\"Alerte rapide sur anomalies.\"},<!-- [et_pb_line_break_holder] -->      {id:\"mdp\",icon:\"\ud83d\udd11\",name:\"Gestionnaire de mots de passe\",price:80,covers:[\"bec\",\"insider\"],why:\"Mots forts uniques; partage s\u00e9curis\u00e9.\"},<!-- [et_pb_line_break_holder] -->      {id:\"mdm\",icon:\"\ud83d\udcf1\",name:\"Gestion des appareils (MDM)\",price:80,covers:[\"insider\"],why:\"Configuration\/effacement \u00e0 distance.\"},<!-- [et_pb_line_break_holder] -->      {id:\"vpn\",icon:\"\ud83d\udef0\ufe0f\",name:\"VPN mobilit\u00e9 obligatoire\",price:80,covers:[\"wifi\"],why:\"Chiffre les sessions en d\u00e9placement.\"},<!-- [et_pb_line_break_holder] -->      {id:\"usbguard\",icon:\"\ud83e\uddf2\",name:\"Contr\u00f4le p\u00e9riph\u00e9riques USB\",price:70,covers:[\"usb\"],why:\"Liste blanche; pas de p\u00e9riph\u00e9rique pi\u00e9g\u00e9.\"},<!-- [et_pb_line_break_holder] -->      {id:\"opsec\",icon:\"\ud83e\udd2b\",name:\"Kit OPSEC d\u00e9placements\",price:65,covers:[\"spy\"],why:\"Bonnes pratiques anti-espionnage.\"}<!-- [et_pb_line_break_holder] -->    ];<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    const ACTIONS_COMMON = [<!-- [et_pb_line_break_holder] -->      {id:\"mit50\",icon:\"\ud83e\uddef\",name:\"Playbook d\u2019intervention\",desc:\"Proc\u00e9dures d\u2019urgence. R\u00e9duit \u2248 50%.\",uses:1,type:\"mitigation\"},<!-- [et_pb_line_break_holder] -->      {id:\"com\",icon:\"\ud83d\udce3\",name:\"Communication de crise\",desc:\"Impact r\u00e9putation \u2248 \u221250%.\",uses:1,type:\"mitigation\"},<!-- [et_pb_line_break_holder] -->      {id:\"table\",icon:\"\ud83c\udf9b\ufe0f\",name:\"Exercice de simulation\",desc:\"\u00c9quipe entra\u00een\u00e9e. R\u00e9duit \u2248 50%.\",uses:1,type:\"mitigation\"},<!-- [et_pb_line_break_holder] -->      {id:\"audit\",icon:\"\ud83d\udd0e\",name:\"Audit flash\",desc:\"Corrige r\u00e9glages critiques. R\u00e9duit \u2248 50%.\",uses:1,type:\"mitigation\"}<!-- [et_pb_line_break_holder] -->    ];<!-- [et_pb_line_break_holder] -->    const QUIZ = [<!-- [et_pb_line_break_holder] -->      {q:\"Un email urgent demande un virement. Premier r\u00e9flexe ?\",choices:[\"R\u00e9pondre vite\",\"Appeler pour v\u00e9rifier\",\"Cliquer sur le lien\",\"Transf\u00e9rer \u00e0 tous\"],correct:1},<!-- [et_pb_line_break_holder] -->      {q:\"Pourquoi faire des mises \u00e0 jour ?\",choices:[\"C\u2019est esth\u00e9tique\",\"\u00c7a ajoute des pubs\",\"\u00c7a corrige des failles\",\"\u00c7a enl\u00e8ve des fonctions\"],correct:2},<!-- [et_pb_line_break_holder] -->      {q:\"Le Wi-Fi public d\u2019un caf\u00e9 ?\",choices:[\"Toujours s\u00fbr\",\"\u00c0 \u00e9viter pour donn\u00e9es sensibles\",\"Mieux que 4G\",\"Permet d\u2019envoyer des mdp\"],correct:1}<!-- [et_pb_line_break_holder] -->    ];<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    const TILE = { START:\"START\", EQUIP:\"EQUIP\", ACTION:\"ACTION\", HAZARD:\"HAZARD\" };<!-- [et_pb_line_break_holder] -->    const fair = (h) => { const tef = rnd(h.tef[0], h.tef[1]); const p = clamp((tef * h.vuln) \/ 12, 0, 1); const lm = rnd(h.lm[0], h.lm[1]); return { pIncident: p, lm, rep: h.rep, incident: Math.random() < p }; };<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    \/* ======================== NET (Firebase) ======================== *\/<!-- [et_pb_line_break_holder] -->    const NET = {<!-- [et_pb_line_break_holder] -->  online:false, roomId:null, me: (Math.random().toString(36).slice(2,10)).toUpperCase(),<!-- [et_pb_line_break_holder] -->  myName:'', myColor:'#111827', isHost:false, app:null, db:null,<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  init(){<!-- [et_pb_line_break_holder] -->  try{<!-- [et_pb_line_break_holder] -->    const cfg = window.CYBER_ARCADE_FIREBASE;<!-- [et_pb_line_break_holder] -->    if(!cfg){ alert(\"\u26a0\ufe0f Config Firebase absente.\"); return false; }<!-- [et_pb_line_break_holder] -->    if (!window.firebase || !firebase.initializeApp) { alert(\"\u26a0\ufe0f Librairies Firebase non charg\u00e9es.\"); return false; }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    \/\/ \u2705 R\u00c9UTILISER l\u2019app si d\u00e9j\u00e0 initialis\u00e9e (badge de test)<!-- [et_pb_line_break_holder] -->    this.app = (firebase.apps && firebase.apps.length) ? firebase.app() : firebase.initializeApp(cfg);<!-- [et_pb_line_break_holder] -->    this.db  = firebase.database();<!-- [et_pb_line_break_holder] -->    return true;<!-- [et_pb_line_break_holder] -->  }catch(e){<!-- [et_pb_line_break_holder] -->    console.error(\"Firebase init error:\", e);<!-- [et_pb_line_break_holder] -->    alert(\"\u274c Init Firebase \u00e9chou\u00e9e : \" + (e?.message||e));<!-- [et_pb_line_break_holder] -->    return false;<!-- [et_pb_line_break_holder] -->  }<!-- [et_pb_line_break_holder] -->},<!-- [et_pb_line_break_holder] -->  async ping(){<!-- [et_pb_line_break_holder] -->    try{<!-- [et_pb_line_break_holder] -->      const k = \"ping_\"+Math.random().toString(36).slice(2,8);<!-- [et_pb_line_break_holder] -->      await this.db.ref(\"_ping\/\"+k).set(Date.now());<!-- [et_pb_line_break_holder] -->      await this.db.ref(\"_ping\/\"+k).remove();<!-- [et_pb_line_break_holder] -->      return true;<!-- [et_pb_line_break_holder] -->    }catch(e){<!-- [et_pb_line_break_holder] -->      console.error(\"Ping DB failed:\", e);<!-- [et_pb_line_break_holder] -->      alert(\"\u274c Acc\u00e8s Realtime DB refus\u00e9 (v\u00e9rifie URL et r\u00e8gles). D\u00e9tail: \"+(e?.message||e));<!-- [et_pb_line_break_holder] -->      return false;<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] -->  },<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  genCode(len=4){<!-- [et_pb_line_break_holder] -->    const A=\"ABCDEFGHJKMNPQRSTUVWXYZ23456789\";<!-- [et_pb_line_break_holder] -->    let s=\"\"; for(let i=0;i<len;i++) s += A[Math.floor(Math.random()*A.length)];<!-- [et_pb_line_break_holder] -->    return s;<!-- [et_pb_line_break_holder] -->  },<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  async createRoom(){<!-- [et_pb_line_break_holder] -->    this.isHost = true;<!-- [et_pb_line_break_holder] -->    this.roomId = this.genCode(4);<!-- [et_pb_line_break_holder] -->    await this.db.ref(`rooms\/${this.roomId}`).set({ createdAt: Date.now(), state: null, players: {} });<!-- [et_pb_line_break_holder] -->    return this.roomId;<!-- [et_pb_line_break_holder] -->  },<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  async joinRoom(code){<!-- [et_pb_line_break_holder] -->    this.isHost = false;<!-- [et_pb_line_break_holder] -->    this.roomId = code.toUpperCase();<!-- [et_pb_line_break_holder] -->    const snap = await this.db.ref(`rooms\/${this.roomId}`).get();<!-- [et_pb_line_break_holder] -->    if(!snap.exists()) throw new Error(\"Salle introuvable.\");<!-- [et_pb_line_break_holder] -->    return this.roomId;<!-- [et_pb_line_break_holder] -->  },<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  async addMe(name,color){<!-- [et_pb_line_break_holder] -->    const pRef = this.db.ref(`rooms\/${this.roomId}\/players`);<!-- [et_pb_line_break_holder] -->    const snap = await pRef.get();<!-- [et_pb_line_break_holder] -->    const used = new Set(Object.values(snap.val()||{}).map(p=>p.color));<!-- [et_pb_line_break_holder] -->    const PALETTE = [\"#111827\",\"#ef4444\",\"#3b82f6\",\"#10b981\",\"#a855f7\",\"#f59e0b\",\"#06b6d4\",\"#f43f5e\",\"#84cc16\",\"#8b5cf6\"];<!-- [et_pb_line_break_holder] -->    let c = color && \/^#([0-9a-f]{3}|[0-9a-f]{6})$\/i.test(color) ? color : (PALETTE.find(x=>!used.has(x))||PALETTE[0]);<!-- [et_pb_line_break_holder] -->    if(used.has(c)) c = PALETTE.find(x=>!used.has(x)) || c;<!-- [et_pb_line_break_holder] -->    await pRef.child(this.me).set({ id:this.me, name, color:c, joinAt:Date.now() });<!-- [et_pb_line_break_holder] -->    this.myName = name; this.myColor = c;<!-- [et_pb_line_break_holder] -->  },<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  async setState(state){<!-- [et_pb_line_break_holder] -->    await this.db.ref(`rooms\/${this.roomId}\/state`).set(state);<!-- [et_pb_line_break_holder] -->  },<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  onState(cb){<!-- [et_pb_line_break_holder] -->  const ref = this.db.ref(`rooms\/${this.roomId}\/state`);<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  \/\/ 1) \u00e9coute temps r\u00e9el<!-- [et_pb_line_break_holder] -->  ref.on('value', snap => {<!-- [et_pb_line_break_holder] -->    const val = snap.val();<!-- [et_pb_line_break_holder] -->    if (val) cb(val);<!-- [et_pb_line_break_holder] -->  });<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  \/\/ 2) lecture imm\u00e9diate au cas o\u00f9 l'\u00e9tat existe d\u00e9j\u00e0<!-- [et_pb_line_break_holder] -->  ref.get().then(snap => {<!-- [et_pb_line_break_holder] -->    if (snap.exists()) cb(snap.val());<!-- [et_pb_line_break_holder] -->  }).catch(()=>{});<!-- [et_pb_line_break_holder] -->}<!-- [et_pb_line_break_holder] -->};<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->\/* ======================== startGame \u2014 \u201cOK \u21d2 action\u201d garantie ======================== *\/<!-- [et_pb_line_break_holder] -->window.__CA_STARTING = false;<!-- [et_pb_line_break_holder] -->    \/* ======================== VUES (HTML) ======================== *\/<!-- [et_pb_line_break_holder] -->    const home = H(`<!-- [et_pb_line_break_holder] -->      <\/p>\n<div id=\"ca-home\"><!-- [et_pb_line_break_holder] -->        <\/p>\n<h1>Arcade Cyber<\/h1>\n<p><!-- [et_pb_line_break_holder] -->        <\/p>\n<div class=\"sub\">Local (m\u00eame \u00e9cran) ou En ligne (plusieurs ordinateurs).<\/div>\n<p><!\u2013- [et_pb_br_holder] -\u2013><!-- [et_pb_line_break_holder] -->        <\/p>\n<div class=\"ca-card\" style=\"margin-bottom:16px\"><!-- [et_pb_line_break_holder] -->          <\/p>\n<h3>Mode de jeu<\/h3>\n<p><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"ca-row\"><!-- [et_pb_line_break_holder] -->            <label><input type=\"radio\" name=\"mode\" id=\"modeLocal\" checked> Local<\/label><!-- [et_pb_line_break_holder] -->            <label><input type=\"radio\" name=\"mode\" id=\"modeOnline\"> En ligne<\/label><!-- [et_pb_line_break_holder] -->          <\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/p>\n<div id=\"localCfg\" style=\"margin-top:12px\"><!-- [et_pb_line_break_holder] -->            <\/p>\n<div class=\"ca-row\"><!-- [et_pb_line_break_holder] -->              <label>Nombre :<\/label><!-- [et_pb_line_break_holder] -->              <select id=\"nb\" class=\"ca-in\"><option>1<\/option><option selected>2<\/option><option>3<\/option><option>4<\/option><option>5<\/option><option>6<\/option><\/select><!-- [et_pb_line_break_holder] -->              <label style=\"margin-left:10px\">Tours :<\/label><!-- [et_pb_line_break_holder] -->              <label id=\"rounds\" class=\"ca-in\" style=\"margin-left:10px\">365<\/label> <!-- [et_pb_line_break_holder] -->              <!-- [et_pb_line_break_holder] -->              <label style=\"margin-left:10px\">Tr\u00e9so d\u00e9part :<\/label><!-- [et_pb_line_break_holder] -->              <input id=\"cash\" class=\"ca-in\" type=\"number\" value=\"500\" style=\"width:90px\"><!-- [et_pb_line_break_holder] -->              <label style=\"margin-left:10px\">Notori\u00e9t\u00e9 :<\/label><!-- [et_pb_line_break_holder] -->              <input id=\"brand\" class=\"ca-in\" type=\"number\" value=\"100\" style=\"width:90px\"><!-- [et_pb_line_break_holder] -->            <\/div>\n<p><!-- [et_pb_line_break_holder] -->            <\/p>\n<div id=\"playersBox\" class=\"ca-players\"><\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/div>\n<p><!-- [et_pb_line_break_holder] -->        <\/div>\n<p><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->        <\/p>\n<div class=\"ca-card\"><!-- [et_pb_line_break_holder] -->          <\/p>\n<h3>Plateau \u201cChallenge Global (J1+J2)\u201d<\/h3>\n<p><!-- [et_pb_line_break_holder] -->          <pee style=\"margin:0 0 12px\">Regroupe messagerie, sauvegardes, mises \u00e0 jour, r\u00f4les\u2026<\/pee><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"ca-row\"><!-- [et_pb_line_break_holder] -->            <button class=\"ca-btn\" id=\"goChallenge\">Lancer (mode s\u00e9lectionn\u00e9)<\/button><!-- [et_pb_line_break_holder] -->            <button class=\"ca-btn ghost\" id=\"rulesChallenge\">\ud83d\udcd8 R\u00e8gles<\/button><!-- [et_pb_line_break_holder] -->          <\/div>\n<p><!-- [et_pb_line_break_holder] -->        <\/div>\n<p><!-- [et_pb_line_break_holder] -->      <\/div>\n<p><!-- [et_pb_line_break_holder] -->    `);<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    const board = H(`<!-- [et_pb_line_break_holder] -->      <\/p>\n<div id=\"ca-board\" style=\"display:none\"><!-- [et_pb_line_break_holder] -->        <\/p>\n<div class=\"ca-top\"><!-- [et_pb_line_break_holder] -->          <\/p>\n<div><!-- [et_pb_line_break_holder] -->            <\/p>\n<div class=\"ca-h\" id=\"boardTitle\" style=\"font-size:28px\">Arcade Cyber<\/div>\n<p><!-- [et_pb_line_break_holder] -->            <\/p>\n<div class=\"ca-soft\" id=\"boardSub\" style=\"font-size:13px\"><\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/p>\n<div><!-- [et_pb_line_break_holder] -->            <button class=\"ca-btnBar\" id=\"backHome\">Accueil<\/button><!-- [et_pb_line_break_holder] -->            <button class=\"ca-btnBar\" id=\"reset\">R\u00e9initialiser<\/button><!-- [et_pb_line_break_holder] -->            <button class=\"ca-btnBar\" id=\"zoom-\">\u2212 Zoom<\/button><!-- [et_pb_line_break_holder] -->            <button class=\"ca-btnBar\" id=\"zoom+\">+ Zoom<\/button><!-- [et_pb_line_break_holder] -->            <button class=\"ca-btnBar\" id=\"rulesHere\">\ud83d\udcd8 R\u00e8gles<\/button><!-- [et_pb_line_break_holder] -->            <button class=\"ca-btnBar ca-btnPri\" id=\"fs\">\u26f6 Plein \u00e9cran<\/button><!-- [et_pb_line_break_holder] -->          <\/div>\n<p><!-- [et_pb_line_break_holder] -->        <\/div>\n<p><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->        <\/p>\n<div class=\"ca-box ca-score\"><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"sb-head\"><!-- [et_pb_line_break_holder] -->            <\/p>\n<div class=\"ca-h\">Tableau de bord joueurs <span id=\"roomBadge\" class=\"sb-badge\" style=\"margin-left:8px;display:none\"><\/span><\/div>\n<p><!-- [et_pb_line_break_holder] -->            <button class=\"ca-btnBar sb-toggle\" id=\"sbToggle\">Afficher\/Cacher<\/button><!-- [et_pb_line_break_holder] -->          <\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/p>\n<div id=\"scoreboardBody\" class=\"sb-list\"><\/div>\n<p><!-- [et_pb_line_break_holder] -->        <\/div>\n<p><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->        <\/p>\n<div class=\"ca-box ca-wrap\"><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"ca-stage\">\n<div class=\"ca-iso\">\n<div class=\"ca-grid\" id=\"grid\"><\/div>\n<\/div>\n<\/div>\n<p><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"ca-box ca-strip\"><!-- [et_pb_line_break_holder] -->            <\/p>\n<div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:6px\"><!-- [et_pb_line_break_holder] -->              <\/p>\n<div class=\"ca-h\">Main<\/div>\n<p><!-- [et_pb_line_break_holder] -->              <\/p>\n<div class=\"ca-soft\" style=\"font-size:12px\">Clique une carte pour revoir son explication.<\/div>\n<p><!-- [et_pb_line_break_holder] -->            <\/div>\n<p><!-- [et_pb_line_break_holder] -->            <\/p>\n<div class=\"ca-hand\" id=\"hand\"><\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/div>\n<p><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"ca-box ca-strip\"><!-- [et_pb_line_break_holder] -->            <\/p>\n<div class=\"ca-h\" style=\"margin-bottom:6px\">Journal<\/div>\n<p><!-- [et_pb_line_break_holder] -->            <\/p>\n<div id=\"log\" style=\"max-height:34vh;overflow:auto\"><\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/div>\n<p><!-- [et_pb_line_break_holder] -->        <\/div>\n<p><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->        <\/p>\n<div class=\"ca-hud\"><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"ca-hudCard\" id=\"hudPlayer\"><\/div>\n<p><!-- [et_pb_line_break_holder] -->          <button class=\"ca-dice\" id=\"dice\" aria-disabled=\"true\">\u2022<\/button><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"ca-hudCard\" id=\"hudStats\"><\/div>\n<p><!-- [et_pb_line_break_holder] -->        <\/div>\n<p><!-- [et_pb_line_break_holder] -->      <\/div>\n<p><!-- [et_pb_line_break_holder] -->    `);<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    const modal = H(`<!-- [et_pb_line_break_holder] -->      <\/p>\n<div class=\"ca-modal\" id=\"modal\"><!-- [et_pb_line_break_holder] -->        <\/p>\n<div class=\"ca-boxM\"><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"ca-boxHead\"><!-- [et_pb_line_break_holder] -->            <\/p>\n<div class=\"ca-h\" id=\"mTitle\"><\/div>\n<p><!-- [et_pb_line_break_holder] -->            <button class=\"ca-btnBar\" id=\"mClose\">\u2715<\/button><!-- [et_pb_line_break_holder] -->          <\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"ca-boxBody\" id=\"mBody\"><\/div>\n<p><!-- [et_pb_line_break_holder] -->        <\/div>\n<p><!-- [et_pb_line_break_holder] -->      <\/div>\n<p><!-- [et_pb_line_break_holder] -->    `);<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    mount.append(home, board, modal);<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    \/* ======================== ETAT \/ HELPERS ======================== *\/<!-- [et_pb_line_break_holder] -->    const show = (id) => { q(\"#ca-home\").style.display = id === \"home\" ? \"block\" : \"none\"; q(\"#ca-board\").style.display = id === \"board\" ? \"block\" : \"none\"; };<!-- [et_pb_line_break_holder] -->    let MODAL_LOCK = false, BUSY_ROLL = false;<!-- [et_pb_line_break_holder] -->    let G = null;<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    function setDiceEnabled(on) { const d = q(\"#dice\"); if (!d) return; d.disabled = !on; d.setAttribute(\"aria-disabled\", String(!on)); }<!-- [et_pb_line_break_holder] -->    function rulesHTML() {<!-- [et_pb_line_break_holder] -->      return `<\/p>\n<div style=\"display:grid;gap:12px\"><!-- [et_pb_line_break_holder] -->        <\/p>\n<div><b>But<\/b> : finir avec le plus de <b>tr\u00e9sorerie<\/b> et de <b>notori\u00e9t\u00e9<\/b>.<\/div>\n<p><!-- [et_pb_line_break_holder] -->        <\/p>\n<div><b>Cases<\/b> : START (+50 \u20ac), \u00c9QUIPEMENT (achat), ACTION (pioche), AL\u00c9A (\u00e9v\u00e9nement incertain).<\/div>\n<p><!-- [et_pb_line_break_holder] -->        <\/p>\n<div><b>R\u00e9ductions<\/b> : \u00c9quipement \u2248 \u221275 % \u2022 Action \u2248 \u221250 % \u2022 Quiz \u2248 \u221225 % si bonne r\u00e9ponse.<\/div>\n<p><!-- [et_pb_line_break_holder] -->        <\/p>\n<div><b>Revenus par tour<\/b> : + tr\u00e9sorerieInitiale\/nbCases ; + notori\u00e9t\u00e9Initiale\/nbCases (max 100).<\/div>\n<p><!-- [et_pb_line_break_holder] -->      <\/div>\n<p>`;<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    const sideOf = (i) => (i <= 10 ? \"top\" : i <= 20 ? \"right\" : i <= 30 ? \"bottom\" : \"left\");<!-- [et_pb_line_break_holder] -->    function distributeTypes() {<!-- [et_pb_line_break_holder] -->      const total = 39, targets = { EQUIP: 12, ACTION: 10, HAZARD: 17 }, out = new Array(total).fill(null);<!-- [et_pb_line_break_holder] -->      function placeEven(type, count) {<!-- [et_pb_line_break_holder] -->        for (let k = 0; k < count; k++) {<!-- [et_pb_line_break_holder] -->          const ideal = Math.round((k + 0.5) * total \/ count) - 1;<!-- [et_pb_line_break_holder] -->          let pos = Math.max(0, Math.min(total - 1, ideal));<!-- [et_pb_line_break_holder] -->          if (out[pos] == null) { out[pos] = type; continue; }<!-- [et_pb_line_break_holder] -->          for (let d = 1; d < total; d++) {<!-- [et_pb_line_break_holder] -->            const p1 = pos + d, p2 = pos - d;<!-- [et_pb_line_break_holder] -->            if (p1 < total &#038;&#038; out[p1] == null) { out[p1] = type; break; }<!-- [et_pb_line_break_holder] -->            if (p2 >= 0 && out[p2] == null) { out[p2] = type; break; }<!-- [et_pb_line_break_holder] -->          }<!-- [et_pb_line_break_holder] -->        }<!-- [et_pb_line_break_holder] -->      }<!-- [et_pb_line_break_holder] -->      placeEven(\"EQUIP\", targets.EQUIP); placeEven(\"ACTION\", targets.ACTION); placeEven(\"HAZARD\", targets.HAZARD);<!-- [et_pb_line_break_holder] -->      const need = (t) => targets[t] - out.filter((x) => x === t).length;<!-- [et_pb_line_break_holder] -->      for (let i = 0; i < total; i++)<!-- [et_pb_line_break_holder] -->        if (out[i] == null) {<!-- [et_pb_line_break_holder] -->          const pk = [[\"EQUIP\", need(\"EQUIP\")], [\"ACTION\", need(\"ACTION\")], [\"HAZARD\", need(\"HAZARD\")]].sort((a, b) => b[1] - a[1])[0][0];<!-- [et_pb_line_break_holder] -->          out[i] = pk;<!-- [et_pb_line_break_holder] -->        }<!-- [et_pb_line_break_holder] -->      return out;<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] -->    function buildTiles() {<!-- [et_pb_line_break_holder] -->      const types = distributeTypes();<!-- [et_pb_line_break_holder] -->      const tiles = [{ type: TILE.START }];<!-- [et_pb_line_break_holder] -->      let eq = 0;<!-- [et_pb_line_break_holder] -->      types.forEach((t) => {<!-- [et_pb_line_break_holder] -->        if (t === \"EQUIP\") {<!-- [et_pb_line_break_holder] -->          const e = EQUIPS_CHALLENGE[eq++ % EQUIPS_CHALLENGE.length];<!-- [et_pb_line_break_holder] -->          tiles.push({ type: TILE.EQUIP, equipId: e.id });<!-- [et_pb_line_break_holder] -->        } else tiles.push({ type: TILE[t] });<!-- [et_pb_line_break_holder] -->      });<!-- [et_pb_line_break_holder] -->      return tiles;<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] -->    function sizeBoard(zoom = 1) {<!-- [et_pb_line_break_holder] -->      const stage = mount.querySelector(\".ca-stage\")?.getBoundingClientRect?.();<!-- [et_pb_line_break_holder] -->      if (!stage) return;<!-- [et_pb_line_break_holder] -->      const gap = parseFloat(getComputedStyle(mount).getPropertyValue(\"--gap\")) || 8;<!-- [et_pb_line_break_holder] -->      const P = 28, gaps = 10 * gap;<!-- [et_pb_line_break_holder] -->      const tile = Math.max(62, Math.floor((stage.width - P - gaps) \/ 11)) * zoom;<!-- [et_pb_line_break_holder] -->      mount.style.setProperty(\"--tile\", tile + \"px\");<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] -->    \/* met \u00e0 jour visuellement le point couleur de la carte joueur *\/<!-- [et_pb_line_break_holder] -->function refreshRowDot(cardEl){<!-- [et_pb_line_break_holder] -->  const sel = cardEl.querySelector('.ca-swatch.selected');<!-- [et_pb_line_break_holder] -->  const dot = cardEl.querySelector('.ca-dot');<!-- [et_pb_line_break_holder] -->  if (sel && dot) dot.style.background = sel.dataset.color;<!-- [et_pb_line_break_holder] -->}<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    const cur = () => (G ? G.players.find((p) => p.id === G.order[G.idx]) : null);<!-- [et_pb_line_break_holder] -->    function logLine(msg) { G.log = G.log || []; G.log.push(msg); renderLog(); if (NET.online) NET.db.ref(`rooms\/${NET.roomId}\/state`).set(G); }<!-- [et_pb_line_break_holder] -->    function renderLog() { const el = q(\"#log\"); if (!el || !G) return; el.innerHTML = (G.log || []).map((m) => `<\/p>\n<div style=\"font-size:14px\">${m}<\/div>\n<p>`).join(\"\"); el.scrollTop = el.scrollHeight; }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    function renderBoard() {<!-- [et_pb_line_break_holder] -->      const grid = q(\"#grid\"); if (!grid || !G) return; grid.innerHTML = \"\";<!-- [et_pb_line_break_holder] -->      const ring = []; for (let x = 0; x < 11; x++) ring.push([0, x]); for (let y = 1; y < 11; y++) ring.push([y, 10]); for (let x = 9; x >= 0; x--) ring.push([10, x]); for (let y = 9; y >= 1; y--) ring.push([y, 0]);<!-- [et_pb_line_break_holder] -->      for (let r = 0; r < 11; r++) for (let c = 0; c < 11; c++) {<!-- [et_pb_line_break_holder] -->        const idx = ring.findIndex(([rr, cc]) => rr === r && cc === c);<!-- [et_pb_line_break_holder] -->        const cell = document.createElement(\"div\");<!-- [et_pb_line_break_holder] -->        if (idx === -1 || idx >= 40) { cell.style.minHeight = \"var(--tile)\"; grid.appendChild(cell); continue; }<!-- [et_pb_line_break_holder] -->        const t = G.tiles[idx], side = sideOf(idx), on = G.players.filter((p) => p.pos === idx);<!-- [et_pb_line_break_holder] -->        const cls = [\"ca-tile\"]; if ([0, 10, 20, 30].includes(idx)) cls.push(\"ca-corner\");<!-- [et_pb_line_break_holder] -->        if (t.type === TILE.START) cls.push(\"ca-start\"); if (t.type === TILE.EQUIP) cls.push(\"ca-equip\"); if (t.type === TILE.ACTION) cls.push(\"ca-action\"); if (t.type === TILE.HAZARD) cls.push(\"ca-hazard\");<!-- [et_pb_line_break_holder] -->        cell.className = cls.join(\" \");<!-- [et_pb_line_break_holder] -->        let icon = \"\u2b1c\", label = \"\", price = null, tip = \"\";<!-- [et_pb_line_break_holder] -->        if (t.type === TILE.START) { icon = \"\ud83c\udfc1\"; label = \"START\"; tip = \"Passez par START : +50 \u20ac\"; }<!-- [et_pb_line_break_holder] -->        if (t.type === TILE.ACTION) { icon = \"\ud83c\udfb4\"; label = \"Action\"; tip = \"Pioche 1 carte ACTION (\u221250 % si tu l\u2019emploies)\"; }<!-- [et_pb_line_break_holder] -->        if (t.type === TILE.HAZARD) { icon = \"\u26a0\ufe0f\"; label = \"Al\u00e9a\"; tip = \"\u00c9v\u00e9nement incertain\"; }<!-- [et_pb_line_break_holder] -->        if (t.type === TILE.EQUIP) {<!-- [et_pb_line_break_holder] -->          const eq = EQUIPS_CHALLENGE.find((e) => e.id === t.equipId);<!-- [et_pb_line_break_holder] -->          icon = eq.icon; label = eq.name; price = eq.price; tip = `${eq.name} \u2022 ${eq.price} \u20ac \u2022 Prot\u00e8ge : ${eq.covers.join(\", \")}`;<!-- [et_pb_line_break_holder] -->        }<!-- [et_pb_line_break_holder] -->        cell.append(H(`<\/p>\n<div class=\"ca-ico\">${icon}<\/div>\n<p>`));<!-- [et_pb_line_break_holder] -->        if (price != null) cell.append(H(`<\/p>\n<div class=\"ca-price\">\u20ac${price}<\/div>\n<p>`));<!-- [et_pb_line_break_holder] -->        const sideCls = side === \"left\" ? \"ca-left\" : side === \"right\" ? \"ca-right\" : \"\";<!-- [et_pb_line_break_holder] -->        cell.append(H(`<\/p>\n<div class=\"ca-lab ${sideCls}\"><span class=\"ca-labIn\">${label}<\/span><\/div>\n<p>`));<!-- [et_pb_line_break_holder] -->        const toks = document.createElement(\"div\"); toks.className = \"ca-tokens\";<!-- [et_pb_line_break_holder] -->        on.forEach((p) => toks.append(H(`<span class=\"ca-token\" title=\"${p.name}\" style=\"background:${p.color}\"><\/span>`)));<!-- [et_pb_line_break_holder] -->        cell.append(toks); cell.title = tip; grid.append(cell);<!-- [et_pb_line_break_holder] -->      }<!-- [et_pb_line_break_holder] -->     <!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    function delta(pId, chg, msg) {<!-- [et_pb_line_break_holder] -->      G.players = G.players.map((pl) =><!-- [et_pb_line_break_holder] -->        pl.id !== pId ? pl : {<!-- [et_pb_line_break_holder] -->          ...pl,<!-- [et_pb_line_break_holder] -->          cash: pl.cash + (chg.cash || 0),<!-- [et_pb_line_break_holder] -->          brand: clamp(pl.brand + (chg.brand || 0), 0, 100),<!-- [et_pb_line_break_holder] -->          lastDelta: {<!-- [et_pb_line_break_holder] -->            cash: (pl.lastDelta.cash || 0) + (chg.cash || 0),<!-- [et_pb_line_break_holder] -->            brand: (pl.lastDelta.brand || 0) + (chg.brand || 0),<!-- [et_pb_line_break_holder] -->          },<!-- [et_pb_line_break_holder] -->        }<!-- [et_pb_line_break_holder] -->      );<!-- [et_pb_line_break_holder] -->      if (msg) logLine(msg);<!-- [et_pb_line_break_holder] -->      renderHUD(); renderScoreboard();<!-- [et_pb_line_break_holder] -->      if (NET.online) NET.db.ref(`rooms\/${NET.roomId}\/state`).set(G);<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] -->\/\/ Normalise au cas o\u00f9 (\u00e9vite l\u2019erreur \"reading 'some'\")<!-- [et_pb_line_break_holder] -->function normalizePlayer(p){<!-- [et_pb_line_break_holder] -->  return {<!-- [et_pb_line_break_holder] -->    id: p.id,<!-- [et_pb_line_break_holder] -->    name: p.name || \"Joueur\",<!-- [et_pb_line_break_holder] -->    color: p.color || \"#111827\",<!-- [et_pb_line_break_holder] -->    cash: Number.isFinite(p.cash) ? p.cash : 500,<!-- [et_pb_line_break_holder] -->    brand: Number.isFinite(p.brand) ? p.brand : 100,<!-- [et_pb_line_break_holder] -->    cash0: Number.isFinite(p.cash0) ? p.cash0 : (Number.isFinite(p.cash) ? p.cash : 500),<!-- [et_pb_line_break_holder] -->    brand0: Number.isFinite(p.brand0) ? p.brand0 : (Number.isFinite(p.brand) ? p.brand : 100),<!-- [et_pb_line_break_holder] -->    equips: Array.isArray(p.equips) ? p.equips : [],<!-- [et_pb_line_break_holder] -->    actions: Array.isArray(p.actions) ? p.actions : [],<!-- [et_pb_line_break_holder] -->    pos: Number.isFinite(p.pos) ? p.pos : 0,<!-- [et_pb_line_break_holder] -->    turns: Number.isFinite(p.turns) ? p.turns : 0,<!-- [et_pb_line_break_holder] -->    lastDelta: p.lastDelta || {cash:0, brand:0}<!-- [et_pb_line_break_holder] -->  };<!-- [et_pb_line_break_holder] -->}<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->\/\/ Affiche une \"salle d\u2019attente\" temps r\u00e9el pour l\u2019h\u00f4te et les invit\u00e9s<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->\/\/ Remplace TOUTE ta fonction openLobby par celle-ci<!-- [et_pb_line_break_holder] -->function openLobby(title, code, playersList, onStart){<!-- [et_pb_line_break_holder] -->  const bodyHTML = `<!-- [et_pb_line_break_holder] -->    <\/p>\n<div class=\"ca-box\" style=\"padding:14px;border-radius:16px\"><!-- [et_pb_line_break_holder] -->      <\/p>\n<div style=\"margin-bottom:12px\"><!-- [et_pb_line_break_holder] -->        <\/p>\n<div class=\"ca-soft\">Code salle :<\/div>\n<p><!-- [et_pb_line_break_holder] -->        <\/p>\n<div style=\"font-size:22px;font-weight:900;display:inline-block;background:#f3f0ff;border:1px solid var(--ring);<!-- [et_pb_line_break_holder] -->            padding:4px 10px;border-radius:10px\">${code}<\/div>\n<p><!-- [et_pb_line_break_holder] -->      <\/div>\n<p><!-- [et_pb_line_break_holder] -->      <\/p>\n<div class=\"ca-soft\" style=\"color:#16a34a;margin-bottom:12px\">Donne ce code aux autres joueurs.<\/div>\n<p><!-- [et_pb_line_break_holder] -->      <\/p>\n<div><!-- [et_pb_line_break_holder] -->        <\/p>\n<div class=\"ca-h\" style=\"margin-bottom:6px\">Joueurs connect\u00e9s (${playersList?.length||0})<\/div>\n<p><!-- [et_pb_line_break_holder] -->        ${<!-- [et_pb_line_break_holder] -->          (playersList && playersList.length)<!-- [et_pb_line_break_holder] -->          ? `<\/p>\n<ul style=\"margin:0;padding-left:18px\">${playersList.map(p =><!-- [et_pb_line_break_holder] -->              `<\/p>\n<li><span class=\"ca-token\" style=\"background:${p.color||'#111827'}\"><\/span> ${p.name||'Joueur'}<\/li>\n<p>`<!-- [et_pb_line_break_holder] -->            ).join(\"\")}<\/ul>\n<p>`<!-- [et_pb_line_break_holder] -->          : `<\/p>\n<div class=\"ca-soft\">En attente de joueurs\u2026<\/div>\n<p>`<!-- [et_pb_line_break_holder] -->        }<!-- [et_pb_line_break_holder] -->      <\/div>\n<p><!-- [et_pb_line_break_holder] -->      <\/p>\n<div style=\"display:flex;justify-content:flex-end;margin-top:16px\"><!-- [et_pb_line_break_holder] -->        ${<!-- [et_pb_line_break_holder] -->          onStart<!-- [et_pb_line_break_holder] -->          ? `<button class=\"ca-btn ca-btnPri\" onclick=\"window.__startHostGame &#038;&#038; window.__startHostGame()\">D\u00e9marrer la partie<\/button>`<!-- [et_pb_line_break_holder] -->          : `<\/p>\n<div class=\"ca-soft\">Le jeu d\u00e9marrera quand l\u2019h\u00f4te lancera la partie.<\/div>\n<p>`<!-- [et_pb_line_break_holder] -->        }<!-- [et_pb_line_break_holder] -->      <\/div>\n<p><!-- [et_pb_line_break_holder] -->    <\/div>\n<p>`;<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  \/\/ on locke (emp\u00eache la fermeture tant que l\u2019h\u00f4te n\u2019a pas cliqu\u00e9)<!-- [et_pb_line_break_holder] -->  openModal(title, bodyHTML, {lock: !onStart ? true : false});<!-- [et_pb_line_break_holder] -->  \/\/ expose le handler de d\u00e9marrage c\u00f4t\u00e9 fen\u00eatre (appel\u00e9 par onclick)<!-- [et_pb_line_break_holder] -->  window.__startHostGame = onStart || null;<!-- [et_pb_line_break_holder] -->}<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->function closeModal(force = false) {<!-- [et_pb_line_break_holder] -->  if (MODAL_LOCK && !force) return;<!-- [et_pb_line_break_holder] -->  MODAL_LOCK = false;<!-- [et_pb_line_break_holder] -->  const M = q(\"#modal\");<!-- [et_pb_line_break_holder] -->  if (M) M.style.display = \"none\";<!-- [et_pb_line_break_holder] -->  if (!BUSY_ROLL) syncLocks();<!-- [et_pb_line_break_holder] -->}<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    function endTurn(pId, opts = {}) {<!-- [et_pb_line_break_holder] -->  const { skipIncome = false } = opts;<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  const p = G.players.find((x) => x.id === pId);<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  \/\/ revenus de fin de tour, sauf si on les saute (al\u00e9a)<!-- [et_pb_line_break_holder] -->  if (!skipIncome) {<!-- [et_pb_line_break_holder] -->    const nbCases = G.tiles.length;<!-- [et_pb_line_break_holder] -->    const cashGain  = Math.floor((p.cash0 || 0) \/ nbCases);<!-- [et_pb_line_break_holder] -->    const brandGain = Math.floor((p.brand0 || 0) \/ nbCases);<!-- [et_pb_line_break_holder] -->    delta(pId, { cash: cashGain, brand: brandGain }, `${p.name} revenu du tour : +${cashGain} \u20ac ; +${brandGain} notori\u00e9t\u00e9`);<!-- [et_pb_line_break_holder] -->  } else {<!-- [et_pb_line_break_holder] -->    logLine(`${p.name} fin de tour sans revenus (AL\u00c9A).`);<!-- [et_pb_line_break_holder] -->  }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  \/\/ +1 tour pour ce joueur<!-- [et_pb_line_break_holder] -->  G.players = G.players.map((pl) =><!-- [et_pb_line_break_holder] -->    pl.id !== pId ? pl : { ...pl, turns: pl.turns + 1, lastIncident: false, lastDelta: { cash: 0, brand: 0 } }<!-- [et_pb_line_break_holder] -->  );<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  \/\/ \u2705 arr\u00eat d\u00e8s que le joueur courant atteint 365<!-- [et_pb_line_break_holder] -->  if (G.players.find(pl => pl.id === pId).turns >= G.roundsTarget) {<!-- [et_pb_line_break_holder] -->    logLine(\"<b>Fin de partie (365 tours atteints) !<\/b>\");<!-- [et_pb_line_break_holder] -->    G.gameOver = true;<!-- [et_pb_line_break_holder] -->    BUSY_ROLL = false;<!-- [et_pb_line_break_holder] -->    setDiceEnabled(false);<!-- [et_pb_line_break_holder] -->    if (NET.online) NET.db.ref(`rooms\/${NET.roomId}\/state`).set(G);<!-- [et_pb_line_break_holder] -->    return;<!-- [et_pb_line_break_holder] -->  }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  \/\/ sinon on passe au joueur suivant<!-- [et_pb_line_break_holder] -->  let ni = (G.idx + 1) % G.order.length;<!-- [et_pb_line_break_holder] -->  \/\/ (si tu veux permettre aux autres de finir leurs tours: enl\u00e8ve ce while)<!-- [et_pb_line_break_holder] -->  G.idx = ni;<!-- [et_pb_line_break_holder] -->  BUSY_ROLL = false;<!-- [et_pb_line_break_holder] -->  syncLocks(); renderHUD(); renderHand(); renderScoreboard();<!-- [et_pb_line_break_holder] -->  if (NET.online) NET.db.ref(`rooms\/${NET.roomId}\/state`).set(G);<!-- [et_pb_line_break_holder] -->}<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    const hasEquip = (p, hz) => {<!-- [et_pb_line_break_holder] -->  if (!p || !Array.isArray(p.equips)) return false;<!-- [et_pb_line_break_holder] -->  return p.equips.some(e =><!-- [et_pb_line_break_holder] -->    (EQUIPS_CHALLENGE.find(x => x.id === e.id)?.covers || []).includes(hz)<!-- [et_pb_line_break_holder] -->  );<!-- [et_pb_line_break_holder] -->};<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->const hasMit = (p) => {<!-- [et_pb_line_break_holder] -->  if (!p || !Array.isArray(p.actions)) return false;<!-- [et_pb_line_break_holder] -->  return p.actions.some(a => a.type === \"mitigation\" && a.uses > 0);<!-- [et_pb_line_break_holder] -->};<!-- [et_pb_line_break_holder] -->    function useMit(pId) {<!-- [et_pb_line_break_holder] -->      G.players = G.players.map((pl) => {<!-- [et_pb_line_break_holder] -->        if (pl.id !== pId) return pl;<!-- [et_pb_line_break_holder] -->        const i = pl.actions.findIndex((a) => a.type === \"mitigation\" && a.uses > 0);<!-- [et_pb_line_break_holder] -->        if (i >= 0) {<!-- [et_pb_line_break_holder] -->          const c = pl.actions.slice();<!-- [et_pb_line_break_holder] -->          c[i] = { ...c[i], uses: c[i].uses - 1 };<!-- [et_pb_line_break_holder] -->          return { ...pl, actions: c };<!-- [et_pb_line_break_holder] -->        }<!-- [et_pb_line_break_holder] -->        return pl;<!-- [et_pb_line_break_holder] -->      });<!-- [et_pb_line_break_holder] -->      renderHand();<!-- [et_pb_line_break_holder] -->      if (NET.online) NET.db.ref(`rooms\/${NET.roomId}\/state`).set(G);<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    function ensureDice3D() {<!-- [et_pb_line_break_holder] -->      const btn = q(\"#dice\"); if (!btn || btn.querySelector(\".dice3d\")) return;<!-- [et_pb_line_break_holder] -->      btn.innerHTML = \"\";<!-- [et_pb_line_break_holder] -->      const cube = H(`<!-- [et_pb_line_break_holder] -->        <\/p>\n<div class=\"dice3d\" aria-hidden=\"true\"><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"face f1\">\n<div class=\"pips\"><\/div>\n<\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"face f2\">\n<div class=\"pips\"><\/div>\n<\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"face f3\">\n<div class=\"pips\"><\/div>\n<\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"face f4\">\n<div class=\"pips\"><\/div>\n<\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"face f5\">\n<div class=\"pips\"><\/div>\n<\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"face f6\">\n<div class=\"pips\"><\/div>\n<\/div>\n<p><!-- [et_pb_line_break_holder] -->        <\/div>\n<p><!-- [et_pb_line_break_holder] -->      `);<!-- [et_pb_line_break_holder] -->      btn.append(cube);<!-- [et_pb_line_break_holder] -->      const sz = Math.max(56, Math.min(btn.clientWidth, btn.clientHeight) - 18);<!-- [et_pb_line_break_holder] -->      cube.style.setProperty(\"--size\", sz + \"px\");<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] -->    function orientDiceTo(n) {<!-- [et_pb_line_break_holder] -->      const cube = q(\"#dice .dice3d\"); if (!cube) return;<!-- [et_pb_line_break_holder] -->      let tx = \"rotateX(0deg) rotateY(0deg)\";<!-- [et_pb_line_break_holder] -->      if (n === 2) tx = \"rotateX(90deg) rotateY(0deg)\";<!-- [et_pb_line_break_holder] -->      else if (n === 3) tx = \"rotateX(0deg) rotateY(-90deg)\";<!-- [et_pb_line_break_holder] -->      else if (n === 4) tx = \"rotateX(0deg) rotateY(90deg)\";<!-- [et_pb_line_break_holder] -->      else if (n === 5) tx = \"rotateX(-90deg) rotateY(0deg)\";<!-- [et_pb_line_break_holder] -->      else if (n === 6) tx = \"rotateX(0deg) rotateY(180deg)\";<!-- [et_pb_line_break_holder] -->      cube.style.transform = tx;<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] -->    function rollDiceAnimated() {<!-- [et_pb_line_break_holder] -->      return new Promise((resolve) => {<!-- [et_pb_line_break_holder] -->        ensureDice3D();<!-- [et_pb_line_break_holder] -->        const btn = q(\"#dice\");<!-- [et_pb_line_break_holder] -->        const cube = btn.querySelector(\".dice3d\");<!-- [et_pb_line_break_holder] -->        btn.classList.add(\"is-rolling\");<!-- [et_pb_line_break_holder] -->        btn.disabled = true; btn.setAttribute(\"aria-disabled\", \"true\");<!-- [et_pb_line_break_holder] -->        const total = 1100, tick = 90, target = d6();<!-- [et_pb_line_break_holder] -->        let elapsed = 0;<!-- [et_pb_line_break_holder] -->        const spin = setInterval(() => {<!-- [et_pb_line_break_holder] -->          elapsed += tick;<!-- [et_pb_line_break_holder] -->          const rx = Math.floor(rnd(-720, 720));<!-- [et_pb_line_break_holder] -->          const ry = Math.floor(rnd(-720, 720));<!-- [et_pb_line_break_holder] -->          const rz = Math.floor(rnd(-90, 90));<!-- [et_pb_line_break_holder] -->          cube.style.transform = `rotateX(${rx}deg) rotateY(${ry}deg) rotateZ(${rz}deg)`;<!-- [et_pb_line_break_holder] -->          if (elapsed >= total) {<!-- [et_pb_line_break_holder] -->            clearInterval(spin);<!-- [et_pb_line_break_holder] -->            setTimeout(() => { orientDiceTo(target); btn.classList.remove(\"is-rolling\"); resolve(target); }, 180);<!-- [et_pb_line_break_holder] -->          }<!-- [et_pb_line_break_holder] -->        }, tick);<!-- [et_pb_line_break_holder] -->      });<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    function renderHUD() {<!-- [et_pb_line_break_holder] -->      if (!G) return;<!-- [et_pb_line_break_holder] -->      const p = cur(); if (!p) return;<!-- [et_pb_line_break_holder] -->      q(\"#hudPlayer\").innerHTML =<!-- [et_pb_line_break_holder] -->        `<\/p>\n<div style=\"display:flex;align-items:center;gap:10px\"><!-- [et_pb_line_break_holder] -->          <span class=\"ca-token\" style=\"background:${p.color}\"><\/span><!-- [et_pb_line_break_holder] -->          <\/p>\n<div><!-- [et_pb_line_break_holder] -->            <\/p>\n<div class=\"ca-h\">${p.name}<\/div>\n<p><!-- [et_pb_line_break_holder] -->            <\/p>\n<div class=\"ca-soft\" style=\"font-size:12px\">Tour ${p.turns + 1} \/ ${G.roundsTarget}<\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/div>\n<p><!-- [et_pb_line_break_holder] -->        <\/div>\n<p>`;<!-- [et_pb_line_break_holder] -->      ensureDice3D();<!-- [et_pb_line_break_holder] -->      if (typeof G.lastRoll === \"number\") orientDiceTo(G.lastRoll);<!-- [et_pb_line_break_holder] -->      q(\"#hudStats\").innerHTML =<!-- [et_pb_line_break_holder] -->        `<\/p>\n<div style=\"display:flex;gap:18px\"><!-- [et_pb_line_break_holder] -->          <\/p>\n<div><!-- [et_pb_line_break_holder] -->            <\/p>\n<div class=\"ca-soft\" style=\"font-size:12px\">Tr\u00e9so<\/div>\n<p><!-- [et_pb_line_break_holder] -->            <\/p>\n<div style=\"font-weight:900\">${p.cash.toLocaleString()} \u20ac<\/div>\n<p><!-- [et_pb_line_break_holder] -->            <\/p>\n<div style=\"font-size:12px;color:${(p.lastDelta?.cash || 0) >= 0 ? \"#16a34a\" : \"#dc2626\"}\"><!-- [et_pb_line_break_holder] -->              ${(p.lastDelta?.cash || 0) >= 0 ? \"+\" : \"\"}${p.lastDelta?.cash || 0} \u20ac ce tour<!-- [et_pb_line_break_holder] -->            <\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/p>\n<div><!-- [et_pb_line_break_holder] -->            <\/p>\n<div class=\"ca-soft\" style=\"font-size:12px\">Notori\u00e9t\u00e9<\/div>\n<p><!-- [et_pb_line_break_holder] -->            <\/p>\n<div style=\"font-weight:900\">${p.brand}\/100<\/div>\n<p><!-- [et_pb_line_break_holder] -->            <\/p>\n<div style=\"font-size:12px;color:${(p.lastDelta?.brand || 0) >= 0 ? \"#16a34a\" : \"#dc2626\"}\"><!-- [et_pb_line_break_holder] -->              ${(p.lastDelta?.brand || 0) >= 0 ? \"+\" : \"\"}${p.lastDelta?.brand || 0} ce tour<!-- [et_pb_line_break_holder] -->            <\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/div>\n<p><!-- [et_pb_line_break_holder] -->        <\/div>\n<p>`;<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] -->    function renderScoreboard() {<!-- [et_pb_line_break_holder] -->      if (!G) return;<!-- [et_pb_line_break_holder] -->      const body = q(\"#scoreboardBody\"); if (!body) return;<!-- [et_pb_line_break_holder] -->      const collapsed = body.dataset.collapse === \"1\";<!-- [et_pb_line_break_holder] -->      body.innerHTML = G.players.map((pl) => {<!-- [et_pb_line_break_holder] -->        const isTurn = G.order[G.idx] === pl.id;<!-- [et_pb_line_break_holder] -->        return `<\/p>\n<div class=\"sb-row\" style=\"${collapsed ? \"display:none\" : \"\"}\"><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"sb-left\"><span class=\"ca-token\" style=\"background:${pl.color}\"><\/span><b>${pl.name}<\/b><\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"sb-badge\">Tr\u00e9so : ${pl.cash.toLocaleString()} \u20ac<\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"sb-badge\">Noto : ${pl.brand}\/100<\/div>\n<p><!-- [et_pb_line_break_holder] -->          ${isTurn ? '<\/p>\n<div class=\"sb-badge sb-turn\">tour<\/div>\n<p>' : \"\"}<!-- [et_pb_line_break_holder] -->        <\/div>\n<p>`;<!-- [et_pb_line_break_holder] -->      }).join(\"\");<!-- [et_pb_line_break_holder] -->      const badge = q(\"#roomBadge\");<!-- [et_pb_line_break_holder] -->      if (NET.online && NET.roomId) { badge.style.display = \"inline-block\"; badge.textContent = `Salle : ${NET.roomId}`; }<!-- [et_pb_line_break_holder] -->      else badge.style.display = \"none\";<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] -->    function renderHand() {<!-- [et_pb_line_break_holder] -->      if (!G) return;<!-- [et_pb_line_break_holder] -->      const p = cur(), hand = q(\"#hand\"); if (!hand || !p) return;<!-- [et_pb_line_break_holder] -->      hand.innerHTML = \"\";<!-- [et_pb_line_break_holder] -->      p.equips.forEach((e) => {<!-- [et_pb_line_break_holder] -->        const it = EQUIPS_CHALLENGE.find((x) => x.id === e.id);<!-- [et_pb_line_break_holder] -->        hand.append(H(`<!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"ca-cardTile ca-ctEquip\" data-k=\"equip\" data-id=\"${it.id}\"><!-- [et_pb_line_break_holder] -->            <\/p>\n<div class=\"ca-ctHead\"><span class=\"i\">${it.icon}<\/span>${it.name}<\/div>\n<p><!-- [et_pb_line_break_holder] -->            <\/p>\n<div class=\"ca-soft\" style=\"font-size:12px\">${it.why}<\/div>\n<p><!-- [et_pb_line_break_holder] -->            <\/p>\n<div class=\"ca-ctTag\">\u00c9QUIPEMENT<\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/div>\n<p>`));<!-- [et_pb_line_break_holder] -->      });<!-- [et_pb_line_break_holder] -->      p.actions.forEach((a, i) =><!-- [et_pb_line_break_holder] -->        hand.append(H(`<!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"ca-cardTile ca-ctAction\" data-k=\"action\" data-idx=\"${i}\"><!-- [et_pb_line_break_holder] -->            <\/p>\n<div class=\"ca-ctHead\"><span class=\"i\">${a.icon}<\/span>${a.name}<\/div>\n<p><!-- [et_pb_line_break_holder] -->            <\/p>\n<div class=\"ca-soft\" style=\"font-size:12px\">${a.desc}<\/div>\n<p><!-- [et_pb_line_break_holder] -->            <\/p>\n<div class=\"ca-ctTag\">ACTION \u00d7${a.uses}<\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/div>\n<p>`)));<!-- [et_pb_line_break_holder] -->      if (!p.equips.length && !p.actions.length) hand.innerHTML = '<\/p>\n<div class=\"ca-soft\">Aucune carte<\/div>\n<p>';<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] -->    function renderAll() { if (!G) return; sizeBoard(G.zoom); renderBoard(); renderHUD(); renderHand(); renderScoreboard(); renderLog(); }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    function openModal(title, html, { lock = false } = {}) {<!-- [et_pb_line_break_holder] -->      MODAL_LOCK = lock; q(\"#mTitle\").textContent = title; q(\"#mBody\").innerHTML = html;<!-- [et_pb_line_break_holder] -->      q(\"#modal\").style.display = \"flex\"; q(\"#modal\").classList.toggle(\"ca-locked\", !!lock);<!-- [et_pb_line_break_holder] -->      if (lock) setDiceEnabled(false);<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] -->    function closeModal() { if (MODAL_LOCK) return; q(\"#modal\").style.display = \"none\"; if (!BUSY_ROLL) syncLocks(); }<!-- [et_pb_line_break_holder] -->    mount.addEventListener(\"click\", (e) => { if (e.target?.id === \"mClose\" && !MODAL_LOCK) closeModal(); if (e.target?.id === \"modal\" && !MODAL_LOCK) closeModal(); });<!-- [et_pb_line_break_holder] -->    window.addEventListener(\"keydown\", (e) => { if (e.key === \"Escape\" && !MODAL_LOCK) closeModal(); });<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    const hazardPoolForMode = () => HAZARDS_CORE.concat(HAZARDS_MOB);<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    function handleTile(pos, landed) {<!-- [et_pb_line_break_holder] -->      const t = G.tiles[pos];<!-- [et_pb_line_break_holder] -->      if (t.type === TILE.START) { delta(landed.id, { cash: +50 }, `${landed.name} passe par START : +50 \u20ac`); endTurn(landed.id); return; }<!-- [et_pb_line_break_holder] -->      if (t.type === TILE.EQUIP) {<!-- [et_pb_line_break_holder] -->        const eq = EQUIPS_CHALLENGE.find((e) => e.id === t.equipId);<!-- [et_pb_line_break_holder] -->        openModal(`\u00c9quipement \u2014 ${eq.icon} ${eq.name}`, `<!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"ca-box\" style=\"padding:12px;margin-bottom:8px\"><!-- [et_pb_line_break_holder] -->            <\/p>\n<div><b>\u00c0 quoi \u00e7a sert ?<\/b> ${eq.why}<\/div>\n<p><!-- [et_pb_line_break_holder] -->            <\/p>\n<div class=\"ca-soft\" style=\"margin-top:6px\">Prot\u00e8ge surtout : ${eq.covers.join(\", \")}<\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"ca-box\" style=\"padding:12px\">\n<div class=\"ca-soft\" style=\"font-size:12px\">Prix<\/div>\n<div style=\"font-weight:900;font-size:22px\">${eq.price} \u20ac<\/div>\n<\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/p>\n<div style=\"display:flex;justify-content:flex-end;gap:8px;margin-top:12px\"><!-- [et_pb_line_break_holder] -->            <button class=\"ca-btnBar\" id=\"pass\">Passer<\/button><!-- [et_pb_line_break_holder] -->            <button class=\"ca-btnBar ca-btnPri\" id=\"buy\">Acheter (achat unique)<\/button><!-- [et_pb_line_break_holder] -->          <\/div>\n<p>`, { lock: true });<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->        const pl = G.players.find((x) => x.id === landed.id);<!-- [et_pb_line_break_holder] -->        q(\"#pass\").onclick = () => { MODAL_LOCK = false; closeModal(); endTurn(landed.id); };<!-- [et_pb_line_break_holder] -->        q(\"#buy\").onclick = () => {<!-- [et_pb_line_break_holder] -->          if (pl.equips.some((e) => e.id === eq.id)) return alert(\"D\u00e9j\u00e0 poss\u00e9d\u00e9.\");<!-- [et_pb_line_break_holder] -->          if (pl.cash < eq.price) return alert(\"Tr\u00e9sorerie insuffisante.\");<!-- [et_pb_line_break_holder] -->          G.players = G.players.map((p) => p.id === landed.id ? { ...p, cash: p.cash - eq.price, equips: [...p.equips, { id: eq.id }] } : p);<!-- [et_pb_line_break_holder] -->          logLine(`${pl.name} ach\u00e8te ${eq.name} (\u2212${eq.price} \u20ac)`);<!-- [et_pb_line_break_holder] -->          MODAL_LOCK = false; closeModal(); renderHand(); renderHUD(); renderScoreboard();<!-- [et_pb_line_break_holder] -->          if (NET.online) NET.db.ref(`rooms\/${NET.roomId}\/state`).set(G);<!-- [et_pb_line_break_holder] -->          endTurn(landed.id);<!-- [et_pb_line_break_holder] -->        };<!-- [et_pb_line_break_holder] -->        return;<!-- [et_pb_line_break_holder] -->      }<!-- [et_pb_line_break_holder] -->      if (t.type === TILE.ACTION) {<!-- [et_pb_line_break_holder] -->        const card = pick(ACTIONS_COMMON);<!-- [et_pb_line_break_holder] -->        openModal(`Carte ACTION`, `<!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"ca-box\" style=\"padding:12px\"><!-- [et_pb_line_break_holder] -->            <\/p>\n<div style=\"font-weight:900;margin-bottom:6px\">${card.icon} ${card.name}<\/div>\n<p><!-- [et_pb_line_break_holder] -->            <\/p>\n<div class=\"ca-soft\" style=\"margin-bottom:8px\">${card.desc}<\/div>\n<p><!-- [et_pb_line_break_holder] -->            <\/p>\n<div class=\"ca-soft\" style=\"font-size:12px\">Utilisation : sur un AL\u00c9A, clique \u201cCarte (\u221250 %)\u201d.<\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/p>\n<div style=\"display:flex;justify-content:flex-end;gap:8px;margin-top:12px\"><!-- [et_pb_line_break_holder] -->            <button class=\"ca-btnBar ca-btnPri\" id=\"addAct\">Ajouter \u00e0 ma main<\/button><!-- [et_pb_line_break_holder] -->          <\/div>\n<p>`, { lock: true });<!-- [et_pb_line_break_holder] -->        q(\"#addAct\").onclick = () => {<!-- [et_pb_line_break_holder] -->          G.players = G.players.map((pl) => pl.id === landed.id ? { ...pl, actions: [...pl.actions, { ...card }] } : pl);<!-- [et_pb_line_break_holder] -->          const p = G.players.find((x) => x.id === landed.id);<!-- [et_pb_line_break_holder] -->          logLine(`${p.name} pioche une carte ACTION : \u201c${card.name}\u201d`);<!-- [et_pb_line_break_holder] -->          MODAL_LOCK = false; closeModal(); renderHand(); renderScoreboard(); renderHUD();<!-- [et_pb_line_break_holder] -->          if (NET.online) NET.db.ref(`rooms\/${NET.roomId}\/state`).set(G);<!-- [et_pb_line_break_holder] -->          endTurn(landed.id);<!-- [et_pb_line_break_holder] -->        };<!-- [et_pb_line_break_holder] -->        return;<!-- [et_pb_line_break_holder] -->      }<!-- [et_pb_line_break_holder] -->      if (t.type === TILE.HAZARD) {<!-- [et_pb_line_break_holder] -->  const pool = hazardPoolForMode();<!-- [et_pb_line_break_holder] -->  const hz = pick(pool);              \/\/ type d'al\u00e9a (ransom, wifi, etc.)<!-- [et_pb_line_break_holder] -->  const inc = fair(hz);               \/\/ calcule proba \/ pertes \/ r\u00e9putation<!-- [et_pb_line_break_holder] -->  const pl = G.players.find(x => x.id === landed.id); \/\/ joueur courant<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  \/\/ est-ce qu'il a un \u00e9quipement qui couvre cet al\u00e9a ?<!-- [et_pb_line_break_holder] -->  const eqOK  = hasEquip(pl, hz.id);<!-- [et_pb_line_break_holder] -->  \/\/ est-ce qu'il a une carte ACTION dispo ?<!-- [et_pb_line_break_holder] -->  const mitOK = hasMit(pl);<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  \/\/ on ouvre la modale<!-- [et_pb_line_break_holder] -->  openModal(`${hz.icon} Al\u00e9a \u2014 ${hz.name}`, `<!-- [et_pb_line_break_holder] -->    <\/p>\n<div class=\"ca-box\" style=\"padding:12px;margin-bottom:10px\"><!-- [et_pb_line_break_holder] -->      <\/p>\n<div>${hz.explain}<\/div>\n<p><!-- [et_pb_line_break_holder] -->      <\/p>\n<div style=\"margin-top:8px\"><!-- [et_pb_line_break_holder] -->        <b>Estimation<\/b> :<!-- [et_pb_line_break_holder] -->        probabilit\u00e9 ~ <b>${Math.round(inc.pIncident * 100)} %<\/b> \u2022<!-- [et_pb_line_break_holder] -->        pertes : <b>${hz.lm[0].toLocaleString()}\u2013${hz.lm[1].toLocaleString()} \u20ac<\/b> \u2022<!-- [et_pb_line_break_holder] -->        notori\u00e9t\u00e9 : \u2212${hz.rep}<!-- [et_pb_line_break_holder] -->      <\/div>\n<p><!-- [et_pb_line_break_holder] -->    <\/div>\n<p><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    <\/p>\n<div class=\"ca-soft\" style=\"font-size:14px;margin-bottom:10px\"><!-- [et_pb_line_break_holder] -->      Protection :<!-- [et_pb_line_break_holder] -->      \u00c9quipement <b style=\"color:${eqOK ? \"#16a34a\" : \"#dc2626\"}\">${eqOK ? \"oui\" : \"non\"}<\/b> (\u2248 \u221275 %) \u2022<!-- [et_pb_line_break_holder] -->      Carte ACTION <b style=\"color:${mitOK ? \"#16a34a\" : \"#dc2626\"}\">${mitOK ? \"oui\" : \"non\"}<\/b> (\u2248 \u221250 %) \u2022<!-- [et_pb_line_break_holder] -->      Quiz si tu n\u2019as rien (\u2248 \u221225 % si bonne r\u00e9ponse)<!-- [et_pb_line_break_holder] -->    <\/div>\n<p><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    <\/p>\n<div id=\"hzBtns\" style=\"display:flex;flex-wrap:wrap;gap:8px;justify-content:flex-end\"><!-- [et_pb_line_break_holder] -->      ${eqOK            ? `<button class=\"ca-btnBar ca-btnPri\" id=\"bEq\">\u00c9quipement (\u221275 %)<\/button>` : \"\"}<!-- [et_pb_line_break_holder] -->      ${!eqOK && mitOK  ? `<button class=\"ca-btnBar ca-btnPri\" id=\"bMit\">Carte (\u221250 %)<\/button>`       : \"\"}<!-- [et_pb_line_break_holder] -->      ${!eqOK && !mitOK ? `<button class=\"ca-btnBar\" id=\"bQuiz\">Quiz (\u221225 %)<\/button>`                 : \"\"}<!-- [et_pb_line_break_holder] -->    <\/div>\n<p><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    <\/p>\n<div id=\"quizBox\"><\/div>\n<p><!-- [et_pb_line_break_holder] -->  `, { lock: true });<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  \/\/ -------- fonction interne = applique les pertes, ferme la modale, passe au joueur suivant<!-- [et_pb_line_break_holder] -->  function resolveHazard(finalFactor, noteText) {<!-- [et_pb_line_break_holder] -->    \/\/ finalFactor = 0.25 (\u00e9quipement), 0.5 (carte), 0.75 (quiz bonne r\u00e9ponse), 1.0 (rien \/ rat\u00e9)<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    const incidentHappened = inc.incident === true; \/\/ tirage proba<!-- [et_pb_line_break_holder] -->    let cashLoss = 0;<!-- [et_pb_line_break_holder] -->    let repLoss  = 0;<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    if (incidentHappened) {<!-- [et_pb_line_break_holder] -->      \/\/ vrai incident => grosses pertes<!-- [et_pb_line_break_holder] -->      cashLoss = Math.round(inc.lm * finalFactor);<!-- [et_pb_line_break_holder] -->      repLoss  = Math.round(hz.rep * finalFactor);<!-- [et_pb_line_break_holder] -->    } else {<!-- [et_pb_line_break_holder] -->      \/\/ pas d'incident, mais tu as quand m\u00eame d\u00fb r\u00e9pondre \u00e0 l'alerte => co\u00fbt mini<!-- [et_pb_line_break_holder] -->      cashLoss = Math.round((inc.lm || 100) * 0.05);     \/\/ ~5%<!-- [et_pb_line_break_holder] -->      repLoss  = Math.round((hz.rep || 2) * 0.2);        \/\/ ~20%<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    \/\/ applique les pertes sur le joueur courant<!-- [et_pb_line_break_holder] -->    delta(<!-- [et_pb_line_break_holder] -->      landed.id,<!-- [et_pb_line_break_holder] -->      { cash: -cashLoss, brand: -repLoss },<!-- [et_pb_line_break_holder] -->      `${pl.name} \u2014 ${hz.icon} ${hz.name} : ${<!-- [et_pb_line_break_holder] -->        incidentHappened<!-- [et_pb_line_break_holder] -->          ? `incident (\u2212${cashLoss} \u20ac ; notori\u00e9t\u00e9 \u2212${repLoss})`<!-- [et_pb_line_break_holder] -->          : `alerte g\u00e9r\u00e9e (\u2212${cashLoss} \u20ac ; notori\u00e9t\u00e9 \u2212${repLoss})`<!-- [et_pb_line_break_holder] -->      } ${noteText || \"\"}`<!-- [et_pb_line_break_holder] -->    );<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    \/\/ maintenant on ferme proprement la modale, on finit le tour,<!-- [et_pb_line_break_holder] -->    \/\/ ET on rouvre le d\u00e9 pour le joueur suivant<!-- [et_pb_line_break_holder] -->    MODAL_LOCK = false;           \/\/ on d\u00e9bloque l'UI<!-- [et_pb_line_break_holder] -->    BUSY_ROLL  = false;           \/\/ plus en cours d'action<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    closeModal(true);             \/\/ ferme la popup m\u00eame si lock<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    \/\/ fin de tour APR\u00c8S un al\u00e9a : pas de revenu automatique<!-- [et_pb_line_break_holder] -->    endTurn(landed.id, { skipIncome: true });<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    \/\/ IMPORTANT : comme endTurn peut changer G.idx,<!-- [et_pb_line_break_holder] -->    \/\/ on resynchronise le d\u00e9 pour le NOUVEAU joueur<!-- [et_pb_line_break_holder] -->    syncLocks();<!-- [et_pb_line_break_holder] -->  }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  \/\/ -------- boutons de choix dans la modale<!-- [et_pb_line_break_holder] -->  const bEq  = q(\"#bEq\");<!-- [et_pb_line_break_holder] -->  const bMit = q(\"#bMit\");<!-- [et_pb_line_break_holder] -->  const bQuiz= q(\"#bQuiz\");<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  if (bEq) {<!-- [et_pb_line_break_holder] -->    bEq.onclick = () => {<!-- [et_pb_line_break_holder] -->      \/\/ \u00e9quipement => grosse r\u00e9duction (\u2248 75%)<!-- [et_pb_line_break_holder] -->      resolveHazard(0.25, \"(\u00c9quipement activ\u00e9)\");<!-- [et_pb_line_break_holder] -->    };<!-- [et_pb_line_break_holder] -->  }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  if (bMit) {<!-- [et_pb_line_break_holder] -->    bMit.onclick = () => {<!-- [et_pb_line_break_holder] -->      \/\/ consomme la carte ACTION avant de calculer<!-- [et_pb_line_break_holder] -->      useMit(landed.id);<!-- [et_pb_line_break_holder] -->      resolveHazard(0.5, \"(Carte ACTION utilis\u00e9e)\");<!-- [et_pb_line_break_holder] -->    };<!-- [et_pb_line_break_holder] -->  }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  if (bQuiz) {<!-- [et_pb_line_break_holder] -->    bQuiz.onclick = () => {<!-- [et_pb_line_break_holder] -->      \/\/ on affiche une mini-question<!-- [et_pb_line_break_holder] -->      const Q = pick(QUIZ);<!-- [et_pb_line_break_holder] -->      q(\"#quizBox\").innerHTML = `<!-- [et_pb_line_break_holder] -->        <\/p>\n<div class=\"ca-box\" style=\"padding:12px\"><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"ca-h\" style=\"margin-bottom:8px\">${Q.q}<\/div>\n<p><!-- [et_pb_line_break_holder] -->          <\/p>\n<div style=\"display:flex;flex-wrap:wrap;gap:8px\"><!-- [et_pb_line_break_holder] -->            ${Q.choices.map((c, i) =><!-- [et_pb_line_break_holder] -->              `<button class=\"ca-btnBar\" data-qidx=\"${i}\">${c}<\/button>`<!-- [et_pb_line_break_holder] -->            ).join(\"\")}<!-- [et_pb_line_break_holder] -->          <\/div>\n<p><!-- [et_pb_line_break_holder] -->        <\/div>\n<p><!-- [et_pb_line_break_holder] -->      `;<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->      \/\/ quand le joueur clique une r\u00e9ponse<!-- [et_pb_line_break_holder] -->      q(\"#quizBox\").addEventListener(\"click\", (ev) => {<!-- [et_pb_line_break_holder] -->        const btn = ev.target.closest(\"button[data-qidx]\");<!-- [et_pb_line_break_holder] -->        if (!btn) return;<!-- [et_pb_line_break_holder] -->        const good = (+btn.dataset.qidx === Q.correct);<!-- [et_pb_line_break_holder] -->        \/\/ bonne r\u00e9ponse => facteur 0.75 (~ -25%), mauvaise => 1.0 (= plein tarif)<!-- [et_pb_line_break_holder] -->        resolveHazard(good ? 0.75 : 1.0, good ? \"(Bonne r\u00e9ponse au quiz)\" : \"(Mauvaise r\u00e9ponse)\");<!-- [et_pb_line_break_holder] -->      }, { once:true });<!-- [et_pb_line_break_holder] -->    };<!-- [et_pb_line_break_holder] -->  }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  return;<!-- [et_pb_line_break_holder] -->}<!-- [et_pb_line_break_holder] -->}<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->function syncLocks(){<!-- [et_pb_line_break_holder] -->  if (!G){ setDiceEnabled(false); return; }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  \/\/ id du joueur courant selon l'\u00e9tat<!-- [et_pb_line_break_holder] -->  const currentId = G.order[G.idx];<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  \/\/ mon id local (en ligne = NET.me, en local = id du joueur courant affich\u00e9 par mon instance)<!-- [et_pb_line_break_holder] -->  const myId = NET.online ? NET.me : (cur()?.id);<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  const myTurn = (currentId === myId);<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  const allow = myTurn && !MODAL_LOCK && !BUSY_ROLL;<!-- [et_pb_line_break_holder] -->  setDiceEnabled(!!allow);<!-- [et_pb_line_break_holder] -->}<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    \/* anti-double lancement *\/<!-- [et_pb_line_break_holder] -->    window.__CA_STARTING = false;<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->async function startGame(){<!-- [et_pb_line_break_holder] -->  \/\/ anti double-d\u00e9clenchement<!-- [et_pb_line_break_holder] -->  if (window.__CA_FLOW_BUSY) return;<!-- [et_pb_line_break_holder] -->  window.__CA_FLOW_BUSY = true;<!-- [et_pb_line_break_holder] -->  setTimeout(()=>{ window.__CA_FLOW_BUSY = false; }, 1200);<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  \/\/ si on est d\u00e9j\u00e0 en partie et qu'on est sur le plateau, on ne red\u00e9marre pas<!-- [et_pb_line_break_holder] -->  if (typeof G === \"object\" && G && q(\"#ca-board\")?.style.display === \"block\") return;<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  \/\/ m\u00e9mo pour pr\u00e9-remplir les prompts<!-- [et_pb_line_break_holder] -->  window.__CA_SESSION = window.__CA_SESSION || { myName:\"\", roomId:\"\" };<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  try{<!-- [et_pb_line_break_holder] -->    const online = q(\"#modeOnline\")?.checked;<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    const genCode = (n=4)=>{<!-- [et_pb_line_break_holder] -->      const A=\"ABCDEFGHJKMNPQRSTUVWXYZ23456789\";<!-- [et_pb_line_break_holder] -->      let s=\"\"; for(let i=0;i<n;i++) s += A[Math.floor(Math.random()*A.length)];<!-- [et_pb_line_break_holder] -->      return s;<!-- [et_pb_line_break_holder] -->    };<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    \/\/ r\u00e9cup\u00e8re la couleur choisie dans la ligne i (sinon fallback)<!-- [et_pb_line_break_holder] -->    const getSelectedColor = (rowIndex, fallback) => {<!-- [et_pb_line_break_holder] -->      const row = document.querySelector(`.ca-swatchRow[data-for=\"${rowIndex}\"]`);<!-- [et_pb_line_break_holder] -->      const sel = row?.querySelector(\".ca-swatch.selected\");<!-- [et_pb_line_break_holder] -->      return sel ? sel.dataset.color : fallback;<!-- [et_pb_line_break_holder] -->    };<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    \/\/ ------- MODE EN LIGNE (Firebase) -------<!-- [et_pb_line_break_holder] -->    if (online){<!-- [et_pb_line_break_holder] -->      \/\/ 0) init firebase + ping<!-- [et_pb_line_break_holder] -->      if (!NET.app && !NET.init()){<!-- [et_pb_line_break_holder] -->        alert(\"\u274c Firebase introuvable. V\u00e9rifie les <script> firebase-* ou repasse en local.\");<!-- [et_pb_line_break_holder] -->        return;<!-- [et_pb_line_break_holder] -->      }<!-- [et_pb_line_break_holder] -->      const okDB = await NET.ping();<!-- [et_pb_line_break_holder] -->      if (!okDB) return;<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->      \/\/ 1) saisies<!-- [et_pb_line_break_holder] -->      const rawCode = (prompt(\"Entrer un code pour REJOINDRE (laisser vide pour CR\u00c9ER) :\", window.__CA_SESSION.roomId || \"\") || \"\").trim().toUpperCase();<!-- [et_pb_line_break_holder] -->      const myName  = (prompt(\"Ton nom ?\", window.__CA_SESSION.myName || \"Joueur\") || \"Joueur\").trim() || \"Joueur\";<!-- [et_pb_line_break_holder] -->      window.__CA_SESSION.myName = myName;<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->      \/\/ couleur choisie par J1 (ou noir)<!-- [et_pb_line_break_holder] -->      const myColor = getSelectedColor(0, \"#111827\");<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->      \/\/ 2) REJOINDRE (invit\u00e9) OU CR\u00c9ER (h\u00f4te)<!-- [et_pb_line_break_holder] -->      if (rawCode){<!-- [et_pb_line_break_holder] -->        \/\/ ==== Invit\u00e9 ====<!-- [et_pb_line_break_holder] -->        await NET.joinRoom(rawCode);<!-- [et_pb_line_break_holder] -->        await NET.addMe(myName, myColor);<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->        \/\/ salle d\u2019attente c\u00f4t\u00e9 invit\u00e9<!-- [et_pb_line_break_holder] -->        openLobby(\"Salle d\u2019attente\", NET.roomId, [], null);<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->        \/\/ \u00e9coute l\u2019\u00e9tat publi\u00e9 par l\u2019h\u00f4te ; quand il arrive on quitte la salle d\u2019attente<!-- [et_pb_line_break_holder] -->        NET.onState((state)=>{<!-- [et_pb_line_break_holder] -->          if (!state) return;               \/\/ pas encore d\u00e9marr\u00e9<!-- [et_pb_line_break_holder] -->          \/\/ normalisation d\u00e9fensive<!-- [et_pb_line_break_holder] -->          const norm = (p)=>({<!-- [et_pb_line_break_holder] -->            id: p.id, name: p.name, color: p.color,<!-- [et_pb_line_break_holder] -->            cash: +p.cash||0, brand: +p.brand||0,<!-- [et_pb_line_break_holder] -->            cash0:+p.cash0||0, brand0:+p.brand0||0,<!-- [et_pb_line_break_holder] -->            equips: Array.isArray(p.equips)?p.equips:[],<!-- [et_pb_line_break_holder] -->            actions: Array.isArray(p.actions)?p.actions:[],<!-- [et_pb_line_break_holder] -->            pos:+p.pos||0, turns:+p.turns||0, lastDelta:p.lastDelta||{cash:0,brand:0}<!-- [et_pb_line_break_holder] -->          });<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->          G = { ...state, players: (state.players||[]).map(norm) };<!-- [et_pb_line_break_holder] -->          MODAL_LOCK = false;<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->          closeModal(true);            \/\/ ferme la salle d\u2019attente h\u00f4te<!-- [et_pb_line_break_holder] -->          show(\"board\");           \/\/ affiche le plateau local de l\u2019h\u00f4te<!-- [et_pb_line_break_holder] -->               \/\/ \u2b05\ufe0f ferme la salle d\u2019attente<!-- [et_pb_line_break_holder] -->          NET.online = true;<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->          q(\"#boardTitle\").textContent = \"Arcade cyber \u2014 Challenge Global\";<!-- [et_pb_line_break_holder] -->          q(\"#boardSub\").textContent   = `Salle ${NET.roomId} \u2022 ${G.players.length} joueurs \u2022 ${G.roundsTarget} tours`;<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->          show(\"board\"); sizeBoard(G.zoom); renderAll();<!-- [et_pb_line_break_holder] -->          BUSY_ROLL = false; syncLocks();  \/\/ \u2b05\ufe0f active le d\u00e9 seulement si c\u2019est mon tour<!-- [et_pb_line_break_holder] -->        });<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->        return; \/\/ l\u2019invit\u00e9 n\u2019initie rien, il attend l\u2019\u00e9tat<!-- [et_pb_line_break_holder] -->      } else {<!-- [et_pb_line_break_holder] -->        \/\/ ==== H\u00f4te ====<!-- [et_pb_line_break_holder] -->        const roomCode = await NET.createRoom();<!-- [et_pb_line_break_holder] -->        window.__CA_SESSION.roomId = roomCode;<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->        await NET.addMe(myName, myColor);<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->        \/\/ observe la liste des joueurs<!-- [et_pb_line_break_holder] -->        const pRef = NET.db.ref(`rooms\/${roomCode}\/players`);<!-- [et_pb_line_break_holder] -->        let playersList = Object.values((await pRef.get()).val() || {});<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->        const repaintLobby = () => openLobby(<!-- [et_pb_line_break_holder] -->          \"Salle d\u2019attente (H\u00f4te)\",<!-- [et_pb_line_break_holder] -->          roomCode,<!-- [et_pb_line_break_holder] -->          playersList,<!-- [et_pb_line_break_holder] -->          async ()=>{ \/\/ callback \"D\u00e9marrer la partie\"<!-- [et_pb_line_break_holder] -->            \/\/const rounds = parseInt(q(\"#rounds\").value,10) || 6;<!-- [et_pb_line_break_holder] -->            const rounds = 365;<!-- [et_pb_line_break_holder] -->            const cash   = parseInt(q(\"#cash\").value,10)   || 500;<!-- [et_pb_line_break_holder] -->            const brand  = parseInt(q(\"#brand\").value,10)  || 100;<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->            const norm = (p)=>({<!-- [et_pb_line_break_holder] -->              id:p.id, name:p.name, color:p.color,<!-- [et_pb_line_break_holder] -->              cash, brand, cash0:cash, brand0:brand,<!-- [et_pb_line_break_holder] -->              equips:[], actions:[], pos:0, turns:0, lastDelta:{cash:0,brand:0}<!-- [et_pb_line_break_holder] -->            });<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->            const players = playersList.map(norm);<!-- [et_pb_line_break_holder] -->            const tiles   = buildTiles();<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->            G = {<!-- [et_pb_line_break_holder] -->              mode:\"challenge\",<!-- [et_pb_line_break_holder] -->              roundsTarget: rounds,<!-- [et_pb_line_break_holder] -->              tiles,<!-- [et_pb_line_break_holder] -->              players,<!-- [et_pb_line_break_holder] -->              order: players.map(p=>p.id),<!-- [et_pb_line_break_holder] -->              idx:0, log:[], lastRoll:1, zoom:1<!-- [et_pb_line_break_holder] -->            };<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->            \/\/ publie l\u2019\u00e9tat initial pour tous<!-- [et_pb_line_break_holder] -->            await NET.setState(G);   \/\/ \u2b05\ufe0f indispensable<!-- [et_pb_line_break_holder] -->            closeModal(true);            \/\/ ferme la salle d\u2019attente h\u00f4te<!-- [et_pb_line_break_holder] -->            show(\"board\");           \/\/ affiche le plateau local de l\u2019h\u00f4te<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->            NET.online = true;<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->            q(\"#boardTitle\").textContent = \"Arcade cyber \u2014 Challenge Global\";<!-- [et_pb_line_break_holder] -->            q(\"#boardSub\").textContent   = `Salle ${roomCode} \u2022 ${players.length} joueurs \u2022 ${rounds} tours`;<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->            show(\"board\"); sizeBoard(G.zoom); renderAll();<!-- [et_pb_line_break_holder] -->            BUSY_ROLL=false; syncLocks();<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->            \/\/ M\u00eame l\u2019h\u00f4te observe les MAJ (roule quand c\u2019est \u00e0 lui)<!-- [et_pb_line_break_holder] -->            NET.onState((state)=>{<!-- [et_pb_line_break_holder] -->              if (!state) return;<!-- [et_pb_line_break_holder] -->              const normP = (p)=>({<!-- [et_pb_line_break_holder] -->                id:p.id, name:p.name, color:p.color,<!-- [et_pb_line_break_holder] -->                cash:+p.cash||0, brand:+p.brand||0,<!-- [et_pb_line_break_holder] -->                cash0:+p.cash0||0, brand0:+p.brand0||0,<!-- [et_pb_line_break_holder] -->                equips:Array.isArray(p.equips)?p.equips:[],<!-- [et_pb_line_break_holder] -->                actions:Array.isArray(p.actions)?p.actions:[],<!-- [et_pb_line_break_holder] -->                pos:+p.pos||0, turns:+p.turns||0, lastDelta:p.lastDelta||{cash:0,brand:0}<!-- [et_pb_line_break_holder] -->              });<!-- [et_pb_line_break_holder] -->              G = { ...state, players:(state.players||[]).map(normP) };<!-- [et_pb_line_break_holder] -->              renderAll(); BUSY_ROLL=false; syncLocks();<!-- [et_pb_line_break_holder] -->            });<!-- [et_pb_line_break_holder] -->          }<!-- [et_pb_line_break_holder] -->        );<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->        repaintLobby();<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->        \/\/ mises \u00e0 jour temps r\u00e9el de la liste des joueurs dans la salle d\u2019attente<!-- [et_pb_line_break_holder] -->        pRef.on('value', (s)=>{<!-- [et_pb_line_break_holder] -->          playersList = Object.values(s.val() || {});<!-- [et_pb_line_break_holder] -->          repaintLobby();<!-- [et_pb_line_break_holder] -->        });<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->        return; \/\/ plateau affich\u00e9 d\u00e8s clic \"D\u00e9marrer la partie\"<!-- [et_pb_line_break_holder] -->      }<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    \/\/ ------- MODE LOCAL -------<!-- [et_pb_line_break_holder] -->    const n      = parseInt(q(\"#nb\").value, 10) || 2;<!-- [et_pb_line_break_holder] -->    \/\/const rounds = parseInt(q(\"#rounds\").value, 10) || 6;<!-- [et_pb_line_break_holder] -->    const rounds = 365;<!-- [et_pb_line_break_holder] -->    const cash   = parseInt(q(\"#cash\").value, 10)   || 500;<!-- [et_pb_line_break_holder] -->    const brand  = parseInt(q(\"#brand\").value, 10)  || 100;<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    const palette = [\"#111827\",\"#ef4444\",\"#3b82f6\",\"#10b981\",\"#a855f7\",\"#f59e0b\",\"#06b6d4\",\"#f43f5e\",\"#84cc16\",\"#8b5cf6\"];<!-- [et_pb_line_break_holder] -->    const used = new Set();<!-- [et_pb_line_break_holder] -->    const players = [];<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    for (let i=0;i<n;i++){<!-- [et_pb_line_break_holder] -->      const name = (q(\"#pname_\"+i)?.value || \"Joueur \"+(i+1));<!-- [et_pb_line_break_holder] -->      let color  = getSelectedColor(i, palette[i % palette.length]);<!-- [et_pb_line_break_holder] -->      while (used.has(color)) color = palette.find(p=>!used.has(p)) || color;<!-- [et_pb_line_break_holder] -->      used.add(color);<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->      players.push({<!-- [et_pb_line_break_holder] -->        id: Math.random().toString(36).slice(2,9),<!-- [et_pb_line_break_holder] -->        name, color, cash, brand, cash0:cash, brand0:brand,<!-- [et_pb_line_break_holder] -->        equips:[], actions:[], pos:0, turns:0, lastDelta:{cash:0,brand:0}<!-- [et_pb_line_break_holder] -->      });<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    G = {<!-- [et_pb_line_break_holder] -->      mode:\"challenge\",<!-- [et_pb_line_break_holder] -->      roundsTarget: rounds,<!-- [et_pb_line_break_holder] -->      tiles: buildTiles(),<!-- [et_pb_line_break_holder] -->      players,<!-- [et_pb_line_break_holder] -->      order: players.map(p=>p.id),<!-- [et_pb_line_break_holder] -->      idx:0, log:[], lastRoll:1, zoom:1<!-- [et_pb_line_break_holder] -->    };<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    q(\"#boardTitle\").textContent = \"Arcade cyber \u2014 Challenge Global (local)\";<!-- [et_pb_line_break_holder] -->    q(\"#boardSub\").textContent   = `40 cases \u2022 ${players.length} joueurs \u2022 ${rounds} tours`;<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    show(\"board\"); sizeBoard(G.zoom); renderAll();<!-- [et_pb_line_break_holder] -->    BUSY_ROLL=false; syncLocks();<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  } catch(e){<!-- [et_pb_line_break_holder] -->    console.error(e);<!-- [et_pb_line_break_holder] -->    alert(\"Erreur: \" + (e?.message||e));<!-- [et_pb_line_break_holder] -->  }<!-- [et_pb_line_break_holder] -->}<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->\/* ======================== Binding du bouton ======================== *\/<!-- [et_pb_line_break_holder] -->document.addEventListener(\"click\",(ev)=>{<!-- [et_pb_line_break_holder] -->  if (ev.target?.id === \"goChallenge\") startGame();<!-- [et_pb_line_break_holder] -->});<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->\/* ======================== Alerte globale erreurs promises ======================== *\/<!-- [et_pb_line_break_holder] -->window.addEventListener('unhandledrejection', (e)=>{<!-- [et_pb_line_break_holder] -->  console.error(\"Unhandled promise rejection:\", e.reason);<!-- [et_pb_line_break_holder] -->  alert(\"\u274c Erreur asynchrone: \"+(e?.reason?.message || e?.reason || e));<!-- [et_pb_line_break_holder] -->});<!-- [et_pb_line_break_holder] -->    <!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    \/* ======================== EVENEMENTS ======================== *\/<!-- [et_pb_line_break_holder] -->    function syncUIBindings(){<!-- [et_pb_line_break_holder] -->      mount.addEventListener(\"click\", (e) => {<!-- [et_pb_line_break_holder] -->        const id = e.target?.id;<!-- [et_pb_line_break_holder] -->        if (id === \"sbToggle\") { const body = q(\"#scoreboardBody\"); if (body) { body.dataset.collapse = body.dataset.collapse === \"1\" ? \"0\" : \"1\"; renderScoreboard(); } return; }<!-- [et_pb_line_break_holder] -->        if (id === \"rulesChallenge\") { openModal(\"R\u00e8gles \u2014 Challenge Global (J1+J2)\", rulesHTML()); return; }<!-- [et_pb_line_break_holder] -->        if (id === \"goChallenge\") { startGame(); return; }<!-- [et_pb_line_break_holder] -->        if (id === \"rulesHere\") { openModal(\"R\u00e8gles du jeu\", rulesHTML()); return; }<!-- [et_pb_line_break_holder] -->        if (id === \"backHome\" || id === \"reset\") { resetToHome(); return; }<!-- [et_pb_line_break_holder] -->        if (id === \"zoom+\") { if (G) { G.zoom = Math.min(1.5, (G.zoom || 1) + 0.05); sizeBoard(G.zoom); } return; }<!-- [et_pb_line_break_holder] -->        if (id === \"zoom-\") { if (G) { G.zoom = Math.max(0.7, (G.zoom || 1) - 0.05); sizeBoard(G.zoom); } return; }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->        const diceBtn = e.target.closest(\"#dice\");<!-- [et_pb_line_break_holder] -->        if (diceBtn) { if (diceBtn.disabled || diceBtn.getAttribute(\"aria-disabled\") === \"true\") return; onRoll(); return; }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->        const card = e.target.closest(\".ca-cardTile\");<!-- [et_pb_line_break_holder] -->        if (card && G) {<!-- [et_pb_line_break_holder] -->          const kind = card.dataset.k;<!-- [et_pb_line_break_holder] -->          if (kind === \"equip\") {<!-- [et_pb_line_break_holder] -->            const it = EQUIPS_CHALLENGE.find((x) => x.id === card.dataset.id);<!-- [et_pb_line_break_holder] -->            if (it) openModal(`${it.icon} ${it.name}`, `<\/p>\n<div style=\"display:grid;gap:8px\">\n<div>${it.why}<\/div>\n<div class=\"ca-soft\">Prot\u00e8ge surtout : ${it.covers.join(\", \")}<\/div>\n<\/div>\n<p>`);<!-- [et_pb_line_break_holder] -->          } else if (kind === \"action\") {<!-- [et_pb_line_break_holder] -->            const p = cur(); if (!p) return;<!-- [et_pb_line_break_holder] -->            const a = p.actions[+card.dataset.idx];<!-- [et_pb_line_break_holder] -->            if (a) openModal(`${a.icon} ${a.name}`, `<\/p>\n<div style=\"display:grid;gap:8px\">\n<div>${a.desc}<\/div>\n<div class=\"ca-soft\">\u00c0 jouer lors d\u2019un AL\u00c9A, bouton \u201cCarte (\u221250 %)\u201d.<\/div>\n<\/div>\n<p>`);<!-- [et_pb_line_break_holder] -->          }<!-- [et_pb_line_break_holder] -->        }<!-- [et_pb_line_break_holder] -->      });<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->      mount.addEventListener(\"change\", (e) => { if (e.target?.id === \"nb\") renderPlayersForm(); });<!-- [et_pb_line_break_holder] -->      mount.addEventListener(\"click\", (e) => {<!-- [et_pb_line_break_holder] -->        if(e.target?.id===\"modeLocal\"){ q(\"#localCfg\").style.display=\"block\"; }<!-- [et_pb_line_break_holder] -->        if(e.target?.id===\"modeOnline\"){ q(\"#localCfg\").style.display=\"block\"; }<!-- [et_pb_line_break_holder] -->        const sw = e.target.closest(\".ca-swatch\");<!-- [et_pb_line_break_holder] -->  if (sw) {<!-- [et_pb_line_break_holder] -->    const row = sw.parentElement; \/\/ .ca-swatchRow<!-- [et_pb_line_break_holder] -->    \/\/ toggle s\u00e9lection<!-- [et_pb_line_break_holder] -->    row.querySelectorAll(\".ca-swatch\").forEach((b) => b.classList.remove(\"selected\"));<!-- [et_pb_line_break_holder] -->    sw.classList.add(\"selected\");<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    \/\/ MAJ visuelle du point de la carte joueur<!-- [et_pb_line_break_holder] -->    const card = row.closest(\".ca-card\");<!-- [et_pb_line_break_holder] -->    refreshRowDot(card);<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    \/\/ verrouille les couleurs d\u00e9j\u00e0 prises (comportement existant)<!-- [et_pb_line_break_holder] -->    updateSwatchLocks();<!-- [et_pb_line_break_holder] -->  }<!-- [et_pb_line_break_holder] -->      });<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    function renderPlayersForm() {<!-- [et_pb_line_break_holder] -->  const box = q(\"#playersBox\"); if (!box) return;<!-- [et_pb_line_break_holder] -->  box.innerHTML = \"\";<!-- [et_pb_line_break_holder] -->  const n = parseInt(q(\"#nb\").value, 10);<!-- [et_pb_line_break_holder] -->  for (let i = 0; i < n; i++) {<!-- [et_pb_line_break_holder] -->    const sw = PALETTE.map((c, k) =><!-- [et_pb_line_break_holder] -->      `<button type=\"button\" class=\"ca-swatch ${i === k ? \"selected\" : \"\"}\" data-color=\"${c}\" style=\"background:${c}\"><\/button>`<!-- [et_pb_line_break_holder] -->    ).join(\"\");<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    box.append(H(`<!-- [et_pb_line_break_holder] -->      <\/p>\n<div class=\"ca-card\"><!-- [et_pb_line_break_holder] -->        <\/p>\n<div style=\"display:flex;align-items:center;justify-content:space-between\"><!-- [et_pb_line_break_holder] -->          <\/p>\n<div><span class=\"ca-dot\"><\/span><b>Joueur ${i + 1}<\/b><\/div>\n<p><!-- [et_pb_line_break_holder] -->          <input class=\"ca-in\" id=\"pname_${i}\" value=\"Joueur ${i + 1}\" style=\"width:60%\"><!-- [et_pb_line_break_holder] -->        <\/div>\n<p><!-- [et_pb_line_break_holder] -->        <\/p>\n<div class=\"ca-row\" style=\"margin-top:8px\"><!-- [et_pb_line_break_holder] -->          <label>Couleur :<\/label><!-- [et_pb_line_break_holder] -->          <\/p>\n<div class=\"ca-swatchRow\" data-for=\"${i}\">${sw}<\/div>\n<p><!-- [et_pb_line_break_holder] -->        <\/div>\n<p><!-- [et_pb_line_break_holder] -->      <\/div>\n<p><!-- [et_pb_line_break_holder] -->    `));<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    \/\/ met le point \u00e0 la bonne couleur d\u00e8s le rendu<!-- [et_pb_line_break_holder] -->    const card = box.lastElementChild;<!-- [et_pb_line_break_holder] -->    refreshRowDot(card);<!-- [et_pb_line_break_holder] -->  }<!-- [et_pb_line_break_holder] -->  updateSwatchLocks();<!-- [et_pb_line_break_holder] -->}<!-- [et_pb_line_break_holder] -->    function updateSwatchLocks(){<!-- [et_pb_line_break_holder] -->      const rows = [...mount.querySelectorAll(\".ca-swatchRow[data-for]\")];<!-- [et_pb_line_break_holder] -->      const chosen = rows.map(r => r.querySelector(\".ca-swatch.selected\")?.dataset.color).filter(Boolean);<!-- [et_pb_line_break_holder] -->      rows.forEach(row=>{<!-- [et_pb_line_break_holder] -->        const mySel = row.querySelector(\".ca-swatch.selected\")?.dataset.color;<!-- [et_pb_line_break_holder] -->        row.querySelectorAll(\".ca-swatch\").forEach(btn=>{<!-- [et_pb_line_break_holder] -->          const c=btn.dataset.color;<!-- [et_pb_line_break_holder] -->          const taken = chosen.includes(c) && c!==mySel;<!-- [et_pb_line_break_holder] -->          btn.disabled = taken; btn.style.opacity = taken ? .35 : 1;<!-- [et_pb_line_break_holder] -->        });<!-- [et_pb_line_break_holder] -->      });<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] -->    function pickRowColor(i){<!-- [et_pb_line_break_holder] -->      const row = mount.querySelector(`.ca-swatchRow[data-for=\"${i}\"]`);<!-- [et_pb_line_break_holder] -->      const chosen = [...mount.querySelectorAll(\".ca-swatchRow[data-for]\")].map(r=>r.querySelector(\".ca-swatch.selected\")?.dataset.color).filter(Boolean);<!-- [et_pb_line_break_holder] -->      let c = row && row.querySelector(\".ca-swatch.selected\")?.dataset.color;<!-- [et_pb_line_break_holder] -->      if (!c || chosen.filter(x=>x===c).length>1) c = PALETTE.find(p=>!chosen.includes(p)) || PALETTE[i % PALETTE.length];<!-- [et_pb_line_break_holder] -->      return c;<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] -->    renderPlayersForm(); syncUIBindings();<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    function resetToHome() {<!-- [et_pb_line_break_holder] -->      G = null; show(\"home\"); setDiceEnabled(false); MODAL_LOCK = false; closeModal(); renderPlayersForm();<!-- [et_pb_line_break_holder] -->      NET.online = false;<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    async function onRoll() {<!-- [et_pb_line_break_holder] -->      if (G?.gameOver) return;<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->      if (!G || MODAL_LOCK || BUSY_ROLL) return;<!-- [et_pb_line_break_holder] -->      BUSY_ROLL = true; syncLocks();<!-- [et_pb_line_break_holder] -->      const r = await rollDiceAnimated();<!-- [et_pb_line_break_holder] -->      G.lastRoll = r;<!-- [et_pb_line_break_holder] -->      const pId = G.order[G.idx], p = G.players.find((x) => x.id === pId);<!-- [et_pb_line_break_holder] -->      const newPos = (p.pos + r) % G.tiles.length;<!-- [et_pb_line_break_holder] -->      G.players = G.players.map((pl) => (pl.id === pId ? { ...pl, pos: newPos } : pl));<!-- [et_pb_line_break_holder] -->      renderHUD(); renderBoard(); renderScoreboard();<!-- [et_pb_line_break_holder] -->      if (NET.online) NET.db.ref(`rooms\/${NET.roomId}\/state`).set(G);<!-- [et_pb_line_break_holder] -->      handleTile(newPos, p);<!-- [et_pb_line_break_holder] -->    }<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->    \/* ======================== INIT ======================== *\/<!-- [et_pb_line_break_holder] -->    show(\"home\"); setDiceEnabled(false);<!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->  } catch (err) {<!-- [et_pb_line_break_holder] -->    const pre = document.createElement(\"pre\");<!-- [et_pb_line_break_holder] -->    pre.style.cssText = \"background:#fff;border:1px solid #e5e7eb;border-radius:12px;padding:16px;max-width:900px;margin:24px auto;white-space:pre-wrap\";<!-- [et_pb_line_break_holder] -->    pre.textContent = \"\u26a0\ufe0f Erreur :\\n\" + (err?.message || err);<!-- [et_pb_line_break_holder] -->    document.getElementById(\"cyber-arcade\").append(pre);<!-- [et_pb_line_break_holder] -->  }<!-- [et_pb_line_break_holder] -->})();<!-- [et_pb_line_break_holder] --><\/script><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] --><!-- [et_pb_line_break_holder] -->[\/et_pb_code][et_pb_divider _builder_version=\"4.27.4\" _module_preset=\"default\" global_colors_info=\"{}\"][\/et_pb_divider][\/et_pb_column][\/et_pb_row][\/et_pb_section]<\/p>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_et_pb_use_builder":"on","_et_pb_old_content":"","_et_gb_content_width":"","footnotes":""},"class_list":["post-769","page","type-page","status-publish","hentry"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/staging.digitalisetapme.fr\/index.php\/wp-json\/wp\/v2\/pages\/769","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/staging.digitalisetapme.fr\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/staging.digitalisetapme.fr\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/staging.digitalisetapme.fr\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/staging.digitalisetapme.fr\/index.php\/wp-json\/wp\/v2\/comments?post=769"}],"version-history":[{"count":26,"href":"https:\/\/staging.digitalisetapme.fr\/index.php\/wp-json\/wp\/v2\/pages\/769\/revisions"}],"predecessor-version":[{"id":820,"href":"https:\/\/staging.digitalisetapme.fr\/index.php\/wp-json\/wp\/v2\/pages\/769\/revisions\/820"}],"wp:attachment":[{"href":"https:\/\/staging.digitalisetapme.fr\/index.php\/wp-json\/wp\/v2\/media?parent=769"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}