PageSourceSearch

https://jayreddinjr-jr-odysseus-hf.hf.space/

html jayreddinjr-jr-odysseus-hf.hf.space collected 2026-10-04 16:58:58 UTC 223,387 bytes, 2,561 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3<head>
4  <meta charset="UTF-8" />
5  <title>Odysseus Chat</title>
6  <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M16 4L16 22L6 22Z' fill='%23e06c75'/%3E%3Cpath d='M16 8L16 22L24 22Z' fill='%23e06c75' opacity='0.6'/%3E%3Cpath d='M4 24Q10 20 16 24Q22 28 28 24' stroke='%23e06c75' stroke-width='2.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E">
7  <link rel="manifest" href="/static/manifest.json">
8  <meta name="theme-color" content="#282c34">
9  <meta name="apple-mobile-web-app-capable" content="yes">
10  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
11  <!-- Disable iOS / Android auto-linkifying of numbers (phone/date/address)
12       in email bodies — was wrapping random digits in <a href="tel:..."> with
13       browser-default styling that didn't match the Odysseus theme. -->
14  <meta name="format-detection" content="telephone=no, date=no, address=no, email=no">
15  <link rel="apple-touch-icon" href="/static/icon-192.png">
16  
16<script nonce="0ef1c0e2ced0cc537d6ee0258e679162">
17  window._odysseusLoadTime = Date.now();
18  (function(){
19    try {
20      var t = JSON.parse(localStorage.getItem('odysseus-theme'));
21      if (t && t.colors) {
22        var s = document.documentElement.style;
23        var c = t.colors;
24        s.setProperty('--bg', c.bg);
25        s.setProperty('--fg', c.fg);
26        s.setProperty('--panel', c.panel);
27        s.setProperty('--border', c.border);
28        if (c.red) s.setProperty('--red', c.red);
29        // Set --brand-color now (= custom brand or the theme red) so the
30        // loading-screen ASCII wave shows its final colour from the first
31        // paint. Otherwise it starts on --red and visibly switches once the
32        // app boots and applyColors() fills --brand-color.
33        var _bc = (c.advanced && c.advanced.brandColor) || c.red;
34        if (_bc) s.setProperty('--brand-color', _bc);
35        // Match the mobile browser toolbar / status bar to the saved theme bg
36        // from the very first paint. Otherwise the hardcoded dark meta sits
37        // there during load and the bar "switches" colour once the app boots.
38        var mtc = document.querySelector('meta[name="theme-color"]');
39        if (mtc && c.bg) mtc.setAttribute('content', c.bg);
40        // Update favicon to match accent color
41        var ac = c.red || '#e06c75';
42        var fav = document.querySelector("link[rel='icon']");
43        if (fav) fav.href = 'data:image/svg+xml,' + encodeURIComponent("<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><path d='M16 4L16 22L6 22Z' fill='" + ac + "'/><path d='M16 8L16 22L24 22Z' fill='" + ac + "' opacity='0.6'/><path d='M4 24Q10 20 16 24Q22 28 28 24' stroke='" + ac + "' stroke-width='2.5' fill='none' stroke-linecap='round'/></svg>");
44        // Derive syntax highlighting colors from theme
45        function h2hsl(hex) {
46          hex = hex.replace('#','');
47          var r=parseInt(hex.substring(0,2),16)/255, g=parseInt(hex.substring(2,4),16)/255, b=parseInt(hex.substring(4,6),16)/255;
48          var mx=Math.max(r,g,b), mn=Math.min(r,g,b), h, sv, l=(mx+mn)/2;
49          if(mx===mn){h=sv=0}else{var d=mx-mn;sv=l>0.5?d/(2-mx-mn):d/(mx+mn);if(mx===r)h=((g-b)/d+(g<b?6:0))/6;else if(mx===g)h=((b-r)/d+2)/6;else h=((r-g)/d+4)/6}
50          return[h*360,sv*100,l*100];
51        }
52        function hsl2h(h,sv,l) {
53          h=((h%360)+360)%360;sv=Math.max(0,Math.min(100,sv))/100;l=Math.max(0,Math.min(100,l))/100;
54          var a=sv*Math.min(l,1-l);function f(n){var k=(n+h/30)%12;return l-a*Math.max(-1,Math.min(k-3,9-k,1))}
55          function th(v){return Math.round(v*255).toString(16).padStart(2,'0')}
56          return'#'+th(f(0))+th(f(8))+th(f(4));
57        }
58        var fH=h2hsl(c.fg),bH=h2hsl(c.bg),rH=h2hsl(c.red||'#e06c75');
59        var dk=bH[2]<50;
60        s.setProperty('--hl-bg', hsl2h(bH[0],bH[1],dk?Math.max(bH[2]-4,0):Math.min(bH[2]+4,100)));
61        s.setProperty('--hl-fg', c.fg);
62        s.setProperty('--hl-keyword', hsl2h((rH[0]+280)%360,Math.min(rH[1]+10,80),dk?70:45));
63        s.setProperty('--hl-string', hsl2h(40,Math.min(fH[1]+20,70),dk?72:42));
64        s.setProperty('--hl-comment', hsl2h(fH[0],Math.max(fH[1]-20,5),(fH[2]*0.5+bH[2]*0.5)));
65        s.setProperty('--hl-function', hsl2h(210,Math.min(fH[1]+20,75),dk?70:45));
66        s.setProperty('--hl-number', hsl2h(20,Math.min(fH[1]+15,65),dk?68:48));
67        s.setProperty('--hl-builtin', hsl2h(180,Math.min(fH[1]+15,60),dk?65:40));
68        s.setProperty('--hl-variable', hsl2h((fH[0]+30)%360,Math.min(fH[1]+5,60),fH[2]));
69        s.setProperty('--hl-params', hsl2h(fH[0],Math.max(fH[1]-5,10),dk?Math.min(fH[2]+8,85):Math.max(fH[2]-8,25)));
70        // Apply advanced overrides if present
71        if (c.advanced) {
72          var a = c.advanced;
73          var advMap = {userBubbleBg:'--user-bubble-bg',aiBubbleBg:'--ai-bubble-bg',bubbleBorder:'--bubble-border',sidebarBg:'--sidebar-bg',sectionAccent:'--section-accent',brandColor:'--brand-color',inputBg:'--input-bg',inputBorder:'--input-border',sendBtnBg:'--send-btn-bg',sendBtnHover:'--send-btn-hover',codeBg:'--code-bg',codeFg:'--code-fg',toggleBg:'--toggle-bg',toggleActive:'--toggle-active',accentPrimary:'--accent-primary',accentError:'--accent-error'};
74          for (var k in advMap) { if (a[k]) s.setProperty(advMap[k], a[k]); }
75        }
76      }
77      // Apply font early
78      if (t && t.font) {
79        var fm = {mono:"'Fira Code', monospace",sans:"system-ui, -apple-system, 'Segoe UI', sans-serif",serif:"Georgia, 'Times New Roman', serif"};
80        if (fm[t.font]) { s.setProperty('--font-family', fm[t.font]); }
81        else { s.setProperty('--font-family', "'" + t.font.replace(/'/g,'') + "', sans-serif"); }
82      }
83      // Apply density class on html
84      if (t && t.density && t.density !== 'comfortable') {
85        document.documentElement.classList.add('density-' + t.density);
86      }
87      // Apply background pattern on body once available
88      if (t && t.bgPattern && t.bgPattern !== 'none') {
89        document.addEventListener('DOMContentLoaded', function() {
90          document.body.classList.add('bg-pattern-' + t.bgPattern);
91        }, {once:true});
92      }
93    } catch(e){}
94  })();
95  </script>
95
96  <!-- Per-route favicon. Bookmarking /calendar shows a calendar icon,
97       /notes a notes icon, etc. Each shape is rendered in the current
98       theme accent color. Falls back to the boat logo on the root path. -->
99  
99<script nonce="0ef1c0e2ced0cc537d6ee0258e679162">
100  (function(){
101    try {
102      var path = (window.location.pathname || '').toLowerCase();
103      var theme = (function(){ try { return JSON.parse(localStorage.getItem('odysseus-theme')); } catch(_) { return null; } })();
104      var ac = (theme && (theme.red || theme.colors && theme.colors.red)) || '#e06c75';
105      // Shapes are line-stroke SVGs (no emoji glyphs). Each entry returns
106      // the inner SVG markup rendered against currentColor=`ac`.
107      var SHAPES = {
108        '/calendar':
109          "<rect x='4' y='6' width='24' height='22' rx='2' fill='none' stroke='" + ac + "' stroke-width='2.5'/>" +
110          "<line x1='4' y1='12' x2='28' y2='12' stroke='" + ac + "' stroke-width='2.5'/>" +
111          "<line x1='10' y1='3' x2='10' y2='9' stroke='" + ac + "' stroke-width='2.5' stroke-linecap='round'/>" +
112          "<line x1='22' y1='3' x2='22' y2='9' stroke='" + ac + "' stroke-width='2.5' stroke-linecap='round'/>",
113        '/notes':
114          "<rect x='6' y='4' width='20' height='24' rx='2' fill='none' stroke='" + ac + "' stroke-width='2.5'/>" +
115          "<line x1='10' y1='10' x2='22' y2='10' stroke='" + ac + "' stroke-width='2'/>" +
116          "<line x1='10' y1='15' x2='22' y2='15' stroke='" + ac + "' stroke-width='2'/>" +
117          "<line x1='10' y1='20' x2='18' y2='20' stroke='" + ac + "' stroke-width='2'/>",
118        '/cookbook':
119          "<path d='M5 8 L5 26 A2 2 0 0 0 7 28 L25 28 A2 2 0 0 0 27 26 L27 8' fill='none' stroke='" + ac + "' stroke-width='2.5' stroke-linejoin='round'/>" +
120          "<path d='M9 4 L23 4 L23 8 L9 8 Z' fill='none' stroke='" + ac + "' stroke-width='2.5' stroke-linejoin='round'/>" +
121          "<line x1='11' y1='14' x2='21' y2='14' stroke='" + ac + "' stroke-width='2'/>" +
122          "<line x1='11' y1='19' x2='17' y2='19' stroke='" + ac + "' stroke-width='2'/>",
123        '/email':
124          "<rect x='4' y='7' width='24' height='18' rx='2' fill='none' stroke='" + ac + "' stroke-width='2.5'/>" +
125          "<path d='M5 9 L16 17 L27 9' fill='none' stroke='" + ac + "' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'/>",
126        '/memory':
127          "<path d='M16 5 C10 5 6 9 6 14 C6 19 10 21 11 22 L11 26 L21 26 L21 22 C22 21 26 19 26 14 C26 9 22 5 16 5 Z' fill='none' stroke='" + ac + "' stroke-width='2.5' stroke-linejoin='round'/>" +
128          "<line x1='12' y1='28' x2='20' y2='28' stroke='" + ac + "' stroke-width='2'/>",
129        '/gallery':
130          "<rect x='4' y='4' width='24' height='24' rx='2' fill='none' stroke='" + ac + "' stroke-width='2.5'/>" +
131          "<circle cx='12' cy='12' r='2.5' fill='" + ac + "'/>" +
132          "<path d='M4 22 L11 16 L18 21 L23 17 L28 22' fill='none' stroke='" + ac + "' stroke-width='2.5' stroke-linejoin='round'/>",
133        '/tasks':
134          "<rect x='4' y='4' width='24' height='24' rx='3' fill='none' stroke='" + ac + "' stroke-width='2.5'/>" +
135          "<path d='M9 16 L14 21 L23 11' fill='none' stroke='" + ac + "' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'/>",
136        '/library':
137          "<rect x='5' y='5' width='5' height='22' rx='1' fill='none' stroke='" + ac + "' stroke-width='2.5'/>" +
138          "<rect x='13' y='5' width='5' height='22' rx='1' fill='none' stroke='" + ac + "' stroke-width='2.5'/>" +
139          "<rect x='21' y='8' width='6' height='19' rx='1' fill='none' stroke='" + ac + "' stroke-width='2.5' transform='rotate(8 24 17)'/>",
140      };
141      var inner = SHAPES[path];
142      if (!inner) return; // Root path keeps the default boat icon.
143      var svg = "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'>" + inner + "</svg>";
144      var href = 'data:image/svg+xml,' + encodeURIComponent(svg);
145      var fav = document.querySelector("link[rel='icon']");
146      if (!fav) { fav = document.createElement('link'); fav.rel = 'icon'; fav.type = 'image/svg+xml'; document.head.appendChild(fav); }
147      fav.href = href;
148      var apple = document.querySelector("link[rel='apple-touch-icon']");
149      if (!apple) { apple = document.createElement('link'); apple.rel = 'apple-touch-icon'; document.head.appendChild(apple); }
150      apple.href = href;
151      // Also customize the page title so the bookmark inherits a useful name.
152      var titles = {
153        '/calendar': 'Calendar — Odysseus',
154        '/notes': 'Notes — Odysseus',
155        '/cookbook': 'Cookbook — Odysseus',
156        '/email': 'Email — Odysseus',
157        '/memory': 'Memory — Odysseus',
158        '/gallery': 'Gallery — Odysseus',
159        '/tasks': 'Tasks — Odysseus',
160        '/library': 'Library — Odysseus',
161      };
162      if (titles[path]) document.title = titles[path];
163      // Per-route Android home-screen icon. We swap the <link rel="manifest">
164      // to a per-page Blob URL with this route's SVG icon — that way "Add to
165      // Home Screen" picks up the route-specific glyph instead of the shared
166      // boat logo. Falls back silently on browsers without Blob URL support.
167      try {
168        if (inner && typeof Blob !== 'undefined') {
169          var pwa = {
170            name: (titles[path] || 'Odysseus'),
171            short_name: (titles[path] || 'Odysseus').split('—')[0].trim(),
172            start_url: path,
173            scope: '/',
174            display: 'standalone',
175            background_color: '#0e0e10',
176            theme_color: ac,
177            icons: [
178              { src: href, sizes: '192x192', type: 'image/svg+xml', purpose: 'any maskable' },
179              { src: href, sizes: '512x512', type: 'image/svg+xml', purpose: 'any maskable' },
180            ],
181          };
182          var blob = new Blob([JSON.stringify(pwa)], { type: 'application/manifest+json' });
183          var url = URL.createObjectURL(blob);
184          var ml = document.querySelector("link[rel='manifest']");
185          if (!ml) { ml = document.createElement('link'); ml.rel = 'manifest'; document.head.appendChild(ml); }
186          ml.href = url;
187        }
188      } catch(_) {}
189    } catch(e){}
190  })();
191  </script>
191
192  
192<script defer src="/static/lib/highlight.min.js"></script>
192
193  <!-- Inter font — self-hosted, no Google dependencies -->
194  <style>
195    @font-face { font-family: 'Inter'; font-weight: 400; font-style: normal; font-display: swap; src: url('/static/fonts/Inter-Regular.woff2') format('woff2'); }
196    @font-face { font-family: 'Inter'; font-weight: 500; font-style: normal; font-display: swap; src: url('/static/fonts/Inter-Medium.woff2') format('woff2'); }
197    @font-face { font-family: 'Inter'; font-weight: 600; font-style: normal; font-display: swap; src: url('/static/fonts/Inter-SemiBold.woff2') format('woff2'); }
198  </style>
199  <!-- KaTeX CSS is loaded with media="print" so it doesn't block render,
200       then flipped to "all" via JS after load. Mermaid init runs once the
201       library finishes loading. Both hooks are wired via addEventListener
202       below (inline onload= attrs are blocked by CSP script-src-attr). -->
203  <link id="katex-css" rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css" media="print">
204  
204<script async src="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js"></script>
204
205  
205<script id="mermaid-script" async src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
205
206  
206<script nonce="0ef1c0e2ced0cc537d6ee0258e679162">
207    (function(){
208      var k = document.getElementById('katex-css');
209      if (k) k.addEventListener('load', function(){ k.media = 'all'; }, { once: true });
210      var m = document.getElementById('mermaid-script');
211      if (m) m.addEventListener('load', function(){
212        if (window.odysseusInitMermaid) window.odysseusInitMermaid();
213      }, { once: true });
214    })();
215  </script>
215
216  <link rel="stylesheet" href="/static/style.css">
217  <link rel="modulepreload" href="/static/app.js">
218  <link rel="modulepreload" href="/static/js/chat.js">
219  <link rel="modulepreload" href="/static/js/ui.js">
220  <link rel="modulepreload" href="/static/js/sessions.js">
221  <link rel="modulepreload" href="/static/js/markdown.js">
222  <meta name="viewport" content="width=device-width, initial-scale=1.0, interactive-widget=resizes-content, viewport-fit=cover" />
223</head>
224<body>
225  <!-- Loading overlay — minimal flash then immediate dismiss -->
226  <div id="app-loader" style="position:fixed;inset:0;z-index:99999;background:var(--bg,#282c34);display:flex;align-items:center;justify-content:center;flex-direction:column;gap:8px;transition:opacity .15s;pointer-events:none">
227  </div>
228  
228<script nonce="0ef1c0e2ced0cc537d6ee0258e679162">
229  (function(){
230    // Dismiss loader almost immediately — no animation needed
231    var l=document.getElementById('app-loader');
232    if(l){l.style.opacity='0';setTimeout(function(){l.remove()},150)}
233  })();
234  </script>
234
235  <!-- Memory Management Modal -->
236  <div id="memory-modal" class="modal hidden">
237    <div class="modal-content memory-modal-content" role="dialog" aria-label="Brain" style="background:var(--bg)">
238      <div class="modal-header">
239        <h4><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:6px"><path d="M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z"/><path d="M12 5a3 3 0 1 1 5.997.125 4 4 0 0 1 2.526 5.77 4 4 0 0 1-.556 6.588A4 4 0 1 1 12 18Z"/><path d="M15 13a4.5 4.5 0 0 1-3-4 4.5 4.5 0 0 1-3 4"/></svg>Brain</h4>
240        <button class="close-btn" id="close-memory-modal" aria-label="Close memory modal">✖</button>
241      </div>
242      <div class="modal-body memory-modal-body">
243        <div class="memory-tabs">
244          <button class="memory-tab active" data-memory-tab="browse"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px"><path d="M12 2a7 7 0 0 1 7 7c0 2.4-1.2 4.5-3 5.7V17a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-2.3C6.2 13.5 5 11.4 5 9a7 7 0 0 1 7-7z"/><line x1="10" y1="22" x2="14" y2="22"/></svg>Memories <span id="memory-count" class="memory-count" style="font-size:0.8em;opacity:0.6;font-weight:normal;margin-left:4px">0</span></button>
245          <button class="memory-tab" data-memory-tab="skills"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>Skills <span id="skills-count" class="memory-count" style="font-size:0.8em;opacity:0.6;font-weight:normal;margin-left:4px">0</span></button>
246          <button class="memory-tab" data-memory-tab="add"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="16"/><line x1="8" y1="12" x2="16" y2="12"/></svg>Add</button>
247          <button class="memory-tab" data-memory-tab="settings"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>Settings</button>
248        </div>
249        <!-- ── Browse tab ── -->
250        <div class="memory-tab-panel" data-memory-panel="browse">
251          <div class="admin-card" style="display:flex;flex-direction:column;overflow:hidden;flex:1;min-height:0;">
252            <div style="display:flex;align-items:center;gap:8px;margin-bottom:2px;">
253              <h2 style="display:flex;align-items:center;gap:6px;margin:0;padding:0;line-height:1;">Memories <span id="memory-count-h2" class="memory-count" style="font-size:0.6em;opacity:0.6;font-weight:normal"></span></h2>
254              <span style="flex:1"></span>
255              <label class="admin-switch" title="Include memories in chat context"><input type="checkbox" id="memory-enabled-header-toggle" checked /><span class="admin-slider"></span></label>
256            </div>
257            <p class="memory-desc doclib-desc" style="margin-top:6px;">Long-term facts the AI remembers across chats — recall, edit, or curate.</p>
258            <div class="memory-toolbar">
259              <div class="memory-toolbar-row">
260                <select id="memory-sort" class="memory-sort-select" aria-label="Sort memories">
261                  <option value="newest">Newest</option>
262                  <option value="oldest">
262Oldest</option>
263                  <option value="alpha">A-Z</option>
264                  <option value="uses">Most used</option>
265                </select>
266                <button id="memory-select-btn" class="memory-toolbar-btn" title="Select multiple memories">Select</button>
267                <button id="memory-tidy-btn" class="memory-toolbar-btn" title="AI tidy: deduplicate and clean up memories"><svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor" style="vertical-align:-1px;margin-right:2px;"><path d="M12 0L14.59 8.41L23 12L14.59 15.59L12 24L9.41 15.59L1 12L9.41 8.41Z"/></svg> Tidy</button>
268              </div>
269              <input type="text" id="memory-search" placeholder="Search memories…" class="memory-search-input" aria-label="Search memories" />
270              <div id="memory-category-filters" class="memory-category-filters">
271                <button class="memory-cat-chip active" data-cat="all">all</button>
272              </div>
273            </div>
274            <div id="memory-bulk-bar" class="memory-bulk-bar hidden">
275              <label class="memory-bulk-check-all" style="position:relative;top:0px;"><input type="checkbox" id="memory-select-all" /> All</label>
276              <span id="memory-selected-count">0 Selected</span>
277              <button id="memory-bulk-delete" class="memory-toolbar-btn danger" disabled>
277<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-1px;margin-right:3px;"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/></svg>Delete</button>
278              <button id="memory-bulk-cancel" class="memory-toolbar-btn" title="Cancel (Esc)" style="margin-left:4px;padding:3px 6px;"><svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
279            </div>
280            <div id="memory-list" class="memory-list"></div>
281            <div id="memory-suggestions-body" class="memory-suggestions hidden"></div>
282          </div>
283        </div>
284        <!-- ── Add tab ── -->
285        <div class="memory-tab-panel hidden" data-memory-panel="add">
286          <div class="admin-card">
287            <div style="display:flex;align-items:center;gap:8px;margin-bottom:2px;">
288              <h2 style="margin:0;padding:0;line-height:1;"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:6px"><path d="M12 2a7 7 0 0 1 7 7c0 2.4-1.2 4.5-3 5.7V17a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-2.3C6.2 13.5 5 11.4 5 9a7 7 0 0 1 7-7z"/><line x1="10" y1="22" x2="14" y2="22"/></svg>Add Memory</h2>
289              <span style="flex:1"></span>
290              <button id="memory-import-btn" class="theme-io-btn" title="Import memories from a file" style="height:26px;font-size:12px;"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:4px;"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>Import</button>
291              <button id="memory-export-btn" class="theme-io-btn" title="Export all memories as JSON" style="height:26px;font-size:12px;"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:4px;"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>Export</button>
292              <input type="file" id="memory-import-file" accept=".txt,.md,.pdf,.csv,.log,.json,.py,.js,.html" hidden />
293            </div>
294            <p class="memory-desc doclib-desc" style="margin:4px 0 6px;">
295              Import a <code>.txt</code>, <code>.md</code>, <code>.pdf</code>, <code>.csv</code>, <code>.log</code>, <code>.json</code>, <code>.py</code>, <code>.js</code>, or <code>.html</code> file &mdash; the AI reads it and suggests candidate memories you can approve.
296            </p>
297            <div class="memory-add-row" style="margin-top:8px;">
298              <div class="skill-ph-wrap" style="flex:1;min-width:0;">
299                <input type="text" id="new-memory-input" placeholder=" " class="memory-add-input skill-hint-input" aria-label="New memory text" />
300                <span class="skill-rich-ph"><span class="k">Add a memory</span> &mdash; e.g. 'I prefer concise replies' <svg class="k" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-left:4px;" aria-hidden="true"><polyline points="9 10 4 15 9 20"/><path d="M20 4v7a4 4 0 0 1-4 4H4"/></svg></span>
301              </div>
302              <select id="new-memory-category" class="memory-edit-cat-select" aria-label="Memory category"></select>
303            </div>
304          </div>
305          <div class="admin-card">
306            <div style="display:flex;align-items:baseline;gap:8px;margin-bottom:2px;">
307              <h2 style="margin:0;padding:0;line-height:1;"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:6px"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>Add Skill</h2>
308            </div>
309            <p class="memory-desc doclib-desc" style="margin-top:6px;">Import a skill from GitHub or <a href="https://skills.sh" target="_blank" rel="noopener noreferrer">skills.sh</a> (folder with <code>SKILL.md</code> and optional templates).</p>
310            <div class="memory-add-row" style="margin-top:6px;margin-bottom:10px;">
311              <div class="skill-ph-wrap" style="flex:1;min-width:0;">
312                <input type="url" id="skill-import-url" placeholder=" " class="memory-add-input skill-hint-input" aria-label="Skill import URL" />
313                <span class="skill-rich-ph"><span class="k">Import URL</span> — e.g. GitHub tree link to a skill folder</span>
314              </div>
315              <button type="button" id="skill-import-url-btn" class="theme-io-btn" title="Import skill from URL" style="flex:none;height:28px;font-size:12px;"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:4px;" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>Import</button>
316            </div>
317            <p class="memory-desc doclib-desc" style="margin-top:0;">Or create a skill by hand — title, what it solves, and an approach.</p>
318            <div class="skill-ph-wrap" style="margin-top:4px;margin-bottom:6px;">
319              <input type="text" id="new-skill-title" placeholder=" " class="memory-add-input skill-hint-input" aria-label="Skill title" />
320              <span class="skill-rich-ph"><span class="k">Title</span> — short name, e.g. “build-vllm-wheel”</span>
321            </div>
322            <div class="skill-ph-wrap" style="margin-bottom:6px;">
323              <input type="text" id="new-skill-problem" placeholder=" " class="memory-add-input skill-hint-input" aria-label="When to use this skill" />
324              <span class="skill-rich-ph"><span class="k">When to use</span> — what problem does this skill solve?</span>
325            </div>
326            <div class="skill-ph-wrap" style="margin-bottom:6px;">
327              <textarea id="new-skill-solution" placeholder=" " class="memory-add-input skill-hint-input" rows="2" style="resize:vertical;" aria-label="How — the approach or steps"></textarea>
328              <span class="skill-rich-ph skill-rich-ph-top"><span class="k">How</span> — the approach, steps, commands, or rules to follow</span>
329            </div>
330            <div class="skill-ph-wrap" style="margin-bottom:8px;">
331              <input type="text" id="new-skill-tags" placeholder=" " class="memory-add-input skill-hint-input" aria-label="Tags" />
332              <span class="skill-rich-ph"><span class="k">Tags</span> — comma-separated, e.g. python, build, vllm</span>
333            </div>
334            <div style="display:flex;justify-content:flex-end;">
335              <button id="add-skill-btn" class="confirm-btn confirm-btn-primary">Add Skill</button>
336            </div>
337          </div>
338        </div>
339        <!-- ── Skills tab ── -->
340        <div class="memory-tab-panel hidden" data-memory-panel="skills">
341          <div class="admin-card" style="display:flex;flex-direction:column;overflow:hidden;flex:1;min-height:0;">
342            <div style="display:flex;align-items:center;gap:8px;margin-bottom:2px;">
343              <h2 style="margin:0;padding:0;line-height:1;">Skills <span id="skills-count-h2" class="memory-count" style="font-size:0.6em;opacity:0.6;font-weight:normal"></span></h2>
344              <span style="flex:1"></span>
345              <label class="admin-switch" title="Inject relevant skills into chat context"><input type="checkbox" id="skills-enabled-header-toggle" checked /><span class="admin-slider"></span></label>
346            </div>
347            <p class="memory-desc doclib-desc" style="margin-top:6px;">Reusable procedures the AI can call via /skill — sort by confidence to surface the proven ones.</p>
348            <div class="memory-toolbar">
349              <div class="memory-toolbar-row">
350                <select id="skills-sort" class="memory-sort-select">
351                  <optgroup label="Sort">
352                    <option value="sort:confidence">Confidence</option>
353                    <option value="sort:uses">Most used</option>
354                    <option value="sort:alpha">A-Z</option>
355                    <option value="sort:recent">Recent</option>
356                  </optgroup>
357                  <optgroup label="Filter">
358                    <option value="filter:all">All skills</option>
359                    <option value="filter:drafts">Drafts only</option>
360                    <option value="filter:published">Published only</option>
361                    <option value="filter:conf95">Confidence ≤ 95%</option>
362                    <option value="filter:conf90">Confidence ≤ 90%</option>
363                    <option value="filter:conf85">Confidence ≤ 85%</option>
364                    <option value="filter:conf80">Confidence ≤ 80%</option>
365                    <option value="filter:conf75">Confidence ≤ 75%</option>
366                    <option value="filter:conf70">Confidence ≤ 70%</option>
367                  </optgroup>
368                </select>
369                <button id="skills-select-btn" class="memory-toolbar-btn" title="Select multiple skills">Select</button>
370                <button id="skills-audit-btn" class="memory-toolbar-btn" title="Test every skill, auto-fix the weak ones, flag what still fails">
370<svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor" style="vertical-align:-1px;margin-right:3px;"><path d="M12 0L14.59 8.41L23 12L14.59 15.59L12 24L9.41 15.59L1 12L9.41 8.41Z"/></svg>Audit all</button>
371              </div>
372              <input type="text" id="skills-search" placeholder="Search skills…" class="memory-search-input" aria-label="Search skills" />
373            </div>
374            <div id="skills-audit-panel" class="skills-audit-panel hidden"></div>
375            <div id="skills-bulk-bar" class="memory-bulk-bar hidden">
376              <label class="memory-bulk-check-all" style="position:relative;top:0px;"><input type="checkbox" id="skills-select-all" /> All</label>
377              <span id="skills-selected-count">0 Selected</span>
378              <button id="skills-bulk-publish" class="memory-toolbar-btn" disabled title="Publish selected drafts" style="margin-left:auto;"><svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-1px;margin-right:3px;"><polyline points="20 6 9 17 4 12"/></svg>Approve</button>
379              <button id="skills-bulk-audit" class="memory-toolbar-btn" disabled title="Audit selected draft skills">
379<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-1px;margin-right:3px;"><polygon points="5 3 19 12 5 21 5 3"/></svg>Audit</button>
380              <button id="skills-bulk-delete-nonpassing" class="memory-toolbar-btn danger" disabled title="Delete selected duplicates, generic/irrelevant skills, failed audits, and skills below threshold"><svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-1px;margin-right:3px;"><path d="M3 6h18"/><path d="M8 6V4h8v2"/><path d="M19 6l-1 14H6L5 6"/><path d="M10 11l4 4"/><path d="M14 11l-4 4"/></svg>Delete non passing</button>
381              <button id="skills-bulk-delete" class="memory-toolbar-btn danger" disabled><svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-1px;margin-right:3px;"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/></svg>Delete</button>
382              <button id="skills-bulk-cancel" class="memory-toolbar-btn" title="Cancel (Esc)" style="padding:3px 6px;">
382<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
383            </div>
384            <div id="skills-list" class="memory-list"></div>
385          </div>
386        </div>
387        <!-- ── Settings tab ── -->
388        <div class="memory-tab-panel hidden" data-memory-panel="settings">
389          <div class="admin-card">
390            <div style="display:flex;align-items:center;justify-content:space-between;gap:12px">
391              <h2 style="margin:0">Auto-extract memories</h2>
392              <label class="admin-switch" style="flex-shrink:0"><input type="checkbox" id="auto-memory-toggle" checked /><span class="admin-slider"></span></label>
393            </div>
394            <span class="admin-toggle-sub" style="display:block;margin-top:6px">Automatically extract memories from conversations.</span>
395          </div>
396          <div class="admin-card">
397            <div style="display:flex;align-items:center;justify-content:space-between;gap:12px">
398              <h2 style="margin:0">Auto-extract skills</h2>
399              <label class="admin-switch" style="flex-shrink:0"><input type="checkbox" id="auto-skills-toggle" /><span class="admin-slider"></span></label>
400            </div>
401            <span class="admin-toggle-sub" style="display:block;margin-top:6px;opacity:0.6">Automatically draft reusable skills from your workflows. Audit all can publish passing skills using the threshold below.</span>
402            <span class="admin-toggle-sub" style="display:block;margin-top:6px;opacity:0.6">The library can grow; cleanup retires weak/duplicate skills only after review.</span>
403          </div>
404          <div class="admin-card">
405            <div style="display:flex;align-items:center;justify-content:space-between;gap:12px">
406              <h2 style="margin:0">Inject Skills</h2>
407            </div>
408            <span class="admin-toggle-sub" style="display:block;margin-top:6px;opacity:0.6">Controls how many relevant published or approved skills are added to each agent request.</span>
409            <div style="display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:8px">
410              <span class="admin-toggle-sub" style="margin:0">Max skills per request</span>
411              <input type="number" id="skill-max-input" min="0" max="12" step="1" value="3" aria-label="Max skills to inject" style="flex-shrink:0;width:72px;background:var(--input-bg,var(--panel));color:var(--fg);border:1px solid var(--border);border-radius:6px;padding:4px 6px;font-size:12px;text-align:right;font-variant-numeric:tabular-nums" />
412            </div>
413            <span class="admin-toggle-sub" style="display:block;margin-top:6px;opacity:0.5">Set to 0 to disable skill injection.</span>
414          </div>
415          <div class="admin-card">
416            <div style="display:flex;align-items:center;justify-content:space-between;gap:12px">
417              <h2 style="margin:0">Auto-approve skills</h2>
418              <label class="admin-switch" style="flex-shrink:0"><input type="checkbox" id="auto-approve-skills-toggle" checked /><span class="admin-slider"></span></label>
419            </div>
420            <span class="admin-toggle-sub" style="display:block;margin-top:6px;opacity:0.6">Audit all publishes passing, necessary skills at or above this confidence. Off = keep audit results as drafts unless manually approved.</span>
421            <div style="display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:6px">
422              <span class="admin-toggle-sub" style="margin:0">Minimum confidence</span>
423              <span style="display:flex;align-items:center;gap:8px;flex-shrink:0">
424                <span id="skill-confidence-label" class="admin-toggle-sub" style="margin:0;min-width:42px;text-align:right;font-variant-numeric:tabular-nums">&ge; 85%</span>
425                <input type="range" id="skill-confidence-slider" class="preset-range" min="50" max="100" step="5" value="85" style="width:120px;margin:0" />
426              </span>
427            </div>
428          </div>
429        </div>
430      </div>
431    </div>
432  </div>
433
434  <!-- Theme Popup (floating panel) -->
435  <div id="theme-modal" class="modal hidden">
436  <div id="theme-popup" class="modal-content admin-modal-content" role="dialog" aria-label="Theme" style="background:var(--bg)">
437    <div class="modal-header theme-popup-header" id="theme-popup-header">
438      <h4><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:6px"><circle cx="12" cy="12" r="10"/><path d="M12 2a7 7 0 0 0 0 20 4 4 0 0 1 0-8 4 4 0 0 0 0-8"/><circle cx="8" cy="9" r="1.5" fill="currentColor"/><circle cx="15" cy="14" r="1.5" fill="currentColor"/><circle cx="9" cy="15" r="1.5" fill="currentColor"/></svg>Theme</h4>
439      <button type="button" class="theme-opacity-wrap theme-opacity-toggle hidden" id="theme-opacity-wrap" title="Fade this window to preview the page behind it" aria-pressed="false">
440        <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
441        <span class="theme-opacity-label">Peek</span>
442      </button>
443      <button class="close-btn" id="close-theme-popup" aria-label="Close theme">&#x2716;</button>
444    </div>
445    <!-- Theme tabs -->
446    <div class="admin-tabs" id="theme-tabs">
447      <button class="admin-tab active" data-tab="theme-tab-browse"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px"><circle cx="12" cy="12" r="10"/><path d="M12 2a7 7 0 0 0 0 20 4 4 0 0 1 0-8 4 4 0 0 0 0-8"/><circle cx="8" cy="9" r="1.4" fill="currentColor"/><circle cx="15" cy="14" r="1.4" fill="currentColor"/><circle cx="9" cy="15" r="1.4" fill="currentColor"/></svg>Themes</button>
448      <button class="admin-tab" data-tab="theme-tab-customize"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px"><path d="M9.06 11.9l-3.5 3.5a2.85 2.85 0 1 0 4.03 4.03l8.49-8.49a4.5 4.5 0 1 0-6.36-6.36L3.18 12.62"/><path d="M14 7l3 3"/></svg>Customize</button>
449    </div>
450
451    <!-- Tab: Browse themes -->
452    <div id="theme-tab-browse" class="theme-tab-panel">
453      <div class="admin-card">
454        <h2>Default Themes</h2>
455        <div class="theme-grid" id="themeGrid"></div>
456      </div>
457      <div class="admin-card" id="themeUserCard" style="display:none">
458        <h2>Your Themes</h2>
459        <div class="theme-grid" id="themeUserGrid"></div>
460      </div>
461    </div>
462
463    <!-- Tab: Customize -->
464    <div id="theme-tab-customize" class="theme-tab-panel" style="display:none">
465      <div class="admin-card">
466        <h2>Colors</h2>
467        <div class="theme-custom" id="themeCustom">
468          <div class="color-row"><label>Background</label><input type="color" id="clr-bg"><button class="color-reset-btn" data-reset="bg" title="Reset this color" aria-label="Reset color">&#x21BA;</button></div>
469          <div class="color-row"><label>Text</label><input type="color" id="clr-fg"><button class="color-reset-btn" data-reset="fg" title="Reset this color" aria-label="Reset color">&#x21BA;</button></div>
470          <div class="color-row"><label>Panel</label><input type="color" id="clr-panel"><button class="color-reset-btn" data-reset="panel" title="Reset this color" aria-label="Reset color">&#x21BA;</button></div>
471          <div class="color-row"><label>Sidebar</label><input type="color" id="adv-sidebarBg"><button class="color-reset-btn" data-reset-adv="sidebarBg" title="Reset this color" aria-label="Reset color">&#x21BA;</button></div>
472          <div class="color-row"><label>Border</label><input type="color" id="clr-border"><button class="color-reset-btn" data-reset="border" title="Reset this color" aria-label="Reset color">&#x21BA;</button></div>
473          <div class="color-row"><label>Accent</label><input type="color" id="clr-red"><button class="color-reset-btn" data-reset="red" title="Reset this color" aria-label="Reset color">&#x21BA;</button></div>
474        </div>
475      </div>
476      <div class="theme-adv-toggle" id="theme-adv-toggle">
477        <span class="theme-adv-arrow">&#x25B6;</span> More Colors
478      </div>
479      <div class="theme-adv-section hidden" id="themeAdvanced">
480        <div class="theme-adv-group">
481          <div class="theme-adv-group-label">Chat Bubbles</div>
482          <div class="theme-custom">
483            <div class="color-row"><label>User Chat Bubble</label><input type="color" id="adv-userBubbleBg"><button class="color-reset-btn" data-reset-adv="userBubbleBg" title="Reset this color" aria-label="Reset color">&#x21BA;</button></div>
484            <div class="color-row"><label>AI Chat Bubble</label><input type="color" id="adv-aiBubbleBg"><button class="color-reset-btn" data-reset-adv="aiBubbleBg" title="Reset this color" aria-label="Reset color">&#x21BA;</button></div>
485            <div class="color-row"><label>Border Chat Bubble</label><input type="color" id="adv-bubbleBorder"><button class="color-reset-btn" data-reset-adv="bubbleBorder" title="Reset this color" aria-label="Reset color">&#x21BA;</button></div>
486          </div>
487        </div>
488        <div class="theme-adv-group">
489          <div class="theme-adv-group-label">Sidebar</div>
490          <div class="theme-custom">
491            <div class="color-row"><label>Odysseus Logo</label><input type="color" id="adv-brandColor"><button class="color-reset-btn" data-reset-adv="brandColor" title="Reset this color" aria-label="Reset color">&#x21BA;</button></div>
492            <div class="color-row"><label title="Hamburger menu"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" style="vertical-align:-2px;"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg></label><input type="color" id="adv-hamburgerColor"><button class="color-reset-btn" data-reset-adv="hamburgerColor" title="Reset this color" aria-label="Reset color">&#x21BA;</button></div>
493          </div>
494        </div>
495        <div class="theme-adv-group">
496          <div class="theme-adv-group-label">Chat Input / Prompt Area</div>
497          <div class="theme-custom">
498            <div class="color-row"><label>Input Bg</label><input type="color" id="adv-inputBg"><button class="color-reset-btn" data-reset-adv="inputBg" title="Reset this color" aria-label="Reset color">&#x21BA;</button></div>
499            <div class="color-row"><label>Input Border</label><input type="color" id="adv-inputBorder"><button class="color-reset-btn" data-reset-adv="inputBorder" title="Reset this color" aria-label="Reset color">&#x21BA;</button></div>
500            <div class="color-row"><label>Send Btn</label><input type="color" id="adv-sendBtnBg"><button class="color-reset-btn" data-reset-adv="sendBtnBg" title="Reset this color" aria-label="Reset color">&#x21BA;</button></div>
501            <div class="color-row"><label>Send Hover</label><input type="color" id="adv-sendBtnHover"><button class="color-reset-btn" data-reset-adv="sendBtnHover" title="Reset this color" aria-label="Reset color">&#x21BA;</button></div>
502          </div>
503        </div>
504        <div class="theme-adv-group">
505          <div class="theme-adv-group-label">Code Blocks</div>
506          <div class="theme-custom">
507            <div class="color-row"><label>Code Bg</label><input type="color" id="adv-codeBg"><button class="color-reset-btn" data-reset-adv="codeBg" title="Reset this color" aria-label="Reset color">&#x21BA;</button></div>
508            <div class="color-row"><label>Code Text</label><input type="color" id="adv-codeFg"><button class="color-reset-btn" data-reset-adv="codeFg" title="Reset this color" aria-label="Reset color">&#x21BA;</button></div>
509          </div>
510        </div>
511        <div class="theme-adv-group">
512          <div class="theme-adv-group-label">Controls</div>
513          <div class="theme-custom">
514            <div class="color-row"><label>Toggle On</label><input type="color" id="adv-toggleActive"><button class="color-reset-btn" data-reset-adv="toggleActive" title="Reset this color" aria-label="Reset color">&#x21BA;</button></div>
515          </div>
516        </div>
517        <div class="theme-adv-group">
518          <div class="theme-adv-group-label">Custom Fonts</div>
519          <div class="theme-fd-label" style="opacity:0.4;">Drop <code>.woff2</code>, <code>.ttf</code>, or <code>.otf</code> files into <code>static/fonts/custom/</code> and reload — they'll appear in the Font dropdown above.</div>
520        </div>
521        <button class="theme-adv-clear-btn" id="theme-adv-clear">Clear Advanced Overrides</button>
522      </div>
523      <!-- Color Harmony Generator (its own card) -->
524      <div class="admin-card" id="theme-harmony-card">
525        <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:6px"><circle cx="13.5" cy="6.5" r="2.5"/><circle cx="19" cy="13" r="2.5"/><circle cx="6" cy="12" r="2.5"/><circle cx="10" cy="20" r="2.5"/></svg>Color Harmony</h2>
526        <div class="theme-harmony-row">
527          <div class="theme-fd-group">
528            <label class="theme-fd-label">Accent Color</label>
529            <div class="color-row" style="justify-content:flex-start;gap:8px;">
530              <input type="color" id="harmony-accent" value="#e06c75">
531              <span id="harmony-accent-hex" style="font-size:11px;opacity:0.65;font-family:ui-monospace,monospace;letter-spacing:0.02em;">#e06c75</span>
532            </div>
533          </div>
534          <div class="theme-fd-group">
535            <label class="theme-fd-label">Harmony</label>
536            <select id="harmony-type" class="theme-fd-select">
537              <option value="complementary">Complementary</option>
538              <option value="analogous">Analogous</option>
539              <option value="triadic">Triadic</option>
540              <option value="monochromatic">Monochromatic</option>
541            </select>
542          </div>
543        </div>
544        <div class="theme-harmony-row" style="margin-top:6px;">
545          <div class="theme-fd-group">
546            <label class="theme-fd-label">Mode</label>
547            <select id="harmony-mode" class="theme-fd-select">
548              <option value="dark">Dark</option>
549              <option value="light">Light</option>
550            </select>
551          </div>
552          <div class="theme-fd-group" style="justify-content:flex-end;">
553            <button id="harmony-generate-btn" class="harmony-generate-btn">Generate</button>
554          </div>
555        </div>
556        <div id="harmony-preview" class="harmony-preview"></div>
557      </div>
558      <div class="admin-card">
559        <h2>Font & Layout</h2>
560        <div class="theme-fd-row">
561          <div class="theme-fd-group">
562            <label class="theme-fd-label">Font</label>
563            <select id="theme-font-select" class="theme-fd-select" aria-label="Font">
564              <option value="mono">Monospace</option>
565              <option value="sans">Sans-serif</option>
566              <option value="serif">Serif</option>
567            </select>
568          </div>
569          <div class="theme-fd-group">
570            <label class="theme-fd-label">Density</label>
571            <select id="theme-density-select" class="theme-fd-select" aria-label="Density">
572              <option value="compact">Compact</option>
573              <option value="comfortable">Comfortable</option>
574              <option value="spacious">Spacious</option>
575            </select>
576          </div>
577          <div class="theme-fd-group" id="theme-frosted-group">
578            <label class="theme-fd-label" for="theme-frosted-toggle">Frosted</label>
579            <label class="admin-switch" style="margin-top:4px;">
580              <input type="checkbox" id="theme-frosted-toggle">
581              <span class="admin-slider"></span>
582            </label>
583          </div>
584        </div>
585        <div class="theme-fd-row">
586          <div class="theme-fd-group" style="flex:1 1 0;">
587            <label class="theme-fd-label">Background / Effect</label>
588            <select id="theme-bg-pattern-select" class="theme-fd-select">
589              <option value="none">Solid</option>
590              <option value="dots">Dots</option>
591              <option value="synapse">Synapse</option>
592              <option value="rain">Rain</option>
593              <option value="constellations">Constellations</option>
594              <option value="perlin-flow">Perlin Flow</option>
595              <option value="petals">Petals</option>
596              <option value="sparkles">Sparkles</option>
597              <option value="embers">Embers</option>
598            </select>
599          </div>
600          <div class="theme-fd-group" style="flex:0 0 auto;align-items:center;">
601            <label class="theme-fd-label">&nbsp;</label>
602            <div class="color-row" style="margin:0;padding:0;">
603              <input type="color" id="theme-bg-effect-color" value="#9cdef2" title="Effect color">
604              <button class="color-reset-btn" data-reset-effect title="Reset to text color">&#x21BA;</button>
605            </div>
606          </div>
607        </div>
608        <div class="theme-fd-row">
609          <div class="theme-fd-group" id="theme-bg-intensity-group" style="flex:1 1 0;">
610            <label class="theme-fd-label">Intensity</label>
611            <input type="range" id="theme-bg-intensity" class="theme-fd-range" min="0" max="100" step="5" value="100">
612          </div>
613          <div class="theme-fd-group" id="theme-bg-size-group" style="flex:1 1 0;">
614            <label class="theme-fd-label">Size</label>
615            <input type="range" id="theme-bg-size" class="theme-fd-range" min="30" max="250" step="10" value="100">
616          </div>
617        </div>
618      </div>
619      <div class="admin-card" style="margin-top:8px;">
620        <h2>Save / Share</h2>
621        <div class="theme-save-row" id="theme-save-row">
622          <input type="text" id="theme-save-name" placeholder="Theme name..." maxlength="32">
623          <button id="theme-save-go">Save</button>
624        </div>
625        <div class="theme-save-error" id="theme-save-error"></div>
626        <div class="theme-io-row" style="margin-top:6px;">
627          <button id="theme-import-btn" class="theme-io-btn" title="Import a theme from JSON">&#x2912; Import</button>
628          <button id="theme-export-btn" class="theme-io-btn" title="Export current colors as JSON">&#x2913; Export</button>
629        </div>
630        <textarea id="theme-import-area" class="theme-import-area hidden" placeholder="Paste theme JSON here..." rows="3"></textarea>
631        <div class="theme-import-actions hidden" id="theme-import-actions">
632          <button id="theme-import-go" class="theme-io-btn">Apply</button>
633          <button id="theme-import-cancel" class="theme-io-btn">Cancel</button>
634        </div>
635      </div>
636      <button id="theme-reset-btn">Reset to Default</button>
637    </div>
638  </div>
639  </div>
640
641  <div id="mobile-backdrop"></div>
642  <button id="mobile-menu-btn" aria-label="Toggle sidebar">&#x2630;</button>
643
644  <button class="hamburger-btn" id="hamburger-btn" title="Show sidebar"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg></button>
645  <!-- new session button removed — use + in send button instead -->
646  <div class="icon-rail" id="icon-rail">
647    <div class="rail-resize-handle" id="rail-resize-handle"></div>
648    <!-- Static: core actions -->
649    <button class="icon-rail-btn" id="rail-search-btn" title="Search conversations (Ctrl+K)">
649<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><circle cx="10" cy="10" r="7"/><path d="M21 21l-4.35-4.35"/></svg></button>
650    <button class="icon-rail-btn rail-new-chat" id="rail-new-session" title="New chat"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg></button>
651    <button class="icon-rail-btn" id="rail-delete-session" title="Delete session">&#x2715;</button>
652    <div class="rail-separator"></div>
653    <!-- Dynamic contextual indicators (shown only while active) -->
654    <button class="icon-rail-btn rail-dynamic" id="rail-chats" title="Chat ready" style="display:none"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg></button>
655    <button class="icon-rail-btn rail-dynamic" id="rail-documents" title="Documents" style="display:none"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="8" y1="13" x2="16" y2="13"/><line x1="8" y1="17" x2="13" y2="17"/></svg></button>
656    <!-- Tool launchers — always visible, alphabetical -->
657    <button class="icon-rail-btn" id="rail-calendar" title="Calendar"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg></button>
658    <button class="icon-rail-btn" id="rail-compare" title="Compare"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="18" cy="18" r="3"/><circle cx="6" cy="6" r="3"/><path d="M13 6h3a2 2 0 0 1 2 2v7"/><path d="M11 18H8a2 2 0 0 1-2-2V9"/></svg></button>
659    <button class="icon-rail-btn" id="rail-cookbook" title="Cookbook"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" style="opacity:0.7"><path d="M12 7v14"/><path d="M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z"/></svg></button>
660    <button class="icon-rail-btn" id="rail-research" title="Deep Research"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/><line x1="11" y1="8" x2="11" y2="14"/><line x1="8" y1="11" x2="14" y2="11"/></svg></button>
661    <button class="icon-rail-btn" id="rail-email" title="Email"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg></button>
662    <button class="icon-rail-btn" id="rail-gallery" title="Gallery"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="M21 15l-5-5L5 21"/></svg></button>
663    <button class="icon-rail-btn" id="rail-archive" title="Library"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/><path d="M9 7h6M9 11h4"/></svg></button>
664    <button class="icon-rail-btn" id="rail-memory" title="Brain">
664<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z"/><path d="M12 5a3 3 0 1 1 5.997.125 4 4 0 0 1 2.526 5.77 4 4 0 0 1-.556 6.588A4 4 0 1 1 12 18Z"/><path d="M15 13a4.5 4.5 0 0 1-3-4 4.5 4.5 0 0 1-3 4"/></svg></button>
665    <button class="icon-rail-btn" id="rail-notes" title="Notes"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 3h10l4 4v14H5z"/><path d="M15 3v5h5"/><path d="M8 17.5 15.5 10l2.5 2.5L10.5 20H8z"/></svg></button>
666    <button class="icon-rail-btn" id="rail-tasks" title="Tasks"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/><path d="M9 16l2 2 4-4"/></svg></button>
667    <button class="icon-rail-btn" id="rail-theme" title="Theme"><svg width="16" height="16" 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"/><path d="M12 2a10 10 0 0 0 0 20 5 5 0 0 0 5-5 3 3 0 0 0-3-3h-2a3 3 0 0 1-3-3 5 5 0 0 1 5-5"/></svg></button>
668    <div style="flex:1"></div>
669    <!-- Static: bottom -->
670    <button class="icon-rail-btn" id="rail-settings" title="Settings"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg></button>
671  </div>
672
673  <nav class="sidebar" id="sidebar" role="navigation" aria-label="Sidebar">
674    <div class="sidebar-resize-handle" id="sidebar-resize-handle"></div>
675    <div class="sidebar-header">
676      <button class="sidebar-hamburger" id="sidebar-toggle-btn" title="Toggle sidebar"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg></button>
677      <div class="sidebar-brand" id="sidebar-brand-btn" style="cursor:pointer;" title="New chat">
678        <span class="sidebar-brand-title">Odysseus</span>
679      </div>
680    </div>
681    <div class="sidebar-inner">
682      <div class="list-item" id="sidebar-new-chat-btn" title="New chat">
683        <svg class="sidebar-action-icon" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" style="position:relative;left:-2px;"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
684        <span class="grow" style="position:relative;left:-3px;">New Chat</span>
685      </div>
686      <div class="list-item" id="sidebar-search-btn" title="Search conversations (Ctrl+K)">
687        <svg class="sidebar-action-icon" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><circle cx="10" cy="10" r="7"/><path d="M21 21l-4.35-4.35"/></svg>
688        <span class="grow" style="position:relative;left:-1px;">Search</span>
689      </div>
690      <!-- Assistant sidebar entry removed — its log + settings live inside
691           the Tasks modal (Activity + Settings tabs). The backend
692           assistant session is still maintained for log_to_assistant()
693           writes from scheduled tasks. -->
694
695      <div class="section" id="sessions-section">
696        <div class="section-header-flex">
697          <span class="section-title" id="chats-section-title"><svg class="section-icon" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg><span id="chats-section-label" class="section-title-label">Chats</span><span id="chats-notif-dot" class="sidebar-notif-dot" style="display:none"></span></span>
698          <div style="position:relative; display:inline-block; display:flex; gap:4px; align-items:center;">
699            <button type="button" class="section-header-btn chats-manage-btn" id="chats-library-btn" title="Manage Chats (Library)">
700              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
701                <path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/>
702                <path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/>
703                <path d="M9 7h6M9 11h4"/>
704              </svg>
705            </button>
706            <button type="button" class="section-header-btn" id="session-sort-btn" title="Sort sessions">
707              <svg class="sort-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
708                <line x1="4" y1="6" x2="20" y2="6"/>
709                <line x1="4" y1="12" x2="14" y2="12"/>
710                <line x1="4" y1="18" x2="9" y2="18"/>
711              </svg>
712              <svg class="sort-spinner" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" style="display:none; animation: spin 0.7s linear infinite;">
713                <path d="M12 2a10 10 0 0 1 10 10" />
714              </svg>
715            </button>
716            <div id="session-sort-dropdown" class="dropdown sort-dropdown" style="display:none;">
717              <div class="dropdown-item sort-option sort-dropdown-item" data-sort="active">Last Active</div>
718              <div class="dropdown-item sort-option sort-dropdown-item" data-sort="newest">Newest First</div>
719              <div class="dropdown-item sort-option sort-dropdown-item" data-sort="group">By Folder</div>
720              <div class="dropdown-item sort-dropdown-item sort-dropdown-sep" id="auto-sort-sessions-row" style="display:flex;align-items:center;padding:0;">
721                <span id="auto-sort-sessions-btn" style="flex:1;padding:5px 10px;cursor:pointer;display:inline-flex;align-items:center;gap:4px;">
722                  <span class="auto-sort-icon">
722<svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor" style="vertical-align:-1px;margin-right:2px;"><path d="M12 0L14.59 8.41L23 12L14.59 15.59L12 24L9.41 15.59L1 12L9.41 8.41Z"/></svg> Tidy</span>
723                  <span class="auto-sort-spinner" style="display:none;">Sorting...</span>
724                </span>
725                <button type="button" id="auto-sort-sessions-more" title="Tidy options" aria-label="Tidy options" style="background:none;border:none;border-left:1px solid var(--border);color:inherit;cursor:pointer;padding:5px 8px;font-size:9px;opacity:0.7;"><svg width="8" height="8" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></button>
726              </div>
727              <div class="dropdown-item sort-dropdown-item" id="auto-sort-sessions-noai-btn" style="display:none;padding-left:24px;">
728                Tidy <span class="auto-sort-noai-spinner" style="display:none;font-size:9px;opacity:0.6;margin-left:4px;">Cleaning...</span>
729              </div>
730              <div class="dropdown-item rearrange-toggle sort-dropdown-item sort-dropdown-sep" id="session-rearrange-toggle">
731                &#8593;&#8595; Rearrange <span class="rearrange-check" style="float:right; opacity:0;">&#x2022;</span>
732              </div>
733              <div class="dropdown-item sort-dropdown-item" id="session-select-from-dropdown">
734                ● Select
735              </div>
736            </div>
737          </div>
738        </div>
739        <div id="session-bulk-bar" class="session-bulk-bar hidden">
740          <span id="session-select-all-dot" style="cursor:pointer;font-size:14px;opacity:0.4;user-select:none;">○</span><input type="checkbox" id="session-select-all" style="display:none;"><span style="font-size:10px;cursor:pointer;opacity:0.5;" id="session-select-all-label">All</span>
741          <div style="margin-left:auto;display:flex;gap:2px;align-items:center;">
742            <button class="session-bulk-btn" id="session-bulk-archive" title="Archive selected"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="5" rx="1"/><path d="M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8"/><path d="M10 12h4"/></svg></button>
743            <button class="session-bulk-btn session-bulk-btn-danger" id="session-bulk-delete" title="Delete selected"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/></svg></button>
744            <button class="session-bulk-btn" id="session-bulk-cancel" title="Cancel"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
745          </div>
746        </div>
747        <div id="session-list" role="listbox"></div>
748      </div>
749      <!-- Hidden dropdown for session actions -->
750      <div id="session-actions-dropdown" class="dropdown hidden">
751        <div class="dropdown-item" id="rename-session-option">
752          <h4>Rename</h4>
753          <p>Change the session name</p>
754        </div>
755        <div class="dropdown-item" id="delete-session-option">
756          <h4>Delete</h4>
757          <p>Remove this session permanently</p>
758        </div>
759        <div class="dropdown-item" id="memory-session-option">
760          <h4>Memory</h4>
761          <p>Extract memories from this session</p>
762        </div>
763      </div>
764
765      <div class="section" id="email-section">
766        <div class="section-header-flex">
767          <span class="section-title" id="email-section-title" style="cursor:pointer;" title="Open email inbox"><svg class="section-icon" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg><span>Email</span></span>
768          <button type="button" class="section-header-btn list-item-plus-btn" id="email-compose-btn" title="Compose email">
769            <svg class="list-item-plus-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
770            <span class="list-item-plus-label">new</span>
771          </button>
772          <!-- Unread dot is a direct header child placed AFTER the compose
773               button (it used to live inside the title, before the button).
774               With the title's flex:1 eating the free space, this lands the
775               dot at the far-right corner with the + just to its left —
776               i.e. the dot and + swap places when the dot appears. -->
777          <span id="email-unread-dot" class="sidebar-notif-dot" style="display:none"></span>
778        </div>
779      </div>
780
781      <div class="section" id="models-section">
782        <div class="section-header-flex">
783          <span class="section-title"> Models</span>
784          <div style="position:relative; display:inline-block;">
785            <button type="button" class="section-header-btn" id="model-sort-btn" title="Sort models">
786              <svg class="sort-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
787                <line x1="4" y1="6" x2="20" y2="6"/>
788                <line x1="4" y1="12" x2="14" y2="12"/>
789                <line x1="4" y1="18" x2="9" y2="18"/>
790              </svg>
791            </button>
792            <div id="model-sort-dropdown" class="dropdown sort-dropdown" style="display:none;">
793              <div class="dropdown-item sort-option sort-dropdown-item" data-sort="alpha">A-Z</div>
794              <div class="dropdown-item sort-option sort-dropdown-item" data-sort="last-used">Last used</div>
795              <div class="dropdown-item sort-option sort-dropdown-item" data-sort="most-used">Most used</div>
796              <div class="dropdown-item rearrange-toggle sort-dropdown-item sort-dropdown-sep" id="model-rearrange-toggle">
797                &#8593;&#8595; Rearrange <span class="rearrange-check" style="float:right; opacity:0;">&#x2022;</span>
798              </div>
799            </div>
800          </div>
801        </div>
802        <div id="models">
803          <div class="models-row">
804            <select id="model-select" aria-label="Select model" style="flex: 1; padding: 6px 8px; border-radius: 4px; border: 1px solid var(--border); background: var(--bg); color: var(--fg);"></select>
805            <button type="button" id="btn-model-chat" class="model-chat-btn" aria-label="Add model chat" style="transition: all 0.2s ease;"><span class="model-chat-btn-label">+ Chat</span></button>
806          </div>
807        </div>
808      </div>
809
810      <div class="section" id="tools-section">
811        <div class="section-header-flex">
812          <span class="section-title"><svg class="section-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>Tools</span>
813        </div>
814        <div class="list-item" id="tool-memory-btn">
815          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
816            stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
817            style="flex-shrink:0;opacity:0.5;">
818            <path d="M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z"/>
819            <path d="M12 5a3 3 0 1 1 5.997.125 4 4 0 0 1 2.526 5.77 4 4 0 0 1-.556 6.588A4 4 0 1 1 12 18Z"/>
820            <path d="M15 13a4.5 4.5 0 0 1-3-4 4.5 4.5 0 0 1-3 4"/>
821          </svg>
822          <span class="grow">Brain</span>
823        </div>
824        <div class="list-item" id="tool-calendar-btn">
825          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
826            stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
827            style="flex-shrink:0;
827opacity:0.5;">
828            <rect x="3" y="4" width="18" height="18" rx="2"/>
829            <line x1="16" y1="2" x2="16" y2="6"/>
830            <line x1="8" y1="2" x2="8" y2="6"/>
831            <line x1="3" y1="10" x2="21" y2="10"/>
832          </svg>
833          <span class="grow">Calendar</span>
834        </div>
835        <div class="list-item" id="tool-compare-btn">
836          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="flex-shrink:0;opacity:0.5;"><circle cx="18" cy="18" r="3"/><circle cx="6" cy="6" r="3"/><path d="M13 6h3a2 2 0 0 1 2 2v7"/><path d="M11 18H8a2 2 0 0 1-2-2V9"/></svg>
837          <span class="grow">Compare</span>
838        </div>
839        <div class="list-item" id="tool-cookbook-btn">
840          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
841            stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"
842            style="flex-shrink:0;opacity:0.5;">
843            <path d="M12 7v14"/>
844            <path d="M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z"/>
845          </svg>
846          <span class="grow">Cookbook</span>
847          <span id="cookbook-bg-status" style="display:none;font-size:9px;opacity:0.5;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-right:12px;flex-shrink:1;min-width:0;position:relative;top:-1px;"></span>
848          <span class="cookbook-notif-dot" id="cookbook-notif-dot" style="display:none;margin-left:6px;margin-right:4px;position:relative;top:-1px;left:0px;"></span>
849        </div>
850        <div class="list-item" id="tool-research-btn">
851          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="flex-shrink:0;opacity:0.5;"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/><line x1="11" y1="8" x2="11" y2="14"/><line x1="8" y1="11" x2="14" y2="11"/></svg>
852          <span class="grow">Deep Research</span>
853        </div>
854        <div class="list-item" id="tool-gallery-btn">
855          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
856            stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
857            style="flex-shrink:0;opacity:0.5;">
858            <rect x="3" y="3" width="18" height="18" rx="2"/>
859            <circle cx="8.5" cy="8.5" r="1.5"/>
860            <path d="M21 15l-5-5L5 21"/>
861          </svg>
862          <span class="grow">Gallery</span>
863        </div>
864        <div class="list-item" id="tool-library-btn">
865          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="flex-shrink:0;opacity:0.5;">
866            <path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/><path d="M9 7h6M9 11h4"/>
867          </svg>
868          <span class="grow">Library</span>
869          <button type="button" class="list-item-plus-btn" id="library-new-doc-btn" title="New document">
870            <svg class="list-item-plus-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" style="width:11px;height:11px;"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
871            <span class="list-item-plus-label">new</span>
872          </button>
873        </div>
874        <div class="list-item" id="tool-notes-btn">
875          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
876            stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
877            style="flex-shrink:0;opacity:0.5;">
878            <path d="M5 3h10l4 4v14H5z"/>
879            <path d="M15 3v5h5"/>
880            <path d="M8 17.5 15.5 10l2.5 2.5L10.5 20H8z"/>
881          </svg>
882          <span class="grow">Notes</span>
883        </div>
884        <div class="list-item" id="tool-tasks-btn">
885          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
886            stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
887            style="flex-shrink:0;
887opacity:0.5;">
888            <rect x="3" y="4" width="18" height="18" rx="2"/>
889            <line x1="16" y1="2" x2="16" y2="6"/>
890            <line x1="8" y1="2" x2="8" y2="6"/>
891            <line x1="3" y1="10" x2="21" y2="10"/>
892            <path d="M9 16l2 2 4-4"/>
893          </svg>
894          <span class="grow">Tasks</span>
895          <span id="assistant-notif-dot" class="sidebar-notif-dot" style="display:none"></span>
896        </div>
897
898        <div class="list-item" id="tool-theme-btn">
899          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
900            stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
901            style="flex-shrink:0;opacity:0.5;">
902            <circle cx="12" cy="12" r="10"/>
903            <path d="M12 2a7 7 0 0 0 0 20 4 4 0 0 1 0-8 4 4 0 0 0 0-8"/>
904            <circle cx="8" cy="9" r="1.5" fill="currentColor"/>
905            <circle cx="15" cy="14" r="1.5" fill="currentColor"/>
906            <circle cx="9" cy="15" r="1.5" fill="currentColor"/>
907          </svg>
908          <span class="grow">Theme</span>
909        </div>
910      </div>
911    </div>
912    <div class="sidebar-user-bar" id="sidebar-user-bar">
913      <!-- Logged in state -->
914      <div class="user-bar-left" id="user-bar-profile">
915        <div class="user-bar-avatar" id="user-bar-avatar"></div>
916        <span class="user-bar-name" id="user-bar-name">User</span>
917      </div>
918      <div class="user-bar-actions" id="user-bar-actions">
919        <button type="button" class="user-bar-btn" id="user-bar-settings" title="Settings">
920          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
921        </button>
922        <button type="button" class="user-bar-btn user-bar-logout-btn" id="user-bar-logout" title="Log Out" style="display:none">
923          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>
924        </button>
925      </div>
926      <!-- Not logged in state -->
927      <button type="button" class="user-bar-signin-btn" id="user-bar-signin" style="display:none">
928        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"/><polyline points="10 17 15 12 10 7"/><line x1="15" y1="12" x2="3" y2="12"/></svg>
929        Sign In
930      </button>
931    </div>
932  </nav>
933
934  <main class="chat-container welcome-active" id="chat-container" aria-label="Chat area" aria-busy="false">
935    <!-- Persistent page heading for assistive tech. Visually hidden so it
936         never affects layout, but always present inside the main landmark
937         (the sidebar that shows the visible brand is hidden off-canvas on
938         mobile) so the page always exposes a single level-1 heading. -->
939    <h1 class="a11y-visually-hidden">Odysseus</h1>
940    <div class="chat-top-bar">
941      <button type="button" class="incognito-indicator" id="incognito-indicator" title="Nobody mode active — click to deactivate" style="display:none;"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><line x1="8" y1="16" x2="16" y2="8"/>
941<line x1="8" y1="8" x2="16" y2="16"/></svg></button>
942      <div class="chat-meta-overlay"><span id="current-meta">Odysseus Chat</span><span id="current-meta-count" class="chat-meta-count" aria-hidden="true"></span><span id="session-cost-display" class="session-cost-display" style="display:none;"></span><span class="export-dropdown-wrap" id="export-dropdown-wrap"><button type="button" class="export-dl-btn" id="export-dl-btn" title="More"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></button><div class="export-dropdown-menu" id="export-dropdown-menu"><div class="export-dropdown-item" id="export-rename-btn"><span class="dropdown-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.83 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/></svg></span><span>Rename</span></div><div class="export-dropdown-item" id="export-copy-btn"><span class="dropdown-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></span><span>Copy Chat</span></div><div class="export-dropdown-item" id="export-pdf-btn"><span class="dropdown-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><path d="M9 15v-2h2a1.5 1.5 0 0 1 0 3H9z"/></svg></span><span>PDF</span></div><div class="export-dropdown-item" id="export-doc-btn"><span class="dropdown-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg></span><span>Save to Documents</span></div></div></span></div>    </div>
943    <div id="welcome-screen">
944      <div class="welcome-name"><svg class="welcome-boat" viewBox="0 0 32 32"><path d="M16 4L16 22L6 22Z" fill="currentColor"/><path d="M16 8L16 22L24 22Z" fill="currentColor" opacity="0.6"/><path d="M4 24Q10 20 16 24Q22 28 28 24" stroke="currentColor" stroke-width="2.5" fill="none" stroke-linecap="round"/></svg>Odysseus</div>
945      <div class="welcome-sub" id="welcome-sub">Welcome, <span class="setup-trigger-link" style="color:var(--accent,var(--red));font-weight:600;cursor:pointer;text-decoration:underline;" title="Click to launch setup">type /setup</span> to get started.</div>
946      <div class="welcome-tip" id="welcome-tip"></div>
947      <button type="button" class="incognito-btn" id="incognito-btn" title="Enable Nobody mode — no memory, no history saved">
948        <svg class="eye-open" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
949          <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>
950        </svg>
951        <svg class="eye-blinded" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display:none">
952          <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><line x1="8" y1="16" x2="16" y2="8"/><line x1="8" y1="8" x2="16" y2="16"/>
953        </svg>
954        <span class="incognito-label">Nobody</span>
955      </button>
956      <div id="welcome-setup" style="display:none"></div>
957    </div>
958    
958<script nonce="0ef1c0e2ced0cc537d6ee0258e679162">
959    (function(){
960      var mobile = window.matchMedia('(max-width: 768px)').matches;
961      var desktop = [
962        'Tip: Press Ctrl+K to search across all your conversations.',
963        'Tip: Press Ctrl+B to quickly toggle the sidebar.',
964        'Tip: Shift-click the sidebar toggle to swap it to the other side.',
965        'Tip: Drag and drop files onto the chat to attach them.',
966        'Tip: Right-click a session for rename, delete, and memory options.',
967      ];
968      var phone = [
969        'Tip: Long-press a session for rename, delete, and memory options.',
970        'Tip: Tap the eye icon for Nobody mode — no history saved.',
971        'Tip: Switch to Agent mode for web search and code execution.',
972        'Tip: Use Compare mode to test different models side by side.',
973        'Tip: Attach images or files using the + button next to the input.',
974      ];
975      var tips = mobile ? phone : desktop;
976      var el = document.getElementById('welcome-tip');
977      if (el) {
978        el.textContent = 'Type /setup, then choose Local models or API.';
979      }
980      fetch('/api/version').then(function(r){return r.json()}).then(function(d){
981        if (d.version) window._appVersion = d.version;
982      }).catch(function(){});
983    })();
984    </script>
984
985    <div id="chat-history" class="chat-history" role="log" aria-live="polite"></div>
986
987    <!-- Attachments strip -->
988    <div id="attach-strip" class="attach-strip"></div>
989
990    <!-- Hidden elements for form logic -->
991    <input type="checkbox" id="research-toggle" style="display:none;">
992    <input type="checkbox" id="rag-toggle" style="display:none;">
993    <input type="checkbox" id="incognito-toggle" style="display:none;">
994    <input type="file" id="file-input" class="hidden" multiple />
995
996    <!-- Unified chat input bar -->
997    <div class="chat-input-bar">
998      <div class="chat-input-top">
999        <div id="message-ghost" class="ghost-text-overlay" aria-hidden="true"></div>
1000        <textarea id="message" placeholder="Message Odysseus..." required autocomplete="off" aria-label="Message input" rows="1" autofocus></textarea>
1001        <!-- Model picker (inside chatbox, top-right) -->
1002        <div class="model-picker-wrap" id="model-picker-wrap">
1003          <button type="button" class="model-picker-btn" id="model-picker-btn" title="Switch model"><span id="model-picker-label">Select model</span> <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 15 12 9 18 15"/></svg></button>
1004          <div class="model-picker-menu hidden" id="model-picker-menu">
1005            <div class="model-picker-search-row">
1006              <input type="text" id="model-picker-search" placeholder="Search models..." autocomplete="off" aria-label="Search models">
1007              <button type="button" class="model-picker-action-btn primary" id="model-picker-add-models-btn" title="Add model endpoints" aria-label="Add model endpoints">
1008                <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5v14"/><path d="M5 12h14"/></svg>
1009              </button>
1010            </div>
1011            <div class="model-picker-list" id="model-picker-list"></div>
1012          </div>
1013        </div>
1014      </div>
1015      <div id="pinned-tools-bar"></div>
1016      <div class="chat-input-bottom" style="visibility:hidden">
1017        <div class="chat-input-left">
1018          <!-- Overflow menu (+) — always first/left -->
1019          <div class="overflow-wrapper">
1020            <button type="button" class="input-icon-btn overflow-plus-btn" id="overflow-plus-btn" title="More tools" aria-label="More tools" aria-haspopup="true">
1021              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
1022                <polyline points="6 15 12 9 18 15"/>
1023              </svg>
1024              <span class="plus-active-dot"></span>
1025            </button>
1026            <div id="overflow-menu" class="overflow-menu hidden">
1027              <button type="button" class="overflow-menu-item" id="overflow-attach-btn">
1028                <svg width="16" height="16" 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 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>
1029                <span>Attach files</span>
1030              </button>
1031              <button type="button" class="overflow-menu-item" id="overflow-doc-btn">
1032                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1033                  <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/>
1034                </svg>
1035                <span>Documents</span>
1036              </button>
1037              <button type="button" class="overflow-menu-item" id="overflow-rag-btn">
1038                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1039                  <ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/>
1040                </svg>
1041                <span>RAG</span>
1042                <span class="overflow-active-dot"></span>
1043              </button>
1044              <button type="button" class="overflow-menu-item" id="overflow-workspace-btn">
1045                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1046                  <path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
1047                </svg>
1048                <span>Workspace</span>
1049                <span class="overflow-active-dot"></span>
1050              </button>
1051              <!-- Inline "deep research mode" toggle removed (superseded by the
1052                   Deep Research sidebar / trigger_research). The hidden
1053                   #research-toggle checkbox is kept inert so existing JS refs
1054                   don't break; without this entry point it can't be enabled. -->
1055              <!-- Group Chat moved to Characters modal Group tab -->
1056              <!-- TTS Mode hidden — read-aloud feature is off in this build. -->
1057              <button type="button" class="overflow-menu-item" id="overflow-tts-btn" hidden style="display:none">
1058                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14"/><path d="M15.54 8.46a5 5 0 0 1 0 7.07"/></svg>
1059                <span>TTS Mode</span>
1060                <span class="overflow-active-dot"></span>
1061              </button>
1062              <button type="button" class="overflow-menu-item" id="overflow-preset-btn">
1063                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1064                  <path d="m18 2 4 4"/><path d="m17 7 3-3"/><path d="M19 9 8.7 19.3c-1 1-2.5 1-3.4 0l-.6-.6c-1-1-1-2.5 0-3.4L15 5"/><path d="m9 11 4 4"/><path d="m5 19-3 3"/><path d="m14 4 6 6"/>
1065                </svg>
1066                <span>Prompt</span>
1067              </button>
1068            </div>
1069          </div>
1070          <!-- Web search (magnifying glass) -->
1071          <button type="button" class="input-icon-btn" title="Web search" id="web-toggle-btn" data-mode-tool="true" aria-label="Web search" aria-pressed="false">
1072            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1073              <circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>
1074            </svg>
1075          </button>
1076          <!-- Shell commands (terminal) -->
1077          <button type="button" class="input-icon-btn" title="Shell Access" id="bash-toggle-btn" data-mode-tool="true" aria-label="Shell access" aria-pressed="false">
1078            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1079              <polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/>
1080            </svg>
1081          </button>
1082          <!-- Workspace indicator (hidden until a folder is set) -->
1083          <button type="button" class="input-icon-btn tool-indicator" title="Workspace — click to clear" id="workspace-indicator-btn" aria-label="Clear workspace" style="display:none;">
1084            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg>
1085            <span style="font-size:11px;margin-left:2px;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" id="workspace-indicator-name"></span>
1086            <svg class="tool-indicator-x" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><line x1="6" y1="6" x2="18" y2="18"/><line x1="18" y1="6" x2="6" y2="18"/></svg>
1087          </button>
1088          <!-- Plan mode (investigate read-only, propose a plan to approve) -->
1089          <button type="button" class="input-icon-btn" title="Plan mode — investigate read-only, then propose a plan to approve" id="plan-toggle-btn" data-mode-tool="true">
1090            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1091              <path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/>
1092            </svg>
1093          </button>
1094          <!-- RAG toolbar indicator (hidden until active) -->
1095          <button type="button" class="input-icon-btn tool-indicator" title="RAG active — click to deactivate" id="rag-indicator-btn" style="display:none;">
1096            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1097              <ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/>
1098            </svg>
1099            <span style="font-size:11px;margin-left:2px;">RAG</span>
1100            <svg class="tool-indicator-x" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><line x1="6" y1="6" x2="18" y2="18"/><line x1="18" y1="6" x2="6" y2="18"/></svg>
1101          </button>
1102          <!-- 6. Deep Research (hidden until active) -->
1103          <button type="button" class="input-icon-btn tool-indicator" title="Deep Research active — click to deactivate" id="research-toggle-btn" style="display:none;">
1104            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/><line x1="11" y1="8" x2="11" y2="14"/><line x1="8" y1="11" x2="14" y2="11"/></svg>
1105            <span style="font-size:11px;margin-left:2px;">Research</span>
1106            <svg class="tool-indicator-x" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><line x1="6" y1="6" x2="18" y2="18"/><line x1="18" y1="6" x2="6" y2="18"/></svg>
1107          </button>
1108          <!-- 7. Group Chat (hidden until active) -->
1109          <button type="button" class="input-icon-btn tool-indicator" title="Group Chat active — click to deactivate" id="group-toggle-btn" style="display:none;">
1110            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
1111            <span style="font-size:11px;margin-left:2px;">Group</span>
1112            <svg class="tool-indicator-x" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><line x1="6" y1="6" x2="18" y2="18"/><line x1="18" y1="6" x2="6" y2="18"/></svg>
1113          </button>
1114          <input type="checkbox" id="group-toggle" style="display:none;">
1115          <!-- Character indicator (hidden until active) -->
1116          <button type="button" class="input-icon-btn tool-indicator" title="Persona active — click to deactivate" id="character-indicator-btn" style="display:none;">
1117            <svg id="char-indicator-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
1118            <span id="character-indicator-name" style="font-size:11px;margin-left:2px;max-width:80px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;"></span>
1119            <svg class="tool-indicator-x" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><line x1="6" y1="6" x2="18" y2="18"/><line x1="18" y1="6" x2="6" y2="18"/></svg>
1120          </button>
1121          <!-- Compare toolbar indicator (hidden until active) -->
1122          <button type="button" class="input-icon-btn tool-indicator" title="Compare active — click to deactivate" id="compare-indicator-btn" style="display:none;">
1123            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="18" cy="18" r="3"/><circle cx="6" cy="6" r="3"/><path d="M13 6h3a2 2 0 0 1 2 2v7"/><path d="M11 18H8a2 2 0 0 1-2-2V9"/></svg>
1124            <span style="font-size:11px;margin-left:2px;">Compare</span>
1125            <svg class="tool-indicator-x" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><line x1="6" y1="6" x2="18" y2="18"/><line x1="18" y1="6" x2="6" y2="18"/></svg>
1126          </button>
1127        </div>
1128        <div class="chat-input-right">
1129          <!-- Agent / Chat mode toggle -->
1130          <div class="mode-toggle">
1131            <button type="button" class="mode-toggle-btn active" id="mode-agent-btn" aria-pressed="true">Agent</button>
1132            <button type="button" class="mode-toggle-btn" id="mode-chat-btn" aria-pressed="false">Chat</button>
1133          </div>
1134          <button type="submit" form="chat-form" class="send-btn newchat-mode" data-mode="newchat" aria-label="New chat">
1135            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg><span class="send-btn-label">+ New</span>
1136          </button>
1137        </div>
1138      </div>
1139      <!-- Hidden checkboxes for state -->
1140      <input type="checkbox" id="web-toggle" style="display:none;">
1141      <input type="checkbox" id="bash-toggle" style="display:none;">
1142      <input type="checkbox" id="plan-toggle" style="display:none;">
1143    </div>
1144    <form id="chat-form" autocomplete="off" action="javascript:void(0);" style="display:none;"></form>
1145
1146    <!-- Character (custom preset) modal -->
1147    <div id="custom-preset-modal" class="modal hidden">
1148      <div class="modal-content preset-modal-content" role="dialog" aria-label="Prompt" style="background:var(--bg)">
1149        <div class="modal-header">
1150          <h4><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:6px"><path d="m18 2 4 4"/><path d="m17 7 3-3"/><path d="M19 9 8.7 19.3c-1 1-2.5 1-3.4 0l-.6-.6c-1-1-1-2.5 0-3.4L15 5"/><path d="m9 11 4 4"/><path d="m5 19-3 3"/><path d="m14 4 6 6"/></svg>Prompt</h4>
1151          <button class="close-btn" id="close-custom-preset" aria-label="Close prompt">✖</button>
1152        </div>
1153        <div class="modal-body preset-modal-body">
1154          <div id="char-fields-wrap">
1155            <div class="preset-tabs">
1156              <button class="preset-tab active" data-chartab="inject"><svg class="preset-tab-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m18 2 4 4"/><path d="m17 7 3-3"/><path d="M19 9 8.7 19.3c-1 1-2.5 1-3.4 0l-.6-.6c-1-1-1-2.5 0-3.4L15 5"/><path d="m9 11 4 4"/><path d="m5 19-3 3"/><path d="m14 4 6 6"/></svg><span>Inject</span></button>
1157              <button class="preset-tab" data-chartab="character"><svg class="preset-tab-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg><span>Persona</span></button>
1158              <button class="preset-tab" data-chartab="group"><svg class="preset-tab-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg><span>Group</span></button>
1159            </div>
1160            <!-- Inject tab (also holds model tuning: temperature + max tokens) -->
1161            <div class="preset-chartab" data-chartab-panel="inject">
1162              <label for="inject-prefix">Prefix</label>
1163              <textarea id="inject-prefix" rows="2" placeholder="Added before your message" style="margin-bottom:8px"></textarea>
1164              <label for="inject-suffix">Suffix</label>
1165              <textarea id="inject-suffix" rows="2" placeholder="Added after your message" style="margin-bottom:12px"></textarea>
1166              <div class="preset-slider-row">
1167                <label>Temperature <span class="preset-hint-icon" title="Controls randomness. Lower values g
1167ive focused, deterministic answers (good for code). Higher values give more creative, varied responses.">?</span></label>
1168                <span class="preset-slider-value" id="temp-value">1.0</span>
1169              </div>
1170              <input type="range" class="preset-range" id="custom-temperature" min="0" max="2" step="0.1" value="1.0">
1171              <div class="preset-temp-hints">
1172                <span>Precise / Code</span>
1173                <span>Balanced</span>
1174                <span>Creative</span>
1175              </div>
1176              <div class="preset-slider-row">
1177                <label>Max Tokens <span class="preset-hint-icon" title="Maximum length of the AI response. 'No limit' lets the model decide when to stop.">?</span></label>
1178                <span class="preset-slider-value" id="tokens-value">No limit</span>
1179              </div>
1180              <input type="range" class="preset-range" id="custom-max-tokens" min="256" max="8448" step="256" value="8448">
1181            </div>
1182            <!-- Prompt (character/persona) tab -->
1183            <div class="preset-chartab" data-chartab-panel="character" style="display:none">
1184              <label>Persona</label>
1185              <div class="char-name-combo">
1186                <select id="char-template-select" class="char-template-select">
1187                  <option value="">Select persona...</option>
1188                </select>
1189                <button type="button" id="char-new-btn" class="char-action-btn" title="Create a new persona">+ New</button>
1190              </div>
1191              <div id="char-name-row">
1192                <label for="custom-character-name">Name</label>
1193                <div class="char-name-combo">
1194                  <input type="text" id="custom-character-name" maxlength="50" placeholder="Give your persona a name..." autocomplete="off" style="flex:1">
1195                  <button type="button" id="char-delete-template-btn" class="char-action-btn" title="Delete this persona and its memories" style="display:none;margin-top:-6px !important"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:4px"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><line x1="10" y1="11" x2="10" y2="17"/><line x1="14" y1="11" x2="14" y2="17"/></svg>Delete</button>
1196                  <button type="button" id="reset-character-btn" class="char-action-btn" title="Reset to default" style="margin-top:-6px !important">&#x21BA; Reset</button>
1197                </div>
1198              </div>
1199              <label for="custom-system-prompt">System prompt</label>
1200              <div class="char-prompt-wrap">
1201                <textarea id="custom-system-prompt" rows="4" placeholder="Write rough notes and click Expand, or leave empty"></textarea>
1202                <button type="button" id="char-expand-btn" class="char-expand-btn" title="AI expand — turn your notes into a full system prompt">
1203                  <svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor" style="vertical-align:-1px;margin-right:2px;"><path d="M12 0L14.59 8.41L23 12L14.59 15.59L12 24L9.41 15.59L1 12L9.41 8.41Z"/></svg>
1204                  Expand
1205                </button>
1206              </div>
1207            </div>
1208            <!-- Group tab -->
1209            <div class="preset-chartab" data-chartab-panel="group" style="display:none">
1210              <div style="display:flex;gap:4px;margin-bottom:8px;">
1211                <button type="button" class="compare-parallel-toggle" id="group-mode-btn" style="flex:1;height:auto;width:auto;">
1212                  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="8" y1="6" x2="20" y2="6"/><line x1="8" y1="12" x2="20" y2="12"/><line x1="8" y1="18" x2="20" y2="18"/><circle cx="4" cy="6" r="1.5" fill="currentColor"/><circle cx="4" cy="12" r="1.5" fill="currentColor"/><circle cx="4" cy="18" r="1.5" fill="currentColor"/></svg>
1213                  <span class="compare-toggle-label">Sequential</span>
1214                </button>
1215              </div>
1216              <div id="group-participants" style="display:flex;flex-direction:column;gap:4px;margin-bottom:0;max-height:220px;overflow-y:auto;"></div>
1217              <button type="button" id="group-add-btn" class="preset-save-btn" style="width:100%;background:none;border:1px dashed var(--border);color:var(--fg);opacity:0.6;font-size:11px;padding:4px;margin-top:0;">+ Add participant</button>
1218            </div>
1219          </div>
1220        </div>
1221        <div class="modal-footer">
1222          <div style="flex:1"></div>
1223          <button type="button" id="cancel-custom-preset" style="margin-right:8px;display:none;">Cancel</button>
1224          <button type="button" id="save-custom-preset">Start</button>
1225        </div>
1226      </div>
1227    </div>
1228
1229
1230  </main>
1231  <button id="scroll-bottom-btn" class="scroll-nav-btn" title="Scroll to bottom">▼</button>
1232  
1232<script nonce="0ef1c0e2ced0cc537d6ee0258e679162">
1233  (function(){
1234    const container = document.getElementById('chat-history');
1235    const chatBar = document.querySelector('.chat-input-bar');
1236    const bottomBtn = document.getElementById('scroll-bottom-btn');
1237    if (!container || !chatBar || !bottomBtn) return;
1238
1239    function reposition() {
1240      const barRect = chatBar.getBoundingClientRect();
1241      bottomBtn.style.bottom = (window.innerHeight - barRect.top + 16) + 'px';
1242      bottomBtn.style.right = (window.innerWidth - barRect.right + 8) + 'px';
1243    }
1244
1245    function update() {
1246      reposition();
1247      const scrollable = container.scrollHeight > container.clientHeight + 10;
1248      const atBottom = container.scrollHeight - container.scrollTop - container.clientHeight < 300;
1249      if (scrollable && !atBottom) {
1250        bottomBtn.classList.remove('slide-out');
1251        bottomBtn.classList.add('show');
1252      } else if (bottomBtn.classList.contains('show')) {
1253        bottomBtn.classList.add('slide-out');
1254        bottomBtn.classList.remove('show');
1255      }
1256    }
1257
1258    let _scrollRaf = null;
1259    let _scrollTimeout = null;
1260    let _scrollingToBottom = false;
1261
1262    function cancelAutoScroll() {
1263      if (_scrollRaf) { cancelAnimationFrame(_scrollRaf); _scrollRaf = null; }
1264      if (_scrollTimeout) { clearTimeout(_scrollTimeout); _scrollTimeout = null; }
1265      _scrollingToBottom = false;
1266    }
1267
1268    container.addEventListener('scroll', update, {passive:true});
1269    container.addEventListener('wheel', () => { if (_scrollingToBottom) cancelAutoScroll(); }, {passive:true});
1270    container.addEventListener('touchstart', () => { if (_scrollingToBottom) cancelAutoScroll(); }, {passive:true});
1271
1272    bottomBtn.addEventListener('click', () => {
1273      cancelAutoScroll();
1274      const target = container.scrollHeight - container.clientHeight;
1275      _scrollingToBottom = true;
1276      function step() {
1277        if (!_scrollingToBottom) return;
1278        const diff = target - container.scrollTop;
1279        if (diff <= 8) { container.scrollTop = target; _scrollingToBottom = false; return; }
1280        container.scrollTop += diff * 0.2;
1281        _scrollRaf = requestAnimationFrame(step);
1282      }
1283      step();
1284      _scrollTimeout = setTimeout(() => { if (_scrollingToBottom) { container.scrollTop = target; _scrollingToBottom = false; } }, 1500);
1285    });
1286    new ResizeObserver(reposition).observe(chatBar);
1287    new MutationObserver(update).observe(container, {childList:true, subtree:true});
1288    window.addEventListener('resize', reposition);
1289    update();
1290  })();
1291  </script>
1291
1292
1293  <!-- Rename Session Modal -->
1294  <div id="rename-session-modal" class="modal hidden">
1295    <div class="modal-content" role="dialog" aria-label="Rename session" style="width: 400px;">
1296      <div class="modal-header">
1297        <h4>Rename Session</h4>
1298        <button class="close-btn" id="close-rename-session" aria-label="Close rename session modal">✖</button>
1299      </div>
1300      <div class="modal-body">
1301        <div style="margin-bottom: 12px;">
1302          <label for="session-name-input" style="display: block; margin-bottom: 6px; font-weight: 500;">Session Name</label>
1303          <input
1304            type="text"
1305            id="session-name-input"
1306            placeholder="Enter session name"
1307            style="width: 100%; padding: 8px; border-radius: 4px;"
1308          />
1309        </div>
1310        <div style="display: flex; justify-content: flex-end; gap: 8px;">
1311          <button id="cancel-rename-session" style="padding: 6px 12px;">Cancel</button>
1312          <button id="save-session-name" style="padding: 6px 12px; background: var(--fg); color: var(--bg);">Save</button>
1313        </div>
1314      </div>
1315    </div>
1316  </div>
1317
1318
1319  <!-- Cookbook Modal -->
1320  <div id="cookbook-modal" class="modal hidden">
1321    <div class="modal-content" role="dialog" aria-label="Cookbook" style="width: min(780px, 92vw); height: 94vh; max-height: 94vh; background: var(--bg);">
1322      <div class="modal-header">
1323        <h4 style="margin:0;margin-right:auto"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:6px"><path d="M12 7v14"/><path d="M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z"/></svg>Cookbook</h4>
1324        <button class="close-btn" id="close-cookbook-modal" aria-label="Close cookbook">✖</button>
1325      </div>
1326      <div class="modal-body cookbook-body"></div>
1327    </div>
1328  </div>
1329
1330  <!-- Settings Modal (all users) -->
1331  <div id="settings-modal" class="modal hidden">
1332    <div class="modal-content settings-modal-content" role="dialog" aria-label="Settings">
1333      <div class="modal-header">
1334        <h4><span style="vertical-align:-1px;margin-right:6px;font-size:15px">&#x2699;</span>Settings</h4>
1335        <button type="button" class="theme-opacity-wrap theme-opacity-toggle hidden" id="settings-opacity-wrap" title="Fade this window to preview the page behind it" aria-pressed="false">
1336          <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle></svg>
1337          <span class="theme-opacity-label">Peek</span>
1338        </button>
1339        <button class="close-btn" aria-label="Close settings">✖</button>
1340      </div>
1341      <div class="admin-toggle-sub" style="padding:0 12px 8px;opacity:0.6;font-size:11px;">Toggle on/off visibility of tools and modules across the interface.</div>
1342      <div class="settings-layout">
1343        <div class="settings-sidebar">
1344          <!-- Section 1: AI plumbing (Add Models → AI Defaults → Search) -->
1345          <button class="settings-nav-item active" data-settings-tab="services">
1346            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="2" width="20" height="8" rx="2"/><rect x="2" y="14" width="20" height="8" rx="2"/><circle cx="6" cy="6" r="1"/><circle cx="6" cy="18" r="1"/></svg>
1347            <span>Add Models</span>
1348          </button>
1349          <button class="settings-nav-item" data-settings-tab="ai">
1350            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2a4 4 0 0 0-4 4v2H6a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2h-2V6a4 4 0 0 0-4-4z"/></svg>
1351            <span>AI Defaults</span>
1352          </button>
1353          <button class="settings-nav-item" data-settings-tab="search">
1354            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
1355            <span>Search</span>
1356          </button>
1357          <div class="settings-sidebar-divider"></div>
1358          <!-- Section 2: Comms (Integrations → Email → Reminders).
1359               Integrations leads here because it's where the underlying
1360               accounts the other two tabs depend on actually live. -->
1361          <button class="settings-nav-item" data-settings-tab="integrations">
1362            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>
1363            <span>Integrations</span>
1364          </button>
1365          <button class="settings-nav-item" data-settings-tab="email">
1366            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>
1367            <span>Email</span>
1368          </button>
1369          <button class="settings-nav-item" data-settings-tab="reminders">
1370            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>
1371            <span>Reminders</span>
1372          </button>
1373          <div class="settings-sidebar-divider"></div>
1374          <!-- Section 3: UX (Appearance → Shortcuts) -->
1375          <button class="settings-nav-item" data-settings-tab="appearance">
1376            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 2a7 7 0 0 0 0 20 4 4 0 0 1 0-8 4 4 0 0 0 0-8"/></svg>
1377            <span>Appearance</span>
1378          </button>
1379          <button class="settings-nav-item" data-settings-tab="shortcuts">
1380            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="M6 8h.01M10 8h.01M14 8h.01M18 8h.01M8 12h.01M12 12h.01M16 12h.01M7 16h10"/></svg>
1381            <span>Shortcuts</span>
1382          </button>
1383          <div class="settings-sidebar-divider"></div>
1384          <!-- Section 4: Account (sits at the bottom of the user section) -->
1385          <button class="settings-nav-item" data-settings-tab="account">
1386            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
1387            <span>Account</span>
1388          </button>
1389          <div class="settings-sidebar-divider"></div>
1390          <!-- Section 5: Cloud Storage (HF Buckets) -->
1391          <button class="settings-nav-item" data-settings-tab="cloud-storage">
1392            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"/></svg>
1393            <span>Cloud Storage</span>
1394          </button>
1395          <!-- Section 6: Secrets & Environment -->
1396          <button class="settings-nav-item" data-settings-tab="secrets">
1397            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"/></svg>
1398            <span>Secrets</span>
1399          </button>
1400          <!-- Section 7: GitHub -->
1401          <button class="settings-nav-item" data-settings-tab="github">
1402            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
1403            <span>GitHub</span>
1404          </button>
1405          <div class="settings-sidebar-divider admin-only"></div>
1406          <div class="settings-sidebar-label admin-only">Admin</div>
1407          <button class="settings-nav-item admin-only" data-settings-tab="tools">
1408            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>
1409            <span>Agent Tools</span>
1410          </button>
1411          <button class="settings-nav-item admin-only" data-settings-tab="users">
1412            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
1413            <span>Users</span>
1414          </button>
1415          <button class="settings-nav-item admin-only" data-settings-tab="system">
1416            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
1417            <span>System</span>
1418          </button>
1419        </div>
1420        <div class="settings-panels">
1421
1422        <!-- ═══ AI TAB ═══ -->
1423
1424        <div data-settings-panel="ai" class="hidden">
1425          <div class="admin-card">
1426            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>Default Chat Model</h2>
1427            <div class="admin-toggle-sub" style="margin-bottom:8px">The model used when creating a new chat session.</div>
1428            <div class="settings-col">
1429              <div class="settings-row">
1430                <label class="settings-label">Endpoint</label>
1431                <select id="set-defaultEpSelect" class="settings-select"></select>
1432              </div>
1433              <div class="settings-row">
1434                <label class="settings-label">Model</label>
1435                <select id="set-defaultModelSelect" class="settings-select"></select>
1436              </div>
1437              <div id="set-defaultFallbacks" class="settings-fallbacks"></div>
1438              <button type="button" class="settings-fallback-add" id="set-defaultAddFallback" title="Add a model to try if the one above fails">+ Add fallback</button>
1439              <div id="set-defaultChatMsg" style="font-size:11px;color:color-mix(in srgb, var(--fg) 45%, transparent);"></div>
1440            </div>
1441          </div>
1442          <div class="admin-card">
1443            <h2 style="display:flex;align-items:center;gap:6px;"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right:1px;opacity:0.6;flex-shrink:0"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>Utility Model <span style="font-size:0.72em;opacity:0.55;font-weight:normal;">(Recommended: Local Endpoint)</span></h2>
1444            <div class="admin-toggle-sub" style="margin-bottom:8px">Runs background tasks (compaction, cleanup, auto-naming, retrieving memories from files) on a 
1444small/local model instead of your chat model. Leave blank to use the chat model.</div>
1445            <div class="settings-col">
1446              <div class="settings-row">
1447                <label class="settings-label">Endpoint</label>
1448                <select id="set-utilityEpSelect" class="settings-select"><option value="">—</option></select>
1449              </div>
1450              <div class="settings-row">
1451                <label class="settings-label">Model</label>
1452                <select id="set-utilityModelSelect" class="settings-select"><option value="">—</option></select>
1453              </div>
1454              <div id="set-utilityFallbacks" class="settings-fallbacks"></div>
1455              <button type="button" class="settings-fallback-add" id="set-utilityAddFallback" title="Add a model to try if the utility model fails">+ Add fallback</button>
1456              <div id="set-utilityChatMsg" style="font-size:11px;color:color-mix(in srgb, var(--fg) 45%, transparent);"></div>
1457            </div>
1458          </div>
1459          <div class="admin-card">
1460            <h2 style="display:flex;align-items:center;gap:6px;"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right:1px;opacity:0.6;flex-shrink:0"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>Vision<span style="flex:1"></span><label class="admin-switch" title="Analyze images with a vision-capable model"><input type="checkbox" id="set-visionEnabledToggle" checked><span class="admin-slider"></span></label></h2>
1461            <div class="admin-toggle-sub" style="margin-bottom:8px">Analyze images with a vision-capable model.</div>
1462            <div style="display:flex;flex-direction:column;gap:0.5rem;">
1463              <div style="display:flex;align-items:center;gap:0.75rem;">
1464                <label class="settings-label">Model</label>
1465                <select id="set-vlModelSelect" class="settings-select"><option value="">Auto-detect</option></select>
1466              </div>
1467              <div id="set-visionFallbacks" class="settings-fallbacks"></div>
1468              <button type="button" class="settings-fallback-add" id="set-visionAddFallback" title="Add a vision model to try if the one above fails">+ Add fallback</button>
1469              <div id="set-visionSettingsMsg" style="font-size:11px;color:color-mix(in srgb, var(--fg) 45%, transparent);"></div>
1470            </div>
1471          </div>
1472          <div class="admin-card">
1473            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/><line x1="11" y1="8" x2="11" y2="14"/><line x1="8" y1="11" x2="14" y2="11"/></svg>Research Model</h2>
1474            <div class="admin-toggle-sub" style="margin-bottom:8px">Model used for Deep Research. Falls back to the default chat model if not set.</div>
1475            <div class="settings-col">
1476              <div class="settings-row">
1477                <label class="settings-label">Endpoint</label>
1478                <select id="set-researchEndpoint" class="settings-select">
1479                  <option value="">Same as chat</option>
1480                </select>
1481              </div>
1482              <div class="settings-row">
1483                <label class="settings-label">Model</label>
1484                <select id="set-researchModel" class="settings-select">
1485                  <option value="">Same as chat</option>
1486                </select>
1487              </div>
1488              <div class="settings-row">
1489                <label class="settings-label">Search</label>
1490                <select id="set-researchSearch" class="settings-select">
1491                  <option value="">Same as web search</option>
1492                  <option value="searxng">SearXNG</option>
1493                  <option value="duckduckgo">DuckDuckGo</option>
1494                  <option value="tavily">Tavily</option>
1495                  <option value="brave">Brave</option>
1496                  <option value="google">Google</option>
1497                  <option value="serper">Serper</option>
1498                </select>
1499              </div>
1500              <div class="settings-row">
1501                <label class="settings-label">Max Tokens</label>
1502                <input id="set-researchMaxTokens" type="text" inputmode="numeric" placeholder="8192 (default)" class="settings-select" style="width:120px;">
1503              </div>
1504              <div class="settings-row">
1505                <label class="settings-label">Extract Timeout</label>
1506                <input id="set-researchExtractTimeout" type="text" inputmode="numeric" placeholder="90 sec" class="settings-select" style="width:120px;">
1507              </div>
1508              <div class="settings-row">
1509                <label class="settings-label">Extract Parallel</label>
1510                <input id="set-researchExtractConcurrency" type="text" inputmode="numeric" placeholder="3" class="settings-select" style="width:120px;">
1511              </div>
1512              <div class="settings-row">
1513                <label class="settings-label">Max Time</label>
1514                <input id="set-researchRunTimeout" type="text" inputmode="numeric" placeholder="1800 sec (0 = no limit)" class="settings-select" style="width:120px;">
1515              </div>
1516              <div id="set-researchMsg" style="font-size:11px;color:color-mix(in srgb, var(--fg) 45%, transparent);"></div>
1517            </div>
1518          </div>
1519          <div class="admin-card">
1520            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>Agent</h2>
1521            <div class="admin-toggle-sub" style="margin-bottom:8px">Controls for the agent tool loop.</div>
1522            <div class="settings-col">
1523              <div class="settings-row">
1524                <label class="settings-label">Tool call limit</label>
1525                <input id="set-agentMaxTools" type="text" inputmode="numeric" placeholder="0 = unlimited" class="settings-select" style="width:120px;">
1526              </div>
1527              <div class="settings-row">
1528                <label class="settings-label">Max steps per message</label>
1529                <input id="set-agentMaxRounds" type="text" inputmode="numeric" placeholder="20" class="settings-select" style="width:120px;">
1530              </div>
1531              <div id="set-agentMsg" style="font-size:11px;color:color-mix(in srgb, var(--fg) 45%, transparent);"></div>
1532            </div>
1533          </div>
1534          <!-- Image Generation removed — only inpaint remains in this build,
1535               and inpaint is configured via the gallery editor not this card.
1536               Keeping the DOM (hidden) so JS wiring against the inputs
1537               doesn't throw. -->
1538          <div class="admin-card" hidden style="display:none">
1539            <h2 style="display:flex;align-items:center;gap:6px;"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right:1px;opacity:0.6;flex-shrink:0"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="M21 15l-5-5L5 21"/></svg>Image Generation<span style="flex:1"></span><label class="admin-switch"><input type="checkbox" id="set-imgEnabledToggle" checked><span class="admin-slider"></span></label></h2>
1540            <div class="admin-toggle-sub" style="margin-bottom:8px">Configure which model to use for image generation.</div>
1541            <div style="display:flex;flex-direction:column;gap:0.5rem;">
1542              <div style="display:flex;align-items:center;gap:0.75rem;">
1543                <label class="settings-label">Model</label>
1544                <select id="set-imgModelSelect" class="settings-select"><option value="">Auto-detect</option></select>
1545              </div>
1546              <div style="display:flex;align-items:center;gap:0.75rem;">
1547                <label class="settings-label">Quality</label>
1548                <select id="set-imgQualitySelect" class="settings-select">
1549                  <option value="low">Low (fastest, cheapest)</option>
1550                  <option value="medium">Medium (default)</option>
1551                  <option value="high">High (best quality)</option>
1552                </select>
1553              </div>
1554              <div id="set-imgSettingsMsg" style="font-size:11px;color:color-mix(in srgb, var(--fg) 45%, transparent);"></div>
1555            </div>
1556          </div>
1557          <!-- TTS panel hidden — user opted out of read-aloud entirely. Kept
1558               in DOM so the JS that wires set-ttsProviderSelect etc. doesn't
1559               throw on missing nodes; not visible to anyone. -->
1560          <div class="admin-card" hidden style="display:none">
1561            <h2 style="display:flex;align-items:center;gap:6px;"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14"/><path d="M15.54 8.46a5 5 0 0 1 0 7.07"/></svg>Text to Speech<span style="flex:1"></span><label class="admin-switch"><input type="checkbox" id="set-ttsEnabledToggle" checked><span class="admin-slider"></span></label></h2>
1562            <div class="admin-toggle-sub" style="margin-bottom:8px">Configure TTS provider for assistant message read-aloud.</div>
1563            <div style="display:flex;flex-direction:column;gap:0.5rem;">
1564              <div style="display:flex;align-items:center;gap:0.75rem;">
1565                <label class="settings-label">Provider</label>
1566                <select id="set-ttsProviderSelect" class="settings-select">
1567                  <option value="disabled">Disabled</option>
1568                  <option value="browser">Browser (built-in)</option>
1569                  <option value="local">Local (Kokoro-82M)</option>
1570                </select>
1571              </div>
1572              <div id="set-ttsModelRow" style="display:flex;align-items:center;gap:0.75rem;">
1573                <label class="settings-label">Model</label>
1574                <select id="set-ttsModelSelect" class="settings-select">
1575                  <option value="tts-1">tts-1 (fast)</option>
1576                  <option value="tts-1-hd">tts-1-hd (quality)</option>
1577                  <option value="gpt-4o-mini-tts">gpt-4o-mini-tts (steerable)</option>
1578                </select>
1579                <input id="set-ttsModelInput" type="text" placeholder="model name" style="flex:1;padding:5px;display:none;">
1580              </div>
1581              <div id="set-ttsVoiceRow" style="display:flex;align-items:center;gap:0.75rem;">
1582                <label class="settings-label">Voice</label>
1583                <select id="set-ttsVoiceSelect" class="settings-select">
1584                  <option value="alloy">Alloy</option>
1585                  <option value="ash">Ash</option>
1586                  <option value="coral">Coral</option>
1587                  <option value="echo">Echo</option>
1588                  <option value="fable">Fable</option>
1589                  <option value="nova">Nova</option>
1590                  <option value="onyx">Onyx</option>
1591                  <option value="sage">Sage</option>
1592                  <option value="shimmer">Shimmer</option>
1593                </select>
1594                <input id="set-ttsVoiceInput" type="text" placeholder="af_heart" style="flex:1;padding:5px;display:none;">
1595              </div>
1596              <div id="set-ttsSpeedRow" style="display:flex;align-items:center;gap:0.75rem;">
1597                <label class="settings-label">
1597Speed</label>
1598                <select id="set-ttsSpeedSelect" class="settings-select">
1599                  <option value="0.5">0.5x</option>
1600                  <option value="0.75">0.75x</option>
1601                  <option value="1" selected>1x (normal)</option>
1602                  <option value="1.25">1.25x</option>
1603                  <option value="1.5">1.5x</option>
1604                  <option value="2">2x</option>
1605                </select>
1606              </div>
1607              <button type="button" id="set-ttsPreviewBtn" class="admin-btn-sm" style="margin-top:4px;padding:5px 16px;font-size:12px;">Preview</button>
1608              <div id="set-ttsSettingsMsg" style="font-size:11px;color:color-mix(in srgb, var(--fg) 45%, transparent);"></div>
1609            </div>
1610          </div>
1611          <div class="admin-card">
1612            <h2 style="display:flex;align-items:center;gap:6px;"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M22 10v6M2 10l10-5 10 5-10 5z"/><path d="M6 12v5c3 3 9 3 12 0v-5"/></svg>Teacher Model <span style="font-size:0.72em;opacity:0.55;font-weight:normal;">(Experimental)</span><span style="flex:1"></span><label class="admin-switch"><input type="checkbox" id="set-teacherEnabledToggle"><span class="admin-slider"></span></label></h2>
1613            <div class="admin-toggle-sub" style="margin-bottom:8px">When a self-hosted student fails an agent-mode task, escalate to a SOTA teacher that writes a SKILL.md procedure so the student can do it next time. Off by default.</div>
1614            <div class="settings-col">
1615              <div class="settings-row">
1616                <label class="settings-label">Endpoint</label>
1617                <select id="set-teacherEpSelect" class="settings-select"><option value="">—</option></select>
1618              </div>
1619              <div class="settings-row">
1620                <label class="settings-label">Model</label>
1621                <select id="set-teacherModelSelect" class="settings-select"><option value="">—</option></select>
1622              </div>
1623              <div id="set-teacherChatMsg" style="font-size:11px;color:color-mix(in srgb, var(--fg) 45%, transparent);"></div>
1624            </div>
1625          </div>
1626        </div>
1627
1628        <!-- ═══ SEARCH TAB ═══ -->
1629        <div data-settings-panel="search" class="hidden">
1630          <div class="admin-card">
1631            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>Web Search</h2>
1632            <div class="admin-toggle-sub" style="margin-bottom:8px">Search API used for web search and deep research.</div>
1633            <div class="settings-col">
1634              <div class="settings-row">
1635                <label class="settings-label">Provider</label>
1636                <!-- Custom picker (with logos). Hidden native <select> mirrors
1637                     its value so the existing JS that reads
1638                     set-searchProvider keeps working unchanged. -->
1639                <div class="adm-provider-picker search-provider-picker" id="search-provider-picker" style="flex:1;position:relative;top:5px;">
1640                  <button type="button" class="adm-provider-btn" id="search-provider-btn">
1641                    <span class="adm-provider-current"><span class="adm-provider-logo"></span><span class="adm-provider-name">SearXNG</span></span>
1642                    <svg class="adm-provider-caret" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
1643                  </button>
1644                  <div class="adm-provider-menu hidden" id="search-provider-menu"></div>
1645                </div>
1646                <select id="set-searchProvider" class="settings-select" style="display:none;">
1647                  <option value="searxng" data-search-logo="searxng">SearXNG (self-hosted)</option>
1648                  <option value="duckduckgo" data-search-logo="duckduckgo">DuckDuckGo (free, no key)</option>
1649                  <option value="brave" data-search-logo="brave">Brave Search</option>
1650                  <option value="google_pse" data-search-logo="google_pse">Google PSE</option>
1651                  <option value="tavily" data-search-logo="tavily">Tavily</option>
1652                  <option value="serper" data-search-logo="serper">Serper.dev</option>
1653                  <option value="disabled" data-search-logo="disabled">Disabled</option>
1654                </select>
1655                <button type="button" class="admin-btn-sm" id="set-searchTestBtn" title="Run a test query against the configured provider" style="margin-left:6px;flex-shrink:0;position:relative;top:2px;">Test</button>
1656              </div>
1657              <div class="settings-row">
1658                <label class="settings-label">Results</label>
1659                <div style="display:flex;gap:8px;flex:1;">
1660                  <select id="set-searchResultCount" class="settings-select" style="flex:1;">
1661                    <option value="3">3</option>
1662                    <option value="5" selected>5</option>
1663                    <option value="10">10</option>
1664                    <option value="20">20</option>
1665                    <option value="custom">Custom</option>
1666                  </select>
1667                  <input id="set-searchResultCountCustom" type="number" class="settings-select" placeholder="Enter custom value" style="flex:1;display:none;min-width:120px;" min="1" max="100">
1668                </div>
1669              </div>
1670              <div id="set-searchUrlRow" class="settings-row">
1671                <label class="settings-label">URL</label>
1672                <input id="set-searchUrl" type="text" placeholder="http://localhost:8080" class="settings-select">
1673              </div>
1674              <div id="set-searchKeyRow" class="settings-row" style="display:none;">
1675                <label class="settings-label">API Key</label>
1676                <input id="set-searchApiKey" type="password" placeholder="API key" class="settings-select">
1677              </div>
1678              <div id="set-searchCxRow" class="settings-row" style="display:none;">
1679                <label class="settings-label">CX ID</label>
1680                <input id="set-searchCx" type="text" placeholder="Google PSE engine ID" class="settings-select">
1681              </div>
1682              <div class="settings-row">
1683                <label class="settings-label" title="Providers tried in order when the primary fails or hits a rate limit">Fallbacks</label>
1684                <div class="search-fallback-chain" id="set-searchFallbackChain"></div>
1685              </div>
1686              <div id="set-searchHint" class="admin-toggle-sub"></div>
1687              <div id="set-searchMsg" style="font-size:11px;"></div>
1688            </div>
1689          </div>
1690        </div>
1691
1692        <!-- ═══ APPEARANCE TAB ═══ -->
1693        <div data-settings-panel="appearance" class="settings-appearance-panel hidden">
1694          <div class="admin-card" style="padding-bottom:6px;">
1695            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="9" y1="3" x2="9" y2="21"/></svg>Sidebar</h2>
1696            <div class="vis-toggles">
1697              <label class="vis-row">
1698                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><path d="M8 12l2.5 2.5L16 9"/></svg></span>
1699                <span class="vis-label">Odysseus <span class="vis-hint">Brand name</span></span>
1700                <input type="checkbox" checked data-ui-key="sidebar-brand"><span class="vis-switch"></span>
1701              </label>
1702              <label class="vis-row">
1703                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><circle cx="10" cy="10" r="7"/><path d="M21 21l-4.35-4.35"/></svg></span>
1704                <span class="vis-label">Search</span>
1705                <input type="checkbox" checked data-ui-key="sidebar-search"><span class="vis-switch"></span>
1706              </label>
1707              <label class="vis-row">
1708                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg></span>
1709                <span class="vis-label">New Chat</span>
1710                <input type="checkbox" checked data-ui-key="sidebar-new-chat"><span class="vis-switch"></span>
1711              </label>
1712              <label class="vis-row">
1713                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg></span>
1714                <span class="vis-label">Chats <span class="vis-hint">Chat history list</span></span>
1715                <input type="checkbox" checked data-ui-key="sessions-section"><span class="vis-switch"></span>
1716              </label>
1717              <label class="vis-row">
1718                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg></span>
1719                <span class="vis-label">Email</span>
1720                <input type="checkbox" checked data-ui-key="email-section"><span class="vis-switch"></span>
1721              </label>
1722              <label class="vis-row">
1723                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg></span>
1724                <span class="vis-label">Models <span class="vis-hint">Model selector &amp; quick-chat</span></span>
1725                <input type="checkbox" checked data-ui-key="models-section"><span class="vis-switch"></span>
1726              </label>
1727              <label class="vis-row">
1728                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg></span>
1729                <span class="vis-label">Tools <span class="vis-hint">Whole section (header + all tools)</span></span>
1730                <input type="checkbox" checked data-ui-key="tools-section"><span class="vis-switch"></span>
1731              </label>
1732              <label class="vis-row">
1733                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z"/><path d="M12 5a3 3 0 1 1 5.997.125 4 4 0 0 1 2.526 5.77 4 4 0 0 1-.556 6.588A4 4 0 1 1 12 18Z"/><path d="M15 13a4.5 4.5 0 0 1-3-4 4.5 4.5 0 0 1-3 4"/></svg></span>
1734                <span class="vis-label">Brain</span>
1735                <input type="checkbox" checked data-ui-key="tool-memory"><span class="vis-switch"></span>
1736              </label>
1737              <label class="vis-row">
1738                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg></span>
1739                <span class="vis-label">Calendar</span>
1740                <input type="checkbox" checked data-ui-key="tool-calendar"><span class="vis-switch"></span>
1741              </label>
1742              <label class="vis-row">
1743                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="18" cy="18" r="3"/><circle cx="6" cy="6" r="3"/><path d="M13 6h3a2 2 0 0 1 2 2v7"/><path d="M11 18H8a2 2 0 0 1-2-2V9"/></svg></span>
1744                <span class="vis-label">Compare</span>
1745                <input type="checkbox" checked data-ui-key="tool-compare"><span class="vis-switch"></span>
1746              </label>
1747              <label class="vis-row">
1748                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/><path d="M9 7h6M9 11h4"/></svg></span>
1749                <span class="vis-label">Cookbook</span>
1750                <input type="checkbox" checked data-ui-key="tool-cookbook"><span class="vis-switch"></span>
1751              </label>
1752              <label class="vis-row">
1753                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/><line x1="11" y1="8" x2="11" y2="14"/><line x1="8" y1="11" x2="14" y2="11"/></svg></span>
1754                <span class="vis-label">Deep Research</span>
1755                <input type="checkbox" checked data-ui-key="tool-research"><span class="vis-switch"></span>
1756              </label>
1757              <label class="vis-row">
1758                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="M21 15l-5-5L5 21"/></svg></span>
1759                <span class="vis-label">Gallery</span>
1760                <input type="checkbox" checked data-ui-key="tool-gallery"><span class="vis-switch"></span>
1761              </label>
1762              <label class="vis-row">
1763                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="8" y1="13" x2="16" y2="13"/><line x1="8" y1="17" x2="13" y2="17"/></svg></span>
1764                <span class="vis-label">Library</span>
1765                <input type="checkbox" checked data-ui-key="tool-library"><span class="vis-switch"></span>
1766              </label>
1767              <label class="vis-row">
1768                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M9 7h6M9 11h6M9 15h4"/></svg></span>
1769                <span class="vis-label">Notes</span>
1770                <input type="checkbox" checked data-ui-key="tool-notes"><span class="vis-switch"></span>
1771              </label>
1772              <label class="vis-row">
1773                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/><path d="M9 16l2 2 4-4"/></svg></span>
1774                <span class="vis-label">Tasks</span>
1775                <input type="checkbox" checked data-ui-key="tool-tasks"><span class="vis-switch"></span>
1776              </label>
1777              <label class="vis-row">
1778                <span class="vis-icon"><svg width="14" height="14" 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"/><path d="M12 2a10 10 0 0 0 0 20 5 5 0 0 0 5-5 3 3 0 0 0-3-3h-2a3 3 0 0 1-3-3 5 5 0 0 1 5-5"/></svg></span>
1779                <span class="vis-label">Theme</span>
1780                <input type="checkbox" checked data-ui-key="tool-theme"><span class="vis-switch"></span>
1781              </label>
1782              <label class="vis-row">
1783                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg></span>
1784                <span class="vis-label">User <span class="vis-hint">Avatar &amp; name</span></span>
1785                <input type="checkbox" checked data-ui-key="user-bar"><span class="vis-switch"></span>
1786              </label>
1787              <label class="vis-row">
1788                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.6 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.6a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg></span>
1789                <span class="vis-label">Settings Button <span class="vis-hint">Cog next to user — re-open with <code>/settings</code></span></span>
1790                <input type="checkbox" checked data-ui-key="sidebar-settings-btn"><span class="vis-switch"></span>
1791              </label>
1792            </div>
1793          </div>
1794          <div class="admin-card" style="padding-bottom:6px;">
1795            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/></svg>Chat Area</h2>
1796            <div class="vis-toggles">
1797              <label class="vis-row">
1798                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 6h16"/><path d="M4 10h8"/></svg></span>
1799                <span class="vis-label">Session Header <span class="vis-hint">Model name &amp; export above chat</span></span>
1800                <input type="checkbox" checked data-ui-key="chat-meta"><span class="vis-switch"></span>
1801              </label>
1802              <label class="vis-row">
1803                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M12 3v2m0 14v2m-7-9H3m18 0h-2m-1.5-6.5L16 7m-8-1.5L6.5 7m11 11l-1.5-1.5M8 18l-1.5 1.5"/><circle cx="12" cy="12" r="4"/></svg></span>
1804                <span class="vis-label">Welcome Message <span class="vis-hint">Logo &amp; tips on empty chat</span></span>
1805                <input type="checkbox" checked data-ui-key="welcome-text"><span class="vis-switch"></span>
1806              </label>
1807              <label class="vis-row">
1808                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg></span>
1809                <span class="vis-label">Incognito Mode <span class="vis-hint">No memory, no history saved</span></span>
1810                <input type="checkbox" checked data-ui-key="incognito-btn"><span class="vis-switch"></span>
1811              </label>
1812              <label class="vis-row">
1813                <span class="vis-icon" style="font-size:13px;line-height:14px;">Aa</span>
1814                <span class="vis-label">Text-only Emojis <span class="vis-hint">Strip emojis from AI replies</span></span>
1815                <input type="checkbox" data-ui-key="text-emojis"><span class="vis-switch"></span>
1816              </label>
1817              <label class="vis-row">
1818                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M12 2a7 7 0 0 0-7 7c0 3 2 5.5 4.5 7.5.7.6 1.2 1.3 1.5 2h2c.3-.7.8-1.4 1.5-2C17 14.5 19 12 19 9a7 7 0 0 0-7-7z"/><line x1="10" y1="22" x2="14" y2="22"/></svg></span>
1819                <span class="vis-label">Thinking Process <span class="vis-hint">Show &lt;think&gt; collapsible bars</span></span>
1820                <input type="checkbox" checked data-ui-key="show-thinking"><span class="vis-switch"></span>
1821              </label>
1822              <label class="vis-row">
1823                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12s4-7 10-7 10 7 10 7-4 7-10 7S2 12 2 12z"/><circle cx="12" cy="12" r="3"/><path d="M4 4l16 16"/></svg></span>
1824                <span class="vis-label">Sensitive Blur <span class="vis-hint">Blur emails, tokens, and secrets in AI output</span></span>
1825                <input type="checkbox" data-privacy-key="sensitive-blur"><span class="vis-switch"></span>
1826              </label>
1827            </div>
1828          </div>
1829          <div class="admin-card" style="padding-bottom:6px;">
1830            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><line x1="17" y1="10" x2="3" y2="10"/><line x1="21" y1="6" x2="3" y2="6"/><line x1="21" y1="14" x2="3" y2="14"/><line x1="17" y1="18" x2="3" y2="18"/></svg>Chat Bar</h2>
1831            <div class="vis-toggles">
1832              <label class="vis-row">
1833                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg></span>
1834                <span class="vis-label">Web Search</span>
1835                <input type="checkbox" checked data-ui-key="web-toggle-btn"><span class="vis-switch"></span>
1836              </label>
1837              <label class="vis-row">
1838                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg></span>
1839                <span class="vis-label">Document Editor</span>
1840                <input type="checkbox" checked data-ui-key="doc-toggle-btn"><span class="vis-switch"></span>
1841              </label>
1842              <label class="vis-row">
1843                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/></svg></span>
1844                <span class="vis-label">Shell</span>
1845                <input type="checkbox" checked data-ui-key="bash-toggle-btn"><span class="vis-switch"></span>
1846              </label>
1847              <label class="vis-row">
1848                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg></span>
1849                <span class="vis-label">More Tools <span class="vis-hint">Overflow menu</span></span>
1850                <input type="checkbox" checked data-ui-key="overflow-plus-btn"><span class="vis-switch"></span>
1851              </label>
1852              <label class="vis-row">
1853                <span class="vis-icon vis-icon-text">A|C</span>
1854                <span class="vis-label">Agent / Chat <span class="vis-hint">Mode switcher</span></span>
1855                <input type="checkbox" checked data-ui-key="mode-toggle"><span class="vis-switch"></span>
1856              </label>
1857              <label class="vis-row">
1858                <span class="vis-icon"><svg width="14" height="14" 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 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg></span>
1859                <span class="vis-label">Attach Files</span>
1860                <input type="checkbox" checked data-ui-key="attach-btn"><span class="vis-switch"></span>
1861              </label>
1862              <label class="vis-row">
1863                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/><line x1="11" y1="8" x2="11" y2="14"/><line x1="8" y1="11" x2="14" y2="11"/></svg></span>
1864                <span class="vis-label">Deep Research</span>
1865                <input type="checkbox" checked data-ui-key="research-btn"><span class="vis-switch"></span>
1866              </label>
1867              <label class="vis-row">
1868                <span class="vis-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg></span>
1869                <span class="vis-label">Personas <span class="vis-hint">Persona picker &amp; system prompt</span></span>
1870                <input type="checkbox" checked data-ui-key="preset-mini-btn"><span class="vis-switch"></span>
1871              </label>
1872            </div>
1873          </div>
1874          <div style="text-align:right;padding:0 4px;">
1875            <button type="button" class="admin-btn-sm" id="set-uiVisResetBtn" style="opacity:0.5;">Reset All</button>
1876          </div>
1877        </div>
1878
1879        <!-- ═══ THEME TAB ═══ -->
1880
1881        <!-- ═══ MEMORY TAB ═══ -->
1882        <!-- ═══ SHORTCUTS TAB ═══ -->
1883        <div data-settings-panel="shortcuts" class="hidden">
1884          <div class="admin-card" style="display:flex;align-items:center;justify-content:space-between;padding:10px 16px;">
1885            <div>
1886              <h2 style="margin:0;font-size:13px;"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="M6 8h.01M10 8h.01M14 8h.01M18 8h.01M8 12h.01M12 12h.01M16 12h.01M7 16h10"/></svg>Keyboard Shortcuts</h2>
1887              <p style="font-size:10px;opacity:0.4;margin:2px 0 0;">Click a shortcut to rebind. Press Escape to cancel.</p>
1888            </div>
1889            <button type="button" class="shortcut-action-btn is-reset" id="shortcuts-reset-btn" title="Reset Shortcuts" style="width:28px;height:28px;font-size:15px;">&#x21A9;</button>
1890          </div>
1891          <div class="admin-card">
1892            <div id="shortcuts-list"></div>
1893          </div>
1894        </div>
1895
1896
1897        <!-- ═══ ACCOUNT TAB ═══ -->
1898        <div data-settings-panel="account" class="hidden">
1899          <div class="admin-card">
1900            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>Account</h2>
1901            <div style="display:flex;align-items:center;gap:10px;margin:4px 0 12px;">
1902              <div class="user-bar-avatar" id="settings-account-avatar" style="width:32px;height:32px;font-size:14px;"></div>
1903              <div style="flex:1;">
1904                <div id="settings-account-username" style="font-size:13px;font-weight:600;"></div>
1905                <div id="settings-account-role" style="font-size:11px;opacity:0.5;"></div>
1906              </div>
1907              <button id="settings-logout-btn" style="background:color-mix(in srgb, var(--color-error) 10%, transparent);border:1px solid var(--color-error);border-radius:6px;padding:6px 12px;color:var(--color-error);font-family:inherit;font-size:12px;font-weight:500;cursor:pointer;transition:opacity 0.15s,background 0.15s;display:inline-flex;align-items:center;gap:6px;">
1908                <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="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>
1909                Logout
1910              </button>
1911            </div>
1912          </div>
1913          <div class="admin-card">
1914            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>Change Password</h2>
1915            <div class="settings-col">
1916              <input id="settings-pw-current" type="password" placeholder="Current password" autocomplete="current-password" style="padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg);font-family:inherit;font-size:12px;">
1917              <input id="settings-pw-new" type="password" placeholder="New password (min 8)" autocomplete="new-password" style="padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg);font-family:inherit;font-size:12px;">
1918              <input id="settings-pw-confirm" type="password" placeholder="Confirm new password" autocomplete="new-password" style="padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg);font-family:inherit;font-size:12px;">
1919              <div class="settings-row" style="margin-top:2px;justify-content:flex-end;">
1920                <span id="settings-pw-msg" style="font-size:11px;margin-right:auto;"></span>
1921                <button class="admin-btn-add" id="settings-pw-save">Update Password</button>
1922              </div>
1923            </div>
1924          </div>
1925          <div class="admin-card" id="settings-2fa-card">
1926            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/><circle cx="12" cy="16" r="1"/></svg>Two-Factor Authentication</h2>
1927            <div id="settings-2fa-content">
1928              <!-- Populated by JS -->
1929            </div>
1930          </div>
1931        </div>
1932
1933        <!-- ═══ CLOUD STORAGE TAB ═══ -->
1934        <div data-settings-panel="cloud-storage" class="hidden">
1935          <div class="admin-card">
1936            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"/></svg>Hugging Face Cloud Storage</h2>
1937            <div class="admin-toggle-sub" style="margin-bottom:12px">
1938              Use Hugging Face Storage Buckets for cloud file storage. Files uploaded to Odysseus are automatically synced to your bucket, enabling persistence across deployments and HF Spaces.
1939            </div>
1940            <div class="settings-col">
1941              <div class="settings-row" style="align-items:center;margin-bottom:8px;">
1942                <label style="font-size:12px;font-weight:500;min-width:90px;">HF Token</label>
1943                <input id="set-bucket-token" type="password" placeholder="hf_xxxxxxxxxxxxxxxxxxxx" style="flex:1;padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg);font-family:inherit;font-size:12px;">
1944                <button class="admin-btn-add" id="set-bucket-token-save" style="margin-left:8px;white-space:nowrap;">Save Token</button>
1945              </div>
1946              <div id="set-bucket-user-info" style="font-size:11px;opacity:0.7;margin-bottom:8px;display:none;"></div>
1947            </div>
1948          </div>
1949
1950          <div class="admin-card" id="set-bucket-config-card" style="opacity:0.5;pointer-events:none;">
1951            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>Bucket Configuration</h2>
1952            <div class="settings-col">
1953              <div class="settings-row" style="align-items:center;margin-bottom:8px;">
1954                <label style="font-size:12px;font-weight:500;min-width:90px;">Active Bucket</label>
1955                <select id="set-bucket-select" style="flex:1;padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg);font-family:inherit;font-size:12px;">
1956                  <option value="">No bucket selected</option>
1957                </select>
1958                <button class="admin-btn-add" id="set-bucket-select-btn" style="margin-left:8px;white-space:nowrap;">Select</button>
1959              </div>
1960              <div id="set-bucket-active-info" style="font-size:11px;opacity:0.7;margin-bottom:12px;display:none;"></div>
1961
1962              <div style="border-top:1px solid var(--border);padding-top:10px;margin-top:4px;">
1963                <div style="font-size:12px;font-weight:500;margin-bottom:8px;">Create New Bucket</div>
1964                <div class="settings-row" style="align-items:center;margin-bottom:8px;">
1965                  <input id="set-bucket-new-name" type="text" placeholder="my-odysseus-data" style="flex:1;padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg);font-family:inherit;font-size:12px;">
1966                  <label style="font-size:11px;display:flex;align-items:center;gap:4px;margin-left:8px;">
1967                    <input type="checkbox" id="set-bucket-new-private" checked> Private
1968                  </label>
1969                  <button class="admin-btn-add" id="set-bucket-create-btn" style="margin-left:8px;white-space:nowrap;">Create</button>
1970                </div>
1971              </div>
1972            </div>
1973          </div>
1974
1975          <div class="admin-card" id="set-bucket-status-card" style="display:none;">
1976            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><circle cx="12" cy="12" r="10"/><path d="M12 8v4l3 3"/></svg>Storage Status</h2>
1977            <div id="set-bucket-status-content" style="font-size:12px;"></div>
1978          </div>
1979
1980          <div class="admin-card" id="set-bucket-files-card" style="display:none;">
1981            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="13 2 13 9 20 9"/></svg>Bucket Files</h2>
1982            <div class="settings-row" style="margin-bottom:8px;">
1983              <button class="admin-btn-add" id="set-bucket-sync-btn" style="display:inline-flex;align-items:center;gap:4px;">
1984                <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>
1985                Sync Uploads to Bucket
1986              </button>
1987              <button class="admin-btn-add" id="set-bucket-refresh-btn" style="margin-left:8px;">Refresh Files</button>
1988              <span id="set-bucket-files-msg" style="font-size:11px;margin-left:8px;"></span>
1989            </div>
1990            <div id="set-bucket-files-list" style="max-height:300px;overflow-y:auto;font-size:11px;font-family:var(--font-mono,'Menlo','Consolas',monospace);"></div>
1991          </div>
1992
1993          <div class="admin-card" id="set-bucket-danger-card" style="display:none;">
1994            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6;color:var(--red)"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>Danger Zone</h2>
1995            <div class="settings-row" style="align-items:center;">
1996              <div style="flex:1;">
1997                <div style="font-size:12px;font-weight:500;">Disconnect Bucket</div>
1998                <div class="admin-toggle-sub" style="margin:2px 0 0;">Stop syncing files to the cloud. Local files are preserved.</div>
1999              </div>
2000              <button id="set-bucket-disconnect-btn" style="background:color-mix(in srgb, var(--color-error) 10%, transparent);border:1px solid var(--color-error);border-radius:6px;padding:6px 12px;color:var(--color-error);font-family:inherit;font-size:12px;font-weight:500;cursor:pointer;">Disconnect</button>
2001            </div>
2002          </div>
2003        </div>
2004
2005        <!-- ═══ SECRETS TAB ═══ -->
2006        <div data-settings-panel="secrets" class="hidden">
2007          <div class="admin-card">
2008            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"/></svg>Secrets &amp; Environment</h2>
2009            <div class="admin-toggle-sub" style="margin-bottom:8px">
2010              Manage API keys, tokens, and configuration as environment variables. In HF Spaces, secrets are set via Space Settings and injected at runtime — <code>.env</code> files are not persistent.
2011            </div>
2012            <div id="secrets-space-banner"></div>
2013            <div class="settings-row" style="align-items:center;margin-bottom:8px;">
2014              <button class="admin-btn-add" id="secrets-refresh-btn" style="font-size:11px;">Refresh</button>
2015              <span id="secrets-summary" style="font-size:11px;margin-left:8px;"></span>
2016              <span id="secrets-status-msg" style="font-size:11px;margin-left:8px;"></span>
2017            </div>
2018            <div id="secrets-list" style="max-height:400px;overflow-y:auto;font-size:11px;border:1px solid var(--border);border-radius:4px;"></div>
2019          </div>
2020
2021          <!-- Add custom secret -->
2022          <div class="admin-card">
2023            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>Add Secret / Variable</h2>
2024            <div class="admin-toggle-sub" style="margin-bottom:8px">
2025              Add a new environment variable or secret. In HF Spaces, this sets it as a Space secret (triggers restart). Locally, it sets it in the current process only.
2026            </div>
2027            <div class="settings-row" style="align-items:center;margin-bottom:6px;">
2028              <input id="secrets-custom-key" type="text" placeholder="API_KEY_NAME" style="flex:1;padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg);font-family:monospace;font-size:12px;text-transform:uppercase;">
2029              <input id="secrets-custom-value" type="password" placeholder="Value" style="flex:1;padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg);font-family:inherit;font-size:12px;margin-left:8px;">
2030              <label style="font-size:11px;display:flex;align-items:center;gap:4px;margin-left:8px;white-space:nowrap;">
2031                <input type="checkbox" id="secrets-custom-is-secret" checked> Secret
2032              </label>
2033              <button class="admin-btn-add" id="secrets-custom-add-btn" style="margin-left:8px;white-space:nowrap;">Add</button>
2034            </div>
2035            <span id="secrets-custom-msg" style="font-size:11px;"></span>
2036          </div>
2037
2038          <!-- Space secrets list (HF Spaces only) -->
2039          <div class="admin-card" id="secrets-space-actions" style="display:none;">
2040            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>Space Secrets</h2>
2041            <div class="admin-toggle-sub" style="margin-bottom:8px">
2042              Secrets currently set on this HF Space. Deleting a secret triggers a restart.
2043            </div>
2044            <div class="settings-row" style="align-items:center;margin-bottom:8px;">
2045              <button class="admin-btn-add" id="secrets-space-refresh-btn" style="font-size:11px;">Refresh</button>
2046              <span id="secrets-space-msg" style="font-size:11px;margin-left:8px;"></span>
2047            </div>
2048            <div id="secrets-space-list" style="max-height:200px;overflow-y:auto;font-size:11px;border:1px solid var(--border);border-radius:4px;"></div>
2049          </div>
2050
2051          <!-- Secret editor modal -->
2052          <div id="secrets-editor-modal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:10000;display:none;align-items:center;justify-content:center;">
2053            <div style="background:var(--bg-panel,var(--bg));border:1px solid var(--border);border-radius:8px;padding:20px;width:400px;max-width:90vw;box-shadow:0 8px 32px rgba(0,0,0,0.3);">
2054              <h3 style="font-size:13px;margin:0 0 12px;">Set Secret Value</h3>
2055              <div style="margin-bottom:8px;">
2056                <label style="font-size:10px;opacity:0.6;display:block;margin-bottom:4px;">Key</label>
2057                <input id="secrets-editor-key" type="text" readonly style="width:100%;padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg);font-family:monospace;font-size:12px;opacity:0.7;">
2058              </div>
2059              <div style="margin-bottom:8px;">
2060                <label style="font-size:10px;opacity:0.6;display:block;margin-bottom:4px;">Value</label>
2061                <div style="display:flex;gap:6px;">
2062                  <input id="secrets-editor-value" type="password" placeholder="Enter value..." style="flex:1;padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg);font-family:inherit;font-size:12px;">
2063                  <button id="secrets-editor-toggle" style="padding:6px 10px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg);font-size:10px;cursor:pointer;">Show</button>
2064                </div>
2065              </div>
2066              <div style="margin-bottom:12px;">
2067                <label style="font-size:11px;display:flex;align-items:center;gap:4px;">
2068                  <input type="checkbox" id="secrets-editor-is-secret" checked> Mark as secret (masked in HF Spaces UI)
2069                </label>
2070              </div>
2071              <div class="settings-row" style="justify-content:flex-end;gap:8px;">
2072                <button id="secrets-editor-cancel" style="padding:6px 14px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg);font-family:inherit;font-size:12px;cursor:pointer;">Cancel</button>
2073                <button class="admin-btn-add" id="secrets-editor-save" style="padding:6px 14px;font-size:12px;">Save</button>
2074              </div>
2075              <span id="secrets-editor-msg" style="font-size:11px;display:block;margin-top:8px;"></span>
2076            </div>
2077          </div>
2078        </div>
2079
2080        <!-- ═══ GITHUB TAB ═══ -->
2081        <div data-settings-panel="github" class="hidden">
2082          <div class="admin-card">
2083            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>GitHub Integration</h2>
2084            <div class="admin-toggle-sub" style="margin-bottom:12px">
2085              Connect your GitHub account to manage repositories directly from Odysseus. Create, publish, and delete repos — all from the UI.
2086            </div>
2087
2088            <!-- Auth section (shown when not connected) -->
2089            <div id="gh-auth-section" style="margin-bottom:8px;">
2090              <div class="settings-col">
2091                <div class="admin-toggle-sub" style="margin-bottom:8px;">
2092                  To get started, you need to create a <a href="https://github.com/settings/developers" target="_blank" rel="noopener" style="color:var(--brand-color,var(--red,#e06c75));">GitHub OAuth App</a> and set the <code>GITHUB_CLIENT_ID</code> and <code>GITHUB_CLIENT_SECRET</code> environment variables. The callback URL should be <code>{your-odysseus-url}/api/github/oauth/callback</code>.
2093                </div>
2094                <button class="admin-btn-add" id="gh-auth-connect" style="display:inline-flex;align-items:center;gap:6px;">
2095                  <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="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"/><polyline points="10 17 15 12 10 7"/><line x1="15" y1="12" x2="3" y2="12"/></svg>
2096                  Connect GitHub Account
2097                </button>
2098                <span id="gh-auth-msg" style="font-size:11px;margin-left:8px;"></span>
2099              </div>
2100            </div>
2101
2102            <!-- Connected section (shown when authenticated) -->
2103            <div id="gh-connected-section" style="display:none;">
2104              <div id="gh-user-info" style="font-size:11px;margin-bottom:8px;"></div>
2105              <div class="settings-row" style="align-items:center;">
2106                <span id="gh-rate-limit" style="font-size:10px;opacity:0.5;flex:1;"></span>
2107                <button id="gh-disconnect-btn" style="background:color-mix(in srgb, var(--color-error) 10%, transparent);border:1px solid var(--color-error);border-radius:6px;padding:4px 10px;color:var(--color-error);font-family:inherit;font-size:11px;font-weight:500;cursor:pointer;">Disconnect</button>
2108                <span id="gh-connected-msg" style="font-size:11px;margin-left:8px;"></span>
2109              </div>
2110            </div>
2111          </div>
2112
2113          <div class="admin-card" id="gh-config-card" style="opacity:0.5;pointer-events:none;">
2114            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>Repositories</h2>
2115            <div class="settings-col">
2116              <div class="settings-row" style="align-items:center;margin-bottom:8px;">
2117                <button class="admin-btn-add" id="gh-refresh-repos-btn" style="font-size:11px;">Refresh</button>
2118                <span id="gh-repos-msg" style="font-size:11px;margin-left:8px;"></span>
2119              </div>
2120              <div id="gh-repos-list" style="max-height:250px;overflow-y:auto;font-size:11px;border:1px solid var(--border);border-radius:4px;"></div>
2121            </div>
2122
2123            <div style="border-top:1px solid var(--border);padding-top:10px;margin-top:10px;">
2124              <div style="font-size:12px;font-weight:500;margin-bottom:8px;">Create New Repository</div>
2125              <div class="settings-row" style="align-items:center;margin-bottom:6px;">
2126                <input id="gh-new-repo-name" type="text" placeholder="my-awesome-project" style="flex:1;padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg);font-family:inherit;font-size:12px;">
2127                <label style="font-size:11px;display:flex;align-items:center;gap:4px;margin-left:8px;">
2128                  <input type="checkbox" id="gh-new-repo-private" checked> Private
2129                </label>
2130                <button class="admin-btn-add" id="gh-create-repo-btn" style="margin-left:8px;white-space:nowrap;">Create</button>
2131              </div>
2132              <input id="gh-new-repo-desc" type="text" placeholder="Repository description (optional)" style="width:100%;padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg);font-family:inherit;font-size:12px;margin-bottom:4px;">
2133              <span id="gh-repo-msg" style="font-size:11px;"></span>
2134            </div>
2135          </div>
2136
2137          <div class="admin-card" id="gh-publish-card" style="opacity:0.5;pointer-events:none;">
2138            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M4 14.899A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.242"/><path d="M12 12v9"/><path d="m8 17 4 4 4-4"/></svg>Publish Project</h2>
2139            <div class="admin-toggle-sub" style="margin-bottom:8px">
2140              Push your Odysseus workspace configuration to a new GitHub repository for backup and sharing.
2141            </div>
2142            <div class="settings-row" style="align-items:center;">
2143              <input id="gh-publish-repo-name" type="text" placeholder="my-odysseus-config" style="flex:1;padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--fg);font-family:inherit;font-size:12px;">
2144              <button class="admin-btn-add" id="gh-publish-btn" style="margin-left:8px;white-space:nowrap;">Publish</button>
2145              <span id="gh-publish-msg" style="font-size:11px;margin-left:8px;"></span>
2146            </div>
2147          </div>
2148        </div>
2149
2150        <!-- ═══ EMAIL TAB ═══ -->
2151        <div data-settings-panel="email" class="hidden">
2152          <div class="admin-card">
2153            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>Email Accounts</h2>
2154            <div class="settings-row" style="align-items:center;">
2155              <div class="admin-toggle-sub" style="margin:0;flex:1;">Add, edit, delete, and test accounts in Integrations.</div>
2156              <button class="admin-btn-add" id="set-email-open-integrations" style="display:inline-flex;align-items:center;gap:6px;"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="opacity:0.7"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>Manage in Integrations</button>
2157            </div>
2158          </div>
2159
2160          <div class="admin-card">
2161            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/><path d="M9 16l2 2 4-4"/></svg>Email Tasks</h2>
2162            <div class="settings-row" style="align-items:center;">
2163              <div class="admin-toggle-sub" style="margin:0;flex:1;">Manage email background tasks in Tasks.</div>
2164              <button class="admin-btn-add" id="set-email-open-tasks" style="display:inline-flex;align-items:center;gap:6px;"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="opacity:0.7"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/><path d="M9 16l2 2 4-4"/></svg>Open Tasks</button>
2165            </div>
2166          </div>
2167
2168          <div class="admin-card">
2169            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>Writing Style</h2>
2170            <div class="admin-toggle-sub" style="margin-bottom:8px">AI-extracted from your sent emails. Used when AI drafts replies.</div>
2171            <div class="settings-col">
2172              <textarea id="set-email-style" rows="4" class="settings-select" style="font-family:inherit;resize:vertical" placeholder="e.g. I write emails in this style. I don't use exclamation marks. I sign emails with: ..."></textarea>
2173              <div class="settings-row" style="margin-top:4px">
2174                <span id="set-email-style-msg" style="font-size:11px;"></span>
2175                <button class="admin-btn-add" id="set-email-style-extract" style="margin-left:auto;">Extract from Sent (15 emails)</button>
2176                <button class="admin-btn-add" id="set-email-style-save">Save</button>
2177              </div>
2178            </div>
2179          </div>
2180        </div>
2181
2182        <!-- ═══ REMINDERS TAB ═══ -->
2183        <div data-settings-panel="reminders" class="hidden">
2184          <div class="admin-card">
2185            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>How you're reminded</h2>
2186            <div class="admin-toggle-sub" style="margin-bottom:8px">Controls how fired note reminders are delivered.</div>
2187            <div class="settings-col">
2188              <div class="settings-row">
2189                <label class="settings-label">Channel</label>
2190                <select id="set-reminder-channel" class="settings-select">
2191                  <option value="browser">Browser notification (default)</option>
2192                  <option value="email" id="set-reminder-channel-email-opt">Email</option>
2193                  <option value="ntfy" id="set-reminder-channel-ntfy-opt">ntfy</option>
2194                  <option value="webhook" id="set-reminder-channel-webhook-opt">Webhook</option>
2195                </select>
2196              </div>
2197              <div id="set-reminder-email-from-row" class="settings-row" style="display:none">
2198                <label class="settings-label">Send from</label>
2199                <select id="set-reminder-email-account" class="settings-select"></select>
2200              </div>
2201              <div id="set-reminder-email-to-row" class="settings-row" style="display:none">
2202                <label class="settings-label">Send to</label>
2203                <input id="set-reminder-email-to" class="settings-select" type="email" placeholder="[email protected]" />
2204              </div>
2205              <div id="set-reminder-ntfy-topic-row" class="settings-row" style="display:none">
2206                <label class="settings-label">ntfy topic</label>
2207                <input id="set-reminder-ntfy-topic" class="settings-select" type="text" placeholder="reminders" />
2208              </div>
2209              <div id="set-reminder-webhook-intg-row" class="settings-row" style="display:none">
2210                <label class="settings-label">Integration</label>
2211                <select id="set-reminder-webhook-intg" class="settings-select"></select>
2212              </div>
2213              <div id="set-reminder-webhook-template-row" class="settings-row" style="display:none;align-items:flex-start">
2214                <label class="settings-label" style="padding-top:6px">Payload</label>
2215                <textarea id="set-reminder-webhook-template" class="settings-select" rows="3" style="font-family:inherit;resize:vertical;flex:1" placeholder='{"content": "{{title}}: {{message}}"}'></textarea>
2216              </div>
2217              <div id="set-reminder-channel-hint" style="font-size:11px;opacity:0.6;"></div>
2218              <div style="font-size:11px;opacity:0.6;margin-top:4px;">Configure email account, ntfy server, etc. in <a href="#" id="set-reminders-open-integrations" style="color:var(--accent, var(--red));text-decoration:none;font-weight:600;">Integrations</a>.</div>
2219            </div>
2220          </div>
2221          <div class="admin-card">
2222            <h2 style="display:flex;align-items:center;gap:6px;"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right:1px;opacity:0.6;flex-shrink:0"><path d="M12 0L14.59 8.41L23 12L14.59 15.59L12 24L9.41 15.59L1 12L9.41 8.41Z"/></svg>AI Synthesis<span style="flex:1"></span><label class="admin-switch" title="Use the utility model to write reminder messages"><input type="checkbox" id="set-reminder-llm-toggle">
2222<span class="admin-slider"></span></label></h2>
2223            <div class="admin-toggle-sub" style="margin-bottom:8px">When on, the utility model writes a short, warm one-line reminder for browser, email, ntfy, AND webhook reminders instead of just the raw note content.</div>
2224          </div>
2225          <div class="admin-card">
2226            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>Public App URL</h2>
2227            <div class="admin-toggle-sub" style="margin-bottom:8px">Used to build clickable links back to Odysseus inside outgoing reminder / urgent-email emails (e.g. <code>https://chat.yourdomain.com</code>). Leave blank to omit links.</div>
2228            <div class="settings-col">
2229              <div class="settings-row">
2230                <label class="settings-label">URL</label>
2231                <input id="set-app-public-url" class="settings-select" type="url" placeholder="https://chat.example.com" style="flex:1;" />
2232              </div>
2233              <div id="set-app-public-url-msg" style="font-size:11px;color:color-mix(in srgb, var(--fg) 55%, transparent);"></div>
2234            </div>
2235          </div>
2236          <div class="admin-card">
2237            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>Test</h2>
2238            <div class="admin-toggle-sub" style="margin-bottom:8px">Fire a test reminder using your current settings to verify everything works.</div>
2239            <div class="settings-row">
2240              <span id="set-reminder-test-msg" style="font-size:11px;"></span>
2241              <button class="admin-btn-add" id="set-reminder-test-btn" style="margin-left:auto;">Send Test Reminder</button>
2242            </div>
2243          </div>
2244        </div>
2245
2246        <!-- ═══ ADMIN: USERS TAB ═══ -->
2247        <div data-settings-panel="users" class="hidden">
2248          <div class="admin-card">
2249            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="8.5" cy="7" r="4"/><line x1="20" y1="8" x2="20" y2="14"/><line x1="23" y1="11" x2="17" y2="11"/></svg>Registration</h2>
2250            <div class="admin-toggle-row">
2251              <div>
2252                <div class="admin-toggle-label">Open signup</div>
2253                <div class="admin-toggle-sub">Allow anyone to create an account from the login page</div>
2254              </div>
2255              <label class="admin-switch"><input type="checkbox" id="adm-signupToggle"><span class="admin-slider"></span></label>
2256            </div>
2257          </div>
2258          <div class="admin-card">
2259            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>Users</h2>
2260            <div id="adm-userList"><div class="admin-empty">Loading...</div></div>
2261          </div>
2262          <div class="admin-card">
2263            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="8.5" cy="7" r="4"/><line x1="20" y1="8" x2="20" y2="14"/><line x1="23" y1="11" x2="17" y2="11"/></svg>Add User</h2>
2264            <div class="admin-add-form">
2265              <input id="adm-newUsername" type="text" placeholder="Username (email)">
2266              <input id="adm-newPassword" type="password" placeholder="Password (min 8)">
2267              <div class="admin-switch-inline" title="Grant full admin access"><label class="admin-switch"><input type="checkbox" id="adm-newIsAdmin">
2267<span class="admin-slider"></span></label> Admin</div>
2268            </div>
2269            <div class="settings-row" style="margin-top:6px;">
2270              <button class="admin-btn-add" id="adm-addBtn">Add User</button>
2271              <span id="adm-addMsg" style="font-size:11px"></span>
2272            </div>
2273          </div>
2274        </div>
2275
2276        <!-- ═══ SERVICES TAB ═══ -->
2277        <div data-settings-panel="services">
2278          <div class="admin-card">
2279            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><rect x="2" y="2" width="20" height="8" rx="2"/><rect x="2" y="14" width="20" height="8" rx="2"/><circle cx="6" cy="6" r="1"/><circle cx="6" cy="18" r="1"/></svg>Add Models <span style="opacity:0.45;font-weight:normal;font-size:0.82em">(Endpoints)</span></h2>
2280            <div class="admin-toggle-sub" style="margin-bottom:10px">Connect local models first, or add a cloud API.</div>
2281
2282            <!-- Local subsection -->
2283            <div class="adm-add-section collapsible collapsed" id="adm-add-local">
2284              <div class="adm-ep-section-head adm-section-toggle" role="button" tabindex="0" aria-expanded="false">
2285                <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-1px;margin-right:4px;"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8"/><path d="M12 17v4"/></svg>
2286                <span>Local</span>
2287                <svg class="adm-section-caret" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
2288              </div>
2289              <div class="admin-model-form">
2290                <div class="admin-model-form-row">
2291                  <input id="adm-epLocalUrl" type="text" placeholder="Paste endpoint URL, e.g. http://localhost:11434/v1" style="flex:1">
2292                  <select id="adm-epLocalType" style="padding:5px;width:72px;flex-shrink:0;">
2293                    <option value="llm">LLM</option>
2294                    <option value="image">Image</option>
2295                  </select>
2296                </div>
2297                <div class="admin-model-form-row">
2298                  <input id="adm-epLocalApiKey" type="password" placeholder="API key (optional — for protected local endpoints)" autocomplete="off" style="flex:1">
2299                </div>
2300                <div class="admin-model-form-row">
2301                  <span style="flex:1"></span>
2302                  <button class="admin-btn-sm" id="adm-epLocalTestBtn" style="width:55px;text-align:center;">Test</button>
2303                  <button class="admin-btn-add" id="adm-epLocalAddBtn" style="width:55px;text-align:center;">Add</button>
2304                </div>
2305                <div class="adm-quickstart-section collapsed" id="adm-add-local-quickstart">
2306                  <div class="adm-quickstart-toggle" role="button" tabindex="0" aria-expanded="false">
2307                    <span>Quickstart</span>
2308                    <svg class="adm-section-caret" width="11" height="11" viewB
2308ox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
2309                  </div>
2310                  <div class="adm-quickstart-body">
2311                    <button class="admin-btn-sm" id="adm-epDiscoverBtn" title="Scan your network for running model servers">
2312                      <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" style="vertical-align:-1px;margin-right:4px;"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>Scan for Servers
2313                    </button>
2314                    <button class="admin-btn-sm" id="adm-epOllamaBtn" title="Fill the default Ollama endpoint">Ollama</button>
2315                  </div>
2316                </div>
2317                <div id="adm-epLocalMsg" class="adm-ep-inline-msg"></div>
2318              </div>
2319            </div>
2320
2321            <!-- API subsection -->
2322            <div class="adm-add-section collapsible collapsed" id="adm-add-api" style="margin-top:14px">
2323              <div class="adm-ep-section-head adm-section-toggle" role="button" tabindex="0" aria-expanded="false">
2324                <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-1px;margin-right:4px;"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
2325                <span>API</span>
2326                <svg class="adm-section-caret" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
2327              </div>
2328              <div class="admin-model-form">
2329                <!-- Custom picker (with logos). Hidden native <select> mirrors
2330                     its value so the existing JS that reads adm-epProvider
2331                     keeps working unchanged. -->
2332                <div class="adm-provider-picker adm-provider-combo" id="adm-provider-picker">
2333                  <input id="adm-epUrl" type="text" placeholder="Base URL or pick provider" autocomplete="off">
2334                  <button type="button" class="adm-provider-btn" id="adm-provider-btn" title="Pick provider">
2335                    <span class="adm-provider-current"><span class="adm-provider-logo"></span><span class="adm-provider-name">Provider</span></span>
2336                    <svg class="adm-provider-caret" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
2337                  </button>
2338                  <div class="adm-provider-menu hidden" id="adm-provider-menu"></div>
2339                </div>
2340                <select id="adm-epProvider" style="display:none">
2341                  <option value="">Custom URL</option>
2342                  <option value="https://api.anthropic.com" data-logo="anthropic">Anthropic</option>
2343                  <option value="https://api.deepseek.com/v1" data-logo="deepseek" selected>DeepSeek</option>
2344                  <option value="https://api.openai.com/v1" data-logo="openai">OpenAI</option>
2345                  <option value="https://openrouter.ai/api/v1" data-logo="openrouter">OpenRouter</option>
2346                  <option value="https://ollama.com/api" data-logo="ollama">Ollama Cloud</option>
2347                  <option value="https://api.groq.com/openai/v1" data-logo="groq">Groq</option>
2348                  <option value="https://api.mistral.ai/v1" data-logo="mistral">Mistral</option>
2349                  <option value="https://api.together.xyz/v1" data-logo="together">Together AI</option>
2350                  <option value="https://api.fireworks.ai/inference/v1" data-logo="fireworks">Fireworks AI</option>
2351                  <option value="https://generativelanguage.googleapis.com/v1beta/openai" data-logo="gemini">Google Gemini</option>
2352                  <option value="https://api.x.ai/v1" data-logo="grok">xAI Grok</option>
2353                  <option value="https://api.z.ai/api/paas/v4" data-logo="zhipu">Z.AI (Zhipu)</option>
2354                  <option value="https://api.z.ai/api/coding/paas/v4" data-logo="zhipu">Z.AI Coding Plan</option>
2355                </select>
2356                <div class="admin-model-form-row">
2357                  <input id="adm-epApiKey" type="password" placeholder="API key">
2358                  <select id="adm-epKind" style="padding:5px;width:82px;">
2359                    <option value="proxy">Proxy</option>
2360                    <option value="api">API</option>
2361                  </select>
2362                  <select id="adm-epType" style="padding:5px;width:80px;">
2363                    <option value="llm">LLM</option>
2364                    <option value="image">Image</option>
2365                  </select>
2366                  <button class="admin-btn-sm" id="adm-epApiTestBtn" style="width:55px;text-align:center;">Test</button>
2367                  <button class="admin-btn-sm hidden" id="adm-epApiCancelTestBtn" style="width:62px;text-align:center;">Cancel</button>
2368                  <button class="admin-btn-add" id="adm-epAddBtn" style="width:55px;text-align:center;">Add</button>
2369                </div>
2370                <div id="adm-epApiMsg" class="adm-ep-inline-msg"></div>
2371              </div>
2372            </div>
2373          </div>
2374          <div class="admin-card">
2375            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>Added Models <span style="opacity:0.45;font-weight:normal;font-size:0.82em">(Endpoints)</span></h2>
2376            <div class="admin-toggle-sub" style="margin-bottom:10px">Manage the endpoints you've added.</div>
2377            <div class="adm-ep-section">
2378              <div class="adm-ep-section-head">
2379                <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-1px;margin-right:4px;"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8"/><path d="M12 17v4"/></svg>
2380                <span>Local</span>
2381              </div>
2382              <div id="adm-epList-local"><div class="admin-empty">Loading...</div></div>
2383            </div>
2384            <div class="adm-ep-section" style="margin-top:14px">
2385              <div class="adm-ep-section-head">
2386                <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-1px;margin-right:4px;"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
2387                <span>API</span>
2388              </div>
2389              <div id="adm-epList-api"></div>
2390            </div>
2391          </div>
2392        </div>
2393
2394        <!-- ═══ TOOLS TAB ═══ -->
2395        <!-- ═══ INTEGRATIONS TAB ═══ -->
2396        <div data-settings-panel="integrations" class="hidden">
2397          <div class="admin-card">
2398            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>Integrations</h2>
2399            <div class="admin-toggle-sub" style="margin-bottom:8px">All external service connections in one place.</div>
2400            <div id="unified-integrations-list"></div>
2401            <div id="unified-intg-form" style="display:none"></div>
2402            <div style="text-align:center;padding:8px 0;">
2403              <button type="button" class="admin-btn-sm" id="unified-intg-add-btn" style="display:inline-flex;align-items:center;gap:6px;">+ Add Integration<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="opacity:0.7;"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></button>
2404            </div>
2405          </div>
2406        </div>
2407
2408        <!-- ═══ TOOLS TAB ═══ -->
2409        <div data-settings-panel="tools" class="hidden">
2410          <div class="admin-card" style="margin-bottom:12px;">
2411            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>Built-in Tools</h2>
2412            <div class="admin-toggle-sub" style="margin-bottom:8px">Enable or disable tools available to the AI agent.</div>
2413            <div id="adm-builtin-tools-list" class="admin-user-list"></div>
2414          </div>
2415        </div>
2416
2417        <!-- ═══ SYSTEM TAB ═══ -->
2418        <div data-settings-panel="system" class="hidden">
2419
2420          <div class="admin-card">
2421            <h2><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:5px;opacity:0.6"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>Data Backup</h2>
2422            <div class="admin-toggle-sub" style="margin-bottom:8px">Export or import your user data (memories, presets, settings, skills, preferences) as a JSON file.</div>
2423            <div style="display:flex;gap:8px;flex-wrap:wrap;">
2424              <button class="admin-btn-add" id="adm-exportDataBtn">Export Data</button>
2425              <button class="admin-btn-add" id="adm-importDataBtn">Import Data</button>
2426              <input type="file" id="adm-importFile" accept=".json" style="display:none;">
2427            </div>
2428            <div id="adm-backupMsg" style="margin-top:6px;"></div>
2429          </div>
2430          <div class="admin-card admin-danger-card">
2431            <h2 style="color:#e55;">Danger Zone</h2>
2432            <div class="admin-toggle-sub" style="margin-bottom:8px">Irreversible. Each wipe targets one category — pick exactly what you want gone.</div>
2433
2434            <div style="display:flex;justify-content:space-between;align-items:center;">
2435              <div>
2436                <div class="admin-toggle-label">Wipe all chats</div>
2437                <div class="admin-toggle-sub">Every session, message, and chat history. Documents/notes/etc. stay.</div>
2438              </div>
2439              <button class="admin-btn-delete" data-wipe-kind="chats" style="white-space:nowrap;">Wipe</button>
2440            </div>
2441
2442            <div style="display:flex;justify-content:space-between;align-items:center;margin-top:8px;">
2443              <div>
2444                <div class="admin-toggle-label">Wipe all memory</div>
2445                <div class="admin-toggle-sub">Clears `memory.json`, the Memory table, and the vector store. Skills not affected.</div>
2446              </div>
2447              <button class="admin-btn-delete" data-wipe-kind="memory" style="white-space:nowrap;">Wipe</button>
2448            </div>
2449
2450            <div style="display:flex;justify-content:space-between;align-items:center;margin-top:8px;">
2451              <div>
2452                <div class="admin-toggle-label">Wipe all skills</div>
2453                <div class="admin-toggle-sub">Drops `data/skills/` (all SKILL.md files). Memory not affected.</div>
2454              </div>
2455              <button class="admin-btn-delete" data-wipe-kind="skills" style="white-space:nowrap;">Wipe</button>
2456            </div>
2457
2458            <div style="display:flex;justify-content:space-between;align-items:center;margin-top:8px;">
2459              <div>
2460                <div class="admin-toggle-label">Wipe all notes</div>
2461                <div class="admin-toggle-sub">Every note, todo, and checklist.</div>
2462              </div>
2463              <button class="admin-btn-delete" data-wipe-kind="notes" style="white-space:nowrap;">Wipe</button>
2464            </div>
2465
2466            <div style="display:flex;justify-content:space-between;align-items:center;margin-top:8px;">
2467              <div>
2468                <div class="admin-toggle-label">Wipe all tasks</div>
2469                <div class="admin-toggle-sub">Every scheduled task and its run history (Tasks tool).</div>
2470              </div>
2471              <button class="admin-btn-delete" data-wipe-kind="tasks" style="white-space:nowrap;">Wipe</button>
2472            </div>
2473
2474            <div style="display:flex;justify-content:space-between;align-items:center;margin-top:8px;">
2475              <div>
2476                <div class="admin-toggle-label">Wipe all documents</div>
2477                <div class="admin-toggle-sub">Every document and version. Drafts, exports, library — all gone.</div>
2478              </div>
2479              <button class="admin-btn-delete" data-wipe-kind="documents" style="white-space:nowrap;">Wipe</button>
2480            </div>
2481
2482            <div style="display:flex;justify-content:space-between;align-items:center;margin-top:8px;">
2483              <div>
2484                <div class="admin-toggle-label">Wipe all gallery</div>
2485                <div class="admin-toggle-sub">Every image record and the upload directory on disk.</div>
2486              </div>
2487              <button class="admin-btn-delete" data-wipe-kind="gallery" style="white-space:nowrap;">Wipe</button>
2488            </div>
2489
2490            <div style="display:flex;justify-content:space-between;align-items:center;margin-top:8px;">
2491              <div>
2492                <div class="admin-toggle-label">Wipe all calendar</div>
2493                <div class="admin-toggle-sub">Every event and every calendar (incl. CalDAV-synced ones; resync to restore).</div>
2494              </div>
2495              <button class="admin-btn-delete" data-wipe-kind="calendar" style="white-space:nowrap;">Wipe</button>
2496            </div>
2497
2498            <div id="adm-wipeMsg" style="margin-top:8px;"></div>
2499          </div>
2500        </div>
2501
2502      </div>
2503      </div>
2504    </div>
2505  </div>
2506
2507  <!-- Search overlay (Ctrl+K command palette) -->
2508  <div class="search-overlay hidden" id="search-overlay">
2509    <div class="search-popup">
2510      <input type="text" id="search-input" placeholder="Search conversations..." autocomplete="off" />
2511      <div class="search-results" id="search-results"></div>
2512    </div>
2513  </div>
2514
2515  <!-- Toast container (aria-live for screen readers) -->
2516  <div id="toast" class="toast" role="status" aria-live="polite"></div>
2517
2518
2519
2520<!-- Load modules in this order -->
2521<script type="module" src="/static/js/storage.js"></script>
vendor: 1 bytes, line 2521
2521
2522<script type="module" src="/static/js/ui.js"></script>
vendor: 1 bytes, line 2522
2522
2523<script type="module" src="/static/js/markdown.js"></script>
vendor: 1 bytes, line 2523
2523
2524<script type="module" src="/static/js/dragSort.js"></script>
vendor: 1 bytes, line 2524
2524
2525<script type="module" src="/static/js/sessions.js"></script>
vendor: 1 bytes, line 2525
2525
2526<script type="module" src="/static/js/memory.js"></script>
vendor: 1 bytes, line 2526
2526
2527<script type="module" src="/static/js/skills.js"></script>
vendor: 1 bytes, line 2527
2527
2528<script type="module" src="/static/js/tourHints.js"></script>
vendor: 1 bytes, line 2528
2528
2529<script type="module" src="/static/js/tourAutoplay.js"></script>
vendor: 1 bytes, line 2529
2529
2530<script type="module" src="/static/js/fileHandler.js"></script>
vendor: 1 bytes, line 2530
2530
2531<script type="module" src="/static/js/voiceRecorder.js"></script>
vendor: 1 bytes, line 2531
2531
2532<script type="module" src="/static/js/models.js"></script>
2532  <!-- This must come BEFORE app.js -->
2533<script type="module" src="/static/js/rag.js"></script>
vendor: 1 bytes, line 2533
2533
2534<script type="module" src="/static/js/presets.js"></script>
vendor: 1 bytes, line 2534
2534
2535<script type="module" src="/static/js/search.js"></script>
vendor: 1 bytes, line 2535
2535
2536<script type="module" src="/static/js/spinner.js"></script>
vendor: 1 bytes, line 2536
2536
2537<script type="module" src="/static/js/tts-ai.js"></script>
vendor: 1 bytes, line 2537
2537
2538<script type="module" src="/static/js/document.js"></script>
vendor: 1 bytes, line 2538
2538
2539<script type="module" src="/static/js/gallery.js"></script>
vendor: 1 bytes, line 2539
2539
2540<script type="module" src="/static/js/chatRenderer.js"></script>
vendor: 1 bytes, line 2540
2540
2541<script type="module" src="/static/js/codeRunner.js"></script>
vendor: 1 bytes, line 2541
2541
2542<script type="module" src="/static/js/chatStream.js"></script>
vendor: 1 bytes, line 2542
2542
2543<script type="module" src="/static/js/chat.js?v=20260604s"></script>
vendor: 1 bytes, line 2543
2543
2544<script type="module" src="/static/js/cookbook.js"></script>
vendor: 1 bytes, line 2544
2544
2545<script src="/static/js/cookbookSchedule.js"></script>
vendor: 1 bytes, line 2545
2545
2546<script type="module" src="/static/js/search-chat.js"></script>
vendor: 1 bytes, line 2546
2546
2547<script type="module" src="/static/js/compare/index.js"></script>
vendor: 1 bytes, line 2547
2547
2548<script type="module" src="/static/js/theme.js"></script>
vendor: 1 bytes, line 2548
2548
2549<script type="module" src="/static/js/censor.js"></script>
vendor: 1 bytes, line 2549
2549
2550<script type="module" src="/static/js/settings.js"></script>
vendor: 1 bytes, line 2550
2550
2551<script type="module" src="/static/js/hfBuckets.js"></script>
vendor: 1 bytes, line 2551
2551
2552<script type="module" src="/static/js/hfSecrets.js"></script>
vendor: 1 bytes, line 2552
2552
2553<script type="module" src="/static/js/githubRepos.js"></script>
vendor: 1 bytes, line 2553
2553
2554<script type="module" src="/static/js/admin.js"></script>
vendor: 1 bytes, line 2554
2554
2555<script type="module" src="/static/js/assistant.js"></script>
vendor: 1 bytes, line 2555
2555
2556<script type="module" src="/static/app.js"></script>
2556  <!-- app.js must be LAST -->
2557<script type="module" src="/static/js/init.js"></script>
vendor: 1 bytes, line 2557
2557
2558<script type="module" src="/static/js/a11y.js"></script>
vendor: 1 bytes, line 2558
2558
2559<script nonce="0ef1c0e2ced0cc537d6ee0258e679162">if('serviceWorker' in navigator){navigator.serviceWorker.register('/static/sw.js').catch(()=>{});}</script>
2559
2560</body>
2561</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.