"""Chatbot UI templates: CSS, JavaScript, HTML, and theme presets."""

from __future__ import annotations

import json

from kiss.agents.sorcar.browser_ui import (
    BASE_CSS,
    EVENT_HANDLER_JS,
    HTML_HEAD,
    OUTPUT_CSS,
)

_THEME_PRESETS: dict[str, dict[str, str]] = {
    "dark": {
        "bg": "#1e1e1e",
        "bg2": "#252526",
        "fg": "#d4d4d4",
        "accent": "#3794ff",
        "border": "#3c3c3c",
        "inputBg": "#313131",
        "green": "#23d18b",
        "red": "#f14c4c",
        "purple": "#b180d7",
        "cyan": "#29b8db",
    },
    "light": {
        "bg": "#ffffff",
        "bg2": "#f3f3f3",
        "fg": "#333333",
        "accent": "#005fb8",
        "border": "#d4d4d4",
        "inputBg": "#ffffff",
        "green": "#388a34",
        "red": "#cd3131",
        "purple": "#7e57c2",
        "cyan": "#0598bc",
    },
    "hcDark": {
        "bg": "#000000",
        "bg2": "#0a0a0a",
        "fg": "#ffffff",
        "accent": "#3794ff",
        "border": "#6fc3df",
        "inputBg": "#0a0a0a",
        "green": "#23d18b",
        "red": "#f48771",
        "purple": "#b180d7",
        "cyan": "#29b8db",
    },
    "hcLight": {
        "bg": "#ffffff",
        "bg2": "#f0f0f0",
        "fg": "#000000",
        "accent": "#0f4a85",
        "border": "#0f4a85",
        "inputBg": "#ffffff",
        "green": "#1b7d2c",
        "red": "#b5200d",
        "purple": "#5e3a8a",
        "cyan": "#0f4a85",
    },
}

CHATBOT_CSS = r"""
body{
  font-family:'Inter',system-ui,-apple-system,BlinkMacSystemFont,sans-serif;
  background:#0a0a0c;display:block;
}
header{
  background:rgba(10,10,12,0.85);backdrop-filter:blur(24px);
  -webkit-backdrop-filter:blur(24px);
  border-bottom:1px solid rgba(255,255,255,0.06);padding:14px 24px;z-index:50;
  box-shadow:0 1px 12px rgba(0,0,0,0.3);
}
.logo{font-size:12px;color:#4da6ff;font-weight:600;letter-spacing:-0.2px}
.status{font-size:12px;color:rgba(255,255,255,0.75)}
.dot{width:7px;height:7px;background:rgba(255,255,255,0.4)}
.dot.running{background:#22c55e}
#output{
  flex:1;overflow-y:auto;overflow-x:hidden;padding:32px 24px 24px;
  scroll-behavior:smooth;min-height:0;
}
.ev,.txt,.spinner,.empty-msg,.user-msg{max-width:820px;margin-left:auto;margin-right:auto}
.user-msg{
  background:rgba(255,255,255,0.04);border:1px solid rgba(255,255,255,0.08);
  border-radius:14px;padding:14px 20px;margin:20px auto 16px;
  font-size:14.5px;line-height:1.6;color:rgba(255,255,255,0.95);
}
.user-msg-images{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:10px}
.user-msg-img{max-width:300px;max-height:200px;border-radius:8px;
object-fit:contain;border:1px solid rgba(255,255,255,0.1)}
.txt{
  font-size:14.5px;line-height:1.75;color:rgba(255,255,255,0.92);padding:8px 14px;
  margin:6px auto;
}
.think{
  border:1px solid rgba(168,130,255,0.12);
  background:rgba(168,130,255,0.03);border-radius:10px;margin:12px auto;
  padding:12px 16px;
}
.think .lbl{color:rgba(168,130,255,0.7)}
.think .cnt{color:rgba(255,255,255,0.55)}
.tc{
  border:1px solid rgba(88,166,255,0.15);border-radius:12px;
  margin:12px auto;background:rgba(88,166,255,0.02);
  transition:border-color 0.2s,box-shadow 0.2s;
}
.tc:hover{box-shadow:0 2px 20px rgba(88,166,255,0.08);border-color:rgba(88,166,255,0.3)}
.tc-h{
  padding:10px 16px;background:rgba(88,166,255,0.03);border-radius:12px 12px 0 0;
  border-bottom:1px solid rgba(88,166,255,0.08);
}
.tc-h:hover{background:rgba(88,166,255,0.06)}
.tn{color:rgba(88,166,255,0.9);font-size:13px}
.tp{font-size:12px;color:rgba(120,180,255,0.65)}
.td{color:rgba(255,255,255,0.5)}
.tr{
  border:1px solid rgba(34,197,94,0.15);
  background:rgba(34,197,94,0.02);border-radius:10px;
}
.tr.err{
  border-color:rgba(248,81,73,0.15);
  background:rgba(248,81,73,0.02);
}
.rc{
  border:1px solid rgba(34,197,94,0.25);border-radius:14px;
  background:rgba(34,197,94,0.02);
  box-shadow:0 0 20px rgba(34,197,94,0.04);
}
.rc-h{
  padding:16px 24px;background:rgba(34,197,94,0.05);
  border-bottom:1px solid rgba(34,197,94,0.12);
}
.usage{
  border:1px solid rgba(255,255,255,0.06);background:rgba(255,255,255,0.02);
  color:rgba(255,255,255,0.5);border-radius:8px;
}
.spinner{color:rgba(255,255,255,0.5)}
.spinner::before{border-color:rgba(255,255,255,0.08);border-top-color:rgba(88,166,255,0.7)}
#input-area{
  flex-shrink:0;padding:0 24px 24px;position:relative;
  background:linear-gradient(transparent,rgba(10,10,12,0.9) 50%);
  padding-top:24px;
}
#input-container{
  max-width:820px;margin:0 auto;position:relative;
  background:rgba(255,255,255,0.035);
  border:1px solid rgba(255,255,255,0.08);
  border-radius:16px;padding:14px 18px;
  box-shadow:0 0 0 1px rgba(255,255,255,0.02),0 8px 40px rgba(0,0,0,0.35);
  transition:border-color 0.3s,box-shadow 0.3s;
}
#input-container:focus-within{
  border-color:rgba(88,166,255,0.4);
  box-shadow:0 0 0 1px rgba(88,166,255,0.12),0 0 30px rgba(88,166,255,0.1),
    0 8px 40px rgba(0,0,0,0.35);
}
#input-wrap{display:flex;align-items:flex-start;gap:8px}
#input-text-wrap{position:relative;flex:1;min-width:0}
#task-input{
  width:100%;background:transparent;border:none;padding:0;margin:0;
  color:rgba(255,255,255,0.88);font-size:15px;font-family:inherit;
  resize:none;outline:none;line-height:1.5;
  max-height:50vh;min-height:68px;overflow-y:hidden;
  position:relative;z-index:1;
}
#task-input::placeholder{color:rgba(255,255,255,0.45)}
#task-input:disabled{opacity:0.35;cursor:not-allowed;pointer-events:none}
#merge-warning{
  position:absolute;bottom:calc(100% + 6px);left:50%;transform:translateX(-50%);
  background:rgba(220,38,38,0.95);color:#fff;font-size:14px;font-weight:800;
  padding:6px 14px;border-radius:6px;white-space:nowrap;pointer-events:none;
  opacity:0;transition:opacity 0.25s;z-index:200;
}
#merge-warning.visible{opacity:1}
#ghost-overlay{
  position:absolute;top:0;left:0;right:0;bottom:0;
  pointer-events:none;user-select:none;
  font-size:15px;font-family:inherit;line-height:1.5;
  white-space:pre-wrap;word-break:break-word;overflow:hidden;
  z-index:0;
}
.gm{visibility:hidden;white-space:pre-wrap}
.gs{color:rgba(255,255,255,0.35)}
#input-footer{
  display:flex;justify-content:space-between;align-items:center;
  margin-top:10px;padding-top:10px;
  border-top:1px solid rgba(255,255,255,0.04);
}
#model-picker{position:relative;display:flex;align-items:center;gap:4px;min-width:0;overflow:visible}
#model-btn{
  background:rgba(255,255,255,0.03);color:rgba(255,255,255,0.5);
  border:1px solid rgba(255,255,255,0.08);border-radius:8px;
  padding:6px 12px;font-size:12px;font-family:inherit;
  outline:none;cursor:pointer;max-width:300px;transition:border-color 0.2s;
  display:flex;align-items:center;gap:6px;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;
}
#model-btn:hover{border-color:rgba(255,255,255,0.16);color:rgba(255,255,255,0.65)}
#model-btn svg{flex-shrink:0;opacity:0.4}
#model-dropdown{
  position:absolute;bottom:100%;left:0;min-width:320px;max-width:420px;
  background:rgba(18,18,20,0.97);backdrop-filter:blur(20px);
  border:1px solid rgba(255,255,255,0.08);border-radius:12px;
  max-height:360px;display:none;z-index:15;
  box-shadow:0 -8px 32px rgba(0,0,0,0.5);overflow:hidden;
  flex-direction:column;
}
#model-dropdown.open{display:flex}
#model-search{
  width:100%;background:transparent;border:none;
  border-bottom:1px solid rgba(255,255,255,0.06);
  color:rgba(255,255,255,0.8);font-size:12px;font-family:inherit;
  padding:10px 14px;outline:none;
}
#model-search::placeholder{color:rgba(255,255,255,0.25)}
#model-list{overflow-y:auto;flex:1}
.model-item{
  padding:7px 14px;cursor:pointer;font-size:12px;
  display:flex;justify-content:space-between;align-items:center;
  border-bottom:1px solid rgba(255,255,255,0.02);transition:background 0.08s;
  color:rgba(255,255,255,0.6);
}
.model-item:hover,.model-item.sel{background:rgba(88,166,255,0.08)}
.model-item.active{color:rgba(88,166,255,0.9);font-weight:500}
.model-cost{font-size:10px;color:rgba(255,255,255,0.2);flex-shrink:0;margin-left:12px}
.model-group-hdr{
  padding:6px 14px 4px;font-size:10px;font-weight:600;
  text-transform:uppercase;letter-spacing:0.05em;
  color:rgba(255,255,255,0.25);
  background:rgba(18,18,20,0.97);
  border-bottom:1px solid rgba(255,255,255,0.04);
  position:sticky;top:0;z-index:1;
}
#upload-btn{
  background:rgba(255,255,255,0.03);color:rgba(255,255,255,0.5);
  border:1px solid rgba(255,255,255,0.08);border-radius:8px;
  padding:6px 8px;cursor:pointer;flex-shrink:0;
  transition:color 0.15s,border-color 0.2s;display:flex;align-items:center;justify-content:center;
}
#upload-btn:hover{color:rgba(255,255,255,0.65);border-color:rgba(255,255,255,0.16);background:rgba(255,255,255,0.05)}
#upload-btn svg{width:12px;height:12px}
#upload-btn:disabled{opacity:0.2;cursor:not-allowed}
#file-chips{
  display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;max-width:820px;margin-left:auto;margin-right:auto;
}
#file-chips:empty{display:none;margin-bottom:0}
.file-chip{
  display:inline-flex;align-items:center;gap:5px;
  background:rgba(88,166,255,0.08);border:1px solid rgba(88,166,255,0.15);
  border-radius:8px;padding:4px 10px;font-size:11px;color:rgba(88,166,255,0.8);
}
.file-chip img{width:24px;height:24px;border-radius:4px;object-fit:cover}
.file-chip .fc-icon{font-size:14px;opacity:0.6}
.file-chip .fc-rm{
  cursor:pointer;color:rgba(255,255,255,0.3);font-size:14px;margin-left:2px;
  transition:color 0.15s;
}
.file-chip .fc-rm:hover{color:rgba(248,81,73,0.8)}
#input-actions{display:flex;gap:8px;align-items:center;flex-shrink:0}
#send-btn{
  background:rgba(88,166,255,0.15);color:rgba(88,166,255,0.9);border:none;
  border-radius:50%;width:36px;height:36px;cursor:pointer;
  transition:all 0.2s;display:flex;align-items:center;justify-content:center;
  flex-shrink:0;
}
#send-btn:hover{background:rgba(88,166,255,0.3);color:#fff;box-shadow:0 0 16px rgba(88,166,255,0.2)}
#send-btn:disabled{opacity:0.2;cursor:not-allowed;box-shadow:none}
#send-btn svg{width:16px;height:16px}
#stop-btn{
  background:rgba(248,81,73,0.1);color:#f85149;
  border:1px solid rgba(248,81,73,0.15);
  border-radius:50%;width:36px;height:36px;
  cursor:pointer;transition:all 0.2s;display:none;
  align-items:center;justify-content:center;flex-shrink:0;
}
#stop-btn:hover{background:rgba(248,81,73,0.2);box-shadow:0 0 16px rgba(248,81,73,0.15)}
#stop-btn svg{width:14px;height:14px}
#wait-spinner{
  width:16px;height:16px;
  border:2px solid rgba(255,255,255,0.08);
  border-top-color:rgba(255,255,255,0.15);
  border-radius:50%;
  flex-shrink:0;
  transition:opacity 0.2s;
  opacity:0.4;
}
#wait-spinner.active{
  border-color:rgba(255,255,255,0.15);
  border-top-color:rgba(88,166,255,0.7);
  animation:spin .8s linear infinite;
  opacity:1;
}
#clear-btn{
  background:none;color:rgba(255,255,255,0.2);border:none;
  width:24px;height:24px;cursor:pointer;flex-shrink:0;
  transition:color 0.15s;display:flex;align-items:center;justify-content:center;
  padding:0;margin-top:1px;
}
#clear-btn:hover{color:rgba(255,255,255,0.6)}
#clear-btn svg{width:14px;height:14px}
@keyframes acSlideUp{
  from{opacity:0;transform:translateY(6px)}
  to{opacity:1;transform:none}
}
#autocomplete{
  position:absolute;bottom:100%;left:0;right:0;
  max-width:820px;margin:0 auto;
  background:rgba(16,16,18,0.98);backdrop-filter:blur(24px);
  -webkit-backdrop-filter:blur(24px);
  border:1px solid rgba(255,255,255,0.07);border-radius:14px;
  max-height:360px;overflow-y:auto;display:none;z-index:10;
  box-shadow:0 -12px 48px rgba(0,0,0,0.55),
    0 0 0 1px rgba(255,255,255,0.04),
    0 -2px 8px rgba(88,166,255,0.04);
  animation:acSlideUp 0.15s ease;
}
.ac-section{
  padding:4px 16px 2px;font-size:9.5px;font-weight:700;
  text-transform:uppercase;letter-spacing:0.08em;
  color:rgba(255,255,255,0.22);
  background:rgba(16,16,18,0.98);
  border-bottom:1px solid rgba(255,255,255,0.035);
  position:sticky;top:0;z-index:1;
}
.ac-item{
  padding:3px 16px;cursor:pointer;font-size:13px;
  border-bottom:1px solid rgba(255,255,255,0.02);
  display:flex;align-items:center;gap:6px;
  transition:background 0.1s,border-color 0.1s;
  border-left:2px solid transparent;
}
.ac-item:last-child{border-bottom:none}
.ac-item:hover{background:rgba(88,166,255,0.06)}
.ac-item.sel{
  background:rgba(88,166,255,0.1);
  border-left-color:rgba(88,166,255,0.7);
}
.ac-icon{
  flex-shrink:0;width:16px;height:16px;
  display:flex;align-items:center;justify-content:center;
  border-radius:4px;
  background:rgba(255,255,255,0.04);
  color:rgba(255,255,255,0.4);font-size:11px;
}
.ac-icon svg{width:11px;height:11px;stroke:currentColor;fill:none;
  stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.ac-item.sel .ac-icon{
  background:rgba(88,166,255,0.12);
  color:rgba(88,166,255,0.8);
}
.ac-text{
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  color:rgba(255,255,255,0.55);flex:1;min-width:0;
  font-family:'SF Mono','Fira Code','Cascadia Code',monospace;
  font-size:12.5px;letter-spacing:-0.01em;
}
.ac-item.sel .ac-text{color:rgba(255,255,255,0.85)}
.ac-dir{color:rgba(255,255,255,0.3)}
.ac-fname{color:rgba(255,255,255,0.7)}
.ac-item.sel .ac-dir{color:rgba(255,255,255,0.45)}
.ac-item.sel .ac-fname{color:rgba(255,255,255,0.95)}
.ac-hl{color:rgba(88,166,255,0.95);font-weight:600}
.ac-hint{
  font-size:9px;color:rgba(255,255,255,0.18);
  background:rgba(255,255,255,0.04);
  border:1px solid rgba(255,255,255,0.05);
  padding:2px 7px;border-radius:4px;margin-left:auto;
  flex-shrink:0;
  font-family:'SF Mono','Fira Code',monospace;
}
.ac-item.sel .ac-hint{
  color:rgba(88,166,255,0.5);
  background:rgba(88,166,255,0.06);
  border-color:rgba(88,166,255,0.12);
}
.ac-footer{
  padding:3px 16px;font-size:10px;color:rgba(255,255,255,0.13);
  border-top:1px solid rgba(255,255,255,0.04);
  display:flex;gap:14px;
  background:rgba(16,16,18,0.98);
  position:sticky;bottom:0;
}
.ac-footer kbd{
  background:rgba(255,255,255,0.05);color:rgba(255,255,255,0.22);
  padding:1px 5px;border-radius:3px;font-size:9px;
  font-family:'SF Mono','Fira Code',monospace;
  border:1px solid rgba(255,255,255,0.04);
}
#welcome{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  min-height:100%;padding:40px 20px;text-align:center;max-width:820px;margin:0 auto;
}
#welcome h2{
  font-size:28px;font-weight:700;color:rgba(255,255,255,0.92);
  margin-bottom:8px;letter-spacing:-0.5px;
  animation:fadeUp 0.5s ease;
}
@keyframes fadeUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
#welcome p{color:rgba(255,255,255,0.55);font-size:14px;margin-bottom:36px;
  animation:fadeUp 0.5s ease 0.1s both}
#suggestions{animation:fadeUp 0.5s ease 0.2s both;
  display:grid;grid-template-columns:1fr 1fr;gap:12px;width:100%;max-width:760px;
}
.suggestion-chip{
  background:rgba(255,255,255,0.025);border:1px solid rgba(255,255,255,0.06);
  border-radius:12px;padding:14px 18px;cursor:pointer;text-align:left;
  font-size:13px;color:rgba(255,255,255,0.82);line-height:1.5;
  transition:all 0.2s ease;
  overflow:hidden;min-width:0;overflow-wrap:break-word;word-break:break-word;
}
.suggestion-chip:hover{
  background:rgba(255,255,255,0.055);border-color:rgba(255,255,255,0.14);
  color:rgba(255,255,255,0.95);transform:translateY(-2px);
  box-shadow:0 4px 24px rgba(0,0,0,0.35),0 0 0 1px rgba(255,255,255,0.05);
}
.suggestion-chip:active{transform:translateY(0);transition-duration:0.05s}
.chip-label{
  font-size:10px;font-weight:600;text-transform:uppercase;
  letter-spacing:0.04em;margin-bottom:5px;display:block;
}
.chip-label.recent{color:rgba(88,166,255,0.7)}

#sidebar{
  position:fixed;right:0;top:0;bottom:0;width:340px;
  background:rgba(12,12,14,0.95);backdrop-filter:blur(24px);
  border-left:1px solid rgba(255,255,255,0.06);
  transform:translateX(100%);transition:transform 0.3s cubic-bezier(0.4,0,0.2,1);
  z-index:200;overflow-y:auto;padding:24px;
}
#sidebar.open{transform:translateX(0)}
#sidebar-overlay{
  position:fixed;inset:0;background:rgba(0,0,0,0.4);
  z-index:199;opacity:0;pointer-events:none;transition:opacity 0.3s;
}
#sidebar-overlay.open{opacity:1;pointer-events:auto}
#history-btn,#run-prompt-btn{
  background:none;border:none;
  color:rgba(255,255,255,0.3);cursor:pointer;
  padding:4px;transition:color 0.15s,opacity 0.15s;display:flex;align-items:center;
}
#history-btn:hover{color:rgba(255,255,255,0.6)}
#run-prompt-btn:not(:disabled):hover{color:rgba(34,197,94,0.9)}
#run-prompt-btn:disabled{opacity:0.15;cursor:not-allowed}
#run-prompt-btn:not(:disabled){color:rgba(34,197,94,0.7)}
#sidebar-close{
  position:absolute;top:16px;right:16px;background:none;border:none;
  color:rgba(255,255,255,0.3);font-size:20px;cursor:pointer;
  padding:4px 8px;border-radius:6px;transition:all 0.15s;
}
#sidebar-close:hover{color:rgba(255,255,255,0.7);background:rgba(255,255,255,0.05)}
.sidebar-section{margin-bottom:28px}
.sidebar-hdr{
  font-size:11px;font-weight:600;text-transform:uppercase;
  letter-spacing:0.06em;color:rgba(255,255,255,0.25);margin-bottom:12px;
}
.sidebar-item{
  padding:10px 14px;background:rgba(255,255,255,0.02);
  border:1px solid rgba(255,255,255,0.04);border-radius:10px;
  margin-bottom:6px;cursor:pointer;font-size:13px;
  color:rgba(255,255,255,0.5);transition:all 0.15s;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.sidebar-item:hover{
  border-color:rgba(255,255,255,0.1);background:rgba(255,255,255,0.04);
  color:rgba(255,255,255,0.8);
}
.sidebar-empty{color:rgba(255,255,255,0.2);font-size:13px;padding:8px 0}
#history-search{
  width:100%;background:rgba(255,255,255,0.04);
  border:1px solid rgba(255,255,255,0.08);border-radius:8px;
  color:rgba(255,255,255,0.8);font-size:12px;font-family:inherit;
  padding:8px 12px;outline:none;margin-bottom:12px;
  transition:border-color 0.2s;
}
#history-search:focus{border-color:rgba(88,166,255,0.4)}
#history-search::placeholder{color:rgba(255,255,255,0.25)}
.followup-bar{
  max-width:820px;margin:16px auto 8px;padding:12px 18px;
  background:rgba(188,140,255,0.04);
  border:1px solid rgba(188,140,255,0.15);border-radius:12px;
  cursor:pointer;transition:all 0.2s;display:flex;align-items:center;gap:10px;
}
.followup-bar:hover{
  background:rgba(188,140,255,0.08);
  border-color:rgba(188,140,255,0.3);
  transform:translateY(-1px);
  box-shadow:0 4px 20px rgba(188,140,255,0.08);
}
.fu-label{
  font-size:10px;font-weight:600;text-transform:uppercase;
  letter-spacing:0.04em;color:rgba(188,140,255,0.7);
  white-space:nowrap;flex-shrink:0;
}
.fu-text{
  font-size:13.5px;color:rgba(255,255,255,0.82);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.llm-panel{
  border:1px solid rgba(88,166,255,0.15);border-radius:10px;
  margin:8px auto;max-height:350px;overflow-y:auto;
  padding:12px 16px;background:rgba(88,166,255,0.03);
  max-width:820px;
}
.llm-panel .txt{font-size:10px;line-height:1.5;color:rgba(255,255,255,0.75)}
.llm-panel .think .cnt{font-size:10px}
.bash-panel{
  max-width:820px;margin-left:auto;margin-right:auto;
  background:rgba(0,0,0,0.5);color:rgba(255,255,255,0.7);
  border-color:rgba(255,255,255,0.05);
}
#split-container{display:flex;height:100%;width:100%;overflow:hidden}
#editor-panel{position:relative;overflow:hidden}
#editor-panel iframe{
  width:125%;height:125%;border:none;
  transform:scale(0.8);transform-origin:0 0;
}
#editor-fallback{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  height:100%;background:#1e1e1e;color:rgba(255,255,255,0.7);
  font-size:14px;text-align:center;padding:40px;gap:4px;
}
#editor-fallback h3{color:rgba(255,255,255,0.9);margin-bottom:12px;font-size:20px}
#editor-fallback code{
  background:rgba(255,255,255,0.08);padding:8px 16px;border-radius:8px;
  display:block;margin:8px 0;font-size:13px;color:rgba(255,255,255,0.8);
}
#editor-fallback p{margin:4px 0;color:rgba(255,255,255,0.5);font-size:13px}
#merge-toolbar{
  display:none;position:fixed;bottom:48px;left:50%;transform:translateX(-50%);
  z-index:100;gap:3px;
  background:rgba(18,18,20,0.95);backdrop-filter:blur(12px);
  -webkit-backdrop-filter:blur(12px);
  border:1px solid rgba(255,255,255,0.15);border-radius:8px;
  padding:4px 6px;
  box-shadow:0 4px 24px rgba(0,0,0,0.5);
}
#merge-toolbar button{
  background:rgba(255,255,255,0.08);border:1px solid rgba(255,255,255,0.12);
  border-radius:4px;color:rgba(255,255,255,0.7);
  width:28px;height:28px;padding:0;cursor:pointer;transition:all 0.15s;
  display:inline-flex;align-items:center;justify-content:center;
}
#merge-toolbar button svg{width:14px;height:14px;flex-shrink:0}
#merge-toolbar button:hover{
  background:rgba(88,166,255,0.15);border-color:rgba(88,166,255,0.3);color:#fff;
}
#merge-toolbar .mt-sep{
  width:1px;height:20px;background:rgba(255,255,255,0.1);margin:0 2px;align-self:center;
}
#divider{
  width:6px;flex-shrink:0;cursor:col-resize;
  background:rgba(255,255,255,0.06);position:relative;z-index:10;
  transition:background 0.15s;
}
#divider:hover,#divider.active{background:rgba(88,166,255,0.5)}
#divider::after{
  content:'';position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  width:2px;height:40px;background:rgba(255,255,255,0.2);border-radius:1px;
}
#assistant-panel{
  display:flex;flex-direction:column;overflow:hidden;min-width:0;
  background:#0a0a0c;position:relative;flex:1;
}
.tp[data-path]{cursor:pointer;text-decoration:underline dotted}
.tp[data-path]:hover{color:rgba(120,180,255,0.8);text-decoration:underline solid}
#assistant-panel{font-size:11px}
#assistant-panel header{padding:8px 12px}
#assistant-panel .logo{font-size:11px}
#assistant-panel .status{font-size:11px}
#assistant-panel #history-btn svg{width:12px;height:12px}
#assistant-panel #welcome{padding:20px 14px}
#assistant-panel #welcome h2{font-size:17px;margin-bottom:3px;letter-spacing:-0.3px}
#assistant-panel #welcome p{font-size:11px;margin-bottom:14px}
#assistant-panel #suggestions{grid-template-columns:1fr;gap:5px;max-width:100%}
#assistant-panel .suggestion-chip{
  padding:7px 11px;border-radius:8px;font-size:11px;line-height:1.35;
}
#assistant-panel .chip-label{font-size:9px;margin-bottom:2px}
#assistant-panel #output{padding:14px 12px 12px}
#assistant-panel .ev,#assistant-panel .txt,#assistant-panel .spinner,
#assistant-panel .empty-msg,#assistant-panel .user-msg,
#assistant-panel .llm-panel,#assistant-panel .bash-panel,
#assistant-panel .followup-bar{max-width:none}
#assistant-panel .user-msg{
  font-size:11px;padding:10px 14px;margin:12px 0 10px;border-radius:10px;
}
#assistant-panel .txt{font-size:11px;padding:4px 10px}
#assistant-panel .tn{font-size:11px}
#assistant-panel .tp{font-size:11px}
#assistant-panel .tc{margin:8px 0;border-radius:8px}
#assistant-panel .tc-h{padding:7px 10px;border-radius:8px 8px 0 0}
#assistant-panel .tc-b{padding:6px 10px;max-height:200px;font-size:10px}
#assistant-panel .tr{padding:5px 10px;max-height:150px;font-size:10px}
#assistant-panel .think{padding:8px 12px;margin:8px 0;border-radius:8px}
#assistant-panel .think .cnt{font-size:10px}
#assistant-panel .rc{border-radius:10px}
#assistant-panel .rc-body{padding:10px 14px;max-height:250px;font-size:10px}
#assistant-panel #input-area{padding:0 12px 12px;padding-top:10px}
#assistant-panel #input-container{padding:8px 10px;border-radius:10px}
#assistant-panel #input-wrap{gap:4px}
#assistant-panel #task-input,#assistant-panel #ghost-overlay{font-size:11px}
#assistant-panel #input-footer{margin-top:5px;padding-top:5px}
#assistant-panel #model-btn{font-size:11px;padding:4px 8px;border-radius:6px}
#assistant-panel #model-search{font-size:11px;padding:7px 10px}
#assistant-panel .model-item{font-size:11px;padding:5px 10px}
#assistant-panel .model-cost{font-size:9px}
#assistant-panel .model-group-hdr{font-size:9px;padding:4px 10px 3px}
#assistant-panel #send-btn{width:28px;height:28px}
#assistant-panel #send-btn svg{width:12px;height:12px}
#assistant-panel #stop-btn{width:28px;height:28px}
#assistant-panel #stop-btn svg{width:11px;height:11px}
#assistant-panel #wait-spinner{width:12px;height:12px}
#assistant-panel #clear-btn{width:18px;height:18px}
#assistant-panel #clear-btn svg{width:11px;height:11px}
#assistant-panel #upload-btn{padding:4px 6px;border-radius:6px}
#assistant-panel #upload-btn svg{width:11px;height:11px}
#assistant-panel #history-search{font-size:11px;padding:6px 10px}
#assistant-panel .sidebar-hdr{font-size:10px}
#assistant-panel .sidebar-item{font-size:11px;padding:7px 10px;border-radius:8px;margin-bottom:4px}
#assistant-panel .sidebar-empty{font-size:11px}
#assistant-panel #sidebar-close{font-size:17px}
#assistant-panel .ac-item{font-size:9px;padding:2px 12px;gap:4px}
#assistant-panel .ac-icon{width:14px;height:14px;border-radius:3px}
#assistant-panel .ac-icon svg{width:10px;height:10px}
#assistant-panel .ac-text{font-size:9px}
#assistant-panel .ac-section{font-size:6px;padding:2px 12px 1px}
#assistant-panel .ac-hint{font-size:6px;padding:1px 5px}
#assistant-panel .ac-footer{font-size:7px;padding:2px 12px}
#assistant-panel .ac-footer kbd{font-size:6px}
#assistant-panel .fu-label{font-size:9px}
#assistant-panel .fu-text{font-size:11px}
#assistant-panel .followup-bar{padding:8px 12px;margin:10px 0 6px;border-radius:8px}
#assistant-panel .llm-panel{padding:8px 10px;margin:6px 0;border-radius:8px}
#assistant-panel .llm-panel .txt{font-size:10px}
#assistant-panel .bash-panel{max-height:200px;font-size:10px}
#assistant-panel .prompt-h{font-size:10px;padding:6px 12px}
#assistant-panel .prompt-body{font-size:10px;padding:8px 12px}
#assistant-panel .rc-h{
  padding:10px 14px;flex-direction:column;align-items:flex-start;gap:6px;
}
#assistant-panel .rc-h h3{font-size:10px;margin-bottom:2px}
#assistant-panel .rs{
  font-size:10px;gap:0;width:100%;
  display:grid;grid-template-columns:repeat(3,1fr);
}
#assistant-panel .rs b{display:block;font-size:11px}
#assistant-panel .td{font-size:10px}
#assistant-panel .sys{font-size:11px}
#assistant-panel .spinner{font-size:11px}
#assistant-panel .empty-msg{font-size:11px}
#assistant-panel .rl{font-size:10px}
#assistant-panel .usage{font-size:11px}
"""

CHATBOT_THEME_CSS = r"""
body,#assistant-panel{
  --bg:#1e1e1e;--surface:#252526;--surface2:#2d2d2d;--border:#3c3c3c;
  --text:#d4d4d4;--dim:#858585;--accent:#3794ff;--green:#23d18b;
  --red:#f14c4c;--yellow:#d29922;--cyan:#29b8db;--purple:#b180d7;
  --bg-rgb:30,30,30;--bg2-rgb:37,37,38;--fg-rgb:212,212,212;
  --accent-rgb:55,148,255;--border-rgb:60,60,60;--green-rgb:35,209,139;
  --red-rgb:241,76,76;--purple-rgb:177,128,215;--cyan-rgb:41,184,219;
  --input-bg:#313131;
}
body{background:var(--bg)}
#assistant-panel{background:var(--bg)}
#assistant-panel header{
  background:rgba(var(--bg2-rgb),0.92);
  border-bottom:1px solid var(--border);
  box-shadow:0 1px 8px rgba(0,0,0,0.2);
}
#assistant-panel .logo{color:var(--accent)}
#assistant-panel .status{color:rgba(var(--fg-rgb),0.65)}
#assistant-panel .dot{background:rgba(var(--fg-rgb),0.35)}
#assistant-panel .dot.running{background:var(--green)}
#assistant-panel .user-msg{
  background:rgba(var(--fg-rgb),0.04);
  border:1px solid rgba(var(--fg-rgb),0.08);
  color:rgba(var(--fg-rgb),0.95);
}
#assistant-panel .txt{color:rgba(var(--fg-rgb),0.92)}
#assistant-panel .think{
  border:1px solid rgba(var(--purple-rgb),0.15);
  background:rgba(var(--purple-rgb),0.04);
}
#assistant-panel .think .lbl{color:rgba(var(--purple-rgb),0.8)}
#assistant-panel .think .cnt{color:rgba(var(--fg-rgb),0.55)}
#assistant-panel .tc{
  border:1px solid var(--border);
  background:rgba(var(--accent-rgb),0.02);
}
#assistant-panel .tc:hover{
  box-shadow:0 2px 16px rgba(var(--accent-rgb),0.06);
  border-color:rgba(var(--accent-rgb),0.25);
}
#assistant-panel .tc-h{
  background:rgba(var(--accent-rgb),0.04);
  border-bottom:1px solid rgba(var(--accent-rgb),0.08);
}
#assistant-panel .tc-h:hover{background:rgba(var(--accent-rgb),0.07)}
#assistant-panel .tn{color:var(--accent)}
#assistant-panel .tp{color:rgba(var(--cyan-rgb),0.85)}
#assistant-panel .td{color:rgba(var(--fg-rgb),0.5)}
#assistant-panel .tr{
  border:1px solid rgba(var(--green-rgb),0.2);
  background:rgba(var(--green-rgb),0.03);
}
#assistant-panel .tr.err{
  border-color:rgba(var(--red-rgb),0.2);
  background:rgba(var(--red-rgb),0.03);
}
#assistant-panel .rc{
  border:1px solid rgba(var(--green-rgb),0.25);
  background:rgba(var(--green-rgb),0.02);
}
#assistant-panel .rc-h{
  background:rgba(var(--green-rgb),0.06);
  border-bottom:1px solid rgba(var(--green-rgb),0.12);
}
#assistant-panel .usage{
  border:1px solid var(--border);background:rgba(var(--fg-rgb),0.02);
  color:rgba(var(--fg-rgb),0.5);
}
#assistant-panel .spinner{color:rgba(var(--fg-rgb),0.55)}
#assistant-panel .spinner::before{
  border-color:var(--border);border-top-color:rgba(var(--accent-rgb),0.7);
}
#assistant-panel #input-area{
  background:linear-gradient(transparent,rgba(var(--bg-rgb),0.95) 50%);
}
#assistant-panel #input-container{
  background:var(--input-bg);
  border:1px solid var(--border);
  box-shadow:0 0 0 1px rgba(var(--fg-rgb),0.02),0 4px 24px rgba(0,0,0,0.25);
}
#assistant-panel #input-container:focus-within{
  border-color:rgba(var(--accent-rgb),0.5);
  box-shadow:0 0 0 1px rgba(var(--accent-rgb),0.15),0 0 20px rgba(var(--accent-rgb),0.08),
    0 4px 24px rgba(0,0,0,0.25);
}
#assistant-panel #task-input{color:var(--text)}
#assistant-panel #task-input::placeholder{color:rgba(var(--fg-rgb),0.45)}
#assistant-panel .gs{color:rgba(var(--fg-rgb),0.4)}
#assistant-panel #input-footer{border-top:1px solid rgba(var(--fg-rgb),0.06)}
#assistant-panel #model-btn{
  background:rgba(var(--fg-rgb),0.04);color:rgba(var(--fg-rgb),0.5);
  border:1px solid var(--border);
}
#assistant-panel #model-btn:hover{
  border-color:rgba(var(--fg-rgb),0.2);color:rgba(var(--fg-rgb),0.7);
}
#assistant-panel #model-dropdown{
  background:rgba(var(--bg2-rgb),0.97);
  border:1px solid var(--border);box-shadow:0 -4px 24px rgba(0,0,0,0.4);
}
#assistant-panel #model-search{
  border-bottom:1px solid rgba(var(--fg-rgb),0.08);color:rgba(var(--fg-rgb),0.8);
}
#assistant-panel #model-search::placeholder{color:rgba(var(--fg-rgb),0.3)}
#assistant-panel .model-item{
  border-bottom:1px solid rgba(var(--fg-rgb),0.03);color:rgba(var(--fg-rgb),0.6);
}
#assistant-panel .model-item:hover,#assistant-panel .model-item.sel{
  background:rgba(var(--accent-rgb),0.1);
}
#assistant-panel .model-item.active{color:var(--accent)}
#assistant-panel .model-cost{color:rgba(var(--fg-rgb),0.25)}
#assistant-panel .model-group-hdr{
  color:rgba(var(--fg-rgb),0.3);background:rgba(var(--bg2-rgb),0.97);
  border-bottom:1px solid rgba(var(--fg-rgb),0.05);
}
#assistant-panel #send-btn{
  background:rgba(var(--accent-rgb),0.18);color:var(--accent);
}
#assistant-panel #send-btn:hover{
  background:rgba(var(--accent-rgb),0.35);color:#fff;
  box-shadow:0 0 12px rgba(var(--accent-rgb),0.2);
}
#assistant-panel #stop-btn{
  background:rgba(var(--red-rgb),0.12);color:var(--red);
  border:1px solid rgba(var(--red-rgb),0.2);
}
#assistant-panel #stop-btn:hover{
  background:rgba(var(--red-rgb),0.25);
  box-shadow:0 0 12px rgba(var(--red-rgb),0.15);
}
#assistant-panel #wait-spinner{
  border-color:rgba(var(--fg-rgb),0.08);
  border-top-color:rgba(var(--fg-rgb),0.15);
}
#assistant-panel #wait-spinner.active{
  border-color:var(--border);border-top-color:var(--accent);
}
#assistant-panel #clear-btn{color:rgba(var(--fg-rgb),0.25)}
#assistant-panel #clear-btn:hover{color:rgba(var(--fg-rgb),0.6)}
#assistant-panel #autocomplete{
  background:rgba(var(--bg2-rgb),0.97);border:1px solid var(--border);
  box-shadow:0 -4px 24px rgba(0,0,0,0.4);
}
#assistant-panel .ac-section{
  color:rgba(var(--fg-rgb),0.25);background:rgba(var(--bg2-rgb),0.97);
  border-bottom:1px solid rgba(var(--fg-rgb),0.04);
}
#assistant-panel .ac-item{
  border-bottom:1px solid rgba(var(--fg-rgb),0.03);
  border-left:2px solid transparent;
}
#assistant-panel .ac-item:hover{
  background:rgba(var(--accent-rgb),0.06);
}
#assistant-panel .ac-item.sel{
  background:rgba(var(--accent-rgb),0.1);
  border-left-color:var(--accent);
}
#assistant-panel .ac-icon{
  background:rgba(var(--fg-rgb),0.05);
  color:rgba(var(--fg-rgb),0.4);
}
#assistant-panel .ac-item.sel .ac-icon{
  background:rgba(var(--accent-rgb),0.12);
  color:var(--accent);
}
#assistant-panel .ac-text{color:rgba(var(--fg-rgb),0.55)}
#assistant-panel .ac-item.sel .ac-text{
  color:rgba(var(--fg-rgb),0.9);
}
#assistant-panel .ac-dir{color:rgba(var(--fg-rgb),0.3)}
#assistant-panel .ac-fname{color:rgba(var(--fg-rgb),0.7)}
#assistant-panel .ac-item.sel .ac-dir{
  color:rgba(var(--fg-rgb),0.45);
}
#assistant-panel .ac-item.sel .ac-fname{
  color:rgba(var(--fg-rgb),0.95);
}
#assistant-panel .ac-hl{color:var(--accent)}
#assistant-panel .ac-hint{
  color:rgba(var(--fg-rgb),0.2);
  background:rgba(var(--fg-rgb),0.04);
  border-color:rgba(var(--fg-rgb),0.06);
}
#assistant-panel .ac-item.sel .ac-hint{
  color:rgba(var(--accent-rgb),0.5);
  background:rgba(var(--accent-rgb),0.06);
  border-color:rgba(var(--accent-rgb),0.12);
}
#assistant-panel .ac-footer{
  color:rgba(var(--fg-rgb),0.15);
  border-top:1px solid rgba(var(--fg-rgb),0.05);
  background:rgba(var(--bg2-rgb),0.98);
}
#assistant-panel .ac-footer kbd{
  background:rgba(var(--fg-rgb),0.06);
  color:rgba(var(--fg-rgb),0.25);
  border:1px solid rgba(var(--fg-rgb),0.04);
}
#assistant-panel #welcome h2{color:var(--text)}
#assistant-panel #welcome p{color:rgba(var(--fg-rgb),0.45)}
#assistant-panel .suggestion-chip{
  background:rgba(var(--fg-rgb),0.03);
  border:1px solid rgba(var(--fg-rgb),0.07);color:rgba(var(--fg-rgb),0.7);
}
#assistant-panel .suggestion-chip:hover{
  background:rgba(var(--fg-rgb),0.07);
  border-color:rgba(var(--fg-rgb),0.15);color:rgba(var(--fg-rgb),0.9);
  box-shadow:0 4px 20px rgba(0,0,0,0.25);
}
#assistant-panel .chip-label.recent{color:rgba(var(--accent-rgb),0.75)}

#assistant-panel #sidebar{
  background:rgba(var(--bg2-rgb),0.97);border-left:1px solid var(--border);
}
#assistant-panel #sidebar-overlay{background:rgba(0,0,0,0.35)}
#assistant-panel #history-btn{
  color:rgba(var(--fg-rgb),0.35);
}
#assistant-panel #history-btn:hover{
  color:rgba(var(--fg-rgb),0.6);
}
#assistant-panel #run-prompt-btn:not(:disabled){color:rgba(var(--green-rgb),0.7)}
#assistant-panel #run-prompt-btn:not(:disabled):hover{color:var(--green)}
#assistant-panel #sidebar-close{color:rgba(var(--fg-rgb),0.35)}
#assistant-panel #sidebar-close:hover{
  color:rgba(var(--fg-rgb),0.7);background:rgba(var(--fg-rgb),0.06);
}
#assistant-panel .sidebar-hdr{color:rgba(var(--fg-rgb),0.3)}
#assistant-panel .sidebar-item{
  background:rgba(var(--fg-rgb),0.02);border:1px solid rgba(var(--fg-rgb),0.05);
  color:rgba(var(--fg-rgb),0.5);
}
#assistant-panel .sidebar-item:hover{
  border-color:rgba(var(--fg-rgb),0.12);background:rgba(var(--fg-rgb),0.05);
  color:rgba(var(--fg-rgb),0.8);
}
#assistant-panel .sidebar-empty{color:rgba(var(--fg-rgb),0.25)}
#assistant-panel #history-search{
  background:rgba(var(--fg-rgb),0.04);border:1px solid var(--border);
  color:rgba(var(--fg-rgb),0.8);
}
#assistant-panel #history-search:focus{border-color:rgba(var(--accent-rgb),0.5)}
#assistant-panel #history-search::placeholder{color:rgba(var(--fg-rgb),0.3)}
#assistant-panel .followup-bar{
  background:rgba(var(--purple-rgb),0.05);
  border:1px solid rgba(var(--purple-rgb),0.18);
}
#assistant-panel .followup-bar:hover{
  background:rgba(var(--purple-rgb),0.1);
  border-color:rgba(var(--purple-rgb),0.3);
  box-shadow:0 4px 16px rgba(var(--purple-rgb),0.08);
}
#assistant-panel .fu-label{color:rgba(var(--purple-rgb),0.75)}
#assistant-panel .fu-text{color:rgba(var(--fg-rgb),0.7)}
#assistant-panel .llm-panel{
  border:1px solid rgba(var(--accent-rgb),0.15);
  background:rgba(var(--accent-rgb),0.03);
}
#assistant-panel .llm-panel .txt{color:rgba(var(--fg-rgb),0.6)}
#assistant-panel .bash-panel{
  background:rgba(0,0,0,0.35);color:rgba(var(--fg-rgb),0.6);
  border-color:var(--border);
}
#divider{background:var(--border)}
#divider:hover,#divider.active{background:var(--accent)}
#editor-fallback{background:var(--bg);color:rgba(var(--fg-rgb),0.7)}
#merge-toolbar{
  background:rgba(var(--bg2-rgb),0.95);border:1px solid var(--border);
  box-shadow:0 4px 24px rgba(0,0,0,0.4);
}
#merge-toolbar button{
  background:rgba(var(--fg-rgb),0.08);border:1px solid rgba(var(--fg-rgb),0.12);
  color:rgba(var(--fg-rgb),0.7);
}
#merge-toolbar button:hover{
  background:rgba(var(--accent-rgb),0.15);
  border-color:rgba(var(--accent-rgb),0.3);color:#fff;
}
#merge-toolbar .mt-sep{background:rgba(var(--fg-rgb),0.1)}
#assistant-panel .prompt-h{
  background:rgba(var(--cyan-rgb),0.08);color:var(--cyan);
}
"""

CHATBOT_JS = r"""
var O=document.getElementById('output');
var D=document.getElementById('dot');
var ST=document.getElementById('stxt');
var inp=document.getElementById('task-input');
var btn=document.getElementById('send-btn');
var stopBtn=document.getElementById('stop-btn');
var clearBtn=document.getElementById('clear-btn');
var ac=document.getElementById('autocomplete');var rl=document.getElementById('recent-list');
var histSearch=document.getElementById('history-search');
var allTasks=[];
var modelLabel=document.getElementById('model-label');
var modelDD=document.getElementById('model-dropdown');
var modelSearch=document.getElementById('model-search');
var modelList=document.getElementById('model-list');
var allModels=[],selectedModel='',modelDDIdx=-1;
var sidebar=document.getElementById('sidebar');
var sidebarOverlay=document.getElementById('sidebar-overlay');
var suggestionsEl=document.getElementById('suggestions');
var running=false,_scrollLock=false,merging=false;
var scrollRaf=0,state=mkS();
var acIdx=-1,t0=null,timerIv=null,evtSrc=null;
var acTimer=null,histIdx=-1,histCache=[];
var lastToolName='',llmPanel=null,pendingPanel=false;
var pendingUserMsg=null;
var llmPanelState=mkS();
var ghostEl=document.getElementById('ghost-overlay');
var ghostSuggest='',ghostTimer2=null,ghostAbort=null;
var ghostCache={q:'',s:''};
var fileInput=document.getElementById('file-input');
var uploadBtn=document.getElementById('upload-btn');
var fileChips=document.getElementById('file-chips');
var pendingFiles=[];
var mergeWarn=document.getElementById('merge-warning');
var _mwTimer=null;
function showMergeWarning(){
  if(_mwTimer){clearTimeout(_mwTimer);_mwTimer=null}
  mergeWarn.classList.add('visible');
  _mwTimer=setTimeout(function(){mergeWarn.classList.remove('visible');_mwTimer=null},2000);
}
document.getElementById('input-text-wrap').addEventListener('click',function(){
  if(merging)showMergeWarning();
});
uploadBtn.addEventListener('click',function(){if(!running)fileInput.click()});
fileInput.addEventListener('change',function(){
  Array.from(this.files||[]).forEach(function(f){
    var reader=new FileReader();
    reader.onload=function(){
      var b64=reader.result.split(',')[1];
      pendingFiles.push({name:f.name,mime_type:f.type,data:b64,url:reader.result});
      renderFileChips();
    };
    reader.readAsDataURL(f);
  });
  this.value='';
});
function renderFileChips(){
  fileChips.innerHTML='';
  pendingFiles.forEach(function(f,i){
    var chip=document.createElement('span');chip.className='file-chip';
    if(f.mime_type.startsWith('image/')){
      var img=document.createElement('img');img.src=f.url;chip.appendChild(img);
    }else{
      var icon=document.createElement('span');
      icon.className='fc-icon';icon.textContent='\ud83d\udcc4';
      chip.appendChild(icon);
    }
    var label=document.createElement('span');label.textContent=f.name;chip.appendChild(label);
    var rm=document.createElement('span');rm.className='fc-rm';rm.textContent='\u00d7';
    rm.onclick=function(){pendingFiles.splice(i,1);renderFileChips()};
    chip.appendChild(rm);
    fileChips.appendChild(chip);
  });
}
function recordFileUsage(path){
  fetch('/record-file-usage',{
    method:'POST',
    headers:{'Content-Type':'application/json'},
    body:JSON.stringify({path:path})
  }).catch(function(){});
}
function mkS(){return{thinkEl:null,txtEl:null,bashPanel:null}}
function resizeInput(){
  inp.style.height='auto';
  inp.style.height=inp.scrollHeight+'px';
  inp.style.overflowY=inp.scrollHeight>inp.clientHeight?'auto':'hidden';
}
function resetOutputState(){
  state=mkS();llmPanel=null;llmPanelState=mkS();
  lastToolName='';pendingPanel=false;_scrollLock=false;
}
function enterRunning(){
  running=true;inp.disabled=true;
  runPromptBtn.disabled=true;
  btn.style.display='none';
  stopBtn.style.display='inline-flex';
  D.classList.add('running');hideAC();startTimer();
  inp.style.height='auto';inp.style.overflowY='hidden';
}
inp.addEventListener('input',function(){
  resizeInput();
  histIdx=-1;
  clearGhost();
  if(getAtCtx()){
    if(acTimer)clearTimeout(acTimer);
    acTimer=setTimeout(fetchAC,150);
  } else {
    hideAC();
    if(ghostTimer2)clearTimeout(ghostTimer2);
    ghostTimer2=setTimeout(fetchGhost,200);
  }
});
function toggleSidebar(){
  sidebar.classList.toggle('open');
  sidebarOverlay.classList.toggle('open');
}
O.addEventListener('wheel',function(e){
  if(running&&e.deltaY<0)_scrollLock=true;
});
O.addEventListener('scroll',function(){
  if(_scrollLock){
    var atBottom=O.scrollTop+O.clientHeight>=O.scrollHeight-150;
    if(atBottom)_scrollLock=false;
  }
});
function sb(){
  if(!_scrollLock&&!scrollRaf){scrollRaf=requestAnimationFrame(function(){
    O.scrollTo({top:O.scrollHeight,behavior:'instant'});scrollRaf=0;
  });}
}
new MutationObserver(function(){sb()}).observe(O,{childList:true,subtree:true,characterData:true});
function startTimer(){
  t0=Date.now();
  if(timerIv)clearInterval(timerIv);
  timerIv=setInterval(function(){
    var s=Math.floor((Date.now()-t0)/1000);
    var m=Math.floor(s/60);
    ST.textContent='Running '+(m>0?m+'m ':'')+s%60+'s';
  },1000);
}
function stopTimer(){if(timerIv){clearInterval(timerIv);timerIv=null;}}
var _spinnerTimer=null;
var waitSpinner=document.getElementById('wait-spinner');
function removeSpinner(){
  if(_spinnerTimer){clearTimeout(_spinnerTimer);_spinnerTimer=null;}
  waitSpinner.classList.remove('active');
}
function showSpinner(){
  removeSpinner();
  _spinnerTimer=setTimeout(function(){
    _spinnerTimer=null;
    waitSpinner.classList.add('active');
  },250);
}
function setReady(label){
  running=false;D.classList.remove('running');
  stopTimer();removeSpinner();
  ST.textContent=label||'Ready';
  if(!merging){inp.disabled=false;btn.disabled=false;uploadBtn.disabled=false;}
  btn.style.display='';
  stopBtn.style.display='none';
  inp.value='';
  checkActiveFile();
  if(!merging)inp.focus();
}
var _sseRetry=0,_sseMaxRetry=30000,_sseReconnTimer=null,_sseConnected=false;
function _sseBackoff(){
  var d=Math.min(1000*Math.pow(1.5,_sseRetry),_sseMaxRetry);_sseRetry++;return d;
}
function _showDisconnBanner(){
  if(document.getElementById('disconn-banner'))return;
  var b=mkEl('div','');b.id='disconn-banner';
  b.style.cssText='position:fixed;top:0;left:0;right:0;z-index:9999;'
    +'background:rgba(248,81,73,0.92);color:#fff;text-align:center;'
    +'padding:8px 16px;font-size:13px;font-weight:500;backdrop-filter:blur(8px);'
    +'-webkit-backdrop-filter:blur(8px)';
  b.textContent='Connection lost. Reconnecting\u2026';
  document.body.appendChild(b);
}
function _hideDisconnBanner(){
  var b=document.getElementById('disconn-banner');
  if(b)b.remove();
}
function connectSSE(){
  if(_sseReconnTimer){clearTimeout(_sseReconnTimer);_sseReconnTimer=null;}
  if(evtSrc){try{evtSrc.close();}catch(x){}}
  evtSrc=new EventSource('/events');
  evtSrc.onopen=function(){
    _sseRetry=0;_sseConnected=true;
    _hideDisconnBanner();
  };
  evtSrc.onmessage=function(e){
    var ev;try{ev=JSON.parse(e.data);}catch(x){return;}
    try{handleEvent(ev);}catch(err){console.error('Event error:',err,ev);}
  };
  evtSrc.onerror=function(){
    _sseConnected=false;
    try{evtSrc.close();}catch(x){}
    _showDisconnBanner();
    var delay=_sseBackoff();
    _sseReconnTimer=setTimeout(connectSSE,delay);
  };
}
function processOutputEvent(ev){
  var t=ev.type;
  if(t==='tool_call'){
    lastToolName=ev.name||'';
    llmPanel=null;llmPanelState=mkS();pendingPanel=false;
  }
  if(t==='tool_result'&&lastToolName!=='finish'){pendingPanel=true;}
  if(pendingPanel&&(t==='thinking_start'||t==='text_delta')){
    llmPanel=mkEl('div','llm-panel');
    O.appendChild(llmPanel);
    llmPanelState=mkS();pendingPanel=false;
  }
  var target=O,tState=state;
  if(llmPanel&&(t==='thinking_start'||t==='thinking_delta'||t==='thinking_end'
    ||t==='text_delta'||t==='text_end')){
    target=llmPanel;tState=llmPanelState;
  }
  handleOutputEvent(ev,target,tState);
  if(target===llmPanel)llmPanel.scrollTop=llmPanel.scrollHeight;
}
function handleEvent(ev){
  var t=ev.type;
  if(t==='thinking_start'||t==='thinking_delta'||t==='text_delta'
    ||t==='tool_call'||t==='tool_result'||t==='system_output'
    ||t==='task_done'||t==='task_error'||t==='task_stopped'
    ||t==='prompt')removeSpinner();
  switch(t){
  case'tasks_updated':loadTasks();loadWelcome();break;

  case'theme_changed':applyTheme(ev);break;
  case'focus_chatbox':window.focus();inp.focus();break;
  case'external_run':
    enterRunning();
    inp.value=ev.text||'';
    pendingUserMsg={text:ev.text,images:[]};
    pendingFiles=[];renderFileChips();
    showSpinner();loadModels();
    break;
  case'merge_started':
    document.getElementById('merge-toolbar').style.display='flex';
    merging=true;inp.disabled=true;
    btn.disabled=true;uploadBtn.disabled=true;
    inp.placeholder='Resolve all diffs in the merge view to continue\u2026';
    document.getElementById('input-text-wrap').style.cursor='not-allowed';
    break;
  case'merge_ended':
    document.getElementById('merge-toolbar').style.display='none';
    merging=false;inp.disabled=false;
    btn.disabled=false;uploadBtn.disabled=false;
    inp.placeholder=_inputPlaceholder;
    document.getElementById('input-text-wrap').style.cursor='';
    inp.focus();break;
  case'code_server_restarted':{
    var csFrame=document.getElementById('code-server-frame');
    if(csFrame){
      setTimeout(function(){csFrame.src=csFrame.src},1500);
    }
    break};
  case'clear':
    O.innerHTML='';resetOutputState();
    showUserMsg(pendingUserMsg);pendingUserMsg=null;
    showSpinner();break;
  case'user_browser_action':{
    var card=mkEl('div','ev user-action-card');
    card.innerHTML=
      '<div style="border:2px solid var(--yellow);border-radius:8px;'
      +'padding:16px;margin:10px 0;background:rgba(210,153,34,.08)">'
      +'<div style="font-weight:600;color:var(--yellow);margin-bottom:8px">'
      +'\u23F8\uFE0F User Action Required</div>'
      +'<div style="margin-bottom:12px">'+esc(ev.instruction||'')+'</div>'
      +'<button onclick="fetch(\'/user-browser-done\',{method:\'POST\'})'
      +'.then(function(){this.disabled=true;this.textContent=\'Resumed\';}.bind(this))"'
      +' style="padding:8px 20px;background:var(--green);color:#000;'
      +'border:none;border-radius:6px;cursor:pointer;font-weight:600">'
      +'I\'m Done</button></div>';
    O.appendChild(card);sb();break}
  case'user_question':{
    var qcard=mkEl('div','ev user-action-card');
    var qid='uq-'+Date.now();
    qcard.innerHTML=
      '<div style="border:2px solid var(--yellow);border-radius:8px;'
      +'padding:16px;margin:10px 0;background:rgba(210,153,34,.08)">'
      +'<div style="font-weight:600;color:var(--yellow);margin-bottom:8px">'
      +'\u2753 Agent Question</div>'
      +'<div style="margin-bottom:12px">'+esc(ev.question||'')+'</div>'
      +'<textarea id="'+qid+'" rows="3" style="width:100%;box-sizing:border-box;'
      +'padding:8px;border:1px solid var(--border);border-radius:6px;'
      +'background:var(--bg);color:var(--fg);font-family:inherit;font-size:13px;'
      +'margin-bottom:10px;resize:vertical" placeholder="Type your answer here..."></textarea>'
      +'<button onclick="(function(btn){'
      +'var ta=document.getElementById(\''+qid+'\');'
      +'var ans=ta?ta.value:\'\';'
      +'fetch(\'/user-question-done\',{method:\'POST\','
      +'headers:{\'Content-Type\':\'application/json\'},'
      +'body:JSON.stringify({answer:ans})})'
      +'.then(function(){btn.disabled=true;btn.textContent=\'Answered\';'
      +'if(ta)ta.disabled=true;});'
      +'})(this)"'
      +' style="padding:8px 20px;background:var(--green);color:#000;'
      +'border:none;border-radius:6px;cursor:pointer;font-weight:600">'
      +'I\'m Done</button></div>';
    O.appendChild(qcard);sb();
    var qta=document.getElementById(qid);
    if(qta)qta.focus();
    break}
  case'task_done':{
    var el=t0?Math.floor((Date.now()-t0)/1000):0;
    var em=Math.floor(el/60);
    setReady('Done ('+(em>0?em+'m ':'')+el%60+'s)');
    loadTasks();break}
  case'followup_suggestion':{
    var fu=mkEl('div','followup-bar');
    fu.title=ev.text;
    fu.innerHTML='<span class="fu-label">Suggested next</span>'
      +'<span class="fu-text">'+esc(ev.text)+'</span>';
    fu.addEventListener('click',function(){
      inp.value=ev.text;inp.focus();
    });
    O.appendChild(fu);sb();break}
  case'task_error':{
    var err=mkEl('div','ev tr err');
    err.innerHTML='<div class="rl fail">ERROR</div>'+esc(ev.text||'Unknown error');
    O.appendChild(err);
    setReady('Error');loadTasks();break}
  case'task_stopped':{
    var stEl=mkEl('div','ev tr err');
    stEl.innerHTML='<div class="rl fail">STOPPED</div>Agent execution stopped by user';
    O.appendChild(stEl);
    setReady('Stopped');loadTasks();break}
  default:{
    processOutputEvent(ev);
    if(running)showSpinner();
  }}
  sb();
}
function loadModels(){
  fetch('/models').then(function(r){return r.json();})
  .then(function(d){
    allModels=d.models;
    if(allModels.length){
      selectedModel=d.selected;
      modelLabel.textContent=selectedModel;
    }
    renderModelList('');
  }).catch(function(){});
}
function modelVendor(name){
  if(name.startsWith('claude-'))return'Anthropic';
  if(/^(gpt|o[134]|codex|computer-use)/.test(name)&&!name.startsWith('openai/'))return'OpenAI';
  if(name.startsWith('gemini-'))return'Gemini';
  if(name.startsWith('minimax-'))return'MiniMax';
  if(name.startsWith('openrouter/'))return'OpenRouter';
  return'Together AI';
}
function renderModelItem(m){
  var d=mkEl('div','model-item'+(m.name===selectedModel?' active':''));
  var price='$'+m.inp.toFixed(2)+' / $'+m.out.toFixed(2);
  d.innerHTML='<span>'+esc(m.name)+'</span><span class="model-cost">'+price+'</span>';
  d.addEventListener('click',function(){selectModel(m.name)});
  return d;
}
function renderModelList(q){
  modelList.innerHTML='';modelDDIdx=-1;
  var ql=q.toLowerCase();
  var used=[],rest=[];
  allModels.forEach(function(m){
    if(ql&&m.name.toLowerCase().indexOf(ql)<0)return;
    if(m.uses>0)used.push(m);else rest.push(m);
  });
  used.sort(function(a,b){return b.uses-a.uses});
  if(used.length){
    var hdr=mkEl('div','model-group-hdr');
    hdr.textContent='Recently Used';
    modelList.appendChild(hdr);
    used.forEach(function(m){modelList.appendChild(renderModelItem(m))});
  }
  var lastVendor='';
  rest.forEach(function(m){
    var v=modelVendor(m.name);
    if(v!==lastVendor){
      var hdr=mkEl('div','model-group-hdr');
      hdr.textContent=v;
      modelList.appendChild(hdr);
      lastVendor=v;
    }
    modelList.appendChild(renderModelItem(m));
  });
}
function selectModel(name){
  if(!allModels.length)return;
  selectedModel=name;
  modelLabel.textContent=name;
  closeModelDD();
  renderModelList('');
  fetch('/select-model',{method:'POST',
    headers:{'Content-Type':'application/json'},
    body:JSON.stringify({model:name})}).catch(function(){});
}
function toggleModelDD(){
  if(modelDD.classList.contains('open')){closeModelDD();return}
  modelDD.classList.add('open');
  modelSearch.value='';
  renderModelList('');
  modelSearch.focus();
}
function closeModelDD(){
  modelDD.classList.remove('open');
  modelSearch.value='';
  modelDDIdx=-1;
}
modelSearch.addEventListener('input',function(){renderModelList(this.value)});
modelSearch.addEventListener('keydown',function(e){
  var items=modelList.querySelectorAll('.model-item');
  if(e.key==='ArrowDown'){e.preventDefault();modelDDIdx=Math.min(modelDDIdx+1,items.length-1);updateModelSel(items);return}
  if(e.key==='ArrowUp'){e.preventDefault();modelDDIdx=Math.max(modelDDIdx-1,-1);updateModelSel(items);return}
  if(e.key==='Enter'){e.preventDefault();var ti=modelDDIdx>=0?modelDDIdx:0;
  if(items[ti])items[ti].click();return}
  if(e.key==='Escape'){e.preventDefault();closeModelDD();return}
});
function updateModelSel(items){
  items.forEach(function(it,i){it.classList.toggle('sel',i===modelDDIdx)});
  if(modelDDIdx>=0)items[modelDDIdx].scrollIntoView({block:'nearest'});
}
document.addEventListener('click',function(e){
  if(!document.getElementById('model-picker').contains(e.target))closeModelDD();
  if(!ac.contains(e.target)&&e.target!==inp)hideAC();
});
function showUserMsg(msg){
  if(!msg)return;
  var um=mkEl('div','user-msg');
  var html='';
  if(msg.images&&msg.images.length){
    html+='<div class="user-msg-images">';
    msg.images.forEach(function(url){
      html+='<img src="'+url+'" class="user-msg-img">';
    });
    html+='</div>';
  }
  html+=esc(msg.text);
  um.innerHTML=html;
  O.appendChild(um);
}
function looksLikeFilePath(s){
  if(s.startsWith('/')||s.startsWith('./')||s.startsWith('../')||s.startsWith('~/'))return true;
  if(!/\s/.test(s)&&(s.indexOf('/')>=0||/\.\w{1,10}$/.test(s)))return true;
  return false;
}
function doSubmitTask(task){
  enterRunning();
  pendingUserMsg={text:task,images:pendingFiles.filter(function(f){
    return f.mime_type.startsWith('image/');
  }).map(function(f){return f.url})};
  var payload={task:task,model:selectedModel};
  if(pendingFiles.length>0){
    payload.attachments=pendingFiles.map(function(f){return{mime_type:f.mime_type,data:f.data}});
  }
  fetch('/run',{
    method:'POST',
    headers:{'Content-Type':'application/json'},
    body:JSON.stringify(payload)
  }).then(function(r){
    if(!r.ok){r.json().then(function(d){setReady('Error');alert(d.error||'Failed')});return;}
    pendingFiles=[];renderFileChips();loadModels();
  }).catch(function(){setReady('Error');alert('Network error')});
}
function submitTask(){
  var task=inp.value.trim();
  if(!task||running||merging)return;
  var fileMatch=task.match(/^@(\S+)$/);
  if(fileMatch){openInEditor(fileMatch[1]);inp.value='';return}
  if(looksLikeFilePath(task)){
    fetch('/open-file',{method:'POST',headers:{'Content-Type':'application/json'},
      body:JSON.stringify({path:task})}).then(function(r){
      if(r.ok){inp.value='';return}
      doSubmitTask(task);
    }).catch(function(){doSubmitTask(task)});
    return;
  }
  doSubmitTask(task);
}
btn.addEventListener('click',submitTask);
stopBtn.addEventListener('click',function(){fetch('/stop',{method:'POST'}).catch(function(){})});
clearBtn.addEventListener('click',function(){
  if(running)return;
  O.innerHTML='<div id="welcome"><h2>What can I help you with?</h2>'
    +'<p>Describe a task and the agent will work on it</p>'
    +'<div id="suggestions"></div></div>';
  suggestionsEl=document.getElementById('suggestions');
  resetOutputState();
  pendingFiles=[];renderFileChips();
  loadWelcome();inp.value='';inp.focus();
});
var inputContainer=document.getElementById('input-container');
['dragenter','dragover'].forEach(function(ev){inputContainer.addEventListener(ev,function(e){
  e.preventDefault();e.stopPropagation();inputContainer.style.borderColor='rgba(88,166,255,0.5)';
})});
['dragleave','drop'].forEach(function(ev){inputContainer.addEventListener(ev,function(e){
  e.preventDefault();e.stopPropagation();inputContainer.style.borderColor='';
})});
inputContainer.addEventListener('drop',function(e){
  if(running)return;
  var files=e.dataTransfer&&e.dataTransfer.files;
  if(!files)return;
  Array.from(files).forEach(function(f){
    var ok=['image/jpeg','image/png','image/gif','image/webp','application/pdf'];
    if(ok.indexOf(f.type)<0)return;
    var reader=new FileReader();
    reader.onload=function(){
      var b64=reader.result.split(',')[1];
      pendingFiles.push({name:f.name,mime_type:f.type,data:b64,url:reader.result});
      renderFileChips();
    };
    reader.readAsDataURL(f);
  });
});
inputContainer.addEventListener('paste',function(e){
  if(running)return;
  var items=e.clipboardData&&e.clipboardData.items;
  if(!items)return;
  var dominated=false;
  var ok=[
    'image/jpeg','image/png','image/gif','image/webp',
    'application/pdf'
  ];
  Array.from(items).forEach(function(item){
    if(ok.indexOf(item.type)<0)return;
    var file=item.getAsFile();if(!file)return;
    dominated=true;
    var reader=new FileReader();
    reader.onload=function(){
      var b64=reader.result.split(',')[1];
      var name=file.name||('pasted.'+item.type.split('/')[1]);
      pendingFiles.push({
        name:name,mime_type:item.type,data:b64,
        url:reader.result
      });
      renderFileChips();
    };
    reader.readAsDataURL(file);
  });
  if(dominated)e.preventDefault();
});
inp.addEventListener('keydown',function(e){
  if(ac.style.display==='block'){
    var items=ac.querySelectorAll('.ac-item');
    if(e.key==='ArrowDown'){e.preventDefault();acIdx=Math.min(acIdx+1,items.length-1);updateACSel(items);return}
    if(e.key==='ArrowUp'){e.preventDefault();acIdx=Math.max(acIdx-1,-1);updateACSel(items);return}
    if(e.key==='Tab'){e.preventDefault();var ti=acIdx>=0?acIdx:0;
      if(items[ti])items[ti].click();return}
    if(e.key==='Enter'&&acIdx>=0){e.preventDefault();items[acIdx].click();return}
    if(e.key==='Escape'){hideAC();return}
  }
  if(ghostSuggest){
    if(e.key==='Tab'){e.preventDefault();acceptGhost();return}
    if(e.key==='ArrowRight'&&inp.selectionStart===inp.value.length){e.preventDefault();acceptGhost();return}
    if(e.key==='Escape'){clearGhost();return}
  }
  if(e.key==='ArrowUp'&&ac.style.display!=='block'&&(!inp.value.trim()||histIdx>=0)){
    e.preventDefault();cycleHistory(1);return;
  }
  if(e.key==='ArrowDown'&&histIdx>=0&&ac.style.display!=='block'){
    e.preventDefault();cycleHistory(-1);return;
  }
  if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();submitTask()}
});
function getAtCtx(){
  var val=inp.value,pos=inp.selectionStart||0;
  var before=val.substring(0,pos);
  var m=before.match(/@([^\s]*)$/);
  return m?{start:before.length-m[0].length,query:m[1]}:null;
}
function fetchAC(){
  var atCtx=getAtCtx();
  if(!atCtx){hideAC();return}
  var doFetch=function(){
    fetch('/suggestions?mode=files&q='+encodeURIComponent(atCtx.query))
      .then(function(r){return r.json()}).then(renderAC).catch(function(){hideAC()});
  };
  if(!atCtx.query){
    fetch('/refresh-files',{method:'POST'}).then(doFetch).catch(doFetch);
  }else{
    doFetch();
  }
}
function hlMatch(text,query){
  if(!query)return esc(text);
  var idx=text.toLowerCase().indexOf(query.toLowerCase());
  if(idx<0)return esc(text);
  return esc(text.substring(0,idx))
    +'<strong class="ac-hl">'+esc(text.substring(idx,idx+query.length))+'</strong>'
    +esc(text.substring(idx+query.length));
}
var _acSvg={
  file:'<svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 00-2'
    +' 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/>'
    +'<polyline points="14 2 14 8 20 8"/></svg>',
  star:'<svg viewBox="0 0 24 24"><path d="M12 2l3.09 6.26L22'
    +' 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7'
    +' 14.14 2 9.27l6.91-1.01L12 2z"/></svg>'
};
function _acIcon(type){
  if(type==='frequent')return _acSvg.star;
  return _acSvg.file;
}
function _acPathHtml(text,query){
  var last=text.lastIndexOf('/');
  if(last<0||last===text.length-1)return hlMatch(text,query);
  var dir=text.substring(0,last+1);
  var fname=text.substring(last+1);
  return '<span class="ac-dir">'+esc(dir)+'</span>'
    +'<span class="ac-fname">'+esc(fname)+'</span>';
}
function renderAC(data){
  if(!data.length){hideAC();return}
  ac.innerHTML='';acIdx=-1;
  var atCtx=getAtCtx();
  var searchQ=atCtx?atCtx.query:'';
  var order=['frequent','file'];
  var labels={frequent:'Frequent',file:'Files'};
  var groups={};
  data.forEach(function(item){
    var t=item.type;
    if(!groups[t])groups[t]=[];
    groups[t].push(item);
  });
  var isFirst=true;
  order.forEach(function(type){
    var g=groups[type];if(!g)return;
    var lbl=labels[type]||type;
    var hdr=mkEl('div','ac-section');
    hdr.textContent=lbl;ac.appendChild(hdr);
    g.forEach(function(item){
      var d=mkEl('div','ac-item');
      d.dataset.text=item.text;
      var useSearch=searchQ&&searchQ.length>0;
      var textHtml=useSearch
        ?hlMatch(item.text,searchQ)
        :_acPathHtml(item.text,searchQ);
      d.innerHTML='<span class="ac-icon">'
        +_acIcon(item.type)+'</span>'
        +'<span class="ac-text">'+textHtml+'</span>';
      if(isFirst){
        d.innerHTML+='<span class="ac-hint">tab</span>';
        isFirst=false;
      }
      d.addEventListener('click',function(){
        selectAC({type:'file',text:item.text});
      });
      ac.appendChild(d);
    });
  });
  var footer=mkEl('div','ac-footer');
  footer.innerHTML='<span><kbd>\u2191\u2193</kbd> navigate</span>'
    +'<span><kbd>Tab</kbd> accept</span>'
    +'<span><kbd>Esc</kbd> dismiss</span>';
  ac.appendChild(footer);
  ac.style.display='block';
  acIdx=0;
  var allItems=ac.querySelectorAll('.ac-item');
  updateACSel(allItems);
}
function selectAC(item){
  var atCtx=getAtCtx();
  if(atCtx){
    var before=inp.value.substring(0,atCtx.start);
    var after=inp.value.substring(
      inp.selectionStart||inp.value.length
    );
    var sep=(!after||/^\s/.test(after))?'':' ';
    inp.value=before+item.text+sep+after;
    var np=before.length+item.text.length+sep.length;
    inp.setSelectionRange(np,np);
    recordFileUsage(item.text);
    resizeInput();
  }
  hideAC();inp.focus();
}
function hideAC(){ac.style.display='none';acIdx=-1;clearGhost()}
function updateACSel(items){
  items.forEach(function(it,i){it.classList.toggle('sel',i===acIdx)});
  if(acIdx>=0){
    items[acIdx].scrollIntoView({block:'nearest'});
    var atCtx=getAtCtx();
    if(atCtx&&items[acIdx].dataset.text){
      var fullPath=items[acIdx].dataset.text;
      var query=atCtx.query;
      if(fullPath.toLowerCase().startsWith(query.toLowerCase())){
        ghostSuggest=fullPath.substring(query.length);
      }else{
        ghostSuggest=fullPath;
      }
      updateGhost();
    }
  }else{
    clearGhost();
  }
}
function clearGhost(){ghostSuggest='';ghostEl.innerHTML=''}
function updateGhost(){
  if(!ghostSuggest){ghostEl.innerHTML='';return}
  ghostEl.innerHTML='<span class="gm">'+esc(inp.value)+'</span>'
    +'<span class="gs">'+esc(ghostSuggest)+'</span>';
}
function acceptGhost(){
  inp.value+=ghostSuggest;
  resizeInput();
  clearGhost();inp.focus();
}
function fetchGhost(){
  var q=inp.value;  if(!q.trim()||q.trim().length<2){clearGhost();return}
  if(ghostCache.q&&q.startsWith(ghostCache.q)&&ghostCache.s){
    var extra=q.substring(ghostCache.q.length);
    if(ghostCache.s.startsWith(extra)){
      ghostSuggest=ghostCache.s.substring(extra.length);
      if(ghostSuggest){updateGhost();return}
    }
  }
  if(ghostAbort)ghostAbort.abort();
  ghostAbort=new AbortController();
  fetch('/complete?q='+encodeURIComponent(q),{signal:ghostAbort.signal})
    .then(function(r){return r.json()})
    .then(function(d){
      if(d.suggestion&&inp.value===q){
        ghostSuggest=d.suggestion;
        ghostCache={q:q,s:d.suggestion};
        updateGhost();
      }
    }).catch(function(){});
}
function cycleHistory(dir){
  if(!histCache.length){
    fetch('/tasks?limit=100').then(function(r){return r.json()}).then(function(tasks){
      histCache=tasks.map(function(t){return typeof t==='string'?t:(t.task||'')});
      doHistCycle(dir);
    });return;
  }
  doHistCycle(dir);
}
function doHistCycle(dir){
  histIdx+=dir;
  if(histIdx<0){histIdx=-1;inp.value='';return}
  if(histIdx>=histCache.length){histIdx=histCache.length-1;return}
  inp.value=histCache[histIdx];
}
function loadTasks(){
  fetch('/tasks?limit=100').then(function(r){return r.json()}).then(function(tasks){
    allTasks=tasks;renderSidebarTasks(tasks);histSearch.value='';
  }).catch(function(){});
}
function replayTaskEvents(idx,txt){
  inp.value=txt;inp.focus();
  if(sidebar.classList.contains('open')){toggleSidebar();}
  O.innerHTML='';resetOutputState();
  suggestionsEl=null;
  showUserMsg({text:txt,images:[]});
  fetch('/task-events?idx='+idx).then(function(r){return r.json()})
  .then(function(events){
    if(!Array.isArray(events))return;
    events.forEach(function(ev){
      var t=ev.type;
      if(t==='clear')return;
      if(t==='task_done'||t==='task_error'||t==='task_stopped'
        ||t==='followup_suggestion'){
        handleEvent(ev);return;
      }
      processOutputEvent(ev);
    });
    inp.value=txt;
    sb();
  }).catch(function(){});
}
function renderSidebarTasks(tasks){
  rl.innerHTML='';
  if(!tasks.length){
    rl.innerHTML='<div class="sidebar-empty">No recent tasks</div>';
    return;
  }
  tasks.forEach(function(t,idx){
    var txt=typeof t==='string'?t:(t.task||'');
    var hasEvents=typeof t==='object'&&t.has_events;
    var d=mkEl('div','sidebar-item');
    d.textContent=txt;d.title=txt;
    d.addEventListener('click',function(){
      if(hasEvents){replayTaskEvents(idx,txt)}
      else{inp.value=txt;inp.focus();toggleSidebar()}
    });
    rl.appendChild(d);
  });
}
var _histSearchTimer=null;
histSearch.addEventListener('input',function(){
  var q=this.value.trim();
  if(_histSearchTimer)clearTimeout(_histSearchTimer);
  _histSearchTimer=setTimeout(function(){
    var url='/tasks?limit=100';
    if(q)url+='&q='+encodeURIComponent(q);
    fetch(url).then(function(r){return r.json()}).then(function(tasks){
      if(!tasks.length&&q){
        rl.innerHTML='<div class="sidebar-empty">No matches</div>';
      }else{
        renderSidebarTasks(tasks);
      }
    }).catch(function(){});
  },200);
});

function loadWelcome(){
  if(!suggestionsEl)return;
  fetch('/tasks?limit=10').then(function(r){return r.json()})
  .catch(function(){return []}).then(function(tasks){
    suggestionsEl.innerHTML='';
    tasks.forEach(function(t,i){
      var hasEvents=typeof t==='object'&&t.has_events;
      var text=typeof t==='string'?t:(t.task||'');
      var chip=mkEl('div','suggestion-chip');
      chip.title=text;
      chip.innerHTML='<span class="chip-label recent">Recent</span>'+esc(text);
      chip.addEventListener('click',function(){
        if(hasEvents){replayTaskEvents(i,text)}
        else{inp.value=text;inp.focus()}
      });
      suggestionsEl.appendChild(chip);
    });
  });
}
var divider=document.getElementById('divider');
var editorPanel=document.getElementById('editor-panel');
var assistantPanel=document.getElementById('assistant-panel');
var splitContainer=document.getElementById('split-container');
var isDragging=false;
if(divider){
  divider.addEventListener('mousedown',function(e){
    isDragging=true;divider.classList.add('active');
    document.body.style.cursor='col-resize';
    document.body.style.userSelect='none';
    var frame=document.getElementById('code-server-frame');
    if(frame)frame.style.pointerEvents='none';
    e.preventDefault();
  });
  document.addEventListener('mousemove',function(e){
    if(!isDragging)return;
    var rect=splitContainer.getBoundingClientRect();
    var x=e.clientX-rect.left;
    var pct=Math.max(15,Math.min(85,(x/rect.width)*100));
    var assistPct=100-pct;
    editorPanel.style.flex=pct+' 1 0%';
    assistantPanel.style.flex=assistPct+' 1 0%';
  });
  document.addEventListener('mouseup',function(){
    if(!isDragging)return;
    isDragging=false;divider.classList.remove('active');
    document.body.style.cursor='';
    document.body.style.userSelect='';
    var frame=document.getElementById('code-server-frame');
    if(frame)frame.style.pointerEvents='';
    var ep=editorPanel.style.flex.split(' ')[0];
    fetch('/ui-state',{method:'POST',headers:{'Content-Type':'application/json'},
      body:JSON.stringify({editorPct:parseFloat(ep)})}).catch(function(){});
  });
  fetch('/ui-state').then(function(r){return r.json()}).then(function(d){
    if(d.editorPct){
      var pct=Math.max(15,Math.min(85,d.editorPct));
      editorPanel.style.flex=pct+' 1 0%';
      assistantPanel.style.flex=(100-pct)+' 1 0%';
    }
  }).catch(function(){});
}
function openInEditor(path){
  fetch('/open-file',{method:'POST',headers:{'Content-Type':'application/json'},
    body:JSON.stringify({path:path})}).catch(function(){});
}
document.addEventListener('click',function(e){
  var el=e.target.closest('[data-path]');
  if(el&&el.dataset.path){openInEditor(el.dataset.path);}
});
function mergeAction(action){
  fetch('/merge-action',{method:'POST',headers:{'Content-Type':'application/json'},
    body:JSON.stringify({action:action})}).catch(function(){});
}

function hexToRgb(h){
  var r=parseInt(h.slice(1,3),16),g=parseInt(h.slice(3,5),16),b=parseInt(h.slice(5,7),16);
  return r+','+g+','+b;
}
function applyTheme(t){
  var p=document.getElementById('assistant-panel')||document.body;
  var map={
    '--bg':t.bg,'--surface':t.bg2,'--surface2':t.bg2,
    '--text':t.fg,'--accent':t.accent,'--border':t.border,
    '--green':t.green,'--red':t.red,'--purple':t.purple,'--cyan':t.cyan,
    '--input-bg':t.inputBg
  };
  for(var k in map){
    if(!map[k])continue;
    p.style.setProperty(k,map[k]);
  }
  var rgbMap={
    '--bg-rgb':t.bg,'--bg2-rgb':t.bg2,'--fg-rgb':t.fg,
    '--accent-rgb':t.accent,'--border-rgb':t.border,
    '--green-rgb':t.green,'--red-rgb':t.red,
    '--purple-rgb':t.purple,'--cyan-rgb':t.cyan
  };
  for(var k in rgbMap){
    if(!rgbMap[k])continue;
    p.style.setProperty(k,hexToRgb(rgbMap[k]));
  }
  document.body.style.setProperty('--bg',t.bg);
  document.body.style.setProperty('background',t.bg);
}
function loadTheme(){
  fetch('/theme').then(function(r){return r.json()}).then(applyTheme).catch(function(){});
}
loadTheme();
connectSSE();loadModels();loadTasks();loadWelcome();inp.focus();
window.addEventListener('beforeunload',function(){navigator.sendBeacon('/closing','')});
var runPromptBtn=document.getElementById('run-prompt-btn');
var _promptPath='';
function checkActiveFile(){
  if(running){runPromptBtn.disabled=true;return}
  fetch('/active-file-info').then(function(r){return r.json()}).then(function(d){
    if(running)return;
    if(d.is_prompt){
      runPromptBtn.disabled=false;
      runPromptBtn.title='Run prompt: '+d.filename;
      _promptPath=d.path;
    }else{
      runPromptBtn.disabled=true;
      runPromptBtn.title='Run current file as prompt (no prompt detected)';
      _promptPath='';
    }
  }).catch(function(){
    runPromptBtn.disabled=true;_promptPath='';
  });
}
checkActiveFile();setInterval(checkActiveFile,2000);
runPromptBtn.addEventListener('click',function(){
  if(runPromptBtn.disabled||running||!_promptPath)return;
  fetch('/get-file-content?path='+encodeURIComponent(_promptPath))
    .then(function(r){return r.json()}).then(function(d){
    if(d.content){
      inp.value=d.content;
      resizeInput();
      submitTask();
    }
  }).catch(function(){});
});
document.addEventListener('keydown',function(e){
  var isMac=navigator.platform.toUpperCase().indexOf('MAC')>=0;
  if((isMac?e.metaKey:e.ctrlKey)&&e.key==='k'&&!e.shiftKey&&!e.altKey){
    e.preventDefault();e.stopPropagation();
    if(document.activeElement===inp||document.activeElement===document.body){
      fetch('/focus-editor',{method:'POST',headers:{'Content-Type':'application/json'},
        body:'{}'}).catch(function(){});
    }else{
      window.focus();inp.focus();
    }
  }
},true);
var _csHealthOk=true,_csBaseUrl='';
(function(){
  var f=document.getElementById('code-server-frame');
  if(f)_csBaseUrl=f.getAttribute('data-base-url')||'';
})();
function _checkCodeServerHealth(){
  if(!_csBaseUrl)return;
  var img=new Image();
  img.onload=function(){
    if(!_csHealthOk){
      _csHealthOk=true;
      var f=document.getElementById('code-server-frame');
      if(f)f.src=f.src;
    }
  };
  img.onerror=function(){_csHealthOk=false};
  img.src=_csBaseUrl+'/favicon.ico?_t='+Date.now();
}
setInterval(_checkCodeServerHealth,15000);
"""


def _build_html(title: str, code_server_url: str = "", work_dir: str = "") -> str:
    font_import = "@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');\n"
    css = font_import + BASE_CSS + OUTPUT_CSS + CHATBOT_CSS + CHATBOT_THEME_CSS

    if code_server_url:
        import urllib.parse

        wd_enc = urllib.parse.quote(work_dir, safe="")
        editor_content = (
            f'<iframe id="code-server-frame"'
            f' src="{code_server_url}/?folder={wd_enc}"'
            f' data-base-url="{code_server_url}"'
            f' data-work-dir="{work_dir}"></iframe>'
        )
    else:
        editor_content = (
            '<div id="editor-fallback">'
            "<h3>VS Code Editor</h3>"
            "<p>code-server is not installed. Install it to enable the embedded editor:</p>"
            "<code>curl -fsSL https://code-server.dev/install.sh | sh</code>"
            "<p>Or via Homebrew:</p>"
            "<code>brew install code-server</code>"
            '<p style="margin-top:16px;font-size:12px;opacity:0.5">'
            "Restart the assistant after installation.</p>"
            "</div>"
        )

    _s25 = (
        ' viewBox="0 0 24 24" fill="none" stroke="currentColor"'
        ' stroke-width="2.5" stroke-linecap="round"'
        ' stroke-linejoin="round"'
    )
    _svg_accept = f'<svg{_s25}><polyline points="20 6 9 17 4 12"/></svg>'
    _svg_reject = (
        f'<svg{_s25}><line x1="18" y1="6" x2="6" y2="18"/>'
        '<line x1="6" y1="6" x2="18" y2="18"/></svg>'
    )
    _svg_prev = f'<svg{_s25}><polyline points="15 18 9 12 15 6"/></svg>'
    _svg_next = f'<svg{_s25}><polyline points="9 18 15 12 9 6"/></svg>'
    _svg_accept_all = (
        f'<svg{_s25}><polyline points="18 7 9.5 17 6 13"/>'
        '<polyline points="22 7 13.5 17 12 15.3"/></svg>'
    )
    _svg_reject_all = (
        f'<svg{_s25}><line x1="17" y1="5" x2="7" y2="15"/>'
        '<line x1="7" y1="5" x2="17" y2="15"/>'
        '<line x1="17" y1="9" x2="7" y2="19"/>'
        '<line x1="7" y1="9" x2="17" y2="19"/></svg>'
    )

    _sep = '<span class="mt-sep"></span>'
    _textarea_placeholder = (
        "Ask anything\u2026 (@ files, \u2318/ctrl-k toggle to editor,"
        " \u2318/ctrl-l to run selected text from the editor, "
        "Shift-enter to add newline)"
    )
    json_placeholder = json.dumps(_textarea_placeholder)

    return (
        HTML_HEAD.format(title=title, css=css)
        + f"""<body>
<div id="split-container">
  <div id="editor-panel" style="flex:3;min-width:0">
    {editor_content}
    <div id="merge-toolbar">
      <button onclick="mergeAction('accept')" title="Accept current change">{_svg_accept}</button>
      <button onclick="mergeAction('reject')" title="Reject current change">{_svg_reject}</button>
      {_sep}
      <button onclick="mergeAction('prev')" title="Previous change">{_svg_prev}</button>
      <button onclick="mergeAction('next')" title="Next change">{_svg_next}</button>
      {_sep}
      <button onclick="mergeAction('accept-all')" title="Accept all">{_svg_accept_all}</button>
      <button onclick="mergeAction('reject-all')" title="Reject all">{_svg_reject_all}</button>
    </div>
  </div>
  <div id="divider"></div>
  <div id="assistant-panel">
    <div id="sidebar-overlay" onclick="toggleSidebar()"></div>
    <div id="sidebar">
      <button id="sidebar-close" onclick="toggleSidebar()">&times;</button>
      <div class="sidebar-section" id="sidebar-history-sec">
        <div class="sidebar-hdr">Recent Tasks</div>
        <input type="text" id="history-search" placeholder="Search history\u2026"
          autocomplete="off"/>
        <div id="recent-list"></div>
      </div>

    </div>
    <header>
      <div class="logo">KISS Sorcar</div>
      <div style="display:flex;align-items:center;gap:10px;flex-shrink:0">
        <div class="status"><div class="dot" id="dot"></div><span id="stxt">Ready</span></div>
      </div>
    </header>
    <div id="output">
      <div id="welcome">
        <h2>What can I help you with?</h2>
        <p>Describe a task and the agent will work on it</p>
        <div id="suggestions"></div>
      </div>
    </div>
    <div id="input-area">
      <div id="autocomplete"></div>
      <div id="input-container">
        <div id="file-chips"></div>
        <div id="input-wrap">
          <div id="input-text-wrap">
            <div id="ghost-overlay"></div>
            <textarea id="task-input" rows="3"
              placeholder="{_textarea_placeholder}"
              autocomplete="off"></textarea>
            <div id="merge-warning">Resolve all diffs before proceeding</div>
          </div>
          <input type="file" id="file-input" multiple
            accept="image/jpeg,image/png,image/gif,image/webp,application/pdf"
            style="display:none"/>
          <button id="clear-btn" title="Clear chat"><svg viewBox="0 0 24 24" fill="none"
            stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
            ><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6"
              x2="18" y2="18"/></svg></button>
        </div>
        <div id="input-footer">
          <div id="model-picker">
            <button type="button" id="model-btn" onclick="toggleModelDD()">
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor"
                stroke-width="2"><path d="M12 2l3 7h7l-5.5 4 2 7L12 16l-6.5 4 2-7L2 9h7z"/></svg>
              <span id="model-label">Loading\u2026</span>
            </button>
            <button id="upload-btn" title="Attach files">
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none"
              stroke="currentColor" stroke-width="2"
              stroke-linecap="round" stroke-linejoin="round"
              ><path d="M21.44 11.05l-9.19 9.19a6 6 0 01-8.49
              -8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2
              2 0 01-2.83-2.83l8.49-8.48"/></svg>
            </button>
            <button id="history-btn" onclick="toggleSidebar()" title="Task history">
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor"
                stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>
              </svg>
            </button>

            <button id="run-prompt-btn" title="Run current file as prompt" disabled>
              <svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"
                stroke="none">
                <polygon points="5,3 19,12 5,21"/>
              </svg>
            </button>
            <div id="model-dropdown">
              <input type="text" id="model-search"
                placeholder="Search models\u2026" autocomplete="off"/>
              <div id="model-list"></div>
            </div>
          </div>
          <div id="input-actions">
            <span id="wait-spinner"></span>
            <button id="send-btn"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"
              stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
              ><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"
              /></svg></button>
            <button id="stop-btn"><svg viewBox="0 0 24 24" fill="currentColor"
              ><rect x="6" y="6" width="12" height="12" rx="2"/></svg></button>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
<script>
var _inputPlaceholder={json_placeholder};
{EVENT_HANDLER_JS}
{CHATBOT_JS}
</script>
</body>
</html>"""
    )
