{"id":2,"date":"2026-08-28T11:57:36","date_gmt":"2026-08-28T08:57:36","guid":{"rendered":"https:\/\/www.object.ks.ua\/?page_id=2"},"modified":"2026-08-28T12:22:11","modified_gmt":"2026-08-28T09:22:11","slug":"sample-page","status":"publish","type":"page","link":"https:\/\/www.object.ks.ua\/?page_id=2","title":{"rendered":""},"content":{"rendered":"<!DOCTYPE html>\n<html lang=\"ru\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>\u0411\u0423\u041d\u041a\u0415\u0420 :: \u043a\u043e\u043d\u0441\u043e\u043b\u044c<\/title>\n<style>\n  :root{\n    --fg:#3ee63e;\n    --fg-dim:#1f8f1f;\n    --bg:#0a0f0a;\n    --panel:#0f1a0f;\n    --accent:#ffcc33;\n    --danger:#ff5555;\n    --border:#1f4d1f;\n  }\n  *{box-sizing:border-box;}\n  body{\n    background:var(--bg);\n    color:var(--fg);\n    font-family:'Courier New', Consolas, monospace;\n    margin:0;\n    padding:16px;\n    line-height:1.5;\n    font-size:15px;\n  }\n  h1,h2,h3{ color:var(--accent); margin:0 0 12px 0; font-weight:normal; letter-spacing:1px;}\n  .dim{ color:var(--fg-dim); }\n  .accent{ color:var(--accent); }\n  .danger{ color:var(--danger); }\n  .box{\n    border:1px solid var(--border);\n    background:var(--panel);\n    padding:16px;\n    margin-bottom:16px;\n    border-radius:4px;\n  }\n  button{\n    font-family:inherit;\n    background:transparent;\n    border:1px solid var(--fg);\n    color:var(--fg);\n    padding:8px 14px;\n    cursor:pointer;\n    font-size:14px;\n    border-radius:3px;\n  }\n  button:hover{ background:var(--fg); color:var(--bg); }\n  button.accent-btn{ border-color:var(--accent); color:var(--accent); }\n  button.accent-btn:hover{ background:var(--accent); color:var(--bg); }\n  button.danger-btn{ border-color:var(--danger); color:var(--danger); }\n  button.danger-btn:hover{ background:var(--danger); color:var(--bg); }\n  button.small{ padding:3px 8px; font-size:12px; }\n  input, select{\n    font-family:inherit;\n    background:#000;\n    border:1px solid var(--border);\n    color:var(--fg);\n    padding:6px 8px;\n    font-size:14px;\n    border-radius:3px;\n  }\n  input.pw-input{ width:90px; text-transform:uppercase; }\n  input.shake{ animation:shake 0.3s; border-color:var(--danger); }\n  @keyframes shake{\n    0%,100%{ transform:translateX(0); }\n    25%{ transform:translateX(-4px); }\n    75%{ transform:translateX(4px); }\n  }\n  .menu-line{ margin-bottom:10px; }\n  .grid{\n    display:grid;\n    grid-template-columns:repeat(auto-fill, minmax(300px,1fr));\n    gap:14px;\n  }\n  .card{\n    border:1px solid var(--border);\n    background:var(--panel);\n    padding:14px;\n    border-radius:4px;\n  }\n  .card.me{ border-color:var(--accent); box-shadow:0 0 8px rgba(255,204,51,0.15); }\n  .card.elim{ opacity:0.4; }\n  .card-head{\n    display:flex; justify-content:space-between; align-items:center;\n    margin-bottom:10px; padding-bottom:8px; border-bottom:1px dashed var(--border);\n  }\n  .field-row{ margin-bottom:8px; font-size:13.5px; }\n  .field-row.said{ opacity:0.55; }\n  .field-label{ color:var(--fg-dim); }\n  .pw-tag{ color:var(--accent); font-size:12px; }\n  .lock-row{ display:flex; gap:6px; align-items:center; flex-wrap:wrap; margin-top:4px; }\n  .topbar{\n    display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap; gap:10px;\n    margin-bottom:16px;\n  }\n  .turn-box{\n    display:flex; align-items:center; gap:10px; font-size:16px;\n  }\n  .code-tag{\n    background:#000; border:1px solid var(--accent); color:var(--accent);\n    padding:4px 10px; border-radius:3px; letter-spacing:2px;\n  }\n  .footer-note{ color:var(--fg-dim); font-size:12px; margin-top:20px; }\n  .rules-hint{ font-size:12.5px; color:var(--fg-dim); margin-bottom:14px; }\n  .log-scroll{ max-height:360px; overflow-y:auto; padding-right:4px; }\n  .tab-bar{ display:flex; gap:6px; margin-bottom:14px; border-bottom:1px solid var(--border); padding-bottom:10px; flex-wrap:wrap; }\n  .tab-btn{ border-color:var(--border); color:var(--fg-dim); }\n  .tab-btn.active{ border-color:var(--accent); color:var(--accent); }\n  .tab-content{ margin-bottom:20px; }\n  .bunker-warn-light{ animation: bunker-blink 1.6s infinite ease-in-out; }\n  .bunker-antenna-light{ animation: bunker-blink 2.4s infinite ease-in-out 0.4s; }\n  @keyframes bunker-blink{ 0%,100%{ opacity:1; } 50%{ opacity:0.15; } }\n  .avatar-grid{\n    display:grid;\n    grid-template-columns:repeat(10, 7px);\n    grid-template-rows:repeat(11, 7px);\n    gap:0;\n    image-rendering:pixelated;\n    flex-shrink:0;\n  }\n  .avatar-cell{ width:7px; height:7px; }\n  .avatar-grid.placeholder .avatar-cell{ background:#0d150d; border:1px solid #142014; box-sizing:border-box; }\n  .appearance-group{ margin-bottom:6px; }\n  .appearance-input{ width:70px; text-transform:none; }\n<\/style>\n<\/head>\n<body>\n<div id=\"app\"><\/div>\n\n<script>\n\/* ===================== \u041d\u0410\u0421\u0422\u0420\u041e\u0419\u041a\u0418 ===================== *\/\n\/\/ \u041f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u0435\u043b\u044c \u0430\u0432\u0442\u043e\u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0432 localStorage. \u0414\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0430 \u043e\u0434\u043d\u043e\u043c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435\n\/\/ \u0443\u0434\u043e\u0431\u043d\u0435\u0435 \u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0432\u044b\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u043c \u2014 \u0442\u043e\u0433\u0434\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043d\u0435 \u0442\u0430\u0449\u0438\u0442 \u0441\u0442\u0430\u0440\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435.\n\/\/ \u041c\u043e\u0436\u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043f\u0440\u044f\u043c\u043e \u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435 (\u043a\u043d\u043e\u043f\u043a\u0430 \u0432 \u0448\u0430\u043f\u043a\u0435 \u043a\u043e\u043c\u043d\u0430\u0442\u044b).\nconst CONFIG = {\n  persist: false\n};\n\n\/* ===================== \u0413\u0415\u041d\u0415\u0420\u0410\u0422\u041e\u0420 (\u0434\u0435\u0442\u0435\u0440\u043c\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439, \u0438\u0437 \u0441\u0438\u0434\u0430) ===================== *\/\n\nfunction cyrb53(str, seed) {\n  seed = seed || 0;\n  let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;\n  for (let i = 0; i < str.length; i++) {\n    const ch = str.charCodeAt(i);\n    h1 = Math.imul(h1 ^ ch, 2654435761);\n    h2 = Math.imul(h2 ^ ch, 1597334677);\n  }\n  h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);\n  h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);\n  return 4294967296 * (2097151 & h2) + (h1 >>> 0);\n}\n\nfunction mulberry32(a) {\n  return function() {\n    a |= 0; a = a + 0x6D2B79F5 | 0;\n    let t = Math.imul(a ^ a >>> 15, 1 | a);\n    t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;\n    return ((t ^ t >>> 14) >>> 0) \/ 4294967296;\n  };\n}\n\nfunction pick(rng, arr){ return arr[Math.floor(rng() * arr.length)]; }\nfunction pickExcept(rng, arr, except){\n  const filtered = arr.filter(x => x !== except);\n  return pick(rng, filtered);\n}\nfunction randInt(rng, min, max){ return min + Math.floor(rng() * (max - min + 1)); }\n\nconst PW_CHARS = \"ABCDEFGHJKLMNPQRSTUVWXYZ23456789\";\nfunction genPassword(rng, len){\n  len = len || 4;\n  let s = \"\";\n  for (let i = 0; i < len; i++) s += PW_CHARS[Math.floor(rng() * PW_CHARS.length)];\n  return s;\n}\nfunction randomSeedString(len){\n  len = len || 6;\n  let s = \"\";\n  for (let i = 0; i < len; i++) s += PW_CHARS[Math.floor(Math.random() * PW_CHARS.length)];\n  return s;\n}\n\nconst CLASSES = [\"\u0413\u043e\u0442\u0443\u0432\u0430\u043d\u043d\u044f\",\"\u041c\u0435\u0434\u0438\u0446\u0438\u043d\u0430\",\"\u0422\u0435\u0445\u043d\u0456\u0447\u043d\u0435 \u043e\u0431\u0441\u043b\u0443\u0433\u043e\u0432\u0443\u0432\u0430\u043d\u043d\u044f\",\"\u0414\u043e\u0437\u0432\u0456\u043b\u043b\u044f\",\"\u0417\u0430\u0445\u0438\u0441\u0442\"];\n\nconst ROLE_NAMES = {\n  \"\u0413\u043e\u0442\u0443\u0432\u0430\u043d\u043d\u044f\": {10:\"\u0428\u0435\u0444-\u043a\u0443\u0445\u0430\u0440 \u041c\u0430\u043a\u0414\u043e\u043b\u0456\u043d\u0441\u0430\", 9:\" \u043a\u0443\u0445\u0430\u0440 \u0448\u0430\u0443\u0440\u043c\u2019\u044f\u0440\u043d\u0456 \u00ab\u041c\u0443\u0440\u0437\u0438\u043a\u00bb\", 8:\"\u041a\u0443\u0445\u0430\u0440 \u0456\u0437 \u0414\u0440\u0438\u0449\u0435\u0432\u043e\u0433\u043e \u0421\u0430\u0440\u0430\u044e\", 7:\"\u041a\u0443\u0445\u0430\u0440 \u0456\u0437 \u0432\u043e\u043a\u0437\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u0456\u043e\u0441\u043a\u0443\"},\n  \"\u041c\u0435\u0434\u0438\u0446\u0438\u043d\u0430\": {10:\"\u0425\u0456\u0440\u0443\u0440\u0433 \u0435\u043b\u0456\u0442\u043d\u043e\u0457 \u043a\u043b\u0456\u043d\u0456\u043a\u0438\", 9:\"\u0422\u0435\u0440\u0430\u043f\u0435\u0432\u0442 \u0440\u0430\u0439\u043e\u043d\u043d\u043e\u0457 \u043f\u043e\u043b\u0456\u043a\u043b\u0456\u043d\u0456\u043a\u0438\", 8:\"\u0424\u0435\u043b\u044c\u0434\u0448\u0435\u0440 \u0448\u0432\u0438\u0434\u043a\u043e\u0457 \u0434\u043e\u043f\u043e\u043c\u043e\u0433\u0438\", 7:\"\u0421\u0442\u0443\u0434\u0435\u043d\u0442-\u043c\u0435\u0434\u0438\u043a 3 \u043a\u0443\u0440\u0441\u0443\"},\n  \"\u0422\u0435\u0445\u043d\u0456\u0447\u043d\u0435 \u043e\u0431\u0441\u043b\u0443\u0433\u043e\u0432\u0443\u0432\u0430\u043d\u043d\u044f\": {10:\"\u0406\u043d\u0436\u0435\u043d\u0435\u0440 \u0430\u0442\u043e\u043c\u043d\u043e\u0457 \u0441\u0442\u0430\u043d\u0446\u0456\u0457\", 9:\"\u041c\u0430\u0439\u0441\u0442\u0435\u0440 \u0456\u0437 \u0416\u0415\u041a\u0443 \u00ab\u0437\u043e\u043b\u043e\u0442\u0456 \u0440\u0443\u043a\u0438\u00bb\", 8:\"\u0421\u0430\u043d\u0442\u0435\u0445\u043d\u0456\u043a \u0434\u044f\u0434\u044c\u043a\u043e \u0422\u043e\u043b\u044f\", 7:\"\u0421\u0442\u0430\u0436\u0435\u0440 \u0430\u0432\u0442\u043e\u0441\u0435\u0440\u0432\u0456\u0441\u0443\"},\n  \"\u0414\u043e\u0437\u0432\u0456\u043b\u043b\u044f\": {10:\"\u0420\u0435\u0437\u0438\u0434\u0435\u043d\u0442 Comedy Club\", 9:\"\u0412\u0443\u043b\u0438\u0447\u043d\u0438\u0439 \u043c\u0443\u0437\u0438\u043a\u0430\u043d\u0442 \u0456\u0437 \u043a\u043e\u043d\u0441\u0435\u0440\u0432\u0430\u0442\u043e\u0440\u0456\u0454\u044e\", 8:\"\u0410\u043d\u0456\u043c\u0430\u0442\u043e\u0440 \u043d\u0430 \u0440\u0430\u043d\u043a\u0430\u0445\", 7:\"\u0422\u0430\u043c\u0430\u0434\u0430 \u0456\u0437 \u0441\u0443\u0441\u0456\u0434\u043d\u044c\u043e\u0433\u043e \u0432\u0435\u0441\u0456\u043b\u043b\u044f\"},\n  \"\u0417\u0430\u0445\u0438\u0441\u0442\": {10:\"\u0415\u043a\u0441\u0431\u043e\u0454\u0446\u044c \u0441\u043f\u0435\u0446\u043d\u0430\u0437\u0443\", 9:\"\u041e\u0445\u043e\u0440\u043e\u043d\u0435\u0446\u044c \u0456\u043d\u043a\u0430\u0441\u0430\u0446\u0456\u0457\", 8:\"\u0412\u0456\u0434\u0441\u0442\u0430\u0432\u043d\u0438\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u0438\u043a\", 7:\"\u041e\u0445\u043e\u0440\u043e\u043d\u0435\u0446\u044c \u0441\u0443\u043f\u0435\u0440\u043c\u0430\u0440\u043a\u0435\u0442\u0443\"}\n};\n\nconst HEALTH_POOL = [\n  \"\u0412\u0456\u0434\u043c\u0456\u043d\u043d\u0435 \u0437\u0434\u043e\u0440\u043e\u0432\u2019\u044f\",\"\u041b\u0435\u0433\u043a\u0430 \u0430\u043b\u0435\u0440\u0433\u0456\u044f \u043d\u0430 \u043f\u0438\u043b\",\"\u0425\u0440\u043e\u043d\u0456\u0447\u043d\u0438\u0439 \u0431\u0440\u043e\u043d\u0445\u0456\u0442\",\n  \"\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0438 \u0456\u0437 \u0441\u0435\u0440\u0446\u0435\u043c\",\"\u041f\u043b\u043e\u0441\u043a\u043e\u0441\u0442\u043e\u043f\u0456\u0441\u0442\u044c, \u043d\u0435 \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u043e\",\"\u0421\u043b\u0430\u0431\u043a\u0438\u0439 \u0437\u0456\u0440, \u043e\u043a\u0443\u043b\u044f\u0440\u0438 \u0440\u043e\u0437\u0431\u0438\u043b\u0438\u0441\u044f\",\n  \"\u0417\u0430\u0433\u0430\u043b\u043e\u043c \u0437\u0434\u043e\u0440\u043e\u0432\u0438\u0439, \u0430\u043b\u0435 \u0445\u0440\u043e\u043f\u0435\",\"\u0412\u0456\u0434\u043d\u043e\u0432\u043b\u044e\u0454\u0442\u044c\u0441\u044f \u043f\u0456\u0441\u043b\u044f \u043f\u0435\u0440\u0435\u043b\u043e\u043c\u0443 \u043d\u043e\u0433\u0438\"\n];\n\nconst HOBBY_POOL = [\n  \"\u041a\u043e\u043b\u0435\u043a\u0446\u0456\u043e\u043d\u0443\u0454 \u043c\u0430\u0440\u043a\u0438\",\"\u0413\u0440\u0430\u0454 \u043d\u0430 \u0433\u0456\u0442\u0430\u0440\u0456\",\"\u0420\u043e\u0437\u0432\u043e\u0434\u0438\u0442\u044c \u043a\u0430\u043a\u0442\u0443\u0441\u0438\",\"\u0417\u0430\u0445\u043e\u043f\u043b\u044e\u0454\u0442\u044c\u0441\u044f \u0448\u0430\u0445\u0430\u043c\u0438\",\n  \"\u0424\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0443\u0454 \u0437\u0430\u0445\u043e\u0434\u0438 \u0441\u043e\u043d\u0446\u044f\",\"\u0412\u2019\u044f\u0436\u0435 \u0448\u043a\u0430\u0440\u043f\u0435\u0442\u043a\u0438\",\"\u0420\u043e\u0437\u0431\u0438\u0440\u0430\u0454\u0442\u044c\u0441\u044f \u0443 \u0441\u0442\u0430\u0440\u0438\u0445 \u0430\u0432\u0442\u043e\u043c\u043e\u0431\u0456\u043b\u044f\u0445\",\"\u041f\u0438\u0448\u0435 \u0432\u0456\u0440\u0448\u0456 \u0432 \u0448\u0443\u0445\u043b\u044f\u0434\u0443\"\n];\n\nconst PHOBIA_POOL = [\n  \"\u041a\u043b\u0430\u0443\u0441\u0442\u0440\u043e\u0444\u043e\u0431\u0456\u044f\",\"\u0411\u043e\u044f\u0437\u043d\u044c \u0442\u0435\u043c\u0440\u044f\u0432\u0438\",\"\u0410\u0440\u0430\u0445\u043d\u043e\u0444\u043e\u0431\u0456\u044f\",\"\u0411\u043e\u044f\u0437\u043d\u044c \u0433\u0443\u0447\u043d\u0438\u0445 \u0437\u0432\u0443\u043a\u0456\u0432\",\n  \"\u0411\u043e\u044f\u0437\u043d\u044c \u043a\u0440\u043e\u0432\u0456\",\"\u0411\u043e\u044f\u0437\u043d\u044c \u0432\u0456\u0434\u043a\u0440\u0438\u0442\u0438\u0445 \u043f\u0440\u043e\u0441\u0442\u043e\u0440\u0456\u0432\",\"\u0411\u043e\u044f\u0437\u043d\u044c \u043d\u0430\u0442\u043e\u0432\u043f\u0443\",\"\u041d\u0456\u043a\u0442\u043e\u0444\u043e\u0431\u0456\u044f\"\n];\n\nconst EXTRA_POOL = [\n  \"\u0420\u0430\u043d\u0456\u0448\u0435 \u0441\u0443\u0434\u0438\u0432\u0441\u044f \u0456\u0437 \u0441\u0443\u0441\u0456\u0434\u043e\u043c\",\"\u0417\u043d\u0430\u0454 \u0442\u0440\u0438 \u043c\u043e\u0432\u0438\",\"\u041a\u043e\u043b\u0438\u0448\u043d\u0456\u0439 \u0432\u0456\u0439\u0441\u044c\u043a\u043e\u0432\u0438\u0439\",\n  \"\u0404 \u0440\u043e\u0434\u0438\u0447\u0435\u043c \u043c\u0435\u0440\u0430 \u043c\u0456\u0441\u0442\u0430\",\"\u041c\u0430\u0454 \u0434\u0440\u0456\u0431\u043d\u0435 \u043a\u0440\u0438\u043c\u0456\u043d\u0430\u043b\u044c\u043d\u0435 \u043c\u0438\u043d\u0443\u043b\u0435\",\n  \"\u041f\u0440\u0430\u0446\u044e\u0432\u0430\u0432 \u043d\u0430 \u0437\u0430\u043a\u0440\u0438\u0442\u043e\u043c\u0443 \u043f\u0456\u0434\u043f\u0440\u0438\u0454\u043c\u0441\u0442\u0432\u0456\",\"\u0412\u0435\u0434\u0435 \u0442\u0430\u0454\u043c\u043d\u0438\u0439 \u0449\u043e\u0434\u0435\u043d\u043d\u0438\u043a\",\"\u0423\u0441\u0435 \u0436\u0438\u0442\u0442\u044f \u043c\u0440\u0456\u044f\u0432 \u043f\u0440\u043e \u043a\u043e\u0441\u043c\u043e\u0441\"\n];\n\nconst BAGGAGE_POOL = [\n  {name:\"\u041c\u0456\u0448\u043e\u043a \u043a\u0430\u0440\u0442\u043e\u043f\u043b\u0456 \u0442\u0430 \u043a\u0440\u0443\u043f\", buff:\"\u0413\u043e\u0442\u0443\u0432\u0430\u043d\u043d\u044f\"},\n  {name:\"\u0410\u043f\u0442\u0435\u0447\u043a\u0430 \u043f\u0435\u0440\u0448\u043e\u0457 \u0434\u043e\u043f\u043e\u043c\u043e\u0433\u0438\", buff:\"\u041c\u0435\u0434\u0438\u0446\u0438\u043d\u0430\"},\n  {name:\"\u041d\u0430\u0431\u0456\u0440 \u0456\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0456\u0432\", buff:\"\u0422\u0435\u0445\u043d\u0456\u0447\u043d\u0435 \u043e\u0431\u0441\u043b\u0443\u0433\u043e\u0432\u0443\u0432\u0430\u043d\u043d\u044f\"},\n  {name:\"\u041a\u043e\u043b\u043e\u0434\u0430 \u043a\u0430\u0440\u0442 \u0456 \u0433\u0456\u0442\u0430\u0440\u0430\", buff:\"\u0414\u043e\u0437\u0432\u0456\u043b\u043b\u044f\"},\n  {name:\"\u041c\u0438\u0441\u043b\u0438\u0432\u0441\u044c\u043a\u0438\u0439 \u043d\u0456\u0436\", buff:\"\u0417\u0430\u0445\u0438\u0441\u0442\"},\n  {name:\"\u0421\u0442\u0430\u0440\u0438\u0439 \u0444\u043e\u0442\u043e\u0430\u043b\u044c\u0431\u043e\u043c\", buff:null},\n  {name:\"\u041f\u043e\u0440\u0442\u0430\u0442\u0438\u0432\u043d\u0430 \u0440\u0430\u0446\u0456\u044f\", buff:null},\n  {name:\"\u042f\u0449\u0438\u043a \u0456\u0437 \u043d\u0430\u0441\u0456\u043d\u043d\u044f\u043c\", buff:\"\u0413\u043e\u0442\u0443\u0432\u0430\u043d\u043d\u044f\"}\n];\n\nconst ILLNESS_POOL = [\n  {name:\"\u0413\u0420\u0412\u0406\", severity:\"\u043b\u0435\u0433\u043a\u0430\"},\n  {name:\"\u0425\u0430\u0440\u0447\u043e\u0432\u0435 \u043e\u0442\u0440\u0443\u0454\u043d\u043d\u044f\", severity:\"\u0441\u0435\u0440\u0435\u0434\u043d\u044f\"},\n  {name:\"\u041f\u0440\u0438\u0445\u043e\u0432\u0430\u043d\u0430 \u043f\u043d\u0435\u0432\u043c\u043e\u043d\u0456\u044f\", severity:\"\u0442\u044f\u0436\u043a\u0430\"}\n];\n\n\/* ===================== \u0421\u0426\u0415\u041d\u0410\u0420\u0406\u0419 \u0411\u0423\u041d\u041a\u0415\u0420\u0410 ===================== *\/\n\nconst CATASTROPHE_POOL = [\n  \"\u0421\u0443\u043f\u0443\u0442\u043d\u0438\u043a\u0438 \u0437\u0430\u0444\u0456\u043a\u0441\u0443\u0432\u0430\u043b\u0438 \u0441\u0435\u0440\u0456\u044e \u0432\u0438\u0431\u0443\u0445\u0456\u0432 \u0431\u0456\u043b\u044f \u0441\u0445\u0456\u0434\u043d\u043e\u0433\u043e \u0443\u0437\u0431\u0435\u0440\u0435\u0436\u0436\u044f \u2014 \u0437\u0432\u2019\u044f\u0437\u043e\u043a \u0456\u0437 \u0437\u043e\u0432\u043d\u0456\u0448\u043d\u0456\u043c \u0441\u0432\u0456\u0442\u043e\u043c \u0437\u043d\u0438\u043a \u0437\u0430 \u043b\u0456\u0447\u0435\u043d\u0456 \u0433\u043e\u0434\u0438\u043d\u0438.\",\n  \"\u041d\u0435\u0432\u0456\u0434\u043e\u043c\u0438\u0439 \u043f\u0430\u0442\u043e\u0433\u0435\u043d \u043f\u043e\u0447\u0430\u0432 \u043f\u043e\u0448\u0438\u0440\u044e\u0432\u0430\u0442\u0438\u0441\u044f \u043c\u0435\u0433\u0430\u043f\u043e\u043b\u0456\u0441\u0430\u043c\u0438 \u0448\u0432\u0438\u0434\u0448\u0435, \u043d\u0456\u0436 \u0432\u0441\u0442\u0438\u0433\u0430\u043b\u0438 \u043e\u0433\u043e\u043b\u043e\u0441\u0438\u0442\u0438 \u043a\u0430\u0440\u0430\u043d\u0442\u0438\u043d.\",\n  \"\u041c\u0435\u0442\u0435\u043e\u0440\u0438\u0442\u043d\u0438\u0439 \u0440\u0456\u0439 \u0443\u0432\u0456\u0439\u0448\u043e\u0432 \u0432 \u0430\u0442\u043c\u043e\u0441\u0444\u0435\u0440\u0443 \u0431\u0435\u0437 \u043f\u043e\u043f\u0435\u0440\u0435\u0434\u0436\u0435\u043d\u043d\u044f, \u0437\u0430\u043b\u0438\u0448\u0438\u0432\u0448\u0438 \u0432\u0438\u043f\u0430\u043b\u0435\u043d\u0456 \u0441\u043c\u0443\u0433\u0438 \u0437\u0430\u0432\u0434\u043e\u0432\u0436\u043a\u0438 \u0432 \u0441\u043e\u0442\u043d\u0456 \u043a\u0456\u043b\u043e\u043c\u0435\u0442\u0440\u0456\u0432.\",\n  \"\u0415\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0437\u0440\u0443\u0439\u043d\u0443\u0432\u0430\u043b\u0430\u0441\u044f \u0437\u0430 \u043e\u0434\u043d\u0443 \u0437\u0438\u043c\u0443 \u2014 \u0432\u0440\u043e\u0436\u0430\u0457 \u0437\u0430\u0433\u0438\u043d\u0443\u043b\u0438, \u0430 \u0441\u043b\u0456\u0434\u043e\u043c \u043f\u0440\u0438\u0439\u0448\u043b\u0438 \u0433\u043e\u043b\u043e\u0434 \u0456 \u0445\u0430\u043e\u0441.\",\n  \"\u0412\u0456\u0439\u0441\u044c\u043a\u043e\u0432\u0438\u0439 \u043a\u043e\u043d\u0444\u043b\u0456\u043a\u0442 \u043c\u0456\u0436 \u043d\u0430\u0434\u0434\u0435\u0440\u0436\u0430\u0432\u0430\u043c\u0438 \u043f\u0435\u0440\u0435\u0442\u043d\u0443\u0432 \u043c\u0435\u0436\u0443, \u044f\u043a\u0443 \u043d\u0456\u0445\u0442\u043e \u043d\u0435 \u0434\u0443\u043c\u0430\u0432 \u043f\u0435\u0440\u0435\u0441\u0442\u0443\u043f\u0430\u0442\u0438.\",\n  \"\u0406\u0437 \u043d\u0430\u0434\u0440 \u0437\u0435\u043c\u043b\u0456 \u043f\u0456\u0434\u043d\u044f\u0432\u0441\u044f \u0442\u043e\u043a\u0441\u0438\u0447\u043d\u0438\u0439 \u0442\u0443\u043c\u0430\u043d, \u044f\u043a\u0438\u0439 \u0437\u0430 \u043a\u0456\u043b\u044c\u043a\u0430 \u0434\u043d\u0456\u0432 \u043e\u0433\u043e\u0440\u043d\u0443\u0432 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0443 \u043a\u043e\u043d\u0442\u0438\u043d\u0435\u043d\u0442\u0443.\",\n  \"\u0415\u043d\u0435\u0440\u0433\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043a\u0456\u043b\u044c\u043a\u043e\u0445 \u043a\u0440\u0430\u0457\u043d \u043e\u0434\u043d\u043e\u0447\u0430\u0441\u043d\u043e \u0432\u0438\u0439\u0448\u043b\u0430 \u0437 \u043b\u0430\u0434\u0443 \u2014 \u0441\u043f\u043e\u0447\u0430\u0442\u043a\u0443 \u0432\u0438\u0440\u0456\u0448\u0438\u043b\u0438, \u0449\u043e \u0446\u0435 \u0430\u0432\u0430\u0440\u0456\u044f.\",\n  \"\u0406\u0437 \u0437\u0430\u043a\u0440\u0438\u0442\u043e\u0457 \u043b\u0430\u0431\u043e\u0440\u0430\u0442\u043e\u0440\u0456\u0457 \u0449\u043e\u0441\u044c \u0432\u0438\u0440\u0432\u0430\u043b\u043e\u0441\u044f \u043d\u0430\u0437\u043e\u0432\u043d\u0456 \u2014 \u043e\u0444\u0456\u0446\u0456\u0439\u043d\u0438\u0445 \u043f\u0456\u0434\u0442\u0432\u0435\u0440\u0434\u0436\u0435\u043d\u044c \u0442\u0430\u043a \u0456 \u043d\u0435 \u043d\u0430\u0434\u0456\u0439\u0448\u043b\u043e.\"\n];\n\nconst BUNKER_TYPES = [\n  {name:\"\u041a\u043e\u043b\u0438\u0448\u043d\u0454 \u0432\u0456\u0439\u0441\u044c\u043a\u043e\u0432\u0435 \u0443\u043a\u0440\u0438\u0442\u0442\u044f\", desc:\"\u0422\u043e\u0432\u0441\u0442\u0456 \u0431\u0435\u0442\u043e\u043d\u043d\u0456 \u0441\u0442\u0456\u043d\u0438 \u0442\u0430 \u0440\u0430\u0434\u044f\u043d\u0441\u044c\u043a\u0438\u0439 \u0437\u0430\u043f\u0430\u0441 \u043a\u043e\u043d\u0441\u0435\u0440\u0432\u0456\u0432 \u2014 \u0431\u0443\u0434\u0443\u0432\u0430\u043b\u0438 \u043d\u0430 \u0441\u043e\u0432\u0456\u0441\u0442\u044c, \u0430\u043b\u0435 \u0434\u0430\u0432\u043d\u043e \u043d\u0435 \u043f\u0435\u0440\u0435\u0432\u0456\u0440\u044f\u043b\u0438.\"},\n  {name:\"\u041a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u0438\u0439 \u0431\u0443\u043d\u043a\u0435\u0440\", desc:\"\u0421\u043a\u043b\u044f\u043d\u0456 \u043f\u0435\u0440\u0435\u0433\u043e\u0440\u043e\u0434\u043a\u0438 \u0442\u0430 \u0432\u0435\u043d\u0442\u0438\u043b\u044f\u0446\u0456\u0439\u043d\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043e\u0441\u0442\u0430\u043d\u043d\u044c\u043e\u0433\u043e \u043f\u043e\u043a\u043e\u043b\u0456\u043d\u043d\u044f \u2014 \u0432\u0440\u0430\u0436\u0430\u0454, \u043f\u043e\u043a\u0438 \u043d\u0435 \u043f\u043e\u0447\u0438\u043d\u0430\u0454 \u0431\u0430\u0440\u0430\u0445\u043b\u0438\u0442\u0438.\"},\n  {name:\"\u0421\u0456\u043c\u0435\u0439\u043d\u0438\u0439 \u043f\u0456\u0434\u0432\u0430\u043b-\u0443\u043a\u0440\u0438\u0442\u0442\u044f\", desc:\"\u0422\u0456\u0441\u043d\u043e, \u0430\u043b\u0435 \u043f\u043e-\u0434\u043e\u043c\u0430\u0448\u043d\u044c\u043e\u043c\u0443 \u2014 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0430 \u0437\u0430\u043f\u0430\u0441\u0456\u0432 \u0432\u0438\u044f\u0432\u0438\u043b\u0430\u0441\u044f \u0431\u0430\u043d\u043a\u0430\u043c\u0438 \u0437 \u0432\u0430\u0440\u0435\u043d\u043d\u044f\u043c.\"},\n  {name:\"\u0421\u0442\u0430\u043d\u0446\u0456\u044f \u043c\u0435\u0442\u0440\u043e\", desc:\"\u041f\u0440\u043e\u0441\u0442\u043e\u0440\u043e \u0439 \u043b\u044e\u0434\u043d\u043e \u2014 \u0430\u043b\u0435 \u0441\u0430\u043c\u0435 \u0442\u043e\u043c\u0443 \u0442\u0456\u0441\u043d\u043e\u0442\u0430 \u0442\u0430 \u0447\u0435\u0440\u0433\u0438 \u0441\u0442\u0430\u043b\u0438 \u043d\u043e\u0432\u043e\u044e \u043d\u043e\u0440\u043c\u043e\u044e.\"},\n  {name:\"\u041d\u0430\u0443\u043a\u043e\u0432\u043e-\u0434\u043e\u0441\u043b\u0456\u0434\u043d\u0438\u0439 \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0441\", desc:\"\u041b\u0430\u0431\u043e\u0440\u0430\u0442\u043e\u0440\u0456\u0457, \u0430\u0432\u0442\u043e\u043d\u043e\u043c\u043d\u0438\u0439 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440 \u0456 \u0436\u043e\u0434\u043d\u043e\u0433\u043e \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043c\u0430\u0442\u0440\u0430\u0446\u0430.\"}\n];\n\n\/\/ \u0421\u043f\u0438\u0441\u043e\u043a \u043c\u043e\u0436\u043b\u0438\u0432\u0438\u0445 \u043e\u0441\u043e\u0431\u043b\u0438\u0432\u0438\u0445 \u043a\u0456\u043c\u043d\u0430\u0442. \u041a\u043e\u0436\u043d\u0430 \u043c\u0430\u0454 \u0441\u0432\u0456\u0439 \u0448\u0430\u043d\u0441 \u0437\u2019\u044f\u0432\u0438\u0442\u0438\u0441\u044f \u0432 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c\u0443 \u0431\u0443\u043d\u043a\u0435\u0440\u0456.\nconst ROOM_POOL = [\n  {id:\"quarantine\", name:\"\u041a\u0430\u0440\u0430\u043d\u0442\u0438\u043d\u043d\u0430 \u043a\u0430\u043c\u0435\u0440\u0430\", chance:0.55,\n   desc:\"\u041e\u043a\u0440\u0435\u043c\u0438\u0439 \u0433\u0435\u0440\u043c\u0435\u0442\u0438\u0447\u043d\u0438\u0439 \u0432\u0456\u0434\u0441\u0456\u043a \u2014 \u043c\u043e\u0436\u043d\u0430 \u0456\u0437\u043e\u043b\u044e\u0432\u0430\u0442\u0438 \u0437\u0430\u0440\u0430\u0436\u0435\u043d\u043e\u0433\u043e, \u043d\u0435 \u0432\u0438\u0433\u0430\u043d\u044f\u044e\u0447\u0438 \u0439\u043e\u0433\u043e \u0437 \u0431\u0443\u043d\u043a\u0435\u0440\u0430.\"}\n];\n\nfunction bunkerCapacityText(n){\n  if (n <= 4) return \"\u0422\u0456\u0441\u043d\u0435, \u0430\u043b\u0435 \u043a\u0435\u0440\u043e\u0432\u0430\u043d\u0435 \u0443\u043a\u0440\u0438\u0442\u0442\u044f \u2014 \u043b\u0438\u0448\u0435 \" + n + \" \u043b\u044e\u0434\u0435\u0439, \u0443\u0441\u0456 \u043d\u0430 \u0432\u0438\u0434\u0443.\";\n  if (n <= 8) return \"\u0423\u043a\u0440\u0438\u0442\u0442\u044f \u0441\u0435\u0440\u0435\u0434\u043d\u044c\u043e\u0433\u043e \u0440\u043e\u0437\u043c\u0456\u0440\u0443 \u043d\u0430 \" + n + \" \u043b\u044e\u0434\u0435\u0439 \u2014 \u0443\u0436\u0435 \u0434\u043e\u0432\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0434\u0456\u043b\u0438\u0442\u0438 \u0437\u043c\u0456\u043d\u0438 \u0431\u0456\u043b\u044f \u0432\u0445\u043e\u0434\u0443.\";\n  return \"\u0412\u0435\u043b\u0438\u043a\u0435 \u0443\u043a\u0440\u0438\u0442\u0442\u044f \u043d\u0430 \" + n + \" \u043b\u044e\u0434\u0435\u0439 \u2014 \u043a\u043e\u0440\u0438\u0434\u043e\u0440\u0438 \u0448\u0432\u0438\u0434\u043a\u043e \u043f\u0435\u0440\u0435\u0442\u0432\u043e\u0440\u044e\u044e\u0442\u044c\u0441\u044f \u043d\u0430 \u0447\u0435\u0440\u0433\u0438.\";\n}\nfunction generateSituation(seed, n){\n  const rng = mulberry32(cyrb53(seed + \"::situation\", n));\n  const catastrophe = CATASTROPHE_POOL[Math.floor(rng() * CATASTROPHE_POOL.length)];\n  const bunkerType = BUNKER_TYPES[Math.floor(rng() * BUNKER_TYPES.length)];\n  const rooms = {};\n  ROOM_POOL.forEach(r => { if (rng() < r.chance) rooms[r.id] = true; });\n  return { catastrophe, bunkerType, rooms };\n}\n\n\/* ===================== \u0412\u041d\u0415\u0428\u041d\u041e\u0421\u0422\u042c (\u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u043d\u044b\u0439 \u043f\u0438\u043a\u0441\u0435\u043b\u044c-\u0430\u0432\u0430\u0442\u0430\u0440) ===================== *\/\n\nconst AV_W = 10, AV_H = 11;\n\nconst HEAD_ROWS = [\n  {row:1, cols:[2,7]}, {row:2, cols:[1,8]}, {row:3, cols:[0,9]}, {row:4, cols:[0,9]},\n  {row:5, cols:[0,9]}, {row:6, cols:[0,9]}, {row:7, cols:[0,9]}, {row:8, cols:[1,8]},\n  {row:9, cols:[2,7]}, {row:10, cols:[3,6]}\n];\nconst HEAD_CELLS = [];\nHEAD_ROWS.forEach(({row, cols}) => { for (let c = cols[0]; c <= cols[1]; c++) HEAD_CELLS.push([row, c]); });\n\nconst SKIN_OPTIONS = [\n  {name:\"\u0421\u0432\u0456\u0442\u043b\u0430\", color:\"#f2c9a1\"},\n  {name:\"\u0421\u043c\u0430\u0433\u043b\u044f\u0432\u0430\", color:\"#d9a066\"},\n  {name:\"\u0422\u0435\u043c\u043d\u0430\", color:\"#8a5a34\"},\n  {name:\"\u0414\u0443\u0436\u0435 \u0442\u0435\u043c\u043d\u0430\", color:\"#4a2e1f\"}\n];\n\nconst HAIRSTYLES = [\n  {name:\"\u041b\u0438\u0441\u0438\u0439\", cells:[], color:null},\n  {name:\"\u041a\u043e\u0440\u043e\u0442\u043a\u0435\", color:\"#2b2b2b\", cells:[[0,2],[0,3],[0,4],[0,5],[0,6],[0,7],[1,2],[1,3],[1,4],[1,5],[1,6],[1,7]]},\n  {name:\"\u0406\u0440\u043e\u043a\u0435\u0437\", color:\"#c9622b\", cells:[[0,4],[0,5],[1,4],[1,5],[2,4],[2,5]]},\n  {name:\"\u0427\u0443\u0431\u0447\u0438\u043a\", color:\"#c2a15a\", cells:[[0,3],[0,4],[0,5],[0,6],[1,3],[1,6]]}\n];\n\nconst EYE_STYLES = [\n  {name:\"\u041a\u0440\u0430\u043f\u043a\u0438\", cells:[[5,3],[5,6]]},\n  {name:\"\u041f\u0440\u0438\u043c\u0440\u0443\u0436\u0435\u043d\u0456\", cells:[[5,2],[5,3],[5,6],[5,7]]},\n  {name:\"\u041e\u043a\u0443\u043b\u044f\u0440\u0438\", cells:[[5,2],[5,3],[5,4],[5,5],[5,6],[5,7]]}\n];\n\nconst MOUTH_STYLES = [\n  {name:\"\u041d\u0435\u0439\u0442\u0440\u0430\u043b\u044c\u043d\u0438\u0439\", cells:[[8,4],[8,5]]},\n  {name:\"\u0423\u0441\u043c\u0456\u0448\u043a\u0430\", cells:[[8,3],[8,4],[8,5],[8,6]]},\n  {name:\"\u0417\u0434\u0438\u0432\u0443\u0432\u0430\u043d\u043d\u044f\", cells:[[8,4],[9,4]]}\n];\n\nfunction encodeAppearance(a){ return \"\" + a.skin + a.hair + a.eyes + a.mouth; }\nfunction decodeAppearance(code){\n  if (!\/^[0-3]{4}$\/.test(code || \"\")) return null;\n  return { skin:+code[0], hair:+code[1], eyes:+code[2], mouth:+code[3] };\n}\nfunction buildAvatarGrid(a){\n  const grid = Array.from({length:AV_H}, () => Array(AV_W).fill(null));\n  const skin = (SKIN_OPTIONS[a.skin] || SKIN_OPTIONS[0]).color;\n  HEAD_CELLS.forEach(([r,c]) => { grid[r][c] = skin; });\n  const hs = HAIRSTYLES[a.hair] || HAIRSTYLES[0];\n  hs.cells.forEach(([r,c]) => { grid[r][c] = hs.color; });\n  (EYE_STYLES[a.eyes] || EYE_STYLES[0]).cells.forEach(([r,c]) => { grid[r][c] = \"#1a1a1a\"; });\n  (MOUTH_STYLES[a.mouth] || MOUTH_STYLES[0]).cells.forEach(([r,c]) => { grid[r][c] = \"#7a2323\"; });\n  return grid;\n}\nfunction renderAvatarHtml(a, placeholder){\n  if (placeholder){\n    return `<div class=\"avatar-grid placeholder\">${\"<div class=\\\"avatar-cell\\\"><\/div>\".repeat(AV_W * AV_H)}<\/div>`;\n  }\n  const grid = buildAvatarGrid(a);\n  let cells = \"\";\n  for (let r = 0; r < AV_H; r++){\n    for (let c = 0; c < AV_W; c++){\n      cells += `<div class=\"avatar-cell\" style=\"background:${grid[r][c] || \"transparent\"}\"><\/div>`;\n    }\n  }\n  return `<div class=\"avatar-grid\">${cells}<\/div>`;\n}\n\n\/* ===================== \u041f\u041e\u041b\u042f \u041f\u0415\u0420\u0421\u041e\u041d\u0410\u0416\u0410 ===================== *\/\n\nconst FIELD_ORDER = [\"profession\",\"health\",\"hobby\",\"phobia\",\"extra\",\"baggage\",\"ability\",\"illness\"];\nconst FIELD_LABELS = {\n  profession:\"\u041f\u0440\u043e\u0444\u0435\u0441\u0456\u044f\",\n  health:\"\u0417\u0434\u043e\u0440\u043e\u0432\u2019\u044f\",\n  hobby:\"\u0425\u043e\u0431\u0456\",\n  phobia:\"\u0424\u043e\u0431\u0456\u044f\",\n  extra:\"\u0414\u043e\u0434. \u0456\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0456\u044f\",\n  baggage:\"\u0411\u0430\u0433\u0430\u0436\",\n  ability:\"\u0417\u0434\u0456\u0431\u043d\u0456\u0441\u0442\u044c (\u0437\u0430\u043c\u0456\u043d\u0430 \u0440\u043e\u043b\u0456)\",\n  illness:\"\u041f\u0440\u0438\u0445\u043e\u0432\u0430\u043d\u0438\u0439 \u0441\u0442\u0430\u043d \u0437\u0434\u043e\u0440\u043e\u0432\u2019\u044f\"\n};\n\nfunction fieldValue(p, field){\n  switch(field){\n    case \"profession\": return p.profName + \" (\" + p.profClass + \", \u0440\u0456\u0432. \" + p.profLevel + \")\";\n    case \"health\": return p.health;\n    case \"hobby\": return p.hobby;\n    case \"phobia\": return p.phobia;\n    case \"extra\": return p.extra;\n    case \"baggage\": return p.baggageBuff ? (p.baggageName + \" \u2014 \u0431\u0430\u0444 \u043a\u043b\u0430\u0441\u0443 \u00ab\" + p.baggageBuff + \"\u00bb\") : p.baggageName;\n    case \"ability\": return \"\u041c\u043e\u0436\u0435 \u0441\u043b\u0430\u0431\u043a\u043e \u0437\u0430\u043c\u0456\u043d\u0438\u0442\u0438 \u043a\u043b\u0430\u0441 \u00ab\" + p.abilityClass + \"\u00bb (\u0440\u0456\u0432. \" + p.abilityLevel + \")\";\n    case \"illness\":\n      if (!p.hasIllness) return \"\u041f\u0440\u0438\u0445\u043e\u0432\u0430\u043d\u0438\u0445 \u0437\u0430\u0445\u0432\u043e\u0440\u044e\u0432\u0430\u043d\u044c \u043d\u0435\u043c\u0430\u0454\";\n      var st = S.diseaseState[p.num] || \"active\";\n      var stLabel = st === \"active\" ? \"\u0430\u043a\u0442\u0438\u0432\u043d\u0430\" : (st === \"cured\" ? \"\u0432\u0438\u043b\u0456\u043a\u0443\u0432\u0430\u043d\u0430\" : \"\u0437\u0430\u0431\u0440\u0430\u043b\u0430 \u0436\u0438\u0442\u0442\u044f\");\n      return p.illness.name + \" (\" + p.illness.severity + \") \u2014 \" + stLabel;\n  }\n}\n\nfunction generateScenario(seedStr, n){\n  const rng = mulberry32(cyrb53(seedStr, n));\n  const players = [];\n  for (let i = 1; i <= n; i++){\n    const profClass = pick(rng, CLASSES);\n    const profLevel = pick(rng, [7,8,9,10]);\n    const profName = ROLE_NAMES[profClass][profLevel];\n    const health = pick(rng, HEALTH_POOL);\n    const hobby = pick(rng, HOBBY_POOL);\n    const phobia = pick(rng, PHOBIA_POOL);\n    const extra = pick(rng, EXTRA_POOL);\n    const bag = pick(rng, BAGGAGE_POOL);\n    const abilityClass = pickExcept(rng, CLASSES, profClass);\n    const abilityLevel = randInt(rng, 2, 4);\n    const hasIllness = rng() < 0.35;\n    const illness = hasIllness ? pick(rng, ILLNESS_POOL) : null;\n\n    const passwords = {};\n    FIELD_ORDER.forEach(f => { passwords[f] = genPassword(rng); });\n\n    players.push({\n      num:i, profClass, profLevel, profName, health, hobby, phobia, extra,\n      baggageName:bag.name, baggageBuff:bag.buff,\n      abilityClass, abilityLevel,\n      hasIllness, illness,\n      passwords\n    });\n  }\n  return players;\n}\n\n\/* ===================== \u0414\u0412\u0418\u0416\u041e\u041a \u0414\u041d\u042f (\u0434\u0435\u0442\u0435\u0440\u043c\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043f\u043e seed+\u0434\u0435\u043d\u044c+\u0441\u043e\u0431\u044b\u0442\u0438\u0435) ===================== *\/\n\nfunction aliveScenario(){ return S.scenario.filter(p => !S.eliminated[p.num]); }\n\nfunction dayRoll(label){\n  const rng = mulberry32(cyrb53(S.seed + \"::day\" + S.day + \"::\" + label, S.playerCount));\n  return rng();\n}\nfunction seedRoll(label){\n  const rng = mulberry32(cyrb53(S.seed + \"::static::\" + label, S.playerCount));\n  return rng();\n}\nfunction dayLevel(cls){\n  const rng = mulberry32(cyrb53(S.seed + \"::lvl::\" + S.day + \"::\" + cls, S.playerCount));\n  const base = 4 + Math.floor(rng() * 4); \/\/ 4..7\n  const escalation = Math.floor((S.day - 1) \/ 2); \/\/ +1 \u043a\u0430\u0436\u0434\u044b\u0435 2 \u0434\u043d\u044f\n  return Math.min(14, base + escalation);\n}\nfunction pickAliveTarget(label){\n  const alive = aliveScenario();\n  if (alive.length === 0) return null;\n  const r = dayRoll(label);\n  return alive[Math.floor(r * alive.length)];\n}\n\nfunction effectiveLevel(p){\n  let lvl = p.profLevel;\n  if (p.hasIllness && S.diseaseState[p.num] === \"active\"){\n    if (p.illness.severity === \"\u043b\u0435\u0433\u043a\u0430\") lvl -= 1;\n    else if (p.illness.severity === \"\u0441\u0435\u0440\u0435\u0434\u043d\u044f\") lvl -= 3;\n    else if (p.illness.severity === \"\u0442\u044f\u0436\u043a\u0430\") lvl = 0;\n  }\n  if (S.hungerPenalty[p.num]) lvl -= 1;\n  return Math.max(0, lvl);\n}\n\n\/\/ \u0418\u0437\u0432\u0435\u0441\u0442\u043d\u043e \u043b\u0438 \u0433\u0440\u0443\u043f\u043f\u0435 \u044d\u0442\u043e \u043f\u043e\u043b\u0435 \u043f\u0440\u044f\u043c\u043e \u0441\u0435\u0439\u0447\u0430\u0441. \u0414\u043b\u044f \u0441\u0432\u043e\u0435\u0433\u043e \u0438\u0433\u0440\u043e\u043a\u0430 \u2014 \u043e\u0442\u043c\u0435\u0442\u0438\u043b \u043b\u0438 \u043e\u043d \u044d\u0442\u043e\n\/\/ \u0443 \u0441\u0435\u0431\u044f \u043a\u0430\u043a \"\u0441\u043a\u0430\u0437\u0430\u043d\u043e\". \u0414\u043b\u044f \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u2014 \u0432\u0432\u0451\u043b \u043b\u0438 \u044d\u0442\u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442 \u0432\u0435\u0440\u043d\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c (\u043b\u0438\u0431\u043e ID-\u043a\u043e\u0434).\n\/\/ \u0411\u043e\u043b\u0435\u0437\u043d\u044c \u0432 effectiveLevel() \u043d\u0430\u043c\u0435\u0440\u0435\u043d\u043d\u043e \u041d\u0415 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 fieldKnown \u2014 \u043e\u043d\u0430 \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442\n\/\/ \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u0432\u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0440\u0430\u0441\u043a\u0440\u044b\u0442\u0438\u044f, \u043f\u043e \u0443\u0441\u043b\u043e\u0432\u0438\u044e \u0437\u0430\u0434\u0430\u0447\u0438.\nfunction fieldKnown(p, field){\n  if (p.num === S.myPlayer) return !!S.announced[field];\n  if (isBot(p.num)) return !!(S.unlocked[p.num] && S.unlocked[p.num][field]);\n  return !!(S.unlocked[p.num] && S.unlocked[p.num][field]);\n}\n\nfunction classLevel(cls){\n  let best = 0;\n  aliveScenario().forEach(p => {\n    if (S.quarantine[p.num]) return; \/\/ \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d \u2014 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442\n    if (p.profClass === cls && fieldKnown(p, \"profession\")) best = Math.max(best, effectiveLevel(p));\n    if (p.abilityClass === cls && fieldKnown(p, \"ability\")) best = Math.max(best, p.abilityLevel);\n  });\n  let buff = 0;\n  aliveScenario().forEach(p => {\n    if (S.quarantine[p.num]) return;\n    if (p.baggageBuff === cls && !S.baggageLost[p.num] && fieldKnown(p, \"baggage\")) buff += 1;\n  });\n  return best + Math.min(buff, 3);\n}\n\nfunction triggerMoodHit(log, reason){\n  S._evtCounter++;\n  const idx = S._evtCounter;\n  const roll = dayRoll(\"mood_event_\" + idx);\n  if (roll < 0.3){\n    const target = pickAliveTarget(\"mood_target_\" + idx);\n    if (target){\n      const deltaRoll = dayRoll(\"mood_delta_\" + idx);\n      const delta = 1 + Math.floor(deltaRoll * 3);\n      S.mood[target.num] = Math.max(0, (S.mood[target.num] === undefined ? 6 : S.mood[target.num]) - delta);\n      log.push(\"\u0427\u0435\u0440\u0435\u0437 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u00ab\" + reason + \"\u00bb \u043d\u0430\u0441\u0442\u0440\u0456\u0439 \u0413\u0440\u0430\u0432\u0446\u044f \" + target.num + \" \u0432\u043f\u0430\u0432 \u043d\u0430 \" + delta + \".\");\n    }\n  }\n}\n\nfunction initPersistentStateIfNeeded(){\n  aliveScenario().forEach(p => { if (S.mood[p.num] === undefined) S.mood[p.num] = 6; });\n  S.scenario.forEach(p => { if (p.hasIllness && S.diseaseState[p.num] === undefined) S.diseaseState[p.num] = \"active\"; });\n  if (!S.foodStock) S.foodStock = S.playerCount * 3;\n}\n\n\/\/ \u0418\u0437 \u043f\u0440\u043e\u0438\u0441\u0448\u0435\u0441\u0442\u0432\u0438\u0439 (\u0411\u043e\u043b\u0435\u0437\u043d\u0438\/\u041f\u043e\u043b\u043e\u043c\u043a\u0438\/\u041d\u0430\u043f\u0430\u0434\u0435\u043d\u0438\u0435) \u0432 \u0434\u0435\u043d\u044c \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e 1-2 \u2014\n\/\/ \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0432 \u044d\u0442\u043e\u0442 \u0434\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0442. \u0415\u0434\u0430 \u0438 \u041d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u2014 \u043d\u0435 \u043f\u0440\u043e\u0438\u0441\u0448\u0435\u0441\u0442\u0432\u0438\u044f,\n\/\/ \u043e\u043d\u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u0442\u0435\u043a\u0443\u0442 \u043f\u043b\u0430\u0432\u043d\u043e.\nfunction pickIncidents(){\n  const candidates = [\"\u041f\u043e\u043b\u043e\u043c\u043a\u0438\", \"\u041d\u0430\u043f\u0430\u0434\u0456\u043d\u043d\u044f\"];\n  const hasActiveIllness = S.scenario.some(p => !S.eliminated[p.num] && p.hasIllness && S.diseaseState[p.num] === \"active\");\n  if (hasActiveIllness) candidates.push(\"\u0425\u0432\u043e\u0440\u043e\u0431\u0438\");\n\n  const scored = candidates.map((c, i) => ({ c, r: dayRoll(\"incident_pick_\" + i + \"_\" + c) }));\n  scored.sort((a, b) => a.r - b.r);\n  const count = Math.min(candidates.length, dayRoll(\"incident_count\") < 0.55 ? 1 : 2);\n  return scored.slice(0, count).map(x => x.c);\n}\n\nfunction collapseDay(){\n  initPersistentStateIfNeeded();\n  S._evtCounter = 0;\n  const meterLines = [];\n  const incidentLines = [];\n  S.hungerPenalty = {};\n\n  \/* ===== \u0407\u0416\u0410 (\u043f\u043b\u0430\u0432\u043d\u0430 \u043c\u0435\u0442\u0440\u0438\u043a\u0430) ===== *\/\n  const hungerLevel = dayLevel(\"\u0413\u043e\u0442\u0443\u0432\u0430\u043d\u043d\u044f\");\n  const cookPower = classLevel(\"\u0413\u043e\u0442\u0443\u0432\u0430\u043d\u043d\u044f\");\n  const net = cookPower - hungerLevel;\n  const cap = S.playerCount * 6;\n  S.foodStock = Math.max(0, Math.min(cap, S.foodStock + net));\n  meterLines.push(\"\u0407\u0436\u0430: \u043f\u043e\u0442\u0440\u0435\u0431\u0430 \" + hungerLevel + \", \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0435 \u0433\u043e\u0442\u0443\u0432\u0430\u043d\u043d\u044f \" + cookPower + \" (\" + (net >= 0 ? \"+\" : \"\") + net + \"), \u0437\u0430\u043f\u0430\u0441 \u0442\u0435\u043f\u0435\u0440 \" + S.foodStock + \"\/\" + cap + \".\");\n  if (S.foodStock === 0 && net < 0){\n    const target = pickAliveTarget(\"hunger_target\");\n    if (target){\n      S.hungerPenalty[target.num] = true;\n      S.mood[target.num] = Math.max(0, (S.mood[target.num] === undefined ? 6 : S.mood[target.num]) - 1);\n      meterLines.push(\"\u0417\u0430\u043f\u0430\u0441\u0438 \u0437\u0430\u043a\u0456\u043d\u0447\u0438\u043b\u0438\u0441\u044f \u2014 \u0413\u0440\u0430\u0432\u0435\u0446\u044c \" + target.num + \" \u0433\u043e\u043b\u043e\u0434\u0443\u0432\u0430\u0432 (\u0448\u0442\u0440\u0430\u0444 \u22121 \u0434\u043e \u0440\u043e\u043b\u0456 \u0437\u0430\u0432\u0442\u0440\u0430, \u22121 \u0434\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u044e).\");\n    }\n  }\n\n  \/* ===== \u041d\u0410\u0421\u0422\u0420\u041e\u0415\u041d\u0418\u0415 (\u043f\u043b\u0430\u0432\u043d\u0430\u044f \u043c\u0435\u0442\u0440\u0438\u043a\u0430) ===== *\/\n  const leisurePower = classLevel(\"\u0414\u043e\u0437\u0432\u0456\u043b\u043b\u044f\");\n  const recover = Math.max(0, Math.floor(leisurePower \/ 4));\n  const baseDrain = 1;\n  const moodDelta = recover - baseDrain;\n  aliveScenario().forEach(p => {\n    const cur = S.mood[p.num] === undefined ? 6 : S.mood[p.num];\n    S.mood[p.num] = Math.max(0, Math.min(10, cur + moodDelta));\n  });\n  meterLines.push(\"\u041d\u0430\u0441\u0442\u0440\u0456\u0439: \u0432\u0456\u0434\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044f \u0432\u0456\u0434 \u0434\u043e\u0437\u0432\u0456\u043b\u043b\u044f +\" + recover + \", \u0431\u0430\u0437\u043e\u0432\u0435 \u043f\u0430\u0434\u0456\u043d\u043d\u044f \u2212\" + baseDrain + \" (\u043f\u0456\u0434\u0441\u0443\u043c\u043e\u043a \" + (moodDelta >= 0 ? \"+\" : \"\") + moodDelta + \"\/\u043b\u044e\u0434. \u0437\u0430 \u0434\u0435\u043d\u044c).\");\n  aliveScenario().forEach(p => {\n    if (S.mood[p.num] <= 0) S.moodLoop[p.num] = true;\n    else if (S.mood[p.num] >= 3) S.moodLoop[p.num] = false;\n  });\n\n  \/* ===== \u041f\u0420\u0418\u0413\u041e\u0414\u0418 (1-2 \u043d\u0430 \u0434\u0435\u043d\u044c) ===== *\/\n  const incidents = pickIncidents();\n  if (incidents.length === 0){\n    incidentLines.push(\"\u0421\u044c\u043e\u0433\u043e\u0434\u043d\u0456 \u0431\u0435\u0437 \u043f\u0440\u0438\u0433\u043e\u0434.\");\n  }\n\n  if (incidents.includes(\"\u0425\u0432\u043e\u0440\u043e\u0431\u0438\")){\n    const docPower = classLevel(\"\u041c\u0435\u0434\u0438\u0446\u0438\u043d\u0430\");\n    S.scenario.forEach(p => {\n      if (S.eliminated[p.num]) return;\n      if (p.hasIllness && S.diseaseState[p.num] === \"active\"){\n        const sevLevel = p.illness.severity === \"\u043b\u0435\u0433\u043a\u0430\" ? 5 : (p.illness.severity === \"\u0441\u0435\u0440\u0435\u0434\u043d\u044f\" ? 8 : 11);\n        if (docPower >= sevLevel){\n          S.diseaseState[p.num] = \"cured\";\n          incidentLines.push(\"[\u0425\u0432\u043e\u0440\u043e\u0431\u0438] \u0413\u0440\u0430\u0432\u0446\u044f \" + p.num + \" (\" + p.illness.name + \") \u0432\u0438\u043b\u0456\u043a\u0443\u0432\u0430\u043d\u043e \u0431\u0435\u0437 \u0440\u0438\u0437\u0438\u043a\u0443.\");\n        } else {\n          const chance = docPower \/ (docPower + sevLevel);\n          if (dayRoll(\"disease_\" + p.num) < chance){\n            S.diseaseState[p.num] = \"cured\";\n            incidentLines.push(\"[\u0425\u0432\u043e\u0440\u043e\u0431\u0438] \u0420\u0438\u0437\u0438\u043a\u043e\u0432\u0430\u043d\u0435 \u043b\u0456\u043a\u0443\u0432\u0430\u043d\u043d\u044f \u0441\u043f\u0440\u0430\u0446\u044e\u0432\u0430\u043b\u043e \u2014 \u0413\u0440\u0430\u0432\u0446\u044f \" + p.num + \" (\" + p.illness.name + \") \u0432\u0438\u043b\u0456\u043a\u0443\u0432\u0430\u043d\u043e.\");\n          } else {\n            S.diseaseState[p.num] = \"dead\";\n            S.eliminated[p.num] = true;\n            incidentLines.push(\"[\u0425\u0432\u043e\u0440\u043e\u0431\u0438] \u041b\u0456\u043a\u0443\u0432\u0430\u043d\u043d\u044f \u043d\u0435 \u0434\u043e\u043f\u043e\u043c\u043e\u0433\u043b\u043e \u2014 \u0413\u0440\u0430\u0432\u0435\u0446\u044c \" + p.num + \" \u0437\u0430\u0433\u0438\u043d\u0443\u0432 (\" + p.illness.name + \").\");\n            if (S.quarantine[p.num]){\n              incidentLines.push(\"[\u0425\u0432\u043e\u0440\u043e\u0431\u0438] \u0413\u0440\u0430\u0432\u0446\u044f \u0431\u0443\u043b\u043e \u0456\u0437\u043e\u043b\u044c\u043e\u0432\u0430\u043d\u043e \u0432 \u043a\u0430\u0440\u0430\u043d\u0442\u0438\u043d\u0456 \u2014 \u0437\u0430\u0440\u0430\u0437\u0430 \u0434\u0430\u043b\u0456 \u043d\u0435 \u043f\u043e\u0448\u0438\u0440\u0438\u043b\u0430\u0441\u044f.\");\n            } else {\n              const target = pickAliveTarget(\"infect_target_\" + p.num);\n              if (target &#038;&#038; !target.hasIllness){\n                S.newIllness[target.num] = p.illness;\n                incidentLines.push(\"[\u0425\u0432\u043e\u0440\u043e\u0431\u0438] \u0417\u0430\u0440\u0430\u0437\u0430 \u043f\u0435\u0440\u0435\u0439\u0448\u043b\u0430 \u0434\u043e \u0413\u0440\u0430\u0432\u0446\u044f \" + target.num + \".\");\n              }\n            }\n            triggerMoodHit(incidentLines, \"\u0441\u043c\u0435\u0440\u0442\u044c \u0432\u0456\u0434 \u0445\u0432\u043e\u0440\u043e\u0431\u0438\");\n          }\n        }\n      }\n    });\n    Object.keys(S.newIllness).forEach(num => {\n      const p = S.scenario.find(pl => pl.num == num);\n      if (p && !p.hasIllness){ p.hasIllness = true; p.illness = S.newIllness[num]; S.diseaseState[num] = \"active\"; }\n    });\n    S.newIllness = {};\n  }\n\n  if (incidents.includes(\"\u041f\u043e\u043b\u043e\u043c\u043a\u0438\")){\n    const breakdownLevel = dayLevel(\"\u0422\u0435\u0445\u043d\u0456\u0447\u043d\u0435 \u043e\u0431\u0441\u043b\u0443\u0433\u043e\u0432\u0443\u0432\u0430\u043d\u043d\u044f\");\n    const techPower = classLevel(\"\u0422\u0435\u0445\u043d\u0456\u0447\u043d\u0435 \u043e\u0431\u0441\u043b\u0443\u0433\u043e\u0432\u0443\u0432\u0430\u043d\u043d\u044f\") + S.techCarryBonus;\n    const bchance = techPower >= breakdownLevel\n      ? Math.min(0.97, 0.85 + (techPower - breakdownLevel) * 0.03)\n      : techPower \/ (techPower + breakdownLevel);\n    if (dayRoll(\"breakdown\") < bchance){\n      incidentLines.push(\"[\u041f\u043e\u043b\u043e\u043c\u043a\u0438] \u0423\u0441\u0443\u043d\u0443\u0442\u043e \u0442\u0435\u0445\u043d\u0456\u043a\u043e\u043c (\u0441\u043a\u043b\u0430\u0434\u043d\u0456\u0441\u0442\u044c \" + breakdownLevel + \", \u0440\u0456\u0432\u0435\u043d\u044c \" + techPower + \").\");\n      S.techCarryBonus = 0;\n    } else {\n      S.techCarryBonus += 1;\n      incidentLines.push(\"[\u041f\u043e\u043b\u043e\u043c\u043a\u0438] \u041d\u0435 \u0443\u0441\u0443\u043d\u0443\u0442\u043e (\u0441\u043a\u043b\u0430\u0434\u043d\u0456\u0441\u0442\u044c \" + breakdownLevel + \") \u2014 \u0441\u043f\u0440\u043e\u0431\u0430 \u043f\u0440\u043e\u0434\u043e\u0432\u0436\u0438\u0442\u044c\u0441\u044f \u0437\u0430\u0432\u0442\u0440\u0430 \u0437 \u0431\u043e\u043d\u0443\u0441\u043e\u043c.\");\n      triggerMoodHit(incidentLines, \"\u043f\u043e\u043b\u043e\u043c\u043a\u0430\");\n    }\n  }\n\n  if (incidents.includes(\"\u041d\u0430\u043f\u0430\u0434\u0456\u043d\u043d\u044f\")){\n    const attackLevel = dayLevel(\"\u0417\u0430\u0445\u0438\u0441\u0442\");\n    const defPower = classLevel(\"\u0417\u0430\u0445\u0438\u0441\u0442\");\n    if (defPower >= attackLevel){\n      incidentLines.push(\"[\u041d\u0430\u043f\u0430\u0434\u0456\u043d\u043d\u044f] \u0412\u0456\u0434\u0431\u0438\u0442\u043e \u0431\u0435\u0437 \u0440\u0438\u0437\u0438\u043a\u0443 (\u0441\u0438\u043b\u0430 \" + attackLevel + \", \u043e\u0431\u043e\u0440\u043e\u043d\u0430 \" + defPower + \").\");\n    } else {\n      const achance = defPower \/ (defPower + attackLevel);\n      if (dayRoll(\"attack\") < achance){\n        incidentLines.push(\"[\u041d\u0430\u043f\u0430\u0434\u0456\u043d\u043d\u044f] \u0412\u0456\u0434\u0431\u0438\u0442\u043e (\u0441\u0438\u043b\u0430 \" + attackLevel + \", \u043e\u0431\u043e\u0440\u043e\u043d\u0430 \" + defPower + \").\");\n      } else {\n        const gap = attackLevel - defPower;\n        const target = pickAliveTarget(\"attack_target\");\n        if (gap <= 2){\n          incidentLines.push(\"[\u041d\u0430\u043f\u0430\u0434\u0456\u043d\u043d\u044f] \u041f\u0440\u043e\u0440\u0432\u0430\u043b\u043e\u0441\u044f \u2014 \u0437\u043d\u0438\u043a\u043b\u0430 \u0447\u0430\u0441\u0442\u0438\u043d\u0430 \u043f\u0440\u043e\u0432\u0456\u0437\u0456\u0457\/\u0431\u0430\u0433\u0430\u0436\u0443.\");\n        } else if (gap <= 4){\n          if (target) S.baggageLost[target.num] = true;\n          incidentLines.push(\"[\u041d\u0430\u043f\u0430\u0434\u0456\u043d\u043d\u044f] \u041f\u0440\u043e\u0440\u0432\u0430\u043b\u043e\u0441\u044f \u2014 \u0413\u0440\u0430\u0432\u0435\u0446\u044c \" + (target ? target.num : \"?\") + \" \u0432\u0442\u0440\u0430\u0442\u0438\u0432 \u0446\u0456\u043d\u043d\u0438\u0439 \u0440\u0435\u0441\u0443\u0440\u0441.\");\n        } else {\n          if (target) S.eliminated[target.num] = true;\n          incidentLines.push(\"[\u041d\u0430\u043f\u0430\u0434\u0456\u043d\u043d\u044f] \u041f\u0440\u043e\u0440\u0432\u0430\u043b\u043e\u0441\u044f \u0432\u0430\u0436\u043a\u043e \u2014 \u0413\u0440\u0430\u0432\u0435\u0446\u044c \" + (target ? target.num : \"?\") + \" \u0437\u0430\u0433\u0438\u043d\u0443\u0432.\");\n        }\n        triggerMoodHit(incidentLines, \"\u043d\u0430\u043f\u0430\u0434\u0456\u043d\u043d\u044f\");\n      }\n    }\n  }\n\n  S.collapseLog.unshift({ day:S.day, meterLines, incidentLines });\n\n  S.day += 1;\n  S.phase = \"reveal\";\n  S.turnSeen = {};\n  const aliveAllNext = aliveScenario().map(p => p.num);\n  S.turn = aliveAllNext.length ? aliveAllNext[0] : S.turn;\n  if (aliveAllNext.length) settleTurn(S.turn);\n\n  saveLocal();\n  renderRoom();\n}\n\n\/* ===================== \u0421\u041e\u0421\u0422\u041e\u042f\u041d\u0418\u0415 ===================== *\/\n\nconst S = {\n  roomCode:null, seed:null, playerCount:0, myPlayer:0, botCount:0,\n  turn:1, scenario:null, unlocked:{}, eliminated:{}, announced:{},\n  day:1, phase:\"reveal\", turnSeen:{},\n  mood:{}, diseaseState:{}, techCarryBonus:0, moodLoop:{},\n  baggageLost:{}, hungerPenalty:{}, collapseLog:[], newIllness:{}, _evtCounter:0,\n  foodStock:0,\n  myAppearance:{skin:0, hair:0, eyes:0, mouth:0}, appearanceCodes:{}, _apSetup:false, uiTab:\"situation\",\n  situation:null, quarantine:{}\n};\n\nfunction storageKey(){ return \"bunker::\" + S.roomCode + \"::\" + S.myPlayer; }\nfunction saveLocal(){\n  if (!CONFIG.persist) return;\n  localStorage.setItem(storageKey(), JSON.stringify({\n    turn:S.turn, unlocked:S.unlocked, eliminated:S.eliminated, announced:S.announced,\n    day:S.day, phase:S.phase, turnSeen:S.turnSeen,\n    mood:S.mood, diseaseState:S.diseaseState, techCarryBonus:S.techCarryBonus, moodLoop:S.moodLoop,\n    baggageLost:S.baggageLost, hungerPenalty:S.hungerPenalty, collapseLog:S.collapseLog, foodStock:S.foodStock,\n    myAppearance:S.myAppearance, appearanceCodes:S.appearanceCodes, quarantine:S.quarantine,\n    illnessOverrides: S.scenario.filter(p => p.hasIllness).map(p => ({num:p.num, name:p.illness.name, severity:p.illness.severity}))\n  }));\n  localStorage.setItem(\"bunker::last\", JSON.stringify({roomCode:S.roomCode, myPlayer:S.myPlayer, playerCount:S.playerCount, seed:S.seed, botCount:S.botCount}));\n}\nfunction loadLocal(){\n  if (!CONFIG.persist) return;\n  const raw = localStorage.getItem(storageKey());\n  if (raw){\n    try{\n      const d = JSON.parse(raw);\n      S.turn = d.turn || 1;\n      S.unlocked = d.unlocked || {};\n      S.eliminated = d.eliminated || {};\n      S.announced = d.announced || {};\n      S.day = d.day || 1;\n      S.phase = d.phase || \"reveal\";\n      S.turnSeen = d.turnSeen || {};\n      S.mood = d.mood || {};\n      S.diseaseState = d.diseaseState || {};\n      S.techCarryBonus = d.techCarryBonus || 0;\n      S.moodLoop = d.moodLoop || {};\n      S.baggageLost = d.baggageLost || {};\n      S.hungerPenalty = d.hungerPenalty || {};\n      S.collapseLog = d.collapseLog || [];\n      S.foodStock = d.foodStock === undefined ? S.foodStock : d.foodStock;\n      S.myAppearance = d.myAppearance || S.myAppearance;\n      S.quarantine = d.quarantine || {};\n      S.appearanceCodes = d.appearanceCodes || {};\n      (d.illnessOverrides || []).forEach(o => {\n        const p = S.scenario.find(pl => pl.num === o.num);\n        if (p && !p.hasIllness){ p.hasIllness = true; p.illness = {name:o.name, severity:o.severity}; }\n      });\n    }catch(e){}\n  }\n}\nfunction clearSavedRoom(){\n  localStorage.removeItem(storageKey());\n  localStorage.removeItem(\"bunker::last\");\n}\nfunction togglePersist(){\n  CONFIG.persist = !CONFIG.persist;\n  if (CONFIG.persist){ saveLocal(); } else { clearSavedRoom(); }\n  renderRoom();\n}\n\n\/* ===================== \u042d\u041a\u0420\u0410\u041d\u042b ===================== *\/\n\nconst app = document.getElementById(\"app\");\n\nfunction screenHome(){\n  localStorage.removeItem(\"bunker::last\");\n  app.innerHTML = `\n    <h1>\u0411\u0423\u041d\u041a\u0415\u0420 :: \u041a\u041e\u041d\u0421\u041e\u041b\u042c v0.1<\/h1>\n    <div class=\"box\">\n      <div class=\"menu-line dim\">\u041e\u0431\u0435\u0440\u0456\u0442\u044c \u0434\u0456\u044e:<\/div>\n      <div class=\"menu-line\"><button data-action=\"home-create\">[1] \u0421\u0442\u0432\u043e\u0440\u0438\u0442\u0438 \u043f\u0430\u0440\u0442\u0456\u044e<\/button><\/div>\n      <div class=\"menu-line\"><button data-action=\"home-join\">[2] \u041f\u0456\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u0438\u0441\u044f<\/button><\/div>\n    <\/div>\n  `;\n}\n\nfunction screenCreate(){\n  app.innerHTML = `\n    <h1>\u0421\u0422\u0412\u041e\u0420\u0415\u041d\u041d\u042f \u041f\u0410\u0420\u0422\u0406\u0407<\/h1>\n    <div class=\"box\">\n      <div class=\"menu-line\">\u041a\u0456\u043b\u044c\u043a\u0456\u0441\u0442\u044c \u0433\u0440\u0430\u0432\u0446\u0456\u0432 (2\u201312):<\/div>\n      <div class=\"menu-line\"><input id=\"playerCountInput\" type=\"number\" min=\"2\" max=\"12\" value=\"5\"><\/div>\n      <div class=\"menu-line\">\u0417 \u043d\u0438\u0445 \u0431\u043e\u0442\u0456\u0432 (0 \u2014 \u0431\u0435\u0437 \u0431\u043e\u0442\u0456\u0432):<\/div>\n      <div class=\"menu-line\"><input id=\"botCountInput\" type=\"number\" min=\"0\" max=\"11\" value=\"0\"><\/div>\n      <div class=\"rules-hint dim\">\u0411\u043e\u0442\u0438 \u0437\u0430\u0439\u043c\u0430\u044e\u0442\u044c \u043e\u0441\u0442\u0430\u043d\u043d\u0456 \u043d\u043e\u043c\u0435\u0440\u0438. \u0407\u0445\u043d\u0456 \u043f\u043e\u043b\u044f \u043e\u0434\u0440\u0430\u0437\u0443 \u0432\u0438\u0434\u043d\u043e \u0432\u0441\u0456\u043c \u2014 \u043e\u0437\u0432\u0443\u0447\u0443\u0432\u0430\u0442\u0438 \u0437\u0430 \u043d\u0438\u0445 \u043d\u0456\u0447\u043e\u0433\u043e \u043d\u0435 \u043f\u043e\u0442\u0440\u0456\u0431\u043d\u043e.<\/div>\n      <div class=\"menu-line\">\n        <button class=\"accent-btn\" data-action=\"do-create\">\u0421\u0442\u0432\u043e\u0440\u0438\u0442\u0438<\/button>\n        <button data-action=\"back-home\">\u041d\u0430\u0437\u0430\u0434<\/button>\n      <\/div>\n    <\/div>\n  `;\n}\n\nfunction screenJoin(){\n  app.innerHTML = `\n    <h1>\u041f\u0406\u0414\u041a\u041b\u042e\u0427\u0415\u041d\u041d\u042f<\/h1>\n    <div class=\"box\">\n      <div class=\"menu-line\">\u041a\u043e\u0434 \u043a\u0456\u043c\u043d\u0430\u0442\u0438 (\u043f\u0440\u0438\u043a\u043b\u0430\u0434: 5-K3J9QZ-2):<\/div>\n      <div class=\"menu-line\"><input id=\"roomCodeInput\" type=\"text\" placeholder=\"N-XXXXXX-B\" style=\"width:220px;\"><\/div>\n      <div class=\"menu-line\">\u0412\u0430\u0448 \u043d\u043e\u043c\u0435\u0440 \u0433\u0440\u0430\u0432\u0446\u044f:<\/div>\n      <div class=\"menu-line\"><input id=\"myPlayerInput\" type=\"number\" min=\"1\" max=\"20\" value=\"2\"><\/div>\n      <div class=\"menu-line\">\n        <button class=\"accent-btn\" data-action=\"do-join\">\u041f\u0456\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u0438\u0441\u044f<\/button>\n        <button data-action=\"back-home\">\u041d\u0430\u0437\u0430\u0434<\/button>\n      <\/div>\n    <\/div>\n  `;\n}\n\nfunction isBot(num){\n  return S.botCount > 0 && num > S.playerCount - S.botCount;\n}\n\nfunction screenAppearanceSetup(){\n  S._apSetup = true;\n  const a = S.myAppearance;\n  const idCode = getMyIdCode();\n  const groupBtns = (cat, list) => list.map((opt, i) =>\n    `<button class=\"small ${a[cat] === i ? \"accent-btn\" : \"\"}\" data-action=\"set-appearance\" data-cat=\"${cat}\" data-idx=\"${i}\">${opt.name}<\/button>`\n  ).join(\" \");\n  app.innerHTML = `\n    <h1>\u0417\u041e\u0412\u041d\u0406\u0428\u041d\u0406\u0421\u0422\u042c \u041f\u0415\u0420\u0421\u041e\u041d\u0410\u0416\u0410<\/h1>\n    <div class=\"box\">\n      <div class=\"rules-hint dim\">\u041d\u0430\u043b\u0430\u0448\u0442\u0443\u0439 \u0430\u0432\u0430\u0442\u0430\u0440 \u2014 \u043f\u043e\u0442\u0456\u043c \u0439\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u0430 \u0437\u043c\u0456\u043d\u0438\u0442\u0438 \u043a\u043d\u043e\u043f\u043a\u043e\u044e \u00ab\u0417\u043c\u0456\u043d\u0438\u0442\u0438 \u0437\u043e\u0432\u043d\u0456\u0448\u043d\u0456\u0441\u0442\u044c\u00bb \u043d\u0430 \u0441\u0432\u043e\u0457\u0439 \u043a\u0430\u0440\u0442\u0446\u0456.<\/div>\n      <div style=\"display:flex; gap:16px; align-items:flex-start; flex-wrap:wrap; margin-bottom:14px;\">\n        <div>${renderAvatarHtml(a, false)}<\/div>\n        <div style=\"flex:1; min-width:200px;\">\n          <div class=\"appearance-group\"><span class=\"field-label\">\u0428\u043a\u0456\u0440\u0430:<\/span> ${groupBtns(\"skin\", SKIN_OPTIONS)}<\/div>\n          <div class=\"appearance-group\"><span class=\"field-label\">\u0417\u0430\u0447\u0456\u0441\u043a\u0430:<\/span> ${groupBtns(\"hair\", HAIRSTYLES)}<\/div>\n          <div class=\"appearance-group\"><span class=\"field-label\">\u041e\u0447\u0456:<\/span> ${groupBtns(\"eyes\", EYE_STYLES)}<\/div>\n          <div class=\"appearance-group\"><span class=\"field-label\">\u0420\u043e\u0442:<\/span> ${groupBtns(\"mouth\", MOUTH_STYLES)}<\/div>\n        <\/div>\n      <\/div>\n      <div class=\"rules-hint dim\">\n        \u0422\u0432\u043e\u0454 \u043f\u043e\u0441\u0432\u0456\u0434\u0447\u0435\u043d\u043d\u044f \u043e\u0441\u043e\u0431\u0438 (\u0440\u043e\u043b\u044c + \u0437\u043e\u0432\u043d\u0456\u0448\u043d\u0456\u0441\u0442\u044c \u0432 \u043e\u0434\u043d\u043e\u043c\u0443 \u043a\u043e\u0434\u0456) \u2014 \u043d\u0430\u0437\u0432\u0438 \u0439\u043e\u0433\u043e \u043f\u0435\u0440\u0448\u0438\u043c \u043f\u0456\u0434 \u0447\u0430\u0441 \u0437\u043d\u0430\u0439\u043e\u043c\u0441\u0442\u0432\u0430:\n      <\/div>\n      <div class=\"code-tag\" style=\"font-size:16px; display:inline-block; margin-bottom:14px;\">${idCode}<\/div>\n      <div class=\"menu-line\">\n        <button class=\"accent-btn\" data-action=\"finish-appearance\">\u041f\u0440\u043e\u0434\u043e\u0432\u0436\u0438\u0442\u0438 \u0434\u043e \u043a\u0456\u043c\u043d\u0430\u0442\u0438<\/button>\n      <\/div>\n    <\/div>\n  `;\n}\n\nfunction getMyIdCode(){\n  const me = S.scenario.find(p => p.num === S.myPlayer);\n  if (!me) return \"--------\";\n  return me.passwords.profession + encodeAppearance(S.myAppearance);\n}\n\nfunction finishAppearanceSetup(){\n  S._apSetup = false;\n  saveLocal();\n  renderRoom();\n}\n\nfunction editAppearance(){\n  screenAppearanceSetup();\n}\n\nfunction setTab(tab){\n  S.uiTab = tab;\n  renderRoom();\n}\n\n\/\/ \u0414\u0435\u0442\u0435\u0440\u043c\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439, \u043d\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u0448\u0430\u043d\u043d\u044b\u0439 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0431\u043e\u0442\u0430 \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0440\u0430\u0441\u043a\u0440\u044b\u0442\u0438\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432.\nfunction botFieldOrder(num){\n  const scored = FIELD_ORDER.map((f, i) => ({ f, r: seedRoll(\"bot_field_order_\" + num + \"_\" + i + \"_\" + f) }));\n  scored.sort((a, b) => a.r - b.r);\n  return scored.map(x => x.f);\n}\nfunction botReveal(num){\n  S.unlocked[num] = S.unlocked[num] || {};\n  const order = botFieldOrder(num);\n  const next = order.find(f => !S.unlocked[num][f]);\n  if (next) S.unlocked[num][next] = true;\n}\nfunction settleTurn(num){\n  if (isBot(num)) botReveal(num);\n  S.turnSeen[num] = true;\n}\n\nfunction doCreate(){\n  const n = parseInt(document.getElementById(\"playerCountInput\").value, 10);\n  if (!n || n < 2 || n > 12){ alert(\"\u0412\u0432\u0435\u0434\u0456\u0442\u044c \u043a\u0456\u043b\u044c\u043a\u0456\u0441\u0442\u044c \u0433\u0440\u0430\u0432\u0446\u0456\u0432 \u0432\u0456\u0434 2 \u0434\u043e 12\"); return; }\n  const botCount = parseInt(document.getElementById(\"botCountInput\").value, 10) || 0;\n  if (botCount < 0 || botCount >= n){ alert(\"\u0411\u043e\u0442\u0456\u0432 \u043c\u0430\u0454 \u0431\u0443\u0442\u0438 \u043c\u0435\u043d\u0448\u0435, \u043d\u0456\u0436 \u0437\u0430\u0433\u0430\u043b\u044c\u043d\u0430 \u043a\u0456\u043b\u044c\u043a\u0456\u0441\u0442\u044c \u0433\u0440\u0430\u0432\u0446\u0456\u0432\"); return; }\n  const seed = randomSeedString(6);\n  S.seed = seed;\n  S.playerCount = n;\n  S.botCount = botCount;\n  S.roomCode = n + \"-\" + seed + \"-\" + botCount;\n  S.myPlayer = 1;\n  S.turn = 1;\n  S.unlocked = {};\n  S.eliminated = {};\n  S.day = 1; S.phase = \"reveal\"; S.turnSeen = {1:true};\n  S.mood = {}; S.diseaseState = {}; S.techCarryBonus = 0; S.moodLoop = {};\n  S.baggageLost = {}; S.hungerPenalty = {}; S.collapseLog = []; S.newIllness = {};\n  S.foodStock = n * 3;\n  S.appearanceCodes = {};\n  S.uiTab = \"situation\";\n  S.scenario = generateScenario(seed, n);\n  S.situation = generateSituation(seed, n);\n  S.quarantine = {};\n  loadLocal();\n  saveLocal();\n  screenAppearanceSetup();\n}\n\nfunction doJoin(){\n  const code = document.getElementById(\"roomCodeInput\").value.trim().toUpperCase();\n  const m = code.match(\/^(\\d+)-([A-Z0-9]+)(?:-(\\d+))?$\/);\n  if (!m){ alert(\"\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u0438\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u043a\u043e\u0434\u0443 \u043a\u0456\u043c\u043d\u0430\u0442\u0438. \u041f\u0440\u0438\u043a\u043b\u0430\u0434: 5-K3J9QZ-2\"); return; }\n  const n = parseInt(m[1], 10);\n  const seed = m[2];\n  const botCount = m[3] ? parseInt(m[3], 10) : 0;\n  const myPlayer = parseInt(document.getElementById(\"myPlayerInput\").value, 10);\n  if (!myPlayer || myPlayer < 1){ alert(\"\u0412\u043a\u0430\u0436\u0456\u0442\u044c \u0441\u0432\u0456\u0439 \u043d\u043e\u043c\u0435\u0440 \u0433\u0440\u0430\u0432\u0446\u044f\"); return; }\n  if (myPlayer > n - botCount){ alert(\"\u0426\u0435\u0439 \u043d\u043e\u043c\u0435\u0440 \u0437\u0430\u0440\u0435\u0437\u0435\u0440\u0432\u043e\u0432\u0430\u043d\u0438\u0439 \u0434\u043b\u044f \u0431\u043e\u0442\u0430 \u2014 \u043e\u0431\u0435\u0440\u0456\u0442\u044c \u043d\u043e\u043c\u0435\u0440 \u0432\u0456\u0434 1 \u0434\u043e \" + (n - botCount)); return; }  S.seed = seed;\n  S.playerCount = n;\n  S.botCount = botCount;\n  S.roomCode = code;\n  S.myPlayer = myPlayer;\n  S.turn = 1;\n  S.unlocked = {};\n  S.eliminated = {};\n  S.day = 1; S.phase = \"reveal\"; S.turnSeen = {1:true};\n  S.mood = {}; S.diseaseState = {}; S.techCarryBonus = 0; S.moodLoop = {};\n  S.baggageLost = {}; S.hungerPenalty = {}; S.collapseLog = []; S.newIllness = {};\n  S.foodStock = n * 3;\n  S.appearanceCodes = {};\n  S.uiTab = \"situation\";\n  S.scenario = generateScenario(seed, n);\n  S.situation = generateSituation(seed, n);\n  S.quarantine = {};\n  loadLocal();\n  saveLocal();\n  screenAppearanceSetup();\n}\n\nfunction turnStep(delta){\n  const aliveAll = aliveScenario().map(p => p.num);\n  if (aliveAll.length === 0) return;\n  let idx = aliveAll.indexOf(S.turn);\n  if (idx === -1) idx = 0;\n  let num, safety = 0;\n  do {\n    idx = (idx + delta + aliveAll.length) % aliveAll.length;\n    num = aliveAll[idx];\n    if (S.phase === \"reveal\") settleTurn(num);\n    safety++;\n  } while (isBot(num) && safety < aliveAll.length + 2);\n  S.turn = num;\n  if (S.phase === \"reveal\" &#038;&#038; aliveAll.every(n => S.turnSeen[n])) S.phase = \"vote\";\n  saveLocal();\n  renderRoom();\n}\n\nfunction tryUnlockAny(playerNum){\n  playerNum = parseInt(playerNum, 10);\n  const input = document.querySelector('input.pw-input[data-player=\"' + playerNum + '\"]');\n  if (!input) return;\n  const val = input.value.trim().toUpperCase();\n  if (!val) return;\n  const p = S.scenario.find(pl => pl.num === playerNum);\n  S.unlocked[playerNum] = S.unlocked[playerNum] || {};\n  const match = FIELD_ORDER.find(f => !S.unlocked[playerNum][f] && p.passwords[f] === val);\n  if (match){\n    S.unlocked[playerNum][match] = true;\n    input.value = \"\";\n    saveLocal();\n    renderRoom();\n  } else {\n    input.classList.add(\"shake\");\n    setTimeout(() => input.classList.remove(\"shake\"), 300);\n  }\n}\n\nfunction setAppearance(cat, idx){\n  S.myAppearance[cat] = parseInt(idx, 10);\n  saveLocal();\n  if (S._apSetup) screenAppearanceSetup(); else renderRoom();\n}\n\nfunction scanId(playerNum){\n  playerNum = parseInt(playerNum, 10);\n  const input = document.querySelector('input.id-input[data-player=\"' + playerNum + '\"]');\n  if (!input) return;\n  const raw = input.value.trim().toUpperCase().replace(\/[^A-Z0-9]\/g, \"\");\n  if (raw.length !== 8){\n    input.classList.add(\"shake\");\n    setTimeout(() => input.classList.remove(\"shake\"), 300);\n    return;\n  }\n  const profPart = raw.slice(0, 4);\n  const apPart = raw.slice(4, 8);\n  const p = S.scenario.find(pl => pl.num === playerNum);\n  let matched = false;\n  if (p.passwords.profession === profPart){\n    S.unlocked[playerNum] = S.unlocked[playerNum] || {};\n    S.unlocked[playerNum].profession = true;\n    matched = true;\n  }\n  if (decodeAppearance(apPart)){\n    S.appearanceCodes[playerNum] = apPart;\n    matched = true;\n  }\n  if (matched){\n    input.value = \"\";\n    saveLocal();\n    renderRoom();\n  } else {\n    input.classList.add(\"shake\");\n    setTimeout(() => input.classList.remove(\"shake\"), 300);\n  }\n}\n\nfunction quarantineOccupant(){\n  const num = Object.keys(S.quarantine).find(k => S.quarantine[k]);\n  return num ? parseInt(num, 10) : null;\n}\n\nfunction toggleQuarantine(playerNum){\n  playerNum = parseInt(playerNum, 10);\n  if (!S.situation || !S.situation.rooms.quarantine) return;\n  const currentlyIn = !!S.quarantine[playerNum];\n  if (!currentlyIn){\n    const occupant = quarantineOccupant();\n    if (occupant !== null && occupant !== playerNum){\n      alert(\"\u041a\u0430\u0440\u0430\u043d\u0442\u0438\u043d\u043d\u0430 \u043a\u0430\u043c\u0435\u0440\u0430 \u0440\u043e\u0437\u0440\u0430\u0445\u043e\u0432\u0430\u043d\u0430 \u043d\u0430 \u043e\u0434\u043d\u043e\u0433\u043e \u2014 \u0441\u043f\u043e\u0447\u0430\u0442\u043a\u0443 \u0432\u0438\u0432\u0435\u0434\u0456\u0442\u044c \u0437\u0432\u0456\u0434\u0442\u0438 \u0413\u0440\u0430\u0432\u0446\u044f \" + occupant + \".\");\n      return;\n    }\n  }\n  S.quarantine[playerNum] = !currentlyIn;\n  saveLocal();\n  renderRoom();\n}\n\nfunction toggleElim(playerNum){\n  playerNum = parseInt(playerNum, 10);\n  const alreadyElim = !!S.eliminated[playerNum];\n  if (!alreadyElim && S.phase !== \"vote\"){\n    alert(\"\u0413\u043e\u043b\u043e\u0441\u0443\u0432\u0430\u043d\u043d\u044f \u0432\u0456\u0434\u043a\u0440\u0438\u0454\u0442\u044c\u0441\u044f \u043b\u0438\u0448\u0435 \u043f\u0456\u0441\u043b\u044f \u0442\u043e\u0433\u043e, \u044f\u043a \u0447\u0435\u0440\u0433\u0430 \u043f\u0440\u043e\u0439\u0434\u0435 \u0432\u0441\u0456\u0445 \u0436\u0438\u0432\u0438\u0445 \u0433\u0440\u0430\u0432\u0446\u0456\u0432.\");\n    return;\n  }\n  S.eliminated[playerNum] = !alreadyElim;\n  saveLocal();\n  renderRoom();\n}\n\nfunction toggleAnnounced(field){\n  S.announced[field] = !S.announced[field];\n  saveLocal();\n  renderRoom();\n}\n\nfunction goHome(){\n  localStorage.removeItem(\"bunker::last\");\n  screenHome();\n}\n\nfunction renderRoom(){\n  const isUnlocked = (num, field) => !!(S.unlocked[num] && S.unlocked[num][field]);\n  const voteOpen = S.phase === \"vote\";\n  const aliveAll = aliveScenario().map(p => p.num);\n  const seenCount = aliveAll.filter(n => S.turnSeen[n]).length;\n  if (!S.uiTab) S.uiTab = \"me\";\n\n  let meCardHtml = \"\";\n  let othersCardsHtml = \"\";\n\n  S.scenario.forEach(p => {\n    const mine = p.num === S.myPlayer;\n    const bot = isBot(p.num);\n    const elim = !!S.eliminated[p.num];\n    const mood = S.mood[p.num] === undefined ? 6 : S.mood[p.num];\n    const looped = !!S.moodLoop[p.num];\n    let fieldsHtml = \"\";\n\n    FIELD_ORDER.forEach(f => {\n      const label = FIELD_LABELS[f];\n      if (mine){\n        const said = !!S.announced[f];\n        fieldsHtml += `\n          <div class=\"field-row ${said ? \"said\" : \"\"}\">\n            <span class=\"field-label\">${label}:<\/span> ${fieldValue(p, f)}\n            <div class=\"lock-row\">\n              <span class=\"pw-tag\">\u043f\u0430\u0440\u043e\u043b\u044c \u0434\u043b\u044f \u043e\u0433\u043e\u043b\u043e\u0448\u0435\u043d\u043d\u044f: ${p.passwords[f]}<\/span>\n              <button class=\"small ${said ? \"accent-btn\" : \"\"}\" data-action=\"toggle-said\" data-field=\"${f}\">\n                ${said ? \"\u2713 \u0421\u043a\u0430\u0437\u0430\u043d\u043e\" : \"\u041f\u043e\u0437\u043d\u0430\u0447\u0438\u0442\u0438 \u044f\u043a \u0441\u043a\u0430\u0437\u0430\u043d\u0435\"}\n              <\/button>\n            <\/div>\n          <\/div>`;\n      } else if (isUnlocked(p.num, f)){\n        fieldsHtml += `\n          <div class=\"field-row\">\n            <span class=\"field-label\">${label}:<\/span> ${fieldValue(p, f)}\n          <\/div>`;\n      } else {\n        fieldsHtml += `\n          <div class=\"field-row\">\n            <span class=\"field-label\">${label}:<\/span> \ud83d\udd12 <span class=\"dim\">\u043f\u0440\u0438\u0445\u043e\u0432\u0430\u043d\u043e<\/span>\n          <\/div>`;\n      }\n    });\n\n    if (!mine && !bot){\n      const remaining = FIELD_ORDER.filter(f => !isUnlocked(p.num, f)).length;\n      fieldsHtml += `\n        <div class=\"lock-row\" style=\"margin-top:6px;\">\n          <input class=\"pw-input\" type=\"text\" maxlength=\"4\" placeholder=\"\u043a\u043e\u0434 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\" data-player=\"${p.num}\">\n          <button class=\"small\" data-action=\"unlock-any\" data-player=\"${p.num}\">\u0412\u0456\u0434\u043a\u0440\u0438\u0442\u0438<\/button>\n          ${remaining ? `<span class=\"dim\" style=\"font-size:12px;\">\u0437\u0430\u043b\u0438\u0448\u0438\u043b\u043e\u0441\u044f: ${remaining}<\/span>` : `<span class=\"dim\" style=\"font-size:12px;\">\u0443\u0441\u0435 \u0440\u043e\u0437\u043a\u0440\u0438\u0442\u043e<\/span>`}\n        <\/div>`;\n    } else if (bot){\n      const revealed = FIELD_ORDER.filter(f => isUnlocked(p.num, f)).length;\n      fieldsHtml += `\n        <div class=\"field-row dim\" style=\"font-size:12px; margin-top:2px;\">\n          \ud83e\udd16 \u0440\u043e\u0437\u043a\u0440\u0438\u0432\u0430\u0454 \u0441\u0430\u043c \u0443 \u043f\u0440\u043e\u0446\u0435\u0441\u0456 \u043a\u043e\u043b\u0430: ${revealed}\/${FIELD_ORDER.length}\n        <\/div>`;\n    }\n\n    const saidCounter = `<span class=\"dim\" style=\"font-size:12px;\">\u0441\u043a\u0430\u0437\u0430\u043d\u043e: ${FIELD_ORDER.filter(f => S.announced[f]).length}\/${FIELD_ORDER.length}<\/span>`;\n    let elimBtn;\n    if (elim){\n      elimBtn = `<button class=\"small\" data-action=\"toggle-elim\" data-player=\"${p.num}\">\u041f\u043e\u0432\u0435\u0440\u043d\u0443\u0442\u0438<\/button>`;\n    } else if (voteOpen){\n      elimBtn = `<button class=\"small danger-btn\" data-action=\"toggle-elim\" data-player=\"${p.num}\">\u0412\u0438\u0433\u043d\u0430\u0442\u0438<\/button>`;\n    } else {\n      elimBtn = `<button class=\"small\" disabled title=\"\u0414\u043e\u0441\u0442\u0443\u043f\u043d\u043e \u043f\u0456\u0441\u043b\u044f \u043f\u043e\u0432\u043d\u043e\u0433\u043e \u043a\u043e\u043b\u0430\">\u0412\u0438\u0433\u043d\u0430\u0442\u0438<\/button>`;\n    }\n    const inQuarantine = !!S.quarantine[p.num];\n    const qOccupant = quarantineOccupant();\n    const qBlocked = !inQuarantine && qOccupant !== null && qOccupant !== p.num;\n    const quarantineBtn = (S.situation && S.situation.rooms.quarantine && !elim)\n      ? (qBlocked\n          ? `<button class=\"small\" disabled title=\"\u041a\u0430\u043c\u0435\u0440\u0430 \u0437\u0430\u0439\u043d\u044f\u0442\u0430 \u0413\u0440\u0430\u0432\u0446\u0435\u043c ${qOccupant}\">\u0414\u043e \u043a\u0430\u0440\u0430\u043d\u0442\u0438\u043d\u0443<\/button>`\n          : `<button class=\"small ${inQuarantine ? \"accent-btn\" : \"\"}\" data-action=\"toggle-quarantine\" data-player=\"${p.num}\">${inQuarantine ? \"\u0406\u0437 \u043a\u0430\u0440\u0430\u043d\u0442\u0438\u043d\u0443\" : \"\u0414\u043e \u043a\u0430\u0440\u0430\u043d\u0442\u0438\u043d\u0443\"}<\/button>`)\n      : \"\";\n    const kickBtn = mine\n      ? `<div style=\"display:flex; gap:8px; align-items:center; flex-wrap:wrap;\">${saidCounter}${quarantineBtn}${elimBtn}<\/div>`\n      : `<div style=\"display:flex; gap:6px; align-items:center; flex-wrap:wrap;\">${quarantineBtn}${elimBtn}<\/div>`;\n\n    let avatarHtml;\n    if (mine){\n      avatarHtml = `\n        <div class=\"field-row\" style=\"display:flex; gap:12px; align-items:center; flex-wrap:wrap;\">\n          ${renderAvatarHtml(S.myAppearance, false)}\n          <div>\n            <div class=\"pw-tag\">\u043f\u043e\u0441\u0432\u0456\u0434\u0447\u0435\u043d\u043d\u044f \u043e\u0441\u043e\u0431\u0438: ${getMyIdCode()}<\/div>\n            <button class=\"small\" style=\"margin-top:4px;\" data-action=\"edit-appearance\">\u0417\u043c\u0456\u043d\u0438\u0442\u0438 \u0437\u043e\u0432\u043d\u0456\u0448\u043d\u0456\u0441\u0442\u044c<\/button>\n          <\/div>\n        <\/div>`;\n    } else if (bot){\n      const botAppearance = {\n        skin: Math.floor(seedRoll(\"bot_skin_\" + p.num) * SKIN_OPTIONS.length),\n        hair: Math.floor(seedRoll(\"bot_hair_\" + p.num) * HAIRSTYLES.length),\n        eyes: Math.floor(seedRoll(\"bot_eyes_\" + p.num) * EYE_STYLES.length),\n        mouth: Math.floor(seedRoll(\"bot_mouth_\" + p.num) * MOUTH_STYLES.length)\n      };\n      avatarHtml = `<div class=\"field-row\">${renderAvatarHtml(botAppearance, false)}<\/div>`;\n    } else {\n      const code = S.appearanceCodes[p.num];\n      const decoded = code ? decodeAppearance(code) : null;\n      const idKnown = isUnlocked(p.num, \"profession\");\n      avatarHtml = `\n        <div class=\"field-row\" style=\"display:flex; gap:10px; align-items:center; flex-wrap:wrap;\">\n          ${decoded ? renderAvatarHtml(decoded, false) : renderAvatarHtml(null, true)}\n          <div class=\"lock-row\">\n            <input class=\"id-input\" type=\"text\" maxlength=\"9\" placeholder=\"\u043f\u043e\u0441\u0432\u0456\u0434\u0447\u0435\u043d\u043d\u044f\" data-player=\"${p.num}\" style=\"width:110px;\">\n            <button class=\"small\" data-action=\"scan-id\" data-player=\"${p.num}\">\u0420\u043e\u0437\u043f\u0456\u0437\u043d\u0430\u0442\u0438<\/button>\n          <\/div>\n          ${idKnown ? `<span class=\"pw-tag\" style=\"font-size:11px;\">\u0440\u043e\u043b\u044c \u0443\u0436\u0435 \u0432\u0456\u0434\u043e\u043c\u0430<\/span>` : \"\"}\n        <\/div>`;\n    }\n\n    const cardHtml = `\n      <div class=\"card ${mine ? \"me\" : \"\"} ${elim ? \"elim\" : \"\"}\">\n        <div class=\"card-head\">\n          <h3 style=\"margin:0;\">\u0413\u0440\u0430\u0432\u0435\u0446\u044c ${p.num}${bot ? \" \ud83e\udd16\" : \"\"}${mine ? \" (\u0412\u0418)\" : \"\"}${inQuarantine && !elim ? \" \ud83e\udda0\" : \"\"}${elim ? \" \u2014 \u0412\u0418\u0411\u0423\u0412\" : \"\"}<\/h3>\n          ${kickBtn}\n        <\/div>\n        ${avatarHtml}\n        ${!elim ? `<div class=\"field-row dim\">\u041d\u0430\u0441\u0442\u0440\u0456\u0439: ${mood}\/10${looped ? \" \u2014 <span class='danger'>\u0443 \u043f\u0435\u0442\u043b\u0456, \u0440\u043e\u043b\u044c \u043e\u0441\u043b\u0430\u0431\u043b\u0435\u043d\u0430<\/span>\" : \"\"}<\/div>` : \"\"}\n        ${fieldsHtml}\n      <\/div>`;\n\n    if (mine) meCardHtml += cardHtml; else othersCardsHtml += cardHtml;\n  });\n\n  const logHtml = S.collapseLog.map(entry => `\n    <div class=\"box\" style=\"margin-bottom:8px;\">\n      <div class=\"accent\" style=\"margin-bottom:6px;\">\u0414\u0435\u043d\u044c ${entry.day}<\/div>\n      <div style=\"margin-bottom:6px;\">\n        <div class=\"dim\" style=\"font-size:11px; text-transform:uppercase; letter-spacing:1px;\">\u041c\u0435\u0442\u0440\u0438\u043a\u0438 (\u0457\u0436\u0430 \/ \u043d\u0430\u0441\u0442\u0440\u0456\u0439)<\/div>\n        ${entry.meterLines.map(l => `<div style=\"font-size:13px;\">${l}<\/div>`).join(\"\")}\n      <\/div>\n      <div>\n        <div class=\"dim\" style=\"font-size:11px; text-transform:uppercase; letter-spacing:1px;\">\u041f\u0440\u0438\u0433\u043e\u0434\u0438<\/div>\n        ${entry.incidentLines.map(l => `<div style=\"font-size:13px;\" class=\"${l.indexOf(\"\u0437\u0430\u0433\u0438\u043d\u0443\u0432\") !== -1 || l.indexOf(\"\u043d\u0435 \u0434\u043e\u043f\u043e\u043c\u043e\u0433\u043b\u043e\") !== -1 ? \"danger\" : \"\"}\">${l}<\/div>`).join(\"\")}\n      <\/div>\n    <\/div>\n  `).join(\"\");\n\n  const tabBtn = (id, label) => `<button class=\"tab-btn ${S.uiTab === id ? \"active\" : \"\"}\" data-action=\"set-tab\" data-tab=\"${id}\">${label}<\/button>`;\n  let tabContent = \"\";\n  if (S.uiTab === \"situation\"){\n    tabContent = renderSituationHtml();\n  } else if (S.uiTab === \"me\"){\n    tabContent = meCardHtml;\n  } else if (S.uiTab === \"others\"){\n    tabContent = `<div class=\"grid\">${othersCardsHtml}<\/div>`;\n  } else if (S.uiTab === \"log\"){\n    tabContent = logHtml ? `<div class=\"log-scroll\">${logHtml}<\/div>` : `<div class=\"dim\">\u041f\u043e\u043a\u0438 \u0449\u043e \u043f\u043e\u0440\u043e\u0436\u043d\u044c\u043e \u2014 \u0436\u0443\u0440\u043d\u0430\u043b \u0437\u0430\u043f\u043e\u0432\u043d\u0438\u0442\u044c\u0441\u044f \u043f\u0456\u0441\u043b\u044f \u043f\u0435\u0440\u0448\u043e\u0433\u043e \u043a\u043e\u043b\u0430\u043f\u0441\u0443 \u0434\u043d\u044f.<\/div>`;\n  }\n\n  app.innerHTML = `\n    <div class=\"topbar\">\n      <div>\n        <div class=\"dim\">\u041a\u0456\u043c\u043d\u0430\u0442\u0430:<\/div>\n        <span class=\"code-tag\">${S.roomCode}<\/span>\n        <span class=\"dim\"> \u00b7 \u0433\u0440\u0430\u0432\u0435\u0446\u044c ${S.myPlayer}\/${S.playerCount}${S.botCount ? \" (\u0431\u043e\u0442\u0456\u0432: \" + S.botCount + \")\" : \"\"} \u00b7 \u0434\u0435\u043d\u044c ${S.day} \u00b7 \u0437\u0430\u043f\u0430\u0441 \u0457\u0436\u0456 ${S.foodStock}\/${S.playerCount * 6}<\/span>\n      <\/div>\n      <div class=\"turn-box\">\n        <button class=\"small\" data-action=\"turn-prev\">\u2039<\/button>\n        <span>\u0417\u0430\u0440\u0430\u0437 \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c: <span class=\"accent\">\u0433\u0440\u0430\u0432\u0435\u0446\u044c ${S.turn}<\/span><\/span>\n        <button class=\"small\" data-action=\"turn-next\">\u203a<\/button>\n      <\/div>\n      <div>\n        <button class=\"small\" data-action=\"toggle-persist\">\u0410\u0432\u0442\u043e\u0437\u0431\u0435\u0440\u0435\u0436\u0435\u043d\u043d\u044f: ${CONFIG.persist ? \"\u0423\u0412\u0406\u041c\u041a\" : \"\u0412\u0418\u041c\u041a\"}<\/button>\n        <button class=\"small\" data-action=\"back-home\">\u0412\u0438\u0439\u0442\u0438 \u0432 \u043c\u0435\u043d\u044e<\/button>\n      <\/div>\n    <\/div>\n    <div class=\"rules-hint dim\">\n      ${voteOpen\n        ? `\u041a\u043e\u043b\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043e (${seenCount}\/${aliveAll.length}) \u2014 \u0433\u043e\u043b\u043e\u0441\u0443\u0432\u0430\u043d\u043d\u044f \u0432\u0456\u0434\u043a\u0440\u0438\u0442\u043e. \u041f\u043e\u0437\u043d\u0430\u0447\u0442\u0435 \u0432\u0438\u0433\u043d\u0430\u043d\u043e\u0433\u043e \u0442\u0430 \u0437\u0430\u043f\u0443\u0441\u0442\u0456\u0442\u044c \u043a\u043e\u043b\u0430\u043f\u0441 \u0434\u043d\u044f.`\n        : `\u041a\u043e\u043b\u043e: \u043e\u0437\u0432\u0443\u0447\u0435\u043d\u043e ${seenCount}\/${aliveAll.length} \u0436\u0438\u0432\u0438\u0445 \u0433\u0440\u0430\u0432\u0446\u0456\u0432 (\u0431\u043e\u0442\u0438 \u0440\u043e\u0437\u043a\u0440\u0438\u0432\u0430\u044e\u0442\u044c\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u043d\u043e). \u0413\u043e\u043b\u043e\u0441\u0443\u0432\u0430\u043d\u043d\u044f \u0432\u0456\u0434\u043a\u0440\u0438\u0454\u0442\u044c\u0441\u044f, \u043a\u043e\u043b\u0438 \u0447\u0435\u0440\u0433\u0430 \u043f\u0440\u043e\u0439\u0434\u0435 \u0432\u0441\u0456\u0445.`}\n    <\/div>\n    ${voteOpen ? `<div class=\"box\"><button class=\"accent-btn\" data-action=\"collapse-day\">\u041f\u0440\u043e\u0432\u0435\u0441\u0442\u0438 \u043a\u043e\u043b\u0430\u043f\u0441 \u0434\u043d\u044f ${S.day}<\/button><\/div>` : \"\"}\n    <div class=\"tab-bar\">\n      ${tabBtn(\"situation\", \"\u0421\u0438\u0442\u0443\u0430\u0446\u0456\u044f\")}\n      ${tabBtn(\"me\", \"\u042f\")}\n      ${tabBtn(\"others\", \"\u0413\u0440\u0430\u0432\u0446\u0456 (\" + (S.playerCount - 1) + \")\")}\n      ${tabBtn(\"log\", \"\u0416\u0443\u0440\u043d\u0430\u043b\" + (S.collapseLog.length ? \" (\" + S.collapseLog.length + \")\" : \"\"))}\n    <\/div>\n    <div class=\"tab-content\">${tabContent}<\/div>\n  `;\n}\n\nfunction bunkerAnimSvg(){\n  return `\n    <svg viewBox=\"0 0 120 90\" width=\"150\" height=\"112\" class=\"bunker-svg\">\n      <rect x=\"0\" y=\"70\" width=\"120\" height=\"20\" fill=\"#101a10\"\/>\n      <path d=\"M8,70 Q60,18 112,70 Z\" fill=\"#233323\" stroke=\"#1f4d1f\" stroke-width=\"2\"\/>\n      <rect x=\"44\" y=\"44\" width=\"32\" height=\"26\" rx=\"3\" fill=\"#0a0f0a\" stroke=\"#3ee63e\" stroke-width=\"2\"\/>\n      <circle cx=\"60\" cy=\"57\" r=\"2.5\" fill=\"#3ee63e\"\/>\n      <line x1=\"92\" y1=\"36\" x2=\"92\" y2=\"14\" stroke=\"#3ee63e\" stroke-width=\"2\"\/>\n      <circle cx=\"92\" cy=\"12\" r=\"2.5\" fill=\"#3ee63e\" class=\"bunker-antenna-light\"\/>\n      <circle cx=\"60\" cy=\"28\" r=\"4\" fill=\"#ff5555\" class=\"bunker-warn-light\"\/>\n    <\/svg>`;\n}\n\nfunction renderSituationHtml(){\n  const s = S.situation;\n  if (!s) return `<div class=\"dim\">\u0421\u0446\u0435\u043d\u0430\u0440\u0456\u0439 \u0449\u0435 \u043d\u0435 \u0437\u0433\u0435\u043d\u0435\u0440\u043e\u0432\u0430\u043d\u043e.<\/div>`;\n  const roomsKnown = ROOM_POOL.filter(r => s.rooms[r.id]);\n  return `\n    <div class=\"box\" style=\"display:flex; gap:18px; align-items:center; flex-wrap:wrap;\">\n      ${bunkerAnimSvg()}\n      <div style=\"flex:1; min-width:220px;\">\n        <div class=\"accent\" style=\"margin-bottom:6px;\">\u0429\u043e \u0441\u0442\u0430\u043b\u043e\u0441\u044f<\/div>\n        <div style=\"margin-bottom:14px;\">${s.catastrophe}<\/div>\n        <div class=\"accent\" style=\"margin-bottom:6px;\">${s.bunkerType.name}<\/div>\n        <div class=\"dim\" style=\"margin-bottom:10px;\">${s.bunkerType.desc}<\/div>\n        <div style=\"margin-bottom:10px;\">${bunkerCapacityText(S.playerCount)}<\/div>\n      <\/div>\n    <\/div>\n    <div class=\"box\">\n      <div class=\"accent\" style=\"margin-bottom:8px;\">\u041e\u0441\u043e\u0431\u043b\u0438\u0432\u0456 \u043f\u0440\u0438\u043c\u0456\u0449\u0435\u043d\u043d\u044f<\/div>\n      ${roomsKnown.length\n        ? roomsKnown.map(r => `<div class=\"field-row\"><span class=\"field-label\">${r.name}:<\/span> ${r.desc}<\/div>`).join(\"\")\n        : `<div class=\"dim\">\u0423 \u0446\u044c\u043e\u043c\u0443 \u0431\u0443\u043d\u043a\u0435\u0440\u0456 \u043e\u0441\u043e\u0431\u043b\u0438\u0432\u0438\u0445 \u043f\u0440\u0438\u043c\u0456\u0449\u0435\u043d\u044c \u043d\u0435 \u0432\u0438\u044f\u0432\u0438\u043b\u043e\u0441\u044f \u2014 \u043b\u0438\u0448\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0456 \u0432\u0456\u0434\u0441\u0456\u043a\u0438.<\/div>`}\n    <\/div>\n  `;\n}\n\n\n\/* ===================== \u0421\u041e\u0411\u042b\u0422\u0418\u042f ===================== *\/\n\napp.addEventListener(\"click\", function(e){\n  const t = e.target;\n  if (t.matches('[data-action=\"home-create\"]')) return screenCreate();\n  if (t.matches('[data-action=\"home-join\"]')) return screenJoin();\n  if (t.matches('[data-action=\"do-create\"]')) return doCreate();\n  if (t.matches('[data-action=\"do-join\"]')) return doJoin();\n  if (t.matches('[data-action=\"back-home\"]')) return goHome();\n  if (t.matches('[data-action=\"turn-prev\"]')) return turnStep(-1);\n  if (t.matches('[data-action=\"turn-next\"]')) return turnStep(1);\n  if (t.matches('[data-action=\"unlock-any\"]')) return tryUnlockAny(t.dataset.player);\n  if (t.matches('[data-action=\"toggle-elim\"]')) return toggleElim(t.dataset.player);\n  if (t.matches('[data-action=\"toggle-said\"]')) return toggleAnnounced(t.dataset.field);\n  if (t.matches('[data-action=\"collapse-day\"]')) return collapseDay();\n  if (t.matches('[data-action=\"toggle-persist\"]')) return togglePersist();\n  if (t.matches('[data-action=\"set-appearance\"]')) return setAppearance(t.dataset.cat, t.dataset.idx);\n  if (t.matches('[data-action=\"scan-id\"]')) return scanId(t.dataset.player);\n  if (t.matches('[data-action=\"edit-appearance\"]')) return editAppearance();\n  if (t.matches('[data-action=\"finish-appearance\"]')) return finishAppearanceSetup();\n  if (t.matches('[data-action=\"set-tab\"]')) return setTab(t.dataset.tab);\n  if (t.matches('[data-action=\"toggle-quarantine\"]')) return toggleQuarantine(t.dataset.player);\n});\n\n\/* ===================== \u0421\u0422\u0410\u0420\u0422 ===================== *\/\n\n(function init(){\n  if (!CONFIG.persist){ screenHome(); return; }\n  const last = localStorage.getItem(\"bunker::last\");\n  if (last){\n    try{\n      const d = JSON.parse(last);\n      S.roomCode = d.roomCode; S.myPlayer = d.myPlayer;\n      S.playerCount = d.playerCount; S.seed = d.seed; S.botCount = d.botCount || 0;\n      S.scenario = generateScenario(S.seed, S.playerCount);\n      S.situation = generateSituation(S.seed, S.playerCount);\n      loadLocal();\n      renderRoom();\n      return;\n    }catch(e){}\n  }\n  screenHome();\n})();\n<\/script>\n<\/body>\n<\/html>\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u0411\u0423\u041d\u041a\u0415\u0420 :: \u043a\u043e\u043d\u0441\u043e\u043b\u044c<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"open","template":"","meta":{"footnotes":""},"class_list":["post-2","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.object.ks.ua\/index.php?rest_route=\/wp\/v2\/pages\/2","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.object.ks.ua\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.object.ks.ua\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.object.ks.ua\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.object.ks.ua\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2"}],"version-history":[{"count":2,"href":"https:\/\/www.object.ks.ua\/index.php?rest_route=\/wp\/v2\/pages\/2\/revisions"}],"predecessor-version":[{"id":8,"href":"https:\/\/www.object.ks.ua\/index.php?rest_route=\/wp\/v2\/pages\/2\/revisions\/8"}],"wp:attachment":[{"href":"https:\/\/www.object.ks.ua\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}