[
    {
        "id": "375436e4-e238-45f4-93ae-3d358057138c",
        "scriptName": "杀全文缩进",
        "disabled": true,
        "runOnEdit": true,
        "findRegex": "/^[ \\t]+/gm",
        "trimStrings": [
            "`",
            "``",
            "```"
        ],
        "replaceString": "",
        "placement": [
            2
        ],
        "substituteRegex": 0,
        "minDepth": null,
        "maxDepth": null,
        "markdownOnly": true,
        "promptOnly": true
    },
    {
        "id": "bd6ce261-500f-44a5-926b-b2279f475ffe",
        "scriptName": "杀代码块（可选，炸了不管）",
        "findRegex": "^([\\s\\S]*)$",
        "replaceString": "$1",
        "trimStrings": [
            "```html",
            "```HTML",
            "```json",
            "```JSON",
            "`"
        ],
        "placement": [
            2
        ],
        "disabled": true,
        "markdownOnly": true,
        "promptOnly": true,
        "runOnEdit": true,
        "substituteRegex": 0,
        "minDepth": null,
        "maxDepth": null
    },
    {
        "id": "89790128-985c-4971-accb-9e7f70894c80",
        "scriptName": "【0】抗截断",
        "disabled": false,
        "runOnEdit": false,
        "findRegex": "<math>([\\s\\S]*?)<\\/math>",
        "trimStrings": [],
        "replaceString": "",
        "placement": [
            2
        ],
        "substituteRegex": 0,
        "minDepth": null,
        "maxDepth": null,
        "markdownOnly": true,
        "promptOnly": true
    },
    {
        "id": "2e396b25-eec5-4d07-97f4-314e5df5484a",
        "scriptName": "MoM-双人成行-I.清除多余内容 - 03.07",
        "disabled": false,
        "runOnEdit": true,
        "findRegex": "/死死[的地]?|一抹|极其|由于|病态的|舐|生理性的?|霸道的?地?|<VariableCheck>[\\s\\S]*<\\/VariableCheck>|(?<=<p style)-|\\s<finish>(?!.+<finish>).*$/gis",
        "trimStrings": [],
        "replaceString": "",
        "placement": [
            2
        ],
        "substituteRegex": 0,
        "minDepth": null,
        "maxDepth": null,
        "markdownOnly": true,
        "promptOnly": true
    },
    {
        "id": "2203f57e-62dd-4fe6-ba09-4f1cfaa0fc7e",
        "scriptName": "MoM-双人成行II.不发送一堆 -  03.07",
        "disabled": false,
        "runOnEdit": true,
        "findRegex": "/^[\\s\\S]+</think(?:ing)?>|<quote>.+?</[^>]+>|<Shiosai.+?</Shiosai>|<branches>.+?</branches>|<snow>.+?</snow>/gis",
        "trimStrings": [],
        "replaceString": "",
        "placement": [
            2
        ],
        "substituteRegex": 0,
        "minDepth": null,
        "maxDepth": null,
        "markdownOnly": false,
        "promptOnly": true
    },
    {
        "id": "909f8de2-817f-49ed-b9d5-c69e62807fb8",
        "scriptName": "MoM-双人成行-III.5楼外只发送摘要 - 12.30",
        "disabled": false,
        "runOnEdit": true,
        "findRegex": "/^.+(<meow_FM>.+</meow_FM>).*$/is",
        "trimStrings": [],
        "replaceString": "$1",
        "placement": [
            2
        ],
        "substituteRegex": 0,
        "minDepth": 5,
        "maxDepth": null,
        "markdownOnly": false,
        "promptOnly": true
    },
    {
        "id": "fcf80a75-acd1-4dee-96cf-4e2da1727553",
        "scriptName": "MoM-双人成行-IV.10楼外伏笔不发送 - 12.30",
        "disabled": false,
        "runOnEdit": true,
        "findRegex": "/(?<=<meow_FM>[\\s\\S]+?)seeds[:：][\\s\\S]+?(?=seri[\\w]{0,4}[:：]\\s*no\\..+)/i",
        "trimStrings": [],
        "replaceString": "",
        "placement": [
            2
        ],
        "substituteRegex": 0,
        "minDepth": 10,
        "maxDepth": null,
        "markdownOnly": false,
        "promptOnly": true
    },
    {
        "id": "e44fd6d0-bb4c-4307-809b-6fa0f6ec736a",
        "scriptName": "抗空回去除",
        "disabled": false,
        "runOnEdit": true,
        "findRegex": "<Q>([\\s\\S]*?)<\\/WF>",
        "trimStrings": [],
        "replaceString": "",
        "placement": [
            2
        ],
        "substituteRegex": 0,
        "minDepth": null,
        "maxDepth": null,
        "markdownOnly": true,
        "promptOnly": true
    },
    {
        "id": "3e739a01-a5fb-475f-9c10-0e25995359ab",
        "scriptName": "去除html注释",
        "findRegex": "/<!--\\s*([\\s\\S]*?)\\s*-->/g",
        "replaceString": "",
        "trimStrings": [],
        "placement": [
            2
        ],
        "disabled": false,
        "markdownOnly": true,
        "promptOnly": true,
        "runOnEdit": true,
        "substituteRegex": 0,
        "minDepth": null,
        "maxDepth": null
    },
    {
        "id": "cf3ae9d8-f5f9-465d-a719-727eec8672aa",
        "scriptName": "Fin.流光CoT",
        "findRegex": "/^([\\s\\S]*)(?:<!-- 1·思考结束 -->|<!-- end_of_Subtext_think -->|<\\/think(?:ing)?>)/i",
        "replaceString": "<style>\n.pf-wrap {\n  border-radius: 16px;\n  border: 1px solid rgba(150, 150, 150, 0.15);\n  background: rgba(127, 127, 127, 0.08); \n  backdrop-filter: blur(24px);\n  -webkit-backdrop-filter: blur(24px);\n  box-shadow: 0 4px 20px rgba(0,0,0,0.15);\n  margin: 8px 0;\n  overflow: hidden;\n}\n.pf-head {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  gap: 10px;\n  padding: 12px 20px 12px 20px; \n  height: 40px;\n  cursor: pointer;\n  font-family: Consolas, 'SF Mono', monospace;\n  font-size: 11px;\n  letter-spacing: 0.2em;\n  color: rgba(56, 189, 248, 0.85);\n  text-transform: uppercase;\n  box-sizing: border-box;\n  outline: none; \n}\n.pf-head::-webkit-details-marker { display: none; }\n.pf-dot {\n  width: 8px;\n  height: 8px;\n  border-radius: 50%;\n  background: #38bdf8;\n  box-shadow: 0 0 12px rgba(56, 189, 248, 0.7);\n  animation: pf-pulse 2s infinite;\n}\ndetails[open].pf-wrap .pf-head { \n  border-bottom: 1px solid rgba(150, 150, 150, 0.1); \n}\n.pf-body {\n  padding: 16px 20px 6px 20px; \n  font-size: 13px;\n  line-height: 1.2;\n  max-height: 280px;\n  overflow-y: auto;\n  white-space: pre-line; \n  overflow-wrap: break-word;\n  box-sizing: border-box;\n}\n.pf-body::-webkit-scrollbar {width:5px;}\n.pf-body::-webkit-scrollbar-thumb {background:rgba(150,150,150,.2);border-radius:5px;}\n\n@keyframes pf-pulse {\n  0%, 100% { opacity: 1; }\n  50% { opacity: 0.4; }\n}\n</style>\n\n<details class=\"pf-wrap\"><summary class=\"pf-head\"><div class=\"pf-dot\"></div><span>ᴘʀɪꜱᴍ//ғᴏх</span></summary><div class=\"pf-body\">$1</div></details>\n",
        "trimStrings": [
            "<thinking>",
            "</thinking>",
            "<think>",
            "</think>",
            " ",
            "`",
            "<",
            ">",
            "<!-- end_of_Subtext_think -->"
        ],
        "placement": [
            2
        ],
        "disabled": false,
        "markdownOnly": true,
        "promptOnly": false,
        "runOnEdit": true,
        "substituteRegex": 0,
        "minDepth": null,
        "maxDepth": null
    },
    {
        "id": "9f978430-aa48-4f09-ae9d-3df695d16a14",
        "scriptName": "Fin.隐藏CoT",
        "findRegex": "^[\\s\\S]*?### 正文",
        "replaceString": "",
        "trimStrings": [],
        "placement": [
            2
        ],
        "disabled": true,
        "markdownOnly": true,
        "promptOnly": true,
        "runOnEdit": true,
        "substituteRegex": 0,
        "minDepth": null,
        "maxDepth": null
    },
    {
        "id": "8a4eb9e1-514f-4a01-b12f-e950fa7334ce",
        "scriptName": "隐藏### 正文",
        "findRegex": "/### 正文\\s*/g",
        "replaceString": "",
        "trimStrings": [],
        "placement": [
            2
        ],
        "disabled": false,
        "markdownOnly": true,
        "promptOnly": false,
        "runOnEdit": true,
        "substituteRegex": 0,
        "minDepth": null,
        "maxDepth": null
    },
    {
        "id": "297fc74c-87b4-4f46-9c76-ae409c841ed5",
        "scriptName": "Fin.心理描写",
        "disabled": false,
        "runOnEdit": true,
        "findRegex": "/(?<=<p style=\")(color:\\s*#[\\dA-Z]+?;)/gi",
        "trimStrings": [],
        "replaceString": "$1font-style: italic;",
        "placement": [
            2
        ],
        "substituteRegex": 0,
        "minDepth": null,
        "maxDepth": null,
        "markdownOnly": true,
        "promptOnly": false
    },
    {
        "id": "2d02bf12-861c-42a1-b1d4-288d272858bf",
        "scriptName": "Fin.时间流光美化",
        "findRegex": "/<time_format>([\\s\\S]*?)<\\/time_format>/gi",
        "replaceString": "<style>\n/* Time Format 专属作用域 (tf-)，避免与 Prism Fox 冲突 */\n.tf-container {\n  display: flex;\n  justify-content: center;\n  width: 100%;\n  margin: 4px 0; /* 修改：将上下外边距从 8px 减小到 4px */\n}\n.tf-wrap {\n  width: fit-content;\n  min-width: 240px;\n  max-width: 100%;\n  border-radius: 16px;\n  border: 1px solid rgba(150, 150, 150, 0.15);\n  background: rgba(127, 127, 127, 0.08);\n  backdrop-filter: blur(24px);\n  -webkit-backdrop-filter: blur(24px);\n  box-shadow: 0 4px 20px rgba(0,0,0,0.15);\n  overflow: hidden;\n  transition: all 0.4s ease;\n}\n.tf-wrap:hover {\n  border-color: rgba(56, 189, 248, 0.3);\n  box-shadow: 0 6px 24px rgba(56, 189, 248, 0.1), 0 8px 32px rgba(0,0,0,0.3);\n}\n.tf-head {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  padding: 8px 12px; /* 修改：将全局 12px 改为上下 8px、左右 12px */\n  cursor: pointer;\n  user-select: none;\n  list-style: none;\n  transition: all 0.3s;\n}\n.tf-head::-webkit-details-marker { display: none; }\ndetails[open].tf-wrap .tf-head {\n  border-bottom: 1px solid rgba(150, 150, 150, 0.1);\n}\n.tf-title {\n  font-size: 12px;\n  color: rgba(56, 189, 248, 0.85);\n  font-family: Consolas, monospace;\n  letter-spacing: 0.15em;\n  padding: 4px 14px; /* 修改：将上下内边距从 6px 减小到 4px */\n  transition: all 0.3s;\n}\n.tf-wrap:hover .tf-title {\n  color: rgba(56, 189, 248, 1);\n  text-shadow: 0 0 12px rgba(56, 189, 248, 0.3);\n}\n.tf-body {\n  padding: 12px 16px; /* 修改：将全局 16px 改为上下 12px、左右 16px */\n  font-size: 13px;\n  line-height: 1.5;   /* 修改：将行高从 1.6 微调到 1.5 让多行文本更紧凑 */\n  max-height: 280px;\n  overflow-y: auto;\n  scrollbar-width: thin;\n  scrollbar-color: rgba(150, 150, 150, 0.3) transparent;\n  white-space: pre-wrap;\n  word-wrap: break-word; \n}\n.tf-body::-webkit-scrollbar { width: 4px; }\n.tf-body::-webkit-scrollbar-thumb { background: rgba(150, 150, 150, 0.3); border-radius: 4px; }\n</style>\n\n<div class=\"tf-container\">\n  <details class=\"tf-wrap\">\n    <summary class=\"tf-head\">\n      <span class=\"tf-title\">✧ Time Format ✧</span>\n    </summary>\n    <div class=\"tf-body\">$1</div>\n  </details>\n</div>",
        "trimStrings": [],
        "placement": [
            2
        ],
        "disabled": false,
        "markdownOnly": true,
        "promptOnly": false,
        "runOnEdit": true,
        "substituteRegex": 0,
        "minDepth": null,
        "maxDepth": null
    },
    {
        "id": "2e38f7e1-aa9c-44d1-87a9-c6ded6f6fb7a",
        "scriptName": "Fin.流光摘要",
        "findRegex": "/(?:.*?)(?:```\\n?)?<meow_FM>(?![\\s\\S]+<meow_FM>)\\s*time[:：]\\s*(.+)☆(.+)\\s*scene[:：]\\s*(.+)\\s*chars[:：]\\s*([\\s\\S]+)\\s*plot[:：]\\s*([\\s\\S]+?)(?:\\s*seeds[:：]\\s*([\\s\\S]+))?\\s+seri[\\w]{0,4}[:：]\\s*(.+)\\s*</[^>]*>(?:\\n?```)?/i",
        "replaceString": "<style>\n/* 专属作用域 ds- (Data Summary)，避免全局冲突 */\n.ds-wrap {\n  border-radius: 16px;\n  border: 1px solid rgba(150, 150, 150, 0.15);\n  background: rgba(127, 127, 127, 0.08);\n  backdrop-filter: blur(24px);\n  -webkit-backdrop-filter: blur(24px);\n  box-shadow: 0 4px 20px rgba(0,0,0,0.15);\n  margin: 8px 0;\n  transition: all 0.4s ease;\n  width: 100%;\n  box-sizing: border-box;\n}\n.ds-wrap:hover {\n  border-color: rgba(56, 189, 248, 0.3);\n  box-shadow: 0 6px 24px rgba(56, 189, 248, 0.1), 0 8px 32px rgba(0,0,0,0.3);\n}\nsummary::-webkit-details-marker { display: none; } \n\n/* 主面板头部 (适配超长标题) */\n.ds-head {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  gap: 10px;\n  padding: 14px 16px; /* 移动端略微缩减内边距 */\n  cursor: pointer;\n  user-select: none;\n  list-style: none;\n  transition: all 0.3s;\n}\ndetails[open].ds-wrap > .ds-head { border-bottom: 1px solid rgba(150, 150, 150, 0.1); }\n.ds-dot {\n  width: 6px;\n  height: 6px;\n  flex-shrink: 0; /* 防止原点被挤压 */\n  border-radius: 50%;\n  background: #38bdf8;\n  box-shadow: 0 0 8px rgba(56, 189, 248, 0.7);\n  animation: ds-pulse 2s infinite;\n}\ndetails[open].ds-wrap > .ds-head .ds-dot { animation: none; box-shadow: 0 0 4px rgba(56, 189, 248, 0.5); }\n.ds-lb { \n  font-size: 12px; \n  font-family: Consolas, 'SF Mono', monospace; \n  letter-spacing: 0.15em; \n  color: rgba(56, 189, 248, 0.85); \n  transition: color 0.3s; \n  text-align: center;\n  word-wrap: break-word; /* 适配超长标题自动换行 */\n}\n.ds-wrap:hover .ds-lb { color: rgba(56, 189, 248, 1); }\n\n/* 主面板内容区 */\n.ds-body { padding: 16px; }\n\n/* 元数据栏 (流式换行，完美适配手机) */\n.ds-meta {\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  flex-wrap: wrap; /* 空间不足时自动换行 */\n  gap: 12px;\n  padding-bottom: 16px;\n  border-bottom: 1px solid rgba(150, 150, 150, 0.1);\n  margin-bottom: 16px;\n}\n.ds-loc { \n  display: flex; \n  align-items: center; \n  gap: 8px; \n  color: rgba(56, 189, 248, 0.85); \n  font-size: 13px; \n  flex: 1 1 auto; /* 自动填充空间 */\n  min-width: 140px; \n}\n.ds-loc svg { flex-shrink: 0; filter: drop-shadow(0 0 4px rgba(56, 189, 248, 0.7)); }\n.ds-tm { \n  display: flex; \n  flex-direction: column; \n  align-items: flex-end; \n  gap: 4px; \n  font-size: 12px; \n  flex-shrink: 0; \n}\n@media (max-width: 400px) {\n  /* 极窄屏幕下时间靠左对齐 */\n  .ds-tm { align-items: flex-start; flex-basis: 100%; } \n  .ds-tm-l { opacity: 0; } /* 极窄时隐藏渐变线 */\n}\n.ds-tm-p { color: rgba(56, 189, 248, 0.85); font-family: Consolas, 'SF Mono', monospace; }\n.ds-tm-s { color: rgba(150, 150, 150, 0.8); font-style: italic; }\n.ds-tm-l { width: 100%; height: 1px; background: linear-gradient(to right, rgba(56, 189, 248, 0.7), transparent); opacity: 0.5; }\n\n/* Plot 内容区 */\n.ds-plot {\n  padding: 14px;\n  border-radius: 12px;\n  background: rgba(127, 127, 127, 0.05);\n  border-left: 3px solid #38bdf8;\n  margin-bottom: 16px;\n  font-size: 14px;\n  line-height: 1.6;\n  white-space: pre-wrap;\n  word-wrap: break-word;\n  box-shadow: inset 0 0 20px rgba(56, 189, 248, 0.03);\n}\n\n/* 嵌套子面板 (自适应伸缩) */\n.ds-dr { \n  display: flex; \n  gap: 12px; \n  flex-wrap: wrap; /* 核心：移动端自动单列排布 */\n}\n.ds-db {\n  position: relative;\n  border-radius: 12px;\n  border: 1px solid rgba(150, 150, 150, 0.15);\n  background: rgba(127, 127, 127, 0.05);\n  overflow: hidden;\n  flex: 1 1 140px; /* 宽屏平分，窄屏独占一行 */\n  max-width: 100%; /* 去除原先的 200px 限制，允许手机端撑满 */\n  transition: all 0.3s;\n}\n.ds-db:hover { border-color: rgba(56, 189, 248, 0.2); box-shadow: 0 0 20px rgba(56, 189, 248, 0.06); }\n.ds-dh {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  padding: 10px;\n  cursor: pointer;\n  font-size: 12px;\n  font-family: Consolas, 'SF Mono', monospace;\n  letter-spacing: 0.15em;\n  color: rgba(150, 150, 150, 0.8);\n  user-select: none;\n  list-style: none;\n  transition: all 0.3s;\n}\n.ds-dh:hover { color: rgba(56, 189, 248, 0.85); }\ndetails[open].ds-db > .ds-dh { border-bottom: 1px solid rgba(150, 150, 150, 0.1); color: rgba(56, 189, 248, 0.85); }\n.ds-dc {\n  padding: 12px;\n  font-size: 13px;\n  line-height: 1.6;\n  max-height: 180px;\n  overflow-y: auto;\n  white-space: pre-wrap;\n  word-wrap: break-word;\n  scrollbar-width: thin;\n  scrollbar-color: rgba(150, 150, 150, 0.3) transparent;\n}\n.ds-dc::-webkit-scrollbar { width: 3px; }\n.ds-dc::-webkit-scrollbar-thumb { background: rgba(150, 150, 150, 0.3); border-radius: 3px; }\n\n/* 悬停解除模糊特效 */\n.ds-blur { filter: blur(4px); opacity: 0.8; transition: all 0.3s; }\n.ds-blur:hover { filter: blur(0); opacity: 1; }\n\n/* 底部签名 */\n.ds-ft {\n  display: flex;\n  justify-content: flex-end;\n  padding-top: 12px;\n  margin-top: 16px;\n  border-top: 1px solid rgba(150, 150, 150, 0.1);\n  font-size: 10px;\n  color: rgba(150, 150, 150, 0.6);\n  font-family: Consolas, 'SF Mono', monospace;\n  letter-spacing: 0.1em;\n}\n\n@keyframes ds-pulse {\n  0%, 100% { opacity: 1; box-shadow: 0 0 8px rgba(56, 189, 248, 0.7); }\n  50% { opacity: 0.4; box-shadow: 0 0 4px rgba(56, 189, 248, 0.3); }\n}\n</style>\n\n<details class=\"ds-wrap\">\n  <summary class=\"ds-head\">\n    <div class=\"ds-dot\"></div>\n    <span class=\"ds-lb\">˹ $7 ˺ DATA SUMMARY</span>\n  </summary>\n  \n  <div class=\"ds-body\">\n    <div class=\"ds-meta\">\n      <div class=\"ds-loc\">\n        <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z\"></path><circle cx=\"12\" cy=\"10\" r=\"3\"></circle></svg>\n        <span>$3</span>\n      </div>\n      <div class=\"ds-tm\">\n        <span class=\"ds-tm-p\">$1</span>\n        <div class=\"ds-tm-l\"></div>\n        <span class=\"ds-tm-s\">$2</span>\n      </div>\n    </div>\n    \n    <div class=\"ds-plot\">$5</div>\n    \n    <div class=\"ds-dr\">\n      <details class=\"ds-db\">\n        <summary class=\"ds-dh\">CHARS</summary>\n        <div class=\"ds-dc\">$4</div>\n      </details>\n      \n      <details class=\"ds-db\">\n        <summary class=\"ds-dh\">SEEDS</summary>\n        <div class=\"ds-dc ds-blur\">$6</div>\n      </details>\n    </div>\n    \n    <div class=\"ds-ft\">— ᴘʀɪꜱᴍ//ғᴏх</div>\n  </div>\n</details>",
        "trimStrings": [
            "**"
        ],
        "placement": [
            2
        ],
        "disabled": false,
        "markdownOnly": true,
        "promptOnly": false,
        "runOnEdit": true,
        "substituteRegex": 0,
        "minDepth": null,
        "maxDepth": null
    },
    {
        "id": "c2cb3477-5b12-4dcd-a3a4-3e94eca935a9",
        "scriptName": "双人成行-流光选项栏",
        "findRegex": "/<branches>(?!.*<branches>)\\s*(?:<details>.*?</summary>\\s*)?(.+?)(?:</details>\\s*)?</[^>]*>/is",
        "replaceString": "```html\n<!DOCTYPE html><html lang=\"zh-CN\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\"><style>\n*{margin:0;padding:0;box-sizing:border-box}body{padding:8px 12px;margin:0;background:transparent;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,\"Noto Sans SC\",sans-serif;-webkit-font-smoothing:antialiased}.wrap{border-radius:16px;border:1px solid rgba(150,150,150,.15);background:rgba(127,127,127,.08);backdrop-filter:blur(24px);-webkit-backdrop-filter:blur(24px);box-shadow:0 8px 32px rgba(0,0,0,.15);margin:8px 0;transition:all .4s ease;width:100%;max-width:720px;color:rgba(255,255,255,.9)}.wrap:hover{border-color:rgba(56,189,248,.3);box-shadow:0 10px 40px rgba(0,0,0,.2)}.head{display:flex;align-items:center;gap:10px;padding:14px 20px;cursor:pointer;user-select:none;list-style:none;outline:none}.head::-webkit-details-marker{display:none}details[open].wrap > .head{border-bottom:1px solid rgba(150,150,150,.1)}.dot{width:8px;height:8px;border-radius:50%;background:#38bdf8;box-shadow:0 0 10px rgba(56,189,248,.8);animation:pulse 2s infinite;flex-shrink:0}details[open].wrap .dot{animation:none;box-shadow:0 0 4px rgba(56,189,248,.5)}.title{font-size:11px;font-family:Consolas,monospace;letter-spacing:.2em;text-transform:uppercase;color:rgba(56,189,248,.85)}.body{padding:16px;display:flex;flex-direction:column;gap:12px}.option-item{position:relative;width:100%;text-align:left;padding:16px 20px;border-radius:14px;overflow:hidden;border:1px solid rgba(150,150,150,.15);background:rgba(127,127,127,.05);cursor:pointer;outline:none;-webkit-tap-highlight-color:transparent;opacity:0;transform:translateY(15px);animation:flyIn .5s forwards;transition:all .3s ease}.option-item:hover{border-color:rgba(56,189,248,.4);transform:scale(1.01);box-shadow:0 8px 24px rgba(0,0,0,.15)}.option-item:active{transform:scale(.98)}.spotlight-border{pointer-events:none;position:absolute;inset:-1px;border-radius:14px;opacity:0;transition:opacity .3s}.spotlight-inner{pointer-events:none;position:absolute;inset:0;border-radius:14px;opacity:0;transition:opacity .3s}.option-item:hover .spotlight-border,.option-item:hover .spotlight-inner{opacity:1}.option-content{position:relative;z-index:2;display:flex;align-items:center;justify-content:space-between;gap:16px}.option-left{display:flex;align-items:center;gap:16px;min-width:0}.option-index{display:flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:50%;background:rgba(150,150,150,.1);border:1px solid rgba(150,150,150,.2);color:rgba(150,150,150,.8);font-size:12px;font-family:Consolas,monospace;flex-shrink:0;transition:all .3s}.option-item:hover .option-index{color:#38bdf8;border-color:rgba(56,189,248,.6);background:rgba(56,189,248,.1)}.option-text{color:inherit;font-size:14px;line-height:1.5;list-style:none}.option-arrow{flex-shrink:0;width:18px;height:18px;color:#38bdf8;opacity:0;transform:translateX(-10px);transition:all .3s}.option-item:hover .option-arrow{opacity:1;transform:translateX(0)}body.lt .wrap{background:rgba(0,0,0,.03);border-color:rgba(0,0,0,.08);box-shadow:0 4px 16px rgba(0,0,0,.05);color:rgba(0,0,0,.85)}body.lt .head{border-bottom-color:rgba(0,0,0,.08)}body.lt .option-item{background:rgba(0,0,0,.02);border-color:rgba(0,0,0,.08)}body.lt .option-item:hover{border-color:rgba(14,165,233,.4);background:rgba(14,165,233,.05)}body.lt .option-text{color:rgba(0,0,0,.85)}@keyframes flyIn{to{opacity:1;transform:translateY(0) scale(1)}}@keyframes pulse{0%,100%{opacity:1;box-shadow:0 0 10px rgba(56,189,248,.8)}50%{opacity:.4;box-shadow:0 0 4px rgba(56,189,248,.3)}}\n/* 移动端紧凑化适配 */\n@media (max-width: 600px) {\n  body { padding: 4px 8px; }\n  .head { padding: 10px 14px; }\n  .title { font-size: 10px; }\n  .body { padding: 10px; gap: 8px; }\n  .option-item { padding: 10px 14px; border-radius: 10px; }\n  .spotlight-border, .spotlight-inner { border-radius: 10px; }\n  .option-content { gap: 10px; }\n  .option-left { gap: 10px; }\n  .option-index { width: 22px; height: 22px; font-size: 11px; }\n  .option-text { font-size: 13px; }\n  .option-arrow { width: 16px; height: 16px; }\n}\n</style></head><body>\n<details class=\"wrap\" open>\n  <summary class=\"head\"><div class=\"dot\"></div><span class=\"title\">Awaiting Input</span></summary>\n  <div class=\"body\" id=\"ol\"></div>\n</details>\n<div id=\"rd\" style=\"display:none;\">$1</div>\n<script>document.addEventListener('DOMContentLoaded',function(){function syncT(){try{var p=window.parent.document;var el=p.querySelector('.mes_text')||p.body;var c=window.parent.getComputedStyle(el).color;var m=c.match(/\\d+/g);if(m){if((parseInt(m[0])*299+parseInt(m[1])*587+parseInt(m[2])*114)/1000<128)document.body.classList.add('lt');else document.body.classList.remove('lt')}}catch(e){}}syncT();setInterval(syncT,500);try{var pDoc=window.parent.document;var mesText=pDoc.querySelector('.mes_text')||pDoc.body;var syncStyle=function(){document.body.style.fontFamily=window.parent.getComputedStyle(mesText).fontFamily};syncStyle();new MutationObserver(syncStyle).observe(pDoc.body,{attributes:true,attributeFilter:['data-theme','style','class']})}catch(e){}function H(){try{var f=window.frameElement;if(f)f.style.height=document.body.scrollHeight+'px'}catch(e){}}new ResizeObserver(H).observe(document.body);setTimeout(H,100);document.querySelector('details').addEventListener('toggle',function(){setTimeout(H,50)});var d=document.getElementById('rd'),l=document.getElementById('ol');if(!d||!l)return;var rawHtml=d.innerHTML;var cleanStr=rawHtml.replace(/<br\\s*\\/?>/gi,'\\n').replace(/<\\/p>/gi,'\\n').replace(/<\\/li>/gi,'\\n');var tempDiv=document.createElement('div');tempDiv.innerHTML=cleanStr;var pureText=tempDiv.textContent||tempDiv.innerText;var lines=pureText.trim().split(/\\r?\\n/).filter(function(x){return x.trim()});lines.forEach(function(line,idx){var text=line.trim().replace(/^([0-9]+[.\\-、)]|[A-Z][.\\-、)]|\\-|\\*)\\s*/i,'');if(!text)return;var item=document.createElement('div');item.className='option-item';item.style.animationDelay=(idx*0.08)+'s';item.innerHTML='<div class=\"spotlight-border\"></div><div class=\"spotlight-inner\"></div><div class=\"option-content\"><div class=\"option-left\"><div class=\"option-index\">'+(idx+1)+'</div><div class=\"option-text\">'+text+'</div></div><svg class=\"option-arrow\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line><polyline points=\"12 5 19 12 12 19\"></polyline></svg></div>';item.addEventListener('mousemove',function(e){var rect=item.getBoundingClientRect();var x=e.clientX-rect.left;var y=e.clientY-rect.top;var lt=document.body.classList.contains('lt');var bc=lt?'rgba(0,0,0,.06)':'rgba(255,255,255,.12)';var ic=lt?'rgba(56,189,248,.12)':'rgba(56,189,248,.1)';item.querySelector('.spotlight-border').style.background='radial-gradient(600px circle at '+x+'px '+y+'px,'+bc+',transparent 40%)';item.querySelector('.spotlight-inner').style.background='radial-gradient(400px circle at '+x+'px '+y+'px,'+ic+',transparent 40%)'});item.addEventListener('mouseleave',function(){item.querySelector('.spotlight-border').style.background='';item.querySelector('.spotlight-inner').style.background=''});item.addEventListener('click',function(){try{var inp=window.parent.document.querySelector('#send_textarea');var tr=window.parent.triggerSlash;if(inp){inp.value+=text;inp.dispatchEvent(new Event('input',{bubbles:true}));inp.focus()}else if(tr){tr('/setinput '+text)}}catch(e){}});l.appendChild(item)});});</script></body></html>\n```",
        "trimStrings": [],
        "placement": [
            2
        ],
        "disabled": false,
        "markdownOnly": true,
        "promptOnly": false,
        "runOnEdit": true,
        "substituteRegex": 0,
        "minDepth": null,
        "maxDepth": 2
    },
    {
        "id": "2fdda326-20c8-4da7-98fb-83e9a6a31a95",
        "scriptName": "双语显示",
        "findRegex": "/([“\"「])([^”\"」]+)([”\"」])\\s*[（(]([^）)]+)[）)]/g",
        "replaceString": "$1<ruby>$2<rt style=\"font-size:0.85em;\">$4</rt></ruby>$3",
        "trimStrings": [],
        "placement": [
            2
        ],
        "disabled": true,
        "markdownOnly": true,
        "promptOnly": false,
        "runOnEdit": true,
        "substituteRegex": 0,
        "minDepth": null,
        "maxDepth": null
    },
    {
        "scriptName": "隐藏同人搜索内容",
        "findRegex": "<details>\\s*<summary>同人搜索内容<\\/summary>[\\s\\S]*?<\\/details>",
        "replaceString": "",
        "trimStrings": [],
        "placement": [
            2
        ],
        "disabled": false,
        "markdownOnly": true,
        "promptOnly": false,
        "runOnEdit": true,
        "substituteRegex": false,
        "minDepth": null,
        "maxDepth": null,
        "id": "3a9b3692-944d-45c0-9feb-9bb732473795"
    },
    {
        "id": "300376c7-21d1-4d7f-9a8b-a9520a40df1e",
        "scriptName": "播放器",
        "findRegex": "/<(?:角色)?状态面板>[\\s\\S]*?<诗词意境>\\s*([\\s\\S]*?)\\s*<\\/诗词意境>[\\s\\S]*?<当前播放>\\s*([\\s\\S]*?)\\s*<\\/当前播放>[\\s\\S]*?<\\/(?:角色)?状态面板>/s",
        "replaceString": "```html\n<!DOCTYPE html><html lang=\"zh-CN\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\"><title>Dynamic Widget - Prism Compact Final</title><script crossorigin src=\"https://unpkg.com/react@18/umd/react.development.js\"></script><script crossorigin src=\"https://unpkg.com/react-dom@18/umd/react-dom.development.js\"></script><script src=\"https://unpkg.com/@babel/standalone/babel.min.js\"></script><script src=\"https://drive.baibai.cv/f/ZKEBuW/Music.js\"></script><style>\n*{margin:0;padding:0;box-sizing:border-box}.prism-wrapper{width:100%;display:flex;justify-content:center;padding:16px 12px;margin:0;font-family:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,\"Noto Sans SC\",sans-serif;-webkit-font-smoothing:antialiased}.p-island{--spring-easing:cubic-bezier(0.19,1,0.22,1);position:relative;color:rgba(255,255,255,.9);border-radius:16px;border:1px solid rgba(150,150,150,.15);background:rgba(127,127,127,.08);backdrop-filter:blur(24px);-webkit-backdrop-filter:blur(24px);box-shadow:0 8px 32px rgba(0,0,0,.15);overflow:hidden;transition:width .6s var(--spring-easing),height .6s var(--spring-easing),border-radius .6s var(--spring-easing),border-color .4s,box-shadow .4s;--mouse-x:50%;--mouse-y:50%;z-index:50}.p-island.collapsed{width:240px;height:56px;border-radius:28px;cursor:pointer}.p-island.collapsed:hover{border-color:rgba(56,189,248,.3);box-shadow:0 6px 24px rgba(56,189,248,.1),0 8px 32px rgba(0,0,0,.3);transform:scale(1.02)}.p-island.collapsed:active{transform:scale(.98)}.p-island.expanded{width:340px;height:280px;cursor:default}.p-island.expanded:hover{border-color:rgba(56,189,248,.2);box-shadow:0 6px 24px rgba(56,189,248,.05),0 8px 32px rgba(0,0,0,.2)}.gb{pointer-events:none;position:absolute;inset:-1px;border-radius:inherit;opacity:0;transition:opacity .3s;z-index:0;background:radial-gradient(400px circle at var(--mouse-x) var(--mouse-y),rgba(150,150,150,.2),transparent 40%)}.gi{pointer-events:none;position:absolute;inset:0;border-radius:inherit;opacity:0;transition:opacity .3s;z-index:0;background:radial-gradient(300px circle at var(--mouse-x) var(--mouse-y),rgba(56,189,248,.15),transparent 40%)}.p-island:hover .gb,.p-island:hover .gi{opacity:1}.capsule-content{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;gap:12px;transition:all .3s ease;z-index:10;padding:0 20px}.p-island.expanded .capsule-content{opacity:0;transform:translateY(-20px);pointer-events:none}.lb{font-size:11px;font-family:Consolas,'SF Mono','Courier New',monospace;letter-spacing:.2em;text-transform:uppercase;color:rgba(56,189,248,.85);transition:color .3s;white-space:nowrap}.p-island.collapsed:hover .lb{color:rgba(56,189,248,1)}.card-content{position:absolute;inset:0;display:flex;flex-direction:column;padding:16px 20px;opacity:0;transform:translateY(20px);transition:all .5s ease .1s;pointer-events:none;z-index:10}.p-island.expanded .card-content{opacity:1;transform:translateY(0);pointer-events:auto}.meta{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;padding-bottom:12px;border-bottom:1px solid rgba(150,150,150,.1);margin-bottom:12px;position:relative;z-index:30}.meta-left{display:flex;align-items:center;gap:10px}.dot{width:8px;height:8px;border-radius:50%;background:#38bdf8;box-shadow:0 0 10px rgba(56,189,248,.8);animation:pulse 2s infinite}.main-title{font-size:1.1rem;font-weight:600;letter-spacing:.1em;color:rgba(255,255,255,.9)}.tg-close{font-size:9px;border:1px solid rgba(56,189,248,.3);padding:2px 8px;color:rgba(56,189,248,.7);font-family:Consolas,monospace;border-radius:4px;transition:all .3s;background:transparent;cursor:pointer}.tg-close:hover{color:rgba(56,189,248,1);border-color:rgba(56,189,248,.8);background:rgba(56,189,248,.1)}.content-display-area{flex:1;display:flex;flex-direction:column;justify-content:flex-start;position:relative;z-index:20}.detail-glass-box{padding:12px 16px;border-radius:12px;background:rgba(127,127,127,.05);border-left:3px solid #38bdf8;color:rgba(255,255,255,.9);font-size:13px;line-height:1.6;box-shadow:inset 0 0 20px rgba(56,189,248,.03);animation:slideUpFade .4s cubic-bezier(.2,.8,.2,1) forwards;margin-bottom:0}.dh-title{font-size:10px;font-family:Consolas,'SF Mono',monospace;letter-spacing:.15em;color:rgba(56,189,248,.85);margin-bottom:8px;border-bottom:1px solid rgba(150,150,150,.1);padding-bottom:6px}.dr{display:flex;gap:8px;justify-content:center;flex-wrap:nowrap;border-top:1px solid rgba(150,150,150,.1);padding-top:12px;z-index:30;margin-top:auto}.dh-btn{position:relative;flex:1;text-align:center;border-radius:8px;border:1px solid rgba(150,150,150,.15);background:rgba(127,127,127,.05);padding:8px;cursor:pointer;font-size:11px;font-family:Consolas,'SF Mono',monospace;letter-spacing:.1em;color:rgba(255,255,255,.68);transition:all .3s;overflow:hidden}.dh-btn:hover{border-color:rgba(56,189,248,.2);box-shadow:0 0 15px rgba(56,189,248,.06);color:rgba(56,189,248,.85)}.dh-btn.on{border-color:rgba(56,189,248,.5);background:rgba(56,189,248,.1);color:rgba(56,189,248,1)}.setting-input{width:100%;background:rgba(127,127,127,.1);border:1px solid rgba(150,150,150,.2);color:#fff;padding:6px 10px;border-radius:6px;font-family:Consolas,monospace;font-size:12px;outline:none;transition:border .3s}.setting-input:focus{border-color:rgba(56,189,248,.5);box-shadow:0 0 8px rgba(56,189,248,.2)}.text-desc{font-style:italic;opacity:.8}.mp-container{display:flex;align-items:center;gap:12px}.mp-vinyl-area{width:44px;height:44px;flex-shrink:0}.mp-vinyl-disc{width:100%;height:100%;border-radius:50%;background:radial-gradient(circle at center,#1a1a1a,#000);border:1px solid rgba(255,255,255,.1);animation:spin 4s linear infinite;animation-play-state:paused;position:relative}.mp-vinyl-disc.spinning{animation-play-state:running}.mp-vinyl-label{position:absolute;inset:30%;background:#38bdf8;border-radius:50%;border:1px solid #111;overflow:hidden;opacity:.8}.mp-vinyl-label img{width:100%;height:100%;object-fit:cover}.mp-interface{flex:1;display:flex;flex-direction:column;justify-content:center;gap:2px;min-width:0}.mp-title{font-size:12px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:rgba(255,255,255,.9)}.mp-artist{font-size:10px;font-family:Consolas,monospace;opacity:.5;text-transform:uppercase;letter-spacing:.05em;color:rgba(56,189,248,.7)}.mp-controls-stack{display:flex;flex-direction:column;gap:4px;margin-top:2px}.mp-time-row{font-family:Consolas,monospace;font-size:10px;color:rgba(255,255,255,.4);min-width:28px;text-align:right}input[type=range].mp-slider{-webkit-appearance:none;width:100%;background:transparent;outline:none;cursor:pointer;height:2px}input[type=range].mp-slider::-webkit-slider-runnable-track{width:100%;height:2px;background:rgba(255,255,255,.1);border-radius:1px}input[type=range].mp-slider::-webkit-slider-thumb{-webkit-appearance:none;height:8px;width:8px;border-radius:50%;background:#38bdf8;margin-top:-3px;box-shadow:0 0 8px rgba(56,189,248,.8);transition:transform .1s}input[type=range].mp-slider:hover::-webkit-slider-thumb{transform:scale(1.5)}.play-btn{background:none;border:none;color:#38bdf8;cursor:pointer;opacity:.8;transition:all .2s;display:flex;align-items:center;justify-content:center}.play-btn:hover{opacity:1;filter:drop-shadow(0 0 4px rgba(56,189,248,.8));transform:scale(1.1)}.play-btn svg{width:14px;height:14px;fill:currentColor}.vol-icon{width:10px;height:10px;fill:none;stroke:currentColor;stroke-width:2;flex-shrink:0}.bubble-trigger-zone{position:absolute;inset:60px 20px;z-index:15;cursor:pointer}.speech-bubble{position:absolute;padding:10px 14px;border-radius:12px;border-bottom-left-radius:2px;background:rgba(127,127,127,.15);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(150,150,150,.2);box-shadow:0 4px 15px rgba(0,0,0,.2);color:rgba(255,255,255,.9);font-size:12px;line-height:1.5;pointer-events:none;z-index:100;max-width:200px;animation:bubblePop .4s cubic-bezier(.34,1.56,.64,1) forwards;transform-origin:bottom left}.speech-bubble.fading{animation:bubbleDissolve 1s ease-out forwards}@keyframes slideUpFade{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes pulse{0%,100%{opacity:1;box-shadow:0 0 10px rgba(56,189,248,.8)}50%{opacity:.4;box-shadow:0 0 4px rgba(56,189,248,.3)}}@keyframes spin{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}@keyframes bubblePop{from{opacity:0;transform:scale(.8) translateY(5px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes bubbleDissolve{0%{opacity:1;filter:blur(0px)}100%{opacity:0;filter:blur(4px);transform:translateY(-10px)}}body.lt{background:transparent!important}body.lt .prism-wrapper{color:rgba(0,0,0,.85)}body.lt .p-island{color:rgba(0,0,0,.8)!important;border-color:rgba(0,0,0,.08)!important;background:rgba(0,0,0,.03)!important;box-shadow:0 4px 16px rgba(0,0,0,.05)!important;backdrop-filter:blur(24px)!important}body.lt .p-island.collapsed:hover{border-color:rgba(56,189,248,.35)!important;box-shadow:0 0 24px rgba(56,189,248,.1),0 6px 20px rgba(0,0,0,.08)!important}body.lt .p-island.expanded:hover{border-color:rgba(56,189,248,.25)!important}body.lt .gb{background:radial-gradient(400px circle at var(--mouse-x) var(--mouse-y),rgba(0,0,0,.06),transparent 40%)!important}body.lt .gi{background:radial-gradient(300px circle at var(--mouse-x) var(--mouse-y),rgba(56,189,248,.12),transparent 40%)!important}body.lt .lb{color:rgba(56,189,248,.9)!important}body.lt .capsule-content{color:rgba(0,0,0,.85)!important}body.lt .meta{border-bottom-color:rgba(0,0,0,.08)!important}body.lt .main-title{color:rgba(0,0,0,.85)!important}body.lt .tg-close{border-color:rgba(56,189,248,.4)!important;color:rgba(56,189,248,.8)!important}body.lt .tg-close:hover{color:rgba(56,189,248,1)!important;background:rgba(56,189,248,.08)!important}body.lt .detail-glass-box{background:rgba(0,0,0,.02)!important;color:rgba(0,0,0,.8)!important;border-left-color:rgba(56,189,248,.6)!important}body.lt .dh-title{color:rgba(56,189,248,.9)!important;border-bottom-color:rgba(0,0,0,.08)!important}body.lt .text-desc{color:rgba(0,0,0,.7)!important}body.lt .dr{border-top-color:rgba(0,0,0,.08)!important}body.lt .dh-btn{border-color:rgba(0,0,0,.08)!important;background:rgba(0,0,0,.02)!important;color:rgba(0,0,0,.5)!important}body.lt .dh-btn:hover{border-color:rgba(56,189,248,.3)!important;color:rgba(56,189,248,.9)!important}body.lt .dh-btn.on{border-color:rgba(56,189,248,.5)!important;background:rgba(56,189,248,.08)!important;color:rgba(56,189,248,1)!important}body.lt .setting-input{background:rgba(0,0,0,.02)!important;border-color:rgba(0,0,0,.1)!important;color:rgba(0,0,0,.8)!important}body.lt .setting-input:focus{border-color:rgba(56,189,248,.5)!important}body.lt .mp-title{color:rgba(0,0,0,.85)!important}body.lt .mp-artist{color:rgba(56,189,248,.85)!important}body.lt .mp-time-row{color:rgba(0,0,0,.5)!important}body.lt .mp-vinyl-disc{background:radial-gradient(circle at center,#e0e0e0,#ccc)!important;border-color:rgba(0,0,0,.15)!important}body.lt input[type=range].mp-slider::-webkit-slider-runnable-track{background:rgba(0,0,0,.1)!important}body.lt .speech-bubble{background:rgba(255,255,255,.85)!important;border-color:rgba(150,150,150,.2)!important;color:rgba(0,0,0,.8)!important;box-shadow:0 4px 15px rgba(0,0,0,.08)!important}\n</style></head><body>\n<div class=\"prism-mount-point unmounted\"><div class=\"data-poem\" style=\"display:none;\">$1</div><div class=\"data-song\" style=\"display:none;\">$2</div><div class=\"prism-wrapper\"></div></div>\n<script type=\"text/babel\">(()=>{function syncH(){try{var f=window.frameElement;if(f)f.style.height=document.body.scrollHeight+'px'}catch(e){}}new ResizeObserver(syncH).observe(document.body);function syncT(){try{var p=window.parent.document;var el=p.querySelector('.mes_text')||p.body;var c=window.parent.getComputedStyle(el).color;var m=c.match(/\\d+/g);if(m){if((parseInt(m[0])*299+parseInt(m[1])*587+parseInt(m[2])*114)/1000<128)document.body.classList.add('lt');else document.body.classList.remove('lt')}}catch(e){}}syncT();setInterval(()=>{syncH();syncT();},500);const mounts=document.querySelectorAll('.prism-mount-point.unmounted');if(mounts.length===0)return;const currentMount=mounts[mounts.length-1];currentMount.classList.remove('unmounted');const getTxt=(el)=>{if(!el)return'';let cln=el.innerHTML.replace(/<br\\s*\\/?>/gi,'\\n').replace(/<\\/p>/gi,'\\n');let t=document.createElement('div');t.innerHTML=cln;return(t.textContent||t.innerText).trim()};const rawPoem=getTxt(currentMount.querySelector('.data-poem'));const rawSong=getTxt(currentMount.querySelector('.data-song'));const {useState,useRef,useEffect}=React;const DEFAULT_NAME=\"双人成行\";const MusicPlayerUI=({songName,songData,isLoading,isPlaying,progress,duration,volume,onTogglePlay,onSeek,onVolumeChange})=>{const formatTime=(time)=>{if(isNaN(time))return\"0:00\";const min=Math.floor(time/60);const sec=Math.floor(time%60);return`${min}:${sec<10?'0':''}${sec}`};const PlayIcon=()=>(<svg viewBox=\"0 0 24 24\"><polygon points=\"8,5 19,12 8,19\"/></svg>);const PauseIcon=()=>(<svg viewBox=\"0 0 24 24\"><path d=\"M6 4h4v16H6V4zm8 0h4v16h-4V4z\"/></svg>);const IconVol=()=>(<svg className=\"vol-icon\" viewBox=\"0 0 24 24\"><polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\"></polygon></svg>);if(songName.startsWith('$')){return(<div style={{fontSize:'10px',opacity:0.6,fontFamily:'Consolas',textAlign:'center',marginTop:'10px',color:'#fca5a5',letterSpacing:'0.05em'}}>[ REGEX FAILED / NO DATA ]</div>)}if(isLoading)return(<div style={{fontSize:'10px',opacity:0.6,fontFamily:'Consolas',textAlign:'center',marginTop:'10px',letterSpacing:'0.05em'}}>[ SEARCHING: {songName} ]</div>);if(!songData||!songData.Url)return(<div style={{fontSize:'10px',opacity:0.6,fontFamily:'Consolas',textAlign:'center',marginTop:'10px',color:'#fca5a5',letterSpacing:'0.05em'}}>[ NO MATCH FOUND ]</div>);return(<div className=\"mp-container\"><div className=\"mp-vinyl-area\"><div className={`mp-vinyl-disc ${isPlaying?'spinning':''}`}><div className=\"mp-vinyl-label\">{songData.Cover&&<img src={songData.Cover} alt=\"cover\"/>}</div></div></div><div className=\"mp-interface\"><div className=\"mp-title\">{songData.Name}</div><div className=\"mp-artist\">{songData.Singer||'Unknown Data'}</div><div className=\"mp-controls-stack\"><div style={{display:'flex',alignItems:'center',gap:'8px'}}><button className=\"play-btn\" onClick={onTogglePlay}>{isPlaying?<PauseIcon/>:<PlayIcon/>}</button><input type=\"range\" className=\"mp-slider\" value={progress} max={duration||100} onChange={onSeek} onClick={(e)=>e.stopPropagation()} style={{flex:1}}/><div className=\"mp-time-row\"><span>{formatTime(progress)}</span></div></div><div style={{display:'flex',alignItems:'center',gap:'6px',paddingLeft:'22px',opacity:0.6}}><IconVol/><input type=\"range\" className=\"mp-slider\" min=\"0\" max=\"1\" step=\"0.05\" value={volume} onChange={onVolumeChange} onClick={(e)=>e.stopPropagation()} style={{width:'60px'}}/></div></div></div></div>)};const PrismWidget=()=>{const [isExpanded,setIsExpanded]=useState(false);const [activeId,setActiveId]=useState('data1');const [charName,setCharName]=useState(()=>localStorage.getItem('prism_name')||DEFAULT_NAME);const [bubbles,setBubbles]=useState([]);const audioRef=useRef(null);const [songData,setSongData]=useState(null);const [isLoading,setIsLoading]=useState(true);const [isPlaying,setIsPlaying]=useState(false);const [progress,setProgress]=useState(0);const [duration,setDuration]=useState(0);const [volume,setVolume]=useState(0.8);useEffect(()=>{try{localStorage.setItem('prism_name',charName)}catch(e){}},[charName]);useEffect(()=>{const initMusic=async()=>{let aiSong=rawSong.replace(/[《》\"\"'']/g,'');if(aiSong&&!aiSong.startsWith('$')){try{let retries=30;while(typeof window.Music==='undefined'&&retries>0){await new Promise(r=>setTimeout(r,100));retries--;}if(typeof window.Music!=='undefined'&&window.Music.SearchMusic){const res=await window.Music.SearchMusic(aiSong);if(res&&res.Url){setSongData(res);if(audioRef.current){audioRef.current.src=res.Url;audioRef.current.load();}}}}catch(e){}}setIsLoading(false)};initMusic()},[]);useEffect(()=>{if(audioRef.current)audioRef.current.volume=volume},[volume]);useEffect(()=>{const audio=audioRef.current;if(!audio)return;const updateProgress=()=>setProgress(audio.currentTime);const setAudioDuration=()=>setDuration(audio.duration);const handleEnd=()=>setIsPlaying(false);audio.addEventListener('timeupdate',updateProgress);audio.addEventListener('loadedmetadata',setAudioDuration);audio.addEventListener('ended',handleEnd);return()=>{audio.removeEventListener('timeupdate',updateProgress);audio.removeEventListener('loadedmetadata',setAudioDuration);audio.removeEventListener('ended',handleEnd)}},[]);const togglePlay=(e)=>{if(e)e.stopPropagation();if(!audioRef.current||!songData?.Url)return;if(isPlaying){audioRef.current.pause();setIsPlaying(false)}else{const p=audioRef.current.play();if(p!==undefined){p.then(()=>setIsPlaying(true)).catch(err=>{setIsPlaying(false)})}else{setIsPlaying(true)}}};const handleSeek=(e)=>{if(audioRef.current){const newTime=Number(e.target.value);audioRef.current.currentTime=newTime;setProgress(newTime)}};const handleMouseMove=(e)=>{const rect=e.currentTarget.getBoundingClientRect();e.currentTarget.style.setProperty('--mouse-x',`${e.clientX-rect.left}px`);e.currentTarget.style.setProperty('--mouse-y',`${e.clientY-rect.top}px`)};const handleTriggerClick=(e)=>{if(!isExpanded)return;const rect=e.currentTarget.getBoundingClientRect();const text=rawPoem&&!rawPoem.startsWith('$')?rawPoem:\"SYSTEM.AWAITING_INPUT();\";const bId=Date.now();setBubbles(p=>{const n=[...p,{id:bId,x:e.clientX-rect.left+20,y:e.clientY-rect.top+60,text,fade:false}];return n.length>2?n.slice(-2):n});setTimeout(()=>setBubbles(p=>p.map(b=>b.id===bId?{...b,fade:true}:b)),3500);setTimeout(()=>setBubbles(p=>p.filter(b=>b.id!==bId)),4500)};const details=[{id:'data1',label:'MOOD',content:(<div><div className=\"dh-title\">CURRENT SCENE LOG</div><div className=\"text-desc\" style={{textAlign:'center',margin:'6px 0'}}>{rawPoem&&!rawPoem.startsWith('$')?rawPoem:\"[ REGEX FAILED / NO DATA ]\"}</div></div>)},{id:'data2',label:'AUDIO',content:(<div><div className=\"dh-title\">MEDIA CORE EXTRACT</div><MusicPlayerUI songName={rawSong.replace(/[《》\"\"'']/g,'')} songData={songData} isLoading={isLoading} isPlaying={isPlaying} progress={progress} duration={duration} volume={volume} onTogglePlay={togglePlay} onSeek={handleSeek} onVolumeChange={e=>setVolume(Number(e.target.value))}/></div>)},{id:'data3',label:'CFG',content:(<div><div className=\"dh-title\">SYSTEM CONFIG</div><div style={{display:'flex',alignItems:'center',gap:'8px',marginTop:'12px'}}><span style={{fontFamily:'Consolas',fontSize:'10px',color:document.body.classList.contains('lt')?'rgba(0,0,0,0.5)':'rgba(255,255,255,0.5)'}}>NAME:</span><input type=\"text\" className=\"setting-input\" value={charName} onChange={e=>setCharName(e.target.value)}/></div></div>)}];const activeItem=details.find(d=>d.id===activeId);return(<div onClick={()=>!isExpanded&&setIsExpanded(true)} onMouseMove={handleMouseMove} className={`p-island ${isExpanded?'expanded':'collapsed'}`}><audio ref={audioRef} style={{display:'none'}}/><div className=\"gb\"></div><div className=\"gi\"></div>{isExpanded&&bubbles.map(b=>(<div key={b.id} className={`speech-bubble ${b.fade?'fading':''}`} style={{left:b.x,top:b.y-40}}>{b.text}</div>))}<div className=\"capsule-content\"><div className=\"dot\"></div><span className=\"lb\">˹ {charName} ˺ ACTIVE</span></div><div className=\"card-content\"><div className=\"bubble-trigger-zone\" onClick={handleTriggerClick}></div><div className=\"meta\"><div className=\"meta-left\"><div className=\"dot\"></div><div className=\"main-title\">{charName}</div></div><button onClick={e=>{e.stopPropagation();setIsExpanded(false)}} className=\"tg-close\">CLOSE</button></div><div className=\"content-display-area\" onClick={e=>e.stopPropagation()}>{activeItem&&(<div className=\"detail-glass-box\" key={activeItem.id}>{activeItem.content}</div>)}</div><div className=\"dr\" onClick={e=>e.stopPropagation()}>{details.map((item)=>(<div key={item.id} className={`dh-btn ${activeId===item.id?'on':''}`} onClick={()=>setActiveId(item.id)}><div className=\"gb\"></div><div className=\"gi\"></div><span style={{position:'relative',zIndex:1}}>{item.label}</span></div>))}</div></div></div>)};const root=ReactDOM.createRoot(currentMount.querySelector('.prism-wrapper'));root.render(<PrismWidget/>)})();</script></body></html>\n```",
        "trimStrings": [],
        "placement": [
            2
        ],
        "disabled": false,
        "markdownOnly": true,
        "promptOnly": false,
        "runOnEdit": true,
        "substituteRegex": 0,
        "minDepth": null,
        "maxDepth": null
    },
    {
        "id": "94b1492b-f526-47b6-be20-291e92cabe14",
        "scriptName": "播放器歌曲/诗句面板不发送AI",
        "findRegex": "<状态面板>[\\s\\S]*?<\\/状态面板>",
        "replaceString": "",
        "trimStrings": [],
        "placement": [
            1,
            2
        ],
        "disabled": true,
        "markdownOnly": false,
        "promptOnly": true,
        "runOnEdit": true,
        "substituteRegex": 0,
        "minDepth": null,
        "maxDepth": null
    },
    {
        "id": "abbdd756-bd25-4a75-8e17-948f2b4f49fb",
        "scriptName": "htm1fenge-渲染（安全容器包裹）",
        "disabled": false,
        "runOnEdit": true,
        "findRegex": "/<htm1fenge>([\\s\\S]*?)<\\/htm1fenge>/g",
        "trimStrings": [],
        "replaceString": "<div style=\"max-width:100%;overflow-x:auto;box-sizing:border-box;\">$1</div>",
        "placement": [
            2
        ],
        "substituteRegex": 0,
        "minDepth": null,
        "maxDepth": null,
        "markdownOnly": true,
        "promptOnly": false
    },
    {
        "id": "92df2779-a786-4800-84bb-613ee0dc18a8",
        "scriptName": "htm1fenge-对AI隐藏（不发送）",
        "disabled": false,
        "runOnEdit": true,
        "findRegex": "/<htm1fenge>[\\s\\S]*?<\\/htm1fenge>/gsi",
        "trimStrings": [],
        "replaceString": "",
        "placement": [
            2
        ],
        "substituteRegex": 0,
        "minDepth": null,
        "maxDepth": null,
        "markdownOnly": false,
        "promptOnly": true
    },
    {
        "id": "38137240-a027-40e4-8049-79cdb2398ecb",
        "scriptName": "htm1fenge-剥离隐藏描述span（可选）",
        "disabled": true,
        "runOnEdit": true,
        "findRegex": "/<span style=\"display:none;\">（[^<]*）<\\/span>/g",
        "trimStrings": [],
        "replaceString": "",
        "placement": [
            2
        ],
        "substituteRegex": 0,
        "minDepth": null,
        "maxDepth": null,
        "markdownOnly": true,
        "promptOnly": false
    },
    {
        "id": "27abe331-854c-4dc9-aadf-69e38df8d3e0",
        "scriptName": "对话渲染v7.1",
        "findRegex": "/<now_plot>([\\s\\S]*?)<\\/now_plot>/gi",
        "replaceString": "````html\n<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<style>\n/* === 基础重置 === */\n.dc-root q{quotes:none}\n.dc-root q::before,.dc-root q::after{content:''}\n.dc-root{font-family:\"Noto Sans SC\",\"Source Han Sans SC\",sans-serif;font-size:1rem;line-height:1.75;color:rgba(255,255,255,0.85)}\n\n/* === 旁白块：思源黑体 + 浅底色 === */\n.dc-narration-block{position:relative;padding:0 16px 0 76px;margin:8px 0;font-family:\"Noto Sans SC\",\"Source Han Sans SC\",sans-serif;background:rgba(255,255,255,0.04)}\n.dc-narration-block p{margin:0.5em 0;text-indent:var(--dc-text-indent,0em)}\n\n/* === 对话消息 === */\n.dc-msg{position:relative;padding:10px 16px 10px 76px;margin:10px 0;min-height:56px}\n\n/* === 头像 === */\n.dc-msg-avatar{position:absolute;left:16px;top:10px;width:52px;height:52px;border-radius:8px;overflow:hidden}\n.dc-msg-avatar img{width:100%;height:100%;object-fit:cover;border-radius:8px}\n.dc-msg-avatar-ph{width:100%;height:100%;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:20px;font-weight:600;color:#fff}\n\n/* === 消息头部：名字 + 情绪标签 === */\n.dc-msg-header{display:flex;align-items:flex-end;flex-wrap:wrap;column-gap:6px;row-gap:2px;margin:0 0 2px;line-height:1}\n\n/* 名字容器 */\n.dc-msg-name{display:inline-flex;align-items:baseline;font-family:\"Noto Serif SC\",\"Source Han Serif SC\",serif;font-size:16px;font-weight:800;letter-spacing:1.5px;line-height:1;color:inherit}\n/* 第1字：大字染色 */\n.dc-msg-name .dc-ch{font-size:22px;line-height:0.95}\n/* 第3字：小字染色 */\n.dc-msg-name .dc-cs{font-size:16px;line-height:1}\n/* 其余字：小字默认色 */\n.dc-msg-name .dc-cn{font-size:16px;line-height:1;color:inherit}\n\n/* 情绪标签（胶囊样式） */\n.dc-msg-mood{display:inline-flex;align-items:center;align-self:flex-end;flex:0 0 auto;font-size:0.60rem;padding:1px 6px;border-radius:999px;font-weight:500;line-height:1.2;font-family:\"Noto Sans SC\",\"Source Han Sans SC\",sans-serif;margin:0 0 1px}\n\n/* === 台词文本：思源宋体 === */\n.dc-msg-text{display:block;margin-top:0;font-size:14.5px;color:rgba(255,255,255,0.85);line-height:1.41;word-wrap:break-word;overflow-wrap:break-word;font-family:\"Noto Serif SC\",\"Source Han Serif SC\",serif}\n.dc-msg-text-content{display:inline}\n.dc-msg-text-content-thought{display:inline;font-style:italic;vertical-align:baseline}\n\n/* === 装饰大引号 / 心里话装饰符 === */\n.dc-msg-quote{display:inline-block;position:relative;font-size:2.3rem;font-family:Georgia,\"Times New Roman\",serif;line-height:0;height:0.5em;margin-left:5px;top:0.45em;transform:scaleY(0.96);transform-origin:center bottom;overflow:visible;vertical-align:baseline;pointer-events:none;font-weight:400}\n.dc-msg-quote-thought{font-size:1.4rem;top:0;line-height:1;height:auto;transform:none;font-family:Georgia,\"Times New Roman\",serif;font-style:normal;vertical-align:baseline}\n\n/* === HTML 嵌入块兼容 === */\n.dc-html-embed{margin:12px 0}\n.dc-html-iframe{display:block;width:100%;min-height:120px;border:0;background:transparent;overflow:hidden;border-radius:12px}\n\n/* === 颜色系统（8色） === */\n.dc-c1{color:#f47b67}.dc-c2{color:#45ddc0}.dc-c3{color:#e78bff}.dc-c4{color:#f0b232}\n.dc-c5{color:#58a6ff}.dc-c6{color:#ff9a76}.dc-c7{color:#7ee787}.dc-c8{color:#d2a8ff}\n.dc-bg1{background:#f47b67}.dc-bg2{background:#45ddc0}.dc-bg3{background:#e78bff}.dc-bg4{background:#f0b232}\n.dc-bg5{background:#58a6ff}.dc-bg6{background:#ff9a76}.dc-bg7{background:#7ee787}.dc-bg8{background:#d2a8ff}\n/* 情绪标签背景（低透明度） */\n.dc-mood1{background:rgba(244,123,103,0.15);color:#f47b67}\n.dc-mood2{background:rgba(69,221,192,0.15);color:#45ddc0}\n.dc-mood3{background:rgba(231,139,255,0.15);color:#e78bff}\n.dc-mood4{background:rgba(240,178,50,0.15);color:#f0b232}\n.dc-mood5{background:rgba(88,166,255,0.15);color:#58a6ff}\n.dc-mood6{background:rgba(255,154,118,0.15);color:#ff9a76}\n.dc-mood7{background:rgba(126,231,135,0.15);color:#7ee787}\n.dc-mood8{background:rgba(210,168,255,0.15);color:#d2a8ff}\n\n/* === Markdown 样式（旁白用） === */\n.dc-narration-block strong{font-weight:700}\n.dc-narration-block em{font-style:italic}\n.dc-narration-block del{text-decoration:line-through;opacity:0.7}\n.dc-narration-block code{background:rgba(255,255,255,0.08);padding:1px 5px;border-radius:3px;font-family:\"Fira Code\",\"Source Code Pro\",monospace;font-size:0.9em}\n.dc-narration-block pre{background:rgba(255,255,255,0.06);padding:10px 14px;border-radius:6px;overflow-x:auto;margin:0.5em 0}\n.dc-narration-block pre code{background:none;padding:0}\n.dc-narration-block blockquote{border-left:3px solid rgba(255,255,255,0.2);padding-left:12px;margin:0.5em 0;color:rgba(255,255,255,0.6)}\n.dc-narration-block ul,.dc-narration-block ol{padding-left:24px;margin:0.5em 0}\n.dc-narration-block li{margin:2px 0}\n.dc-narration-block table{border-collapse:collapse;margin:0.5em 0;width:100%}\n.dc-narration-block th,.dc-narration-block td{border:1px solid rgba(255,255,255,0.15);padding:4px 8px;text-align:left}\n.dc-narration-block th{background:rgba(255,255,255,0.06)}\n.dc-narration-block h1,.dc-narration-block h2,.dc-narration-block h3,.dc-narration-block h4,.dc-narration-block h5,.dc-narration-block h6{margin:0.6em 0 0.3em;font-weight:700;color:rgba(255,255,255,0.9)}\n.dc-narration-block h1{font-size:1.4em}.dc-narration-block h2{font-size:1.25em}.dc-narration-block h3{font-size:1.1em}\n.dc-narration-block hr{border:none;border-top:1px solid rgba(255,255,255,0.15);margin:0.8em 0}\n.dc-narration-block a{color:#58a6ff;text-decoration:underline}\n.dc-narration-block img{max-width:100%;border-radius:4px}\n</style>\n</head>\n<body>\n<xmp id=\"dcSource\" style=\"display:none;\">$1</xmp>\n<div class=\"dc-root\" id=\"dcRoot\"></div>\n<script>\n(function(){\n  var DB_NAME='BubbleDialogueAvatars',DB_VERSION=4,ST_AV='avatars',ST_CF='config';\n  var cMap={},cIdx=0;\n\n  /* 分配颜色索引(1-8) */\n  function gc(name){\n    if(cMap[name])return cMap[name];\n    cIdx=(cIdx%8)+1;\n    cMap[name]=cIdx;\n    return cIdx;\n  }\n\n  function esc(s){return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\"/g,'&quot;');}\n\n  function hex2rgba(h,a){\n    var r=parseInt(h.slice(1,3),16),g=parseInt(h.slice(3,5),16),b=parseInt(h.slice(5,7),16);\n    return'rgba('+r+','+g+','+b+','+a+')';\n  }\n\n  function decodeHtmlEntities(html){\n    var textarea=document.createElement('textarea');\n    textarea.innerHTML=html;\n    return textarea.value;\n  }\n\n  function getHtmlEmbedToken(index){\n    return '@@DC_HTML_EMBED_'+index+'@@';\n  }\n\n  function getInlineHtmlToken(index){\n    return '@@DC_INLINE_HTML_'+index+'@@';\n  }\n\n  function restoreInlineHtmlTokens(text, inlineHtmlTokens){\n    text=String(text==null?'':text);\n    inlineHtmlTokens=Array.isArray(inlineHtmlTokens)?inlineHtmlTokens:[];\n    return text.replace(/@@DC_INLINE_HTML_(\\d+)@@/g,function(_,idx){\n      idx=parseInt(idx,10);\n      return idx>=0&&idx<inlineHtmlTokens.length?inlineHtmlTokens[idx]:'';\n    });\n  }\n\n  function normalizeSourceText(rawHtml){\n    return decodeHtmlEntities(rawHtml||'')\n      .replace(/\\u00a0/g,' ')\n      .replace(/\\r\\n?/g,'\\n')\n      .replace(/<\\/?(now_plot|content)\\b[^>]*>/gi,'');\n  }\n\n  function stripBubbleLineHtmlWrappers(line){\n    var current=String(line==null?'':line).trim();\n    if(!current) return '';\n\n    var htmlTagWrapperPattern=/^<([a-z][\\w:-]*)(?:\\s[^<>]*?)?>([\\s\\S]*)<\\/\\1>$/i;\n    var inlineTokenWrapperPattern=/^(@@DC_INLINE_HTML_(\\d+)@@)([\\s\\S]*)(@@DC_INLINE_HTML_(\\d+)@@)$/;\n    var bubbleLinePattern=/^@bubble:/;\n    var maxDepth=12;\n\n    for(var depth=0;depth<maxDepth;depth++){\n      if(bubbleLinePattern.test(current)) break;\n\n      var next=current;\n      var htmlMatch=current.match(htmlTagWrapperPattern);\n      if(htmlMatch){\n        next=String(htmlMatch[2]||'').trim();\n      }else{\n        var tokenMatch=current.match(inlineTokenWrapperPattern);\n        if(tokenMatch&&tokenMatch[2]===tokenMatch[5]){\n          next=String(tokenMatch[3]||'').trim();\n        }\n      }\n\n      if(next===current) break;\n      current=next;\n    }\n\n    return current;\n  }\n\n  function protectInlineHtml(rawHtml){\n    var tokens=[];\n    var htmlCommentOrTagPattern=new RegExp('(?:'+'<!'+'--[\\\\s\\\\S]*?--'+'>)|(?:<\\\\/?[a-z][\\\\w:-]*(?:\\\\s[^<>]*?)?>)','gi');\n    rawHtml=rawHtml||'';\n    if(!rawHtml)return {text:'',tokens:tokens};\n    rawHtml=rawHtml.replace(htmlCommentOrTagPattern,function(match){\n      var token=getInlineHtmlToken(tokens.length);\n      tokens.push(match);\n      return token;\n    });\n    return {text:rawHtml,tokens:tokens};\n  }\n\n  function buildBubbleDetectionLine(line){\n    var cleaned=String(line==null?'':line);\n    var htmlCommentPattern=new RegExp('<!'+'--[\\\\s\\\\S]*?--'+'>','g');\n    if(!cleaned) return '';\n\n    var previous='';\n    var maxDepth=12;\n    for(var depth=0;depth<maxDepth&&cleaned!==previous;depth++){\n      previous=cleaned;\n      cleaned=cleaned.replace(/@@DC_INLINE_HTML_\\d+@@/g,'');\n      cleaned=cleaned.replace(htmlCommentPattern,'');\n      cleaned=cleaned.replace(/<\\/?[a-z][\\w:-]*(?:\\s[^<>]*?)?>/gi,'');\n      cleaned=stripBubbleLineHtmlWrappers(cleaned);\n    }\n\n    return cleaned.replace(/\\s+/g,' ').trim();\n  }\n\n  function protectHtmlFences(rawHtml){\n    var embeds=[];\n    rawHtml=rawHtml||'';\n    if(!rawHtml)return {text:'',embeds:embeds};\n    rawHtml=rawHtml.replace(/`{3,}\\s*(html|htm|xhtml)\\s*([\\s\\S]*?)`{3,}/gi,function(_,lang,inner){\n      var token=getHtmlEmbedToken(embeds.length);\n      embeds.push((inner||'').replace(/^\\s+|\\s+$/g,''));\n      return '\\n'+token+'\\n';\n    });\n    return {text:rawHtml,embeds:embeds};\n  }\n\n  /* ── 通用块级 HTML 保护 ──\n     检测由其他正则预先替换生成的完整块级 HTML 结构（如 <style>...<div>...</div>），\n     将其整体替换为 @@DC_HTML_EMBED_N@@ token，避免被旁白渲染逻辑破坏。\n     在 normalizeSourceText 之后、protectInlineHtml 之前调用。 */\n  function protectBlockHtml(text, embeds){\n    text=text||'';\n    if(!text)return text;\n    embeds=Array.isArray(embeds)?embeds:[];\n\n    var lines=text.split('\\n');\n    var result=[];\n    var i=0;\n\n    while(i<lines.length){\n      var line=lines[i];\n      var trimmed=line.trim();\n\n      /* 检测块级 HTML 的起始：以 <style 开头，或以块级元素标签开头且该行不含 @bubble: */\n      var isBlockStart=false;\n      if(/^<style[\\s>]/i.test(trimmed)){\n        isBlockStart=true;\n      }else if(/^<(div|section|article|aside|header|footer|nav|main|table|form|fieldset|figure|details|dialog)[\\s>]/i.test(trimmed)\n               && !/@bubble:/i.test(trimmed)){\n        /* 额外检查：如果这个块级标签在同一行内就闭合了，且行很短，可能只是简单的行内使用，不保护 */\n        var selfClosedMatch=trimmed.match(/^<([a-z]+)[\\s>][\\s\\S]*<\\/\\1\\s*>$/i);\n        if(!selfClosedMatch || trimmed.length>200){\n          isBlockStart=true;\n        }\n      }\n\n      if(!isBlockStart){\n        result.push(line);\n        i++;\n        continue;\n      }\n\n      /* 收集块级 HTML 块：追踪标签嵌套深度 */\n      var blockLines=[line];\n      var depth=0;\n      var openTagPattern=/<(style|div|section|article|aside|header|footer|nav|main|table|form|fieldset|figure|details|dialog)[\\s>]/gi;\n      var closeTagPattern=/<\\/(style|div|section|article|aside|header|footer|nav|main|table|form|fieldset|figure|details|dialog)\\s*>/gi;\n\n      /* 计算当前行的深度变化 */\n      var opens=(line.match(openTagPattern)||[]).length;\n      var closes=(line.match(closeTagPattern)||[]).length;\n      depth+=opens-closes;\n      i++;\n\n      /* 如果第一行就闭合了（depth<=0），检查后续是否紧跟更多块级内容 */\n      if(depth<=0){\n        /* 看下一行是否也是块级标签开头（如 <style> 后紧跟 <div>） */\n        while(i<lines.length){\n          var nextTrimmed=lines[i].trim();\n          if(!nextTrimmed){\n            /* 空行：如果后面还有块级标签，继续收集；否则停止 */\n            var lookahead=i+1;\n            while(lookahead<lines.length && !lines[lookahead].trim()) lookahead++;\n            if(lookahead<lines.length && /^<(style|div|section|article|aside|header|footer|nav|main|table|form|fieldset|figure|details|dialog)[\\s>]/i.test(lines[lookahead].trim())){\n              blockLines.push(lines[i]);\n              i++;\n              continue;\n            }\n            break;\n          }\n          if(/^<(style|div|section|article|aside|header|footer|nav|main|table|form|fieldset|figure|details|dialog)[\\s>]/i.test(nextTrimmed)){\n            blockLines.push(lines[i]);\n            openTagPattern.lastIndex=0;\n            closeTagPattern.lastIndex=0;\n            opens=(lines[i].match(/<(style|div|section|article|aside|header|footer|nav|main|table|form|fieldset|figure|details|dialog)[\\s>]/gi)||[]).length;\n            closes=(lines[i].match(/<\\/(style|div|section|article|aside|header|footer|nav|main|table|form|fieldset|figure|details|dialog)\\s*>/gi)||[]).length;\n            depth+=opens-closes;\n            i++;\n            if(depth>0) break; /* 进入嵌套追踪模式 */\n          }else{\n            break;\n          }\n        }\n      }\n\n      /* 如果还有未闭合的标签，继续收集直到闭合，然后再检查后续块级标签 */\n      var maxScan=500; /* 安全上限，防止无限循环 */\n      var scanned=0;\n      var keepScanning=true;\n      while(keepScanning && scanned<maxScan){\n        /* 收集直到当前深度归零 */\n        while(depth>0 && i<lines.length && scanned<maxScan){\n          blockLines.push(lines[i]);\n          opens=(lines[i].match(/<(style|div|section|article|aside|header|footer|nav|main|table|form|fieldset|figure|details|dialog)[\\s>]/gi)||[]).length;\n          closes=(lines[i].match(/<\\/(style|div|section|article|aside|header|footer|nav|main|table|form|fieldset|figure|details|dialog)\\s*>/gi)||[]).length;\n          depth+=opens-closes;\n          i++;\n          scanned++;\n        }\n        /* 深度归零后，检查后续是否紧跟更多块级标签 */\n        keepScanning=false;\n        if(depth<=0 && i<lines.length){\n          var peekIdx=i;\n          /* 跳过空行 */\n          while(peekIdx<lines.length && !lines[peekIdx].trim()) peekIdx++;\n          if(peekIdx<lines.length && /^<(style|div|section|article|aside|header|footer|nav|main|table|form|fieldset|figure|details|dialog)[\\s>]/i.test(lines[peekIdx].trim())){\n            /* 收集中间的空行 */\n            while(i<peekIdx){ blockLines.push(lines[i]); i++; }\n            /* 收集这个新的块级标签行 */\n            blockLines.push(lines[i]);\n            opens=(lines[i].match(/<(style|div|section|article|aside|header|footer|nav|main|table|form|fieldset|figure|details|dialog)[\\s>]/gi)||[]).length;\n            closes=(lines[i].match(/<\\/(style|div|section|article|aside|header|footer|nav|main|table|form|fieldset|figure|details|dialog)\\s*>/gi)||[]).length;\n            depth+=opens-closes;\n            i++;\n            scanned++;\n            keepScanning=true; /* 继续追踪这个新块 */\n          }\n        }\n      }\n\n      /* 最终验证：收集到的块至少包含一个闭合标签，才认为是有效的块级 HTML */\n      var blockContent=blockLines.join('\\n');\n      var hasCloseTag=/<\\/(style|div|section|article|aside|header|footer|nav|main|table|form|fieldset|figure|details|dialog)\\s*>/i.test(blockContent);\n\n      if(hasCloseTag && blockLines.length>=1){\n        /* 有效的块级 HTML 结构，替换为 embed token */\n        var token=getHtmlEmbedToken(embeds.length);\n        embeds.push(blockContent);\n        result.push(token);\n      }else{\n        /* 不是有效的块级结构，保持原样 */\n        for(var b=0;b<blockLines.length;b++){\n          result.push(blockLines[b]);\n        }\n      }\n    }\n\n    return result.join('\\n');\n  }\n\n  function extractSourceText(rawHtml){\n    return (rawHtml||'')\n      .replace(/\\r\\n?/g,'\\n')\n      .split(/\\n/)\n      .map(function(line){\n        return stripBubbleLineHtmlWrappers(line);\n      })\n      .join('\\n')\n      .replace(/([^\\n])\\s*(@bubble:)/g,function(_,prefix,marker){\n        return prefix+'\\n'+marker;\n      })\n      .replace(/(^@bubble:[^\\n]*\\])\\s*([^\\s\\n][^\\n]*)/gm,function(_,bubble,trailing){\n        return bubble+'\\n'+trailing;\n      });\n  }\n\n  function encodeUtf8Base64(text){\n    try{return btoa(unescape(encodeURIComponent(text||'')));}\n    catch(e){return '';}\n  }\n\n  function decodeUtf8Base64(text){\n    try{return decodeURIComponent(escape(atob(text||'')));}\n    catch(e){return '';}\n  }\n\n  function isHtmlFenceLang(lang){\n    return /^(html|htm|xhtml)$/i.test((lang||'').trim());\n  }\n\n  function buildHtmlEmbedPlaceholder(source){\n    return '<div class=\"dc-html-embed\" data-html-b64=\"'+encodeUtf8Base64(source)+'\"></div>';\n  }\n\n  function normalizeHtmlEmbedSource(source){\n    var normalized=source||'';\n    if(!normalized)return '';\n    return normalized.replace(/<q\\b[^>]*>/gi,'').replace(/<\\/q>/gi,'');\n  }\n\n  var HOST_BRIDGE_GLOBAL_ALIASES={\n    '$':['$','jQuery'],\n    'jQuery':['jQuery','$'],\n    'getChatMessages':['getChatMessages'],\n    'getCurrentMessageId':['getCurrentMessageId'],\n    'getContext':['getContext','SillyTavern.getContext'],\n    'SillyTavern':['SillyTavern'],\n    'toastr':['toastr','SillyTavern.toastr'],\n    'eventSource':['eventSource','SillyTavern.eventSource'],\n    'event_types':['event_types','SillyTavern.event_types'],\n    'power_user':['power_user','SillyTavern.power_user'],\n    'chat':['chat','SillyTavern.chat'],\n    'chat_metadata':['chat_metadata','SillyTavern.chat_metadata'],\n    'extension_settings':['extension_settings','SillyTavern.extension_settings'],\n    'characters':['characters','SillyTavern.characters'],\n    'this_chid':['this_chid','SillyTavern.this_chid'],\n    'selected_group':['selected_group','SillyTavern.selected_group'],\n    'eventOn':['eventOn','SillyTavern.eventOn'],\n    'getButtonEvent':['getButtonEvent','SillyTavern.getButtonEvent'],\n    'callGenericPopup':['callGenericPopup','SillyTavern.callGenericPopup'],\n    'Popup':['Popup','SillyTavern.Popup'],\n    'executeSlashCommands':['executeSlashCommands','SillyTavern.executeSlashCommands'],\n    'renderExtensionTemplateAsync':['renderExtensionTemplateAsync','SillyTavern.renderExtensionTemplateAsync'],\n    'Generate':['Generate','SillyTavern.Generate'],\n    'activateSendButtons':['activateSendButtons','SillyTavern.activateSendButtons'],\n    'deactivateSendButtons':['deactivateSendButtons','SillyTavern.deactivateSendButtons'],\n    'BubbleCG':['BubbleCG']\n  };\n\n  function buildHtmlEmbedBridgeConfig(messageText){\n    return {\n      messageText:messageText||'',\n      globalAliases:HOST_BRIDGE_GLOBAL_ALIASES\n    };\n  }\n\n  function buildHtmlEmbedScriptDataUrl(code){\n    return 'data:text/javascript;charset=utf-8;base64,'+encodeUtf8Base64(code||'');\n  }\n\n  function buildHtmlEmbedSrcdoc(source, context){\n    var raw=normalizeHtmlEmbedSource(source).trim();\n    if(!raw)return '';\n    if(!/<(?:!doctype|html|body|head)\\b/i.test(raw)){\n      raw='<!DOCTYPE html><html lang=\"zh-CN\"><head><meta charset=\"UTF-8\"><style>html,body{margin:0;padding:0;background:transparent;}</style></head><body>'+raw+'</body></html>';\n    }\n    context=context||{};\n    var bridgeConfigB64=encodeUtf8Base64(JSON.stringify(buildHtmlEmbedBridgeConfig(context.messageText||'')));\n    var bridgeScriptCode='(function(){try{var bridgeConfig=(function(text){try{return JSON.parse(decodeURIComponent(escape(atob(text||\"\"))));}catch(e){return {};}})(\"'+bridgeConfigB64+'\");var fallbackMessage=typeof bridgeConfig.messageText===\"string\"?bridgeConfig.messageText:\"\";var globalAliases=bridgeConfig&&bridgeConfig.globalAliases?bridgeConfig.globalAliases:{};function listAncestorWindows(){var list=[];var current=window.parent;var guard=0;while(current&&guard<12){list.push(current);try{if(!current.parent||current.parent===current)break;current=current.parent;}catch(e){break;}guard++;}return list;}var ancestorWindows=listAncestorWindows();function resolvePathOn(target,path){if(!target||!path)return null;var parts=String(path).split(\".\");var owner=null;var current=target;for(var i=0;i<parts.length;i++){if(current==null)return null;owner=current;current=current[parts[i]];}return{owner:owner,value:current};}function resolveHostValue(paths){paths=Array.isArray(paths)?paths:[];for(var p=0;p<paths.length;p++){for(var w=0;w<ancestorWindows.length;w++){try{var resolved=resolvePathOn(ancestorWindows[w],paths[p]);if(resolved&&resolved.value!==undefined&&resolved.value!==null){return typeof resolved.value===\"function\"?resolved.value.bind(resolved.owner||ancestorWindows[w]):resolved.value;}}catch(e){}}}return undefined;}function findAncestorElementById(id){for(var w=0;w<ancestorWindows.length;w++){try{var doc=ancestorWindows[w].document;if(!doc)continue;var el=Document.prototype.getElementById.call(doc,id);if(el)return el;}catch(e){}}return null;}function findAncestorSelector(selector,all){for(var w=0;w<ancestorWindows.length;w++){try{var doc=ancestorWindows[w].document;if(!doc)continue;if(all){var list=Document.prototype.querySelectorAll.call(doc,selector);if(list&&list.length)return list;}else{var el=Document.prototype.querySelector.call(doc,selector);if(el)return el;}}catch(e){}}return all?Document.prototype.querySelectorAll.call(document,\".__dc-host-bridge-empty__\"):null;}function patchDocumentBridge(doc){if(!doc||doc.__dcHtmlEmbedPatched)return;var originalGetElementById=function(id){return Document.prototype.getElementById.call(doc,id);};doc.getElementById=function(id){var direct=originalGetElementById(id);if(direct)return direct;return findAncestorElementById(id);};var originalQuerySelector=function(selector){return Document.prototype.querySelector.call(doc,selector);};doc.querySelector=function(selector){var direct=originalQuerySelector(selector);if(direct)return direct;return findAncestorSelector(selector,false);};var originalQuerySelectorAll=function(selector){return Document.prototype.querySelectorAll.call(doc,selector);};doc.querySelectorAll=function(selector){var direct=originalQuerySelectorAll(selector);if(direct&&direct.length)return direct;return findAncestorSelector(selector,true);};doc.__dcHtmlEmbedPatched=true;}function createDollarBridge(){if(window.__dcDollarBridge)return window.__dcDollarBridge;var bridge;if(typeof Proxy===\"function\"){bridge=new Proxy(function(){},{apply:function(target,thisArg,args){var hostDollar=resolveHostValue(globalAliases.$||[\"$\",\"jQuery\"]);if(typeof args[0]===\"function\"){if(typeof hostDollar===\"function\")return hostDollar(args[0]);if(document.readyState===\"loading\")document.addEventListener(\"DOMContentLoaded\",args[0],{once:true});else args[0]();return null;}if(typeof hostDollar===\"function\")return hostDollar.apply(null,args);return null;},get:function(target,prop){if(prop===\"then\")return undefined;var hostDollar=resolveHostValue(globalAliases.$||[\"$\",\"jQuery\"]);if(hostDollar&&prop in hostDollar)return hostDollar[prop];return target[prop];},set:function(target,prop,value){var hostDollar=resolveHostValue(globalAliases.$||[\"$\",\"jQuery\"]);if(hostDollar&&(typeof hostDollar===\"object\"||typeof hostDollar===\"function\")){hostDollar[prop]=value;return true;}target[prop]=value;return true;}});}else{bridge=function(arg){var hostDollar=resolveHostValue(globalAliases.$||[\"$\",\"jQuery\"]);if(typeof arg===\"function\"){if(typeof hostDollar===\"function\")return hostDollar(arg);if(document.readyState===\"loading\")document.addEventListener(\"DOMContentLoaded\",arg,{once:true});else arg();return null;}if(typeof hostDollar===\"function\")return hostDollar.apply(null,arguments);return null;};}window.__dcDollarBridge=bridge;return bridge;}function defineGlobalBridge(name,paths){if(name===\"$\"||name===\"jQuery\")return;if(name in window&&window[name]!==undefined&&window[name]!==null)return;Object.defineProperty(window,name,{configurable:true,enumerable:false,get:function(){if(name===\"getCurrentMessageId\"){var idFn=resolveHostValue(paths);if(typeof idFn===\"function\")return idFn;return function(){return \"__dc_html_embed__\";};}if(name===\"getChatMessages\"){var msgFn=resolveHostValue(paths);if(typeof msgFn===\"function\")return msgFn;return function(){return fallbackMessage?[{message:fallbackMessage}]:[];};}return resolveHostValue(paths);},set:function(value){Object.defineProperty(window,name,{value:value,writable:true,configurable:true,enumerable:true});}});}patchDocumentBridge(document);for(var docIdx=0;docIdx<ancestorWindows.length;docIdx++){try{patchDocumentBridge(ancestorWindows[docIdx].document);}catch(e){}}window.$=createDollarBridge();window.jQuery=window.$;var bridgeNames=Object.keys(globalAliases);for(var i=0;i<bridgeNames.length;i++)defineGlobalBridge(bridgeNames[i],globalAliases[bridgeNames[i]]);if(typeof window.getCurrentMessageId!==\"function\"){window.getCurrentMessageId=function(){return \"__dc_html_embed__\";};}if(typeof window.getChatMessages!==\"function\"){window.getChatMessages=function(){return fallbackMessage?[{message:fallbackMessage}]:[];};}window.__dcHostBridge={config:bridgeConfig,resolve:function(path){return resolveHostValue([path]);},findById:findAncestorElementById,query:function(selector){return findAncestorSelector(selector,false);},queryAll:function(selector){return findAncestorSelector(selector,true);}};}catch(e){console.warn(\"dc html embed bridge failed\",e);}})();';\n    var resizeScriptCode='(function(){function report(){try{var doc=document.documentElement;var body=document.body;var h=Math.max(doc?doc.scrollHeight:0,body?body.scrollHeight:0,body?body.offsetHeight:0,120);if(window.frameElement){window.frameElement.style.height=h+\"px\";}}catch(e){}}function bind(){report();if(typeof ResizeObserver===\"function\"){try{var ro=new ResizeObserver(report);if(document.documentElement)ro.observe(document.documentElement);if(document.body)ro.observe(document.body);}catch(e){}}else{setInterval(report,500);}window.addEventListener(\"load\",report);setTimeout(report,60);setTimeout(report,220);}if(document.readyState===\"loading\"){document.addEventListener(\"DOMContentLoaded\",bind,{once:true});}else{bind();}})();';\n    var bridgeScriptUrl=buildHtmlEmbedScriptDataUrl(bridgeScriptCode);\n    var resizeScriptUrl=buildHtmlEmbedScriptDataUrl(resizeScriptCode);\n    if(typeof DOMParser!==\"function\"){\n      return raw+'<scr'+'ipt src=\"'+bridgeScriptUrl+'\"></scr'+'ipt><scr'+'ipt src=\"'+resizeScriptUrl+'\"></scr'+'ipt>';\n    }\n    try{\n      var parsed=new DOMParser().parseFromString(raw,'text/html');\n      if(!parsed||!parsed.documentElement)return raw;\n      var html=parsed.documentElement;\n      var head=parsed.head;\n      var body=parsed.body;\n      if(!head){\n        head=parsed.createElement('head');\n        if(html.firstChild) html.insertBefore(head, html.firstChild);\n        else html.appendChild(head);\n      }\n      if(!body){\n        body=parsed.createElement('body');\n        html.appendChild(body);\n      }\n      var bridgeScript=parsed.createElement('script');\n      bridgeScript.setAttribute('src', bridgeScriptUrl);\n      if(head.firstChild) head.insertBefore(bridgeScript, head.firstChild);\n      else head.appendChild(bridgeScript);\n      var resizeScript=parsed.createElement('script');\n      resizeScript.setAttribute('src', resizeScriptUrl);\n      body.appendChild(resizeScript);\n      return '<!DOCTYPE html>'+html.outerHTML;\n    }catch(e){\n      console.warn('dc html embed srcdoc build failed',e);\n      return raw+'<scr'+'ipt src=\"'+bridgeScriptUrl+'\"></scr'+'ipt><scr'+'ipt src=\"'+resizeScriptUrl+'\"></scr'+'ipt>';\n    }\n  }\n\n  function hydrateHtmlEmbeds(root, messageText){\n    var embeds=root.querySelectorAll('.dc-html-embed[data-html-b64]');\n    for(var i=0;i<embeds.length;i++){\n      var host=embeds[i];\n      var htmlSource=decodeUtf8Base64(host.getAttribute('data-html-b64')||'');\n      if(!htmlSource.trim()){\n        host.remove();\n        continue;\n      }\n      var frame=document.createElement('iframe');\n      frame.className='dc-html-iframe';\n      frame.setAttribute('scrolling','no');\n      frame.setAttribute('loading','lazy');\n      frame.style.height='120px';\n      frame.srcdoc=buildHtmlEmbedSrcdoc(htmlSource,{messageText:messageText||''});\n      host.innerHTML='';\n      host.appendChild(frame);\n    }\n  }\n\n  /* 从 IndexedDB 读头像 blob url */\n  function getAvatar(charId,name){\n    return new Promise(function(ok){\n      if(!name){ok(null);return;}\n      try{\n        var r=indexedDB.open(DB_NAME,DB_VERSION);\n        r.onsuccess=function(e){\n          var db=e.target.result;\n          if(!db.objectStoreNames.contains(ST_AV)){ok(null);return;}\n          var tx=db.transaction(ST_AV,'readonly');\n          var key=(charId||'_global_')+'__'+name;\n          var g=tx.objectStore(ST_AV).get(key);\n          g.onsuccess=function(){\n            var record=g.result;\n            if(!record){ok(null);return;}\n            if(record.imageBlob){ok(URL.createObjectURL(record.imageBlob));return;}\n            if(record.sourceUrl&&record.sourceUrl!=='null'&&record.sourceUrl.indexOf('http')===0){\n              fetch(record.sourceUrl).then(function(resp){return resp.ok?resp.blob():null;}).then(function(blob){\n                if(!blob){ok(null);return;}\n                record.imageBlob=blob;record.fileSize=blob.size;record.mimeType=blob.type||record.mimeType;record.updatedAt=Date.now();\n                try{var wTx=db.transaction(ST_AV,'readwrite');wTx.objectStore(ST_AV).put(record);}catch(_){}\n                ok(URL.createObjectURL(blob));\n              }).catch(function(){ok(null);});\n              return;\n            }\n            ok(null);\n          };\n          g.onerror=function(){ok(null);};\n        };\n        r.onerror=function(){ok(null);};\n      }catch(e){ok(null);}\n    });\n  }\n\n  /* 从 IndexedDB mood_avatars store 读差分头像 blob url */\n  function getMoodAvatarUrl(charId,name,moodId){\n    return new Promise(function(ok){\n      if(!name||!moodId){ok(null);return;}\n      try{\n        var r=indexedDB.open(DB_NAME,DB_VERSION);\n        r.onsuccess=function(e){\n          var db=e.target.result;\n          if(!db.objectStoreNames.contains('mood_avatars')){ok(null);return;}\n          var tx=db.transaction('mood_avatars','readonly');\n          var key=(charId||'_global_')+'__'+name+'__'+moodId;\n          var g=tx.objectStore('mood_avatars').get(key);\n          g.onsuccess=function(){\n            var record=g.result;\n            if(!record){ok(null);return;}\n            if(record.imageBlob){ok(URL.createObjectURL(record.imageBlob));return;}\n            if(record.sourceUrl&&record.sourceUrl!=='null'&&record.sourceUrl.indexOf('http')===0){\n              fetch(record.sourceUrl).then(function(resp){return resp.ok?resp.blob():null;}).then(function(blob){\n                if(!blob){ok(null);return;}\n                record.imageBlob=blob;record.fileSize=blob.size;record.mimeType=blob.type||record.mimeType;record.updatedAt=Date.now();\n                try{var wTx=db.transaction('mood_avatars','readwrite');wTx.objectStore('mood_avatars').put(record);}catch(_){}\n                ok(URL.createObjectURL(blob));\n              }).catch(function(){ok(null);});\n              return;\n            }\n            ok(null);\n          };\n          g.onerror=function(){ok(null);};\n        };\n        r.onerror=function(){ok(null);};\n      }catch(e){ok(null);}\n    });\n  }\n\n  /* 从 IndexedDB config 读单个 key */\n  function getConfigVal(key){\n    return new Promise(function(ok){\n      try{\n        var r=indexedDB.open(DB_NAME,DB_VERSION);\n        r.onsuccess=function(e){\n          var db=e.target.result;\n          if(!db.objectStoreNames.contains(ST_CF)){ok(null);return;}\n          var tx=db.transaction(ST_CF,'readonly');\n          var g=tx.objectStore(ST_CF).get(key);\n          g.onsuccess=function(){ok(g.result?g.result.value:null);};\n          g.onerror=function(){ok(null);};\n        };\n        r.onerror=function(){ok(null);};\n      }catch(e){ok(null);}\n    });\n  }\n\n  var FONT_CACHE_PREFIX='bubbleDialogueFontCache:';\n  var STYLE_CACHE_KEY='bubbleDialogueStyleSnapshot';\n  var REMOTE_FONT_TIMEOUT=8000;\n  var BUILTIN_FONT_OPTIONS=[\n    {id:'noto-sans-sc',name:'Noto Sans SC',family:'Noto Sans SC',type:'builtin'},\n    {id:'source-han-sans-sc',name:'Source Han Sans SC',family:'Source Han Sans SC',type:'builtin'},\n    {id:'noto-serif-sc',name:'Noto Serif SC',family:'Noto Serif SC',type:'builtin'},\n    {id:'source-han-serif-sc',name:'Source Han Serif SC',family:'Source Han Serif SC',type:'builtin'},\n    {id:'lxgw-wenkai',name:'LXGW WenKai',family:'LXGW WenKai',type:'builtin'},\n    {id:'fira-code',name:'Fira Code',family:'Fira Code',type:'builtin'}\n  ];\n  var DEFAULT_MOOD_COLOR_GROUPS=[\n    {id:'mood-joy',color:'#f59e0b',words:['开心','欢喜','欣喜','愉悦','满足','幸福','甜蜜','狂喜','兴奋','雀跃','畅快','陶醉','得意','骄傲','自豪','自信']},\n    {id:'mood-anger',color:'#ef4444',words:['愤怒','暴怒','气愤','愤慨','暴躁','怨恨','敌意','恼火','窝火','生气','烦躁','烦闷']},\n    {id:'mood-sad',color:'#3b82f6',words:['难过','伤心','心酸','忧伤','惆怅','失落','低落','沮丧','悲伤','心痛','悲痛','痛苦','委屈','不甘','失望','受伤','孤独','寂寞','落寞']},\n    {id:'mood-anxious',color:'#eab308',words:['焦虑','紧张','不安','忐忑','担忧','慌张','焦躁','害怕','恐惧','惊恐','畏惧','胆怯','心慌','警惕','戒备']},\n    {id:'mood-calm',color:'#22c55e',words:['平静','淡然','冷静','沉稳','从容','坦然','淡定','温馨','舒畅','惬意','温暖','欣慰','释然','感动','感恩']},\n    {id:'mood-shy',color:'#06b6d4',words:['害羞','尴尬','窘迫','难堪','困惑','迷茫','疑惑','纠结','犹豫','无奈','无语']},\n    {id:'mood-disgust',color:'#8b5cf6',words:['厌恶','嫌弃','鄙视','反感','排斥','抗拒','不屑','冷淡','冷漠','疏离','麻木']},\n    {id:'mood-love',color:'#ec4899',words:['喜欢','爱慕','迷恋','倾慕','宠溺','依恋','心动','认真']}\n  ];\n  var MOOD_COLOR_GROUPS=DEFAULT_MOOD_COLOR_GROUPS;\n  var MOOD_COLOR_MAP={};\n\n  function rebuildMoodColorMap(){\n    var map={};\n    for(var i=0;i<MOOD_COLOR_GROUPS.length;i++){\n      var group=MOOD_COLOR_GROUPS[i];\n      for(var j=0;j<group.words.length;j++) map[group.words[j]]={color:group.color,id:group.id};\n    }\n    MOOD_COLOR_MAP=map;\n  }\n  rebuildMoodColorMap();\n\n  function loadMoodConfig(){\n    return getConfigVal('mood_config').then(function(raw){\n      if(!raw) return;\n      try{\n        var cfg=JSON.parse(raw);\n        if(cfg&&Array.isArray(cfg.groups)&&cfg.groups.length){\n          MOOD_COLOR_GROUPS=cfg.groups;\n          rebuildMoodColorMap();\n        }\n      }catch(e){\n        /* 解析失败，保持默认值 */\n      }\n    }).catch(function(){\n      /* 读取失败，保持默认值 */\n    });\n  }\n\n  function clampNumber(value,min,max){\n    if(!Number.isFinite(value)) return min;\n    return Math.min(Math.max(value,min),max);\n  }\n\n  function buildFontStack(family,fallbackStack){\n    family=typeof family==='string'?family.trim():'';\n    return family?'\"'+family.replace(/\"/g,'\\\\\"')+'\",'+fallbackStack:fallbackStack;\n  }\n\n  function escapeHtmlAttr(value){\n    return String(value==null?'':value)\n      .replace(/&/g,'&amp;')\n      .replace(/\"/g,'&quot;')\n      .replace(/</g,'&lt;')\n      .replace(/>/g,'&gt;');\n  }\n\n  function getCurrentCharId(){\n    function tryGetContext(target){\n      try{\n        if(target&&target.SillyTavern&&typeof target.SillyTavern.getContext==='function'){\n          return target.SillyTavern.getContext();\n        }\n      }catch(e){}\n      return null;\n    }\n\n    function tryGetChid(target){\n      try{\n        if(target&&typeof target.this_chid!=='undefined'&&target.this_chid!==null){\n          return target.this_chid;\n        }\n      }catch(e){}\n      return undefined;\n    }\n\n    try{\n      var localContext=tryGetContext(window);\n      var parentContext=window.parent&&window.parent!==window?tryGetContext(window.parent):null;\n      var chid=(localContext&&localContext.characterId!=null)?localContext.characterId\n        :(parentContext&&parentContext.characterId!=null)?parentContext.characterId\n        :tryGetChid(window);\n      if(chid==null&&window.parent&&window.parent!==window){\n        chid=tryGetChid(window.parent);\n      }\n      return chid!=null?String(chid):'';\n    }catch(e){\n      return '';\n    }\n  }\n\n  function isInnerThoughtText(text){\n    return /^\\*.+\\*$/.test((text||'').trim());\n  }\n\n  function getMoodRenderState(mood){\n    var entry=MOOD_COLOR_MAP[(mood||'').trim()];\n    if(!entry) return null;\n    return {color:entry.color,background:hex2rgba(entry.color,0.15),id:entry.id};\n  }\n\n  function normalizeRemoteFontConfig(payload){\n    var fonts=Array.isArray(payload&&payload.fonts)?payload.fonts:[];\n    var normalized=[];\n    for(var i=0;i<fonts.length;i++){\n      var item=fonts[i]||{};\n      var family=typeof item.family==='string'?item.family.trim():'';\n      var name=typeof item.name==='string'?item.name.trim():family;\n      var url=typeof item.url==='string'?item.url.trim():'';\n      var type=item.type==='file'?'file':item.type==='css'?'css':'';\n      var format=typeof item.format==='string'?item.format.trim():'';\n      var id=typeof item.id==='string'&&item.id.trim()?item.id.trim():'remote-font-'+i;\n      if(!family||!name||!url||!type) continue;\n      normalized.push({id:id,name:name,family:family,url:url,type:type,format:format});\n    }\n    return normalized;\n  }\n\n  function getFontCacheKey(url){\n    return FONT_CACHE_PREFIX+(url||'');\n  }\n\n  function readCachedFontConfig(url){\n    if(!url) return [];\n    try{\n      var raw=localStorage.getItem(getFontCacheKey(url));\n      if(!raw) return [];\n      var parsed=JSON.parse(raw);\n      return Array.isArray(parsed&&parsed.fonts)?parsed.fonts:[];\n    }catch(e){\n      return [];\n    }\n  }\n\n  function writeCachedFontConfig(url,fonts){\n    if(!url) return;\n    try{\n      localStorage.setItem(getFontCacheKey(url),JSON.stringify({version:'1.0',savedAt:Date.now(),fonts:fonts||[]}));\n    }catch(e){\n      // ignore cache errors\n    }\n  }\n\n  function ensureRemoteFontResources(fonts){\n    fonts=Array.isArray(fonts)?fonts:[];\n    var head=document.head||document.getElementsByTagName('head')[0];\n    if(!head) return;\n\n    for(var i=0;i<fonts.length;i++){\n      var font=fonts[i];\n      if(font.type!=='css'||!font.url) continue;\n      var links=head.querySelectorAll('link[data-dc-font-url]');\n      var exists=false;\n      for(var j=0;j<links.length;j++){\n        if(links[j].getAttribute('data-dc-font-url')===font.url){ exists=true; break; }\n      }\n      if(!exists){\n        var link=document.createElement('link');\n        link.rel='stylesheet';\n        link.href=font.url;\n        link.setAttribute('data-dc-font-url',font.url);\n        head.appendChild(link);\n      }\n    }\n\n    var fileFonts=fonts.filter(function(font){return font.type==='file'&&font.url&&font.family;});\n    if(!fileFonts.length) return;\n    var styleEl=document.getElementById('dcRemoteFontFaceStyle');\n    if(!styleEl){\n      styleEl=document.createElement('style');\n      styleEl.id='dcRemoteFontFaceStyle';\n      head.appendChild(styleEl);\n    }\n    var rules=fileFonts.map(function(font){\n      var formatPart=font.format?\" format('\"+font.format.replace(/'/g,\"\\\\'\")+\"')\":'';\n      return \"@font-face{font-family:'\"+font.family.replace(/'/g,\"\\\\'\")+\"';src:url('\"+font.url.replace(/'/g,\"\\\\'\")+\"')\"+formatPart+\";font-display:swap;}\";\n    }).join('');\n    if(styleEl.textContent!==rules) styleEl.textContent=rules;\n  }\n\n  function fetchRemoteFontConfig(url){\n    return new Promise(function(resolve,reject){\n      if(!url){ resolve([]); return; }\n      var timer=setTimeout(function(){ reject(new Error('字体配置拉取超时')); },REMOTE_FONT_TIMEOUT);\n      fetch(url,{method:'GET',cache:'no-store'}).then(function(response){\n        if(!response.ok) throw new Error('HTTP '+response.status);\n        return response.json();\n      }).then(function(payload){\n        var fonts=normalizeRemoteFontConfig(payload);\n        writeCachedFontConfig(url,fonts);\n        resolve(fonts);\n      }).catch(function(err){\n        reject(err);\n      }).finally(function(){\n        clearTimeout(timer);\n      });\n    });\n  }\n\n  function ensureFontResources(cfg){\n    cfg=cfg||{};\n    var fontConfigUrl=typeof cfg.style_fontConfigUrl==='string'?cfg.style_fontConfigUrl.trim():'';\n    if(!fontConfigUrl) return Promise.resolve(BUILTIN_FONT_OPTIONS.slice());\n    return fetchRemoteFontConfig(fontConfigUrl).then(function(remoteFonts){\n      ensureRemoteFontResources(remoteFonts);\n      return BUILTIN_FONT_OPTIONS.concat(remoteFonts);\n    }).catch(function(err){\n      var cachedFonts=readCachedFontConfig(fontConfigUrl);\n      if(cachedFonts.length){\n        ensureRemoteFontResources(cachedFonts);\n        return BUILTIN_FONT_OPTIONS.concat(cachedFonts);\n      }\n      console.warn('远程字体加载失败:',fontConfigUrl,err);\n      return BUILTIN_FONT_OPTIONS.slice();\n    });\n  }\n\n  function loadLocalFonts(){\n    return new Promise(function(resolve){\n      try{\n        var r=indexedDB.open(DB_NAME,DB_VERSION);\n        r.onsuccess=function(e){\n          var db=e.target.result;\n          if(!db.objectStoreNames.contains('local_fonts')){resolve([]);return;}\n          var tx=db.transaction('local_fonts','readonly');\n          var store=tx.objectStore('local_fonts');\n          var all=store.getAll();\n          all.onsuccess=function(){\n            var fonts=all.result||[];\n            var head=document.head||document.getElementsByTagName('head')[0];\n            if(!head||!fonts.length){resolve(fonts);return;}\n            var styleEl=document.getElementById('dcLocalFontFaceStyle');\n            if(!styleEl){\n              styleEl=document.createElement('style');\n              styleEl.id='dcLocalFontFaceStyle';\n              head.appendChild(styleEl);\n            }\n            var rules=[];\n            for(var i=0;i<fonts.length;i++){\n              var font=fonts[i];\n              if(!font.fontBlob||!font.family) continue;\n              var blobUrl=URL.createObjectURL(font.fontBlob);\n              var formatPart=font.format?\" format('\"+font.format+\"')\":'';\n              rules.push(\"@font-face{font-family:'\"+font.family.replace(/'/g,\"\\\\'\")+\"';src:url('\"+blobUrl+\"')\"+formatPart+\";font-display:swap;}\");\n            }\n            styleEl.textContent=rules.join('');\n            resolve(fonts);\n          };\n          all.onerror=function(){resolve([]);};\n        };\n        r.onerror=function(){resolve([]);};\n      }catch(e){resolve([]);}\n    });\n  }\n\n  function loadCssFontSources(){\n    return getConfigVal('style_cssFontUrls').then(function(raw){\n      var sources=[];\n      try{sources=JSON.parse(raw||'[]');}catch(e){sources=[];}\n      var head=document.head||document.getElementsByTagName('head')[0];\n      if(!head||!sources.length) return;\n      for(var i=0;i<sources.length;i++){\n        var src=sources[i];\n        if(!src||!src.url) continue;\n        var links=head.querySelectorAll('link[data-dc-css-font-url]');\n        var exists=false;\n        for(var j=0;j<links.length;j++){\n          if(links[j].getAttribute('data-dc-css-font-url')===src.url){exists=true;break;}\n        }\n        if(!exists){\n          var link=document.createElement('link');\n          link.rel='stylesheet';\n          link.href=src.url;\n          link.setAttribute('data-dc-css-font-url',src.url);\n          head.appendChild(link);\n        }\n      }\n    }).catch(function(){});\n  }\n\n  function readStyleConfigCache(){\n    try{\n      var raw=localStorage.getItem(STYLE_CACHE_KEY);\n      if(!raw) return {};\n      var parsed=JSON.parse(raw);\n      return parsed&&typeof parsed==='object'?parsed:{};\n    }catch(e){\n      return {};\n    }\n  }\n\n  function getStyleConfig(){\n    var defaults={\n      style_dialogueFontSize:14.5,\n      style_narrationFontSize:14,\n      style_dialogueSpacing:10,\n      style_textColorMode:'global',\n      style_globalTextColor:'#d9d9d9',\n      style_markdownMode:'basic',\n      style_dialogueFontWeight:400,\n      style_narrationFontWeight:400,\n      style_nameFontWeight:800,\n      style_narrationBgColor:'#ffffff',\n      style_narrationBgOpacity:0.04,\n      style_avatarSize:52,\n      style_narrationIndent:76,\n      style_narrationFontFamily:'Noto Sans SC',\n      style_dialogueFontFamily:'Noto Serif SC',\n      style_nameFontFamily:'Noto Serif SC',\n      style_fontConfigUrl:'',\n      style_narrationBorderRadius:0,\n      style_avatarShape:'rounded',\n      style_thoughtSuffixGap:6,\n      style_thoughtSuffixOffsetY:5,\n      style_narrationTextIndent:0,\n      style_narrationLineHeight:1.75,\n      style_narrationPaddingRight:16\n    };\n    var numericKeys={\n      style_dialogueFontSize:true,\n      style_narrationFontSize:true,\n      style_dialogueSpacing:true,\n      style_dialogueFontWeight:true,\n      style_narrationFontWeight:true,\n      style_nameFontWeight:true,\n      style_narrationBgOpacity:true,\n      style_avatarSize:true,\n      style_narrationIndent:true,\n      style_narrationBorderRadius:true,\n      style_thoughtSuffixGap:true,\n      style_thoughtSuffixOffsetY:true,\n      style_narrationTextIndent:true,\n      style_narrationLineHeight:true,\n      style_narrationPaddingRight:true\n    };\n    var intKeys={\n      style_dialogueSpacing:true,\n      style_dialogueFontWeight:true,\n      style_narrationFontWeight:true,\n      style_nameFontWeight:true,\n      style_avatarSize:true,\n      style_narrationIndent:true,\n      style_narrationBorderRadius:true,\n      style_thoughtSuffixGap:true,\n      style_thoughtSuffixOffsetY:true,\n      style_narrationPaddingRight:true\n    };\n    var keys=Object.keys(defaults);\n    var cached=readStyleConfigCache();\n\n    function normalizeStyleValue(key,val,fallback){\n      var base=fallback===undefined?defaults[key]:fallback;\n      if(val===null||val===undefined||val==='') return base;\n      if(numericKeys[key]){\n        var parsed=intKeys[key]?parseInt(val,10):parseFloat(val);\n        return Number.isFinite(parsed)?parsed:base;\n      }\n      return val;\n    }\n\n    var cfg={};\n    for(var c=0;c<keys.length;c++){\n      var cacheKey=keys[c];\n      cfg[cacheKey]=normalizeStyleValue(cacheKey,cached[cacheKey],defaults[cacheKey]);\n    }\n\n    return Promise.all(keys.map(function(key){\n      return getConfigVal(key).then(function(val){\n        return [key,val];\n      });\n    })).then(function(entries){\n      for(var i=0;i<entries.length;i++){\n        var key=entries[i][0];\n        var val=entries[i][1];\n        cfg[key]=normalizeStyleValue(key,val,cfg[key]);\n      }\n      return cfg;\n    });\n  }\n\n  /* 名字渲染：第1字大号染色，第3字小号染色，其余小号默认色 */\n  function renderName(name, colorClass){\n    var html='';\n    for(var i=0;i<name.length;i++){\n      var ch=esc(name[i]);\n      if(i===0){\n        html+='<span class=\"dc-ch '+colorClass+'\">'+ch+'</span>';\n      }else if(i===2){\n        html+='<span class=\"dc-cs '+colorClass+'\">'+ch+'</span>';\n      }else{\n        html+='<span class=\"dc-cn\">'+ch+'</span>';\n      }\n    }\n    return html;\n  }\n\n  /* Markdown 基础模式：粗体、斜体、删除线 */\n  function mdBasic(text, inlineHtmlTokens){\n    text=esc(text);\n    text=text.replace(/\\*\\*(.+?)\\*\\*/g,function(_,g1){return '<strong>'+g1+'</strong>';});\n    text=text.replace(/\\*(.+?)\\*/g,function(_,g1){return '<em>'+g1+'</em>';});\n    text=text.replace(/~~(.+?)~~/g,function(_,g1){return '<del>'+g1+'</del>';});\n    text=text.replace(/`([^`]+)`/g,function(_,g1){return '<code>'+g1+'</code>';});\n    return restoreInlineHtmlTokens(text, inlineHtmlTokens);\n  }\n\n  /* Markdown 完整模式 */\n  function mdFull(lines, inlineHtmlTokens){\n    var html='';\n    var inCode=false,codeBuf=[];\n    var inTable=false,tableBuf=[];\n    var inList=false,listType='',listBuf=[];\n\n    function flushList(){\n      if(!listBuf.length)return;\n      var tag=listType==='ol'?'ol':'ul';\n      html+='<'+tag+'>'+listBuf.join('')+'</'+tag+'>';\n      listBuf=[];inList=false;listType='';\n    }\n    function flushTable(){\n      if(!tableBuf.length)return;\n      html+='<table>';\n      for(var t=0;t<tableBuf.length;t++){\n        if(t===1)continue; /* skip separator row */\n        var cells=tableBuf[t].split('|').map(function(c){return c.trim();}).filter(function(c){return c!=='';});\n        var tag=t===0?'th':'td';\n        var tr='<tr>';\n        for(var c=0;c<cells.length;c++) tr+='<'+tag+'>'+mdInline(cells[c])+'</'+tag+'>';\n        tr+='</tr>';\n        html+=tr;\n      }\n      html+='</table>';\n      tableBuf=[];inTable=false;\n    }\n\n    function mdInline(text){\n      text=esc(text);\n      text=text.replace(/!\\[([^\\]]*)\\]\\(([^)]+)\\)/g,function(_,alt,src){return '<img src=\"'+src+'\" alt=\"'+alt+'\"/>';});\n      text=text.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g,function(_,label,href){return '<a href=\"'+href+'\" target=\"_blank\" rel=\"noopener noreferrer\">'+label+'</a>';});\n      text=text.replace(/\\*\\*(.+?)\\*\\*/g,function(_,g1){return '<strong>'+g1+'</strong>';});\n      text=text.replace(/\\*(.+?)\\*/g,function(_,g1){return '<em>'+g1+'</em>';});\n      text=text.replace(/~~(.+?)~~/g,function(_,g1){return '<del>'+g1+'</del>';});\n      text=text.replace(/`([^`]+)`/g,function(_,g1){return '<code>'+g1+'</code>';});\n      return restoreInlineHtmlTokens(text, inlineHtmlTokens);\n    }\n\n    var codeFencePattern=new RegExp('^'+String.fromCharCode(96)+'{3}');\n    for(var i=0;i<lines.length;i++){\n      var line=lines[i];\n      /* 代码块 */\n      if(codeFencePattern.test(line)){\n        if(inCode){codeBuf.push('</code></pre>');html+=codeBuf.join('\\n');codeBuf=[];inCode=false;}\n        else{flushList();flushTable();inCode=true;codeBuf=['<pre><code>'];}\n        continue;\n      }\n      if(inCode){codeBuf.push(esc(line));continue;}\n\n      var trimmed=line.trim();\n      if(!trimmed){flushList();flushTable();continue;}\n\n      /* 表格检测 */\n      if(trimmed.indexOf('|')!==-1){\n        if(!inTable&&trimmed.match(/^\\|.*\\|$/)){\n          flushList();\n          inTable=true;tableBuf=[trimmed];continue;\n        }\n        if(inTable){\n          if(trimmed.match(/^\\|[\\s\\-:|]+\\|$/)){tableBuf.push(trimmed);continue;}\n          if(trimmed.match(/^\\|.*\\|$/)){tableBuf.push(trimmed);continue;}\n          else{flushTable();}\n        }\n      }else if(inTable){flushTable();}\n\n      /* 标题 */\n      var hm=trimmed.match(/^(#{1,6})\\s+(.+)$/);\n      if(hm){flushList();var lvl=hm[1].length;html+='<h'+lvl+'>'+mdInline(hm[2])+'</h'+lvl+'>';continue;}\n\n      /* 分割线 */\n      if(trimmed.match(/^(-{3,}|\\*{3,}|_{3,})$/)){flushList();html+='<hr/>';continue;}\n\n      /* 引用 */\n      if(trimmed.match(/^>\\s?/)){flushList();html+='<blockquote>'+mdInline(trimmed.replace(/^>\\s?/,''))+'</blockquote>';continue;}\n\n      /* 无序列表 */\n      var ulm=trimmed.match(/^[-*+]\\s+(.+)$/);\n      if(ulm){\n        if(inList&&listType!=='ul'){flushList();}\n        inList=true;listType='ul';\n        listBuf.push('<li>'+mdInline(ulm[1])+'</li>');continue;\n      }\n      /* 有序列表 */\n      var olm=trimmed.match(/^\\d+\\.\\s+(.+)$/);\n      if(olm){\n        if(inList&&listType!=='ol'){flushList();}\n        inList=true;listType='ol';\n        listBuf.push('<li>'+mdInline(olm[1])+'</li>');continue;\n      }\n\n      flushList();\n      html+='<p>'+mdInline(trimmed)+'</p>';\n    }\n    if(inCode){codeBuf.push('</code></pre>');html+=codeBuf.join('\\n');}\n    flushList();flushTable();\n    return html;\n  }\n\n  function renderRichText(text, inlineHtmlTokens){\n    return restoreInlineHtmlTokens(esc(text), inlineHtmlTokens);\n  }\n\n  function renderNarration(lines, markdownMode, htmlEmbeds, inlineHtmlTokens){\n    var tick=String.fromCharCode(96);\n    var codeFenceLinePattern=new RegExp('^'+tick+'{3,}\\\\s*([a-z0-9_-]+)?\\\\s*$','i');\n    var embedTokenPattern=/^@@DC_HTML_EMBED_(\\d+)@@$/;\n    var parts=[];\n    var textBuf=[];\n    var htmlBuf=[];\n    var inHtmlFence=false;\n    htmlEmbeds=Array.isArray(htmlEmbeds)?htmlEmbeds:[];\n\n    function flushText(){\n      if(!textBuf.length)return;\n      if(markdownMode==='full'){\n        parts.push(mdFull(textBuf, inlineHtmlTokens));\n      }else{\n        parts.push(textBuf.map(function(l){return '<p>'+mdBasic(l, inlineHtmlTokens)+'</p>';}).join(''));\n      }\n      textBuf=[];\n    }\n\n    for(var i=0;i<lines.length;i++){\n      var line=lines[i];\n      var embedMatch=line.trim().match(embedTokenPattern);\n      if(embedMatch){\n        flushText();\n        parts.push(buildHtmlEmbedPlaceholder(htmlEmbeds[parseInt(embedMatch[1],10)]||''));\n        continue;\n      }\n      var fenceMatch=line.trim().match(codeFenceLinePattern);\n      if(fenceMatch){\n        var fenceLang=(fenceMatch[1]||'').toLowerCase();\n        if(inHtmlFence){\n          parts.push(buildHtmlEmbedPlaceholder(htmlBuf.join('\\n')));\n          htmlBuf=[];\n          inHtmlFence=false;\n        }else if(isHtmlFenceLang(fenceLang)){\n          flushText();\n          inHtmlFence=true;\n        }else{\n          textBuf.push(line);\n        }\n        continue;\n      }\n      if(inHtmlFence){\n        htmlBuf.push(line);\n      }else{\n        textBuf.push(line);\n      }\n    }\n\n    if(inHtmlFence){\n      parts.push(buildHtmlEmbedPlaceholder(htmlBuf.join('\\n')));\n    }\n    flushText();\n    return parts.join('');\n  }\n\n  function getDialogueLineHeight(fontSize, spacing){\n    var safeFontSize=Number.isFinite(fontSize)?fontSize:14.5;\n    var safeSpacing=Number.isFinite(spacing)?spacing:10;\n    var computed=Math.max(safeFontSize*1.35,safeFontSize+safeSpacing);\n    return Math.round(computed*100)/100;\n  }\n\n  function scheduleFrameTask(callback, delay){\n    var safeDelay=Number.isFinite(delay)?delay:0;\n    var runner=function(){ setTimeout(callback, safeDelay); };\n    if(typeof requestAnimationFrame==='function'){\n      requestAnimationFrame(runner);\n      return;\n    }\n    setTimeout(callback, safeDelay);\n  }\n\n  function scheduleAvatarEnhancement(root,colorMode,globalColor){\n    scheduleFrameTask(function(){\n      loadAvatarsAndColors(root,colorMode,globalColor);\n    }, 60);\n  }\n\n  var bubbleRenderBooted=false;\n  var bubbleRenderSourceObserver=null;\n  var bubbleRenderWatchLogTimer=null;\n  var bubbleRenderStableTimer=null;\n  var bubbleRenderWatchStartedAt=0;\n  var bubbleRenderLastMutationAt=0;\n  var bubbleRenderLastSignature='';\n  var bubbleRenderBootRetryCount=0;\n  var BUBBLE_RENDER_STABLE_MS=3000;\n  var BUBBLE_RENDER_WATCH_LOG_MS=1000;\n  var BUBBLE_RENDER_BOOT_RETRY_MS=180;\n  var BUBBLE_RENDER_BOOT_MAX_RETRIES=20;\n\n  function readBubbleRenderSourceValue(sourceEl){\n    if(!sourceEl)return '';\n    return String(sourceEl.value||sourceEl.textContent||'');\n  }\n\n  function buildBubbleRenderSourceSignature(sourceEl){\n    var rawValue=readBubbleRenderSourceValue(sourceEl);\n    return [rawValue.length, rawValue].join('::');\n  }\n\n  function analyzeBubbleRenderSourceState(sourceEl){\n    var sourceRaw=readBubbleRenderSourceValue(sourceEl);\n    var protectedResult=protectHtmlFences(sourceRaw);\n    var normalizedSource=normalizeSourceText(protectedResult.text);\n    normalizedSource=protectBlockHtml(normalizedSource, protectedResult.embeds);\n    var inlineHtmlResult=protectInlineHtml(normalizedSource);\n    var extractedSource=extractSourceText(inlineHtmlResult.text);\n    var lines=extractedSource.split(/\\n/);\n    var bubbleSourceCount=(sourceRaw.match(/@bubble:/g)||[]).length;\n    var bubbleCandidateCount=0;\n    var visibleTextCount=0;\n    var pollutedLineCount=0;\n    var preview=[];\n\n    for(var i=0;i<lines.length;i++){\n      var rawLine=String(lines[i]||'');\n      var trimmedLine=rawLine.trim();\n      var detectionLine=buildBubbleDetectionLine(rawLine);\n      if(trimmedLine&&preview.length<6){\n        preview.push(trimmedLine);\n      }\n      if(trimmedLine&&/@@DC_INLINE_HTML_\\d+@@/.test(trimmedLine)){\n        pollutedLineCount++;\n      }\n      if(!detectionLine) continue;\n      visibleTextCount++;\n      if(/^@bubble:/.test(detectionLine)){\n        bubbleCandidateCount++;\n      }\n    }\n\n    var parseReady=bubbleSourceCount>0\n      ? bubbleCandidateCount>0\n      : (visibleTextCount>0||normalizedSource.trim().length===0);\n\n    return {\n      sourceLength:sourceRaw.length,\n      normalizedLength:normalizedSource.length,\n      extractedLength:extractedSource.length,\n      bubbleSourceCount:bubbleSourceCount,\n      bubbleCandidateCount:bubbleCandidateCount,\n      visibleTextCount:visibleTextCount,\n      pollutedLineCount:pollutedLineCount,\n      parseReady:parseReady,\n      waitingReason:!parseReady\n        ? (bubbleSourceCount>0?'bubble-markers-not-ready':'visible-text-not-ready')\n        : '',\n      preview:preview\n    };\n  }\n\n  function stopBubbleRenderWatchers(){\n    if(bubbleRenderSourceObserver){\n      bubbleRenderSourceObserver.disconnect();\n      bubbleRenderSourceObserver=null;\n    }\n    if(bubbleRenderWatchLogTimer){\n      clearInterval(bubbleRenderWatchLogTimer);\n      bubbleRenderWatchLogTimer=null;\n    }\n    if(bubbleRenderStableTimer){\n      clearTimeout(bubbleRenderStableTimer);\n      bubbleRenderStableTimer=null;\n    }\n  }\n\n  function logBubbleRenderWatchStatus(stage){\n    var now=Date.now();\n    var watchElapsed=bubbleRenderWatchStartedAt?now-bubbleRenderWatchStartedAt:0;\n    var idleElapsed=bubbleRenderLastMutationAt?now-bubbleRenderLastMutationAt:0;\n    // console.log('[BubbleRenderWatch] '+stage+' | 监听时长='+(watchElapsed/1000).toFixed(1)+'s | 距上次变化='+(idleElapsed/1000).toFixed(1)+'s | 稳定阈值='+(BUBBLE_RENDER_STABLE_MS/1000).toFixed(1)+'s');\n  }\n\n  function scheduleStableBubbleRender(){\n    if(bubbleRenderBooted)return;\n    if(bubbleRenderStableTimer){\n      clearTimeout(bubbleRenderStableTimer);\n      bubbleRenderStableTimer=null;\n    }\n    bubbleRenderStableTimer=setTimeout(function(){\n      bubbleRenderStableTimer=null;\n      if(bubbleRenderBooted)return;\n      logBubbleRenderWatchStatus('内容稳定，开始渲染');\n      stopBubbleRenderWatchers();\n      scheduleBubbleRenderBoot();\n    }, BUBBLE_RENDER_STABLE_MS);\n  }\n\n  function markBubbleRenderSourceChanged(reason, sourceEl){\n    if(bubbleRenderBooted)return;\n    var nextSignature=buildBubbleRenderSourceSignature(sourceEl);\n    if(nextSignature===bubbleRenderLastSignature&&reason!=='initial')return;\n    bubbleRenderLastSignature=nextSignature;\n    bubbleRenderLastMutationAt=Date.now();\n    // console.log('[BubbleRenderWatch] 检测到源内容变化：'+reason+' | 内容长度='+readBubbleRenderSourceValue(sourceEl).length);\n    scheduleStableBubbleRender();\n  }\n\n  function startBubbleRenderWhenStable(){\n    if(bubbleRenderBooted)return;\n    var sourceEl=document.getElementById('dcSource');\n    if(!sourceEl){\n      console.warn('[BubbleRenderWatch] 未找到 #dcSource，无法开始稳定监听');\n      return;\n    }\n    stopBubbleRenderWatchers();\n    bubbleRenderBootRetryCount=0;\n    bubbleRenderWatchStartedAt=Date.now();\n    bubbleRenderLastMutationAt=bubbleRenderWatchStartedAt;\n    bubbleRenderLastSignature='';\n    // console.log('[BubbleRenderWatch] 已开始监听源内容稳定性，连续 3 秒无变化后渲染');\n    bubbleRenderWatchLogTimer=setInterval(function(){\n      logBubbleRenderWatchStatus('监听中');\n    }, BUBBLE_RENDER_WATCH_LOG_MS);\n    bubbleRenderSourceObserver=new MutationObserver(function(){\n      markBubbleRenderSourceChanged('MutationObserver', sourceEl);\n    });\n    bubbleRenderSourceObserver.observe(sourceEl,{characterData:true,childList:true,subtree:true});\n    markBubbleRenderSourceChanged('initial', sourceEl);\n  }\n\n  function bootBubbleRender(){\n    if(bubbleRenderBooted)return;\n    var sourceEl=document.getElementById('dcSource');\n    var sourceRawPreview=sourceEl?String(sourceEl.value||sourceEl.textContent||''):'';\n    var sourceState=analyzeBubbleRenderSourceState(sourceEl);\n    // console.log('[BubbleRender] 开始执行最终渲染');\n    // console.log('[BubbleRender] 渲染入口源摘要',{\n    //   sourceTag:sourceEl&&sourceEl.tagName?sourceEl.tagName.toLowerCase():'',\n    //   sourceLength:sourceRawPreview.length,\n    //   sourcePreview:sourceRawPreview.split(/\\n/).slice(0,6),\n    //   parseReady:sourceState.parseReady,\n    //   bubbleSourceCount:sourceState.bubbleSourceCount,\n    //   bubbleCandidateCount:sourceState.bubbleCandidateCount,\n    //   visibleTextCount:sourceState.visibleTextCount,\n    //   pollutedLineCount:sourceState.pollutedLineCount,\n    //   retryCount:bubbleRenderBootRetryCount\n    // });\n    if(!sourceState.parseReady){\n      if(bubbleRenderBootRetryCount>=BUBBLE_RENDER_BOOT_MAX_RETRIES){\n        bubbleRenderBooted=true;\n        console.warn('[BubbleRender] 源内容在重试上限后仍未进入可解析状态，回退执行最终渲染', sourceState);\n      }else{\n        bubbleRenderBootRetryCount++;\n        console.warn('[BubbleRender] 源内容尚未进入可解析状态，延后重试', {\n          retryCount:bubbleRenderBootRetryCount,\n          maxRetries:BUBBLE_RENDER_BOOT_MAX_RETRIES,\n          retryDelay:BUBBLE_RENDER_BOOT_RETRY_MS,\n          waitingReason:sourceState.waitingReason,\n          preview:sourceState.preview\n        });\n        scheduleFrameTask(bootBubbleRender, BUBBLE_RENDER_BOOT_RETRY_MS);\n        return;\n      }\n    }else{\n      bubbleRenderBooted=true;\n    }\n    // console.log('[BubbleRender] 渲染使用的源状态', sourceState);\n    getStyleConfig().then(function(cfg){\n      return Promise.all([\n        ensureFontResources(cfg),\n        loadLocalFonts(),\n        loadCssFontSources(),\n        loadMoodConfig()\n      ]).then(function(){\n        processText(cfg);\n      });\n    }).catch(function(err){\n      console.warn('Bubble 渲染初始化失败:',err);\n      processText();\n    });\n  }\n\n  function scheduleBubbleRenderBoot(){\n    scheduleFrameTask(bootBubbleRender, 120);\n  }\n\n  /* ====== 主处理函数（同步，确保立即渲染） ====== */\n  function processText(cfg){\n    var root=document.getElementById('dcRoot');\n    if(!root)return;\n\n    cfg=cfg||{};\n    var cfgDialogueFontSize=Number.isFinite(cfg.style_dialogueFontSize)?cfg.style_dialogueFontSize:14.5;\n    var cfgNarrationFontSize=Number.isFinite(cfg.style_narrationFontSize)?cfg.style_narrationFontSize:14;\n    var cfgDialogueSpacing=Number.isFinite(cfg.style_dialogueSpacing)?cfg.style_dialogueSpacing:10;\n    var cfgTextColorMode=cfg.style_textColorMode||'global';\n    var cfgGlobalTextColor=cfg.style_globalTextColor||'#d9d9d9';\n    var cfgMarkdownMode=cfg.style_markdownMode||'basic';\n    var cfgDialogueFontWeight=Number.isFinite(cfg.style_dialogueFontWeight)?cfg.style_dialogueFontWeight:400;\n    var cfgNarrationFontWeight=Number.isFinite(cfg.style_narrationFontWeight)?cfg.style_narrationFontWeight:400;\n    var cfgNameFontWeight=Number.isFinite(cfg.style_nameFontWeight)?cfg.style_nameFontWeight:800;\n    var cfgNarrationBgColor=cfg.style_narrationBgColor||'#ffffff';\n    var cfgNarrationBgOpacity=clampNumber(cfg.style_narrationBgOpacity,0,1);\n    var cfgAvatarSize=clampNumber(cfg.style_avatarSize,36,88);\n    var cfgNarrationIndent=clampNumber(cfg.style_narrationIndent,0,120);\n    var cfgNarrationFontFamily=cfg.style_narrationFontFamily||'Noto Sans SC';\n    var cfgDialogueFontFamily=cfg.style_dialogueFontFamily||'Noto Serif SC';\n    var cfgNameFontFamily=cfg.style_nameFontFamily||'Noto Serif SC';\n    var cfgDialogueLineHeight=getDialogueLineHeight(cfgDialogueFontSize,cfgDialogueSpacing);\n    var cfgNarrationBackground=hex2rgba(cfgNarrationBgColor,cfgNarrationBgOpacity);\n    var cfgNarrationFontStack=buildFontStack(cfgNarrationFontFamily,'\"Source Han Sans SC\",sans-serif');\n    var cfgDialogueFontStack=buildFontStack(cfgDialogueFontFamily,'\"Source Han Serif SC\",serif');\n    var cfgNameFontStack=buildFontStack(cfgNameFontFamily,'\"Source Han Serif SC\",serif');\n    var cfgNarrationBorderRadius=clampNumber(Number.isFinite(cfg.style_narrationBorderRadius)?cfg.style_narrationBorderRadius:0,0,24);\n    var cfgAvatarShape=cfg.style_avatarShape||'rounded';\n    var cfgAvatarShapeRadius=cfgAvatarShape==='circle'?'50%':cfgAvatarShape==='square'?'0px':'8px';\n    var cfgThoughtSuffixGap=clampNumber(Number.isFinite(cfg.style_thoughtSuffixGap)?cfg.style_thoughtSuffixGap:6,0,24);\n    var cfgThoughtSuffixOffsetY=clampNumber(Number.isFinite(cfg.style_thoughtSuffixOffsetY)?cfg.style_thoughtSuffixOffsetY:5,-24,24);\n    var cfgNarrationTextIndent=clampNumber(Number.isFinite(cfg.style_narrationTextIndent)?cfg.style_narrationTextIndent:0,0,4);\n    var cfgNarrationLineHeight=Number.isFinite(cfg.style_narrationLineHeight)?cfg.style_narrationLineHeight:1.75;\n    var cfgNarrationPaddingRight=clampNumber(Number.isFinite(cfg.style_narrationPaddingRight)?cfg.style_narrationPaddingRight:16,0,120);\n\n    var sourceEl=document.getElementById('dcSource');\n    var sourceRaw=sourceEl?(sourceEl.value||sourceEl.textContent||''):'';\n    var protectedResult=protectHtmlFences(sourceRaw);\n    var normalizedSource=normalizeSourceText(protectedResult.text);\n    normalizedSource=protectBlockHtml(normalizedSource, protectedResult.embeds);\n    var inlineHtmlResult=protectInlineHtml(normalizedSource);\n    var htmlEmbeds=protectedResult.embeds;\n    var inlineHtmlTokens=inlineHtmlResult.tokens;\n    var raw=extractSourceText(inlineHtmlResult.text);\n    var lines=raw.split(/\\n/);\n    var html='';\n    var narrBuf=[];\n    var debugSummary={\n      sourceLength:sourceRaw.length,\n      normalizedLength:normalizedSource.length,\n      extractedLength:raw.length,\n      totalLines:lines.length,\n      bubbleMatches:0,\n      narrationLines:0,\n      emptyLines:0,\n      previews:lines.slice(0,8),\n      lineDiagnostics:[]\n    };\n\n    function flushNarr(){\n      if(!narrBuf.length)return;\n      var narrContent=renderNarration(narrBuf,cfgMarkdownMode,htmlEmbeds,inlineHtmlTokens);\n      html+='<div class=\"dc-narration-block\" style=\"font-size:'+cfgNarrationFontSize+'px;color:'+cfgGlobalTextColor+';font-weight:'+cfgNarrationFontWeight+';background:'+cfgNarrationBackground+';padding:0 '+cfgNarrationPaddingRight+'px 0 '+cfgNarrationIndent+'px;border-radius:'+cfgNarrationBorderRadius+'px;line-height:'+cfgNarrationLineHeight+';--dc-text-indent:'+cfgNarrationTextIndent+'em;\">'+narrContent+'</div>';\n      narrBuf=[];\n    }\n\n    for(var i=0;i<lines.length;i++){\n      var sourceLine=lines[i];\n      var line=sourceLine.trim();\n      var detectionLine=buildBubbleDetectionLine(sourceLine);\n      var matchType='';\n      if(!line){\n        debugSummary.emptyLines++;\n        if(debugSummary.lineDiagnostics.length<12){\n          debugSummary.lineDiagnostics.push({index:i,sourceLine:sourceLine,trimmedLine:line,detectionLine:detectionLine,matched:false,matchType:'empty'});\n        }\n        narrBuf.push('');\n        continue;\n      }\n\n      var nm,charName,mood,tx,m;\n      var hasBracketWrapper=false;\n\n      /* 第1优先级：三段含 [] — @bubble:角色名|情绪|[台词] */\n      m=detectionLine.match(/^@bubble:([^|]+)\\|([^|]*)\\|\\[(.+?)\\]$/);\n      if(m){\n        matchType='triple_bracket';\n        charName=m[1].trim();\n        nm=charName.toLowerCase();\n        mood=m[2].trim();\n        tx=m[3].trim();\n        hasBracketWrapper=true;\n      }\n      /* 第2优先级：三段无 [] — @bubble:角色名|情绪|台词 */\n      if(!m){\n        m=detectionLine.match(/^@bubble:([^|]+)\\|([^|]*)\\|([^|]+)$/);\n        if(m){\n          matchType='triple_plain';\n          charName=m[1].trim();\n          nm=charName.toLowerCase();\n          mood=m[2].trim();\n          tx=m[3].trim();\n        }\n      }\n      /* 第3优先级：旧四段兼容（含 []）— @bubble:别名|角色名|情绪|[台词] */\n      if(!m){\n        m=detectionLine.match(/^@bubble:([^|]+)\\|([^|]+)\\|([^|]*)\\|\\[(.+?)\\]$/);\n        if(m){\n          matchType='legacy_quad_bracket';\n          charName=m[2].trim();\n          nm=charName.toLowerCase();\n          mood=m[3].trim();\n          tx=m[4].trim();\n          hasBracketWrapper=true;\n        }\n      }\n      /* 第4优先级：旧四段兼容（无 []）— @bubble:别名|角色名|情绪|台词 */\n      if(!m){\n        m=detectionLine.match(/^@bubble:([^|]+)\\|([^|]+)\\|([^|]*)\\|(.+)$/);\n        if(m){\n          matchType='legacy_quad_plain';\n          charName=m[2].trim();\n          nm=charName.toLowerCase();\n          mood=m[3].trim();\n          tx=m[4].trim();\n        }\n      }\n\n      if(debugSummary.lineDiagnostics.length<12){\n        debugSummary.lineDiagnostics.push({\n          index:i,\n          sourceLine:sourceLine,\n          trimmedLine:line,\n          detectionLine:detectionLine,\n          matched:!!m,\n          matchType:matchType,\n          charName:m?charName:'',\n          mood:m?mood:'',\n          textPreview:m?String(tx||'').slice(0,80):''\n        });\n      }\n\n      if(m){\n        debugSummary.bubbleMatches++;\n        flushNarr();\n        var ci=gc(nm);\n        var ini=esc(charName.charAt(0)||'?');\n        var avatarRadius=cfgAvatarShapeRadius;\n        var avatarPlaceholderFont=Math.max(16,Math.round(cfgAvatarSize*0.38));\n        var av='<div class=\"dc-msg-avatar-ph dc-bg'+ci+'\" style=\"font-size:'+avatarPlaceholderFont+'px;border-radius:'+avatarRadius+';\">'+ini+'</div>';\n        var nameHtml=renderName(charName,'dc-c'+ci);\n        var moodHtml='';\n        var moodState=getMoodRenderState(mood);\n        var msgMoodGroup=moodState?moodState.id:'';\n        if(mood){\n          var moodStyle=moodState?' style=\"color:'+moodState.color+';background:'+moodState.background+';\"':'';\n          var moodGroupClass=moodState?' '+moodState.id:'';\n          var moodGroupAttr=moodState?' data-mood-group=\"'+moodState.id+'\"':'';\n          moodHtml='<span class=\"dc-msg-mood dc-mood'+ci+moodGroupClass+'\" data-mood-mapped=\"'+(moodState?'1':'0')+'\"'+moodGroupAttr+moodStyle+'>'+esc(mood)+'</span>';\n        }\n\n        var textColor=cfgGlobalTextColor;\n        var isInnerThought=hasBracketWrapper&&isInnerThoughtText(tx);\n        var displayTx=isInnerThought?tx.replace(/^\\*|\\*$/g,''):tx;\n        var quoteChar=isInnerThought?'\\uFF0A':'\\u201D';\n        var quoteClass='dc-msg-quote dc-c'+ci+(isInnerThought?' dc-msg-quote-thought':'');\n        var msgPaddingLeft=cfgAvatarSize+24;\n        html+='<div class=\"dc-msg\" data-name=\"'+escapeHtmlAttr(nm)+'\" data-ci=\"'+ci+'\" data-thought=\"'+(isInnerThought?'1':'0')+'\" data-mood-group=\"'+msgMoodGroup+'\" style=\"padding-left:'+msgPaddingLeft+'px;min-height:'+Math.max(56,cfgAvatarSize+4)+'px;\">';\n        html+='<div class=\"dc-msg-avatar\" data-name=\"'+escapeHtmlAttr(nm)+'\" style=\"width:'+cfgAvatarSize+'px;height:'+cfgAvatarSize+'px;border-radius:'+avatarRadius+';\">'+av+'</div>';\n        html+='<div class=\"dc-msg-header\"><span class=\"dc-msg-name\" data-ci=\"'+ci+'\" style=\"color:'+cfgGlobalTextColor+';font-weight:'+cfgNameFontWeight+';\">'+nameHtml+'</span>'+moodHtml+'</div>';\n        var textContentClass='dc-msg-text-content'+(isInnerThought?' dc-msg-text-content-thought':'');\n        var quoteStyle=isInnerThought?' style=\"margin-left:'+cfgThoughtSuffixGap+'px;top:'+cfgThoughtSuffixOffsetY+'px;\"':'';\n        html+='<div class=\"dc-msg-text\" style=\"font-size:'+cfgDialogueFontSize+'px;line-height:'+cfgDialogueLineHeight+'px;color:'+textColor+';font-weight:'+cfgDialogueFontWeight+';\"><span class=\"'+textContentClass+'\">'+renderRichText(displayTx, inlineHtmlTokens)+'</span><span class=\"'+quoteClass+'\"'+quoteStyle+'>'+quoteChar+'</span></div>';\n        html+='</div>';\n      }else{\n        debugSummary.narrationLines++;\n        narrBuf.push(sourceLine);\n      }\n    }\n    flushNarr();\n    root.innerHTML=html;\n    debugSummary.renderedBubbleNodes=root.querySelectorAll('.dc-msg').length;\n    debugSummary.renderedNarrationNodes=root.querySelectorAll('.dc-narration-block').length;\n    debugSummary.renderedHtmlPreview=html.slice(0,800);\n    // console.log('[BubbleRender] 渲染结构摘要',debugSummary);\n    var narrationBlocks=root.querySelectorAll('.dc-narration-block');\n    for(var n=0;n<narrationBlocks.length;n++) narrationBlocks[n].style.fontFamily=cfgNarrationFontStack;\n    var nameEls=root.querySelectorAll('.dc-msg-name');\n    for(var k=0;k<nameEls.length;k++) nameEls[k].style.fontFamily=cfgNameFontStack;\n    var textEls=root.querySelectorAll('.dc-msg-text');\n    for(var t=0;t<textEls.length;t++) textEls[t].style.fontFamily=cfgDialogueFontStack;\n    hydrateHtmlEmbeds(root,sourceRaw);\n    scheduleAvatarEnhancement(root,cfgTextColorMode,cfgGlobalTextColor);\n    // console.log('[BubbleRender] 渲染完成，旁白与气泡已落地');\n  }\n\n  async function loadAvatarsAndColors(root,colorMode,globalColor){\n    var charId=getCurrentCharId()||'_global_';\n    var fallbackCharId='_global_';\n\n    var msgs=root.querySelectorAll('.dc-msg');\n    for(var i=0;i<msgs.length;i++){\n      var msg=msgs[i];\n      var name=msg.dataset.name;\n      if(!name)continue;\n\n      var moodGroup=msg.dataset.moodGroup||'';\n      var avatarUrl=null;\n      if(moodGroup){\n        avatarUrl=await getMoodAvatarUrl(charId,name,moodGroup);\n      }\n      if(!avatarUrl){\n        avatarUrl=await getAvatar(charId,name);\n      }\n      if(!avatarUrl&&charId!==fallbackCharId&&moodGroup){\n        avatarUrl=await getMoodAvatarUrl(fallbackCharId,name,moodGroup);\n      }\n      if(!avatarUrl&&charId!==fallbackCharId){\n        avatarUrl=await getAvatar(fallbackCharId,name);\n      }\n      if(avatarUrl){\n        var avDiv=msg.querySelector('.dc-msg-avatar');\n        if(avDiv) avDiv.innerHTML='<img src=\"'+avatarUrl+'\" alt=\"'+escapeHtmlAttr(name)+'\"/>';\n      }\n\n      var colorKey='color_'+charId+'__'+name;\n      var customColor=await getConfigVal(colorKey);\n      if(!customColor&&charId!==fallbackCharId){\n        customColor=await getConfigVal('color_'+fallbackCharId+'__'+name);\n      }\n      if(customColor){\n        var chs=msg.querySelectorAll('.dc-ch,.dc-cs');\n        for(var j=0;j<chs.length;j++) chs[j].style.color=customColor;\n        var moodEl=msg.querySelector('.dc-msg-mood');\n        if(moodEl&&moodEl.getAttribute('data-mood-mapped')!=='1'){\n          moodEl.style.color=customColor;\n          if(customColor.charAt(0)==='#') moodEl.style.background=hex2rgba(customColor,0.15);\n        }\n        var ph=msg.querySelector('.dc-msg-avatar-ph');\n        if(ph) ph.style.background=customColor;\n        var qt=msg.querySelector('.dc-msg-quote');\n        if(qt) qt.style.color=customColor;\n      }\n\n      if(colorMode==='character'){\n        var charColor=customColor||globalColor;\n        var textEl=msg.querySelector('.dc-msg-text');\n        if(textEl) textEl.style.color=charColor;\n      }\n    }\n  }\n\n  if(document.readyState==='complete'||document.readyState==='interactive'){\n    startBubbleRenderWhenStable();\n  }else{\n    document.addEventListener('DOMContentLoaded', startBubbleRenderWhenStable, { once:true });\n    window.addEventListener('load', startBubbleRenderWhenStable, { once:true });\n  }\n})();\n</script>\n</body>\n</html>\n\n\n````",
        "trimStrings": [],
        "placement": [
            2
        ],
        "disabled": true,
        "markdownOnly": true,
        "promptOnly": false,
        "runOnEdit": true,
        "substituteRegex": 0,
        "minDepth": 0,
        "maxDepth": 999
    }
]