threadshelf 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +185 -0
- package/LICENSE +21 -0
- package/README.md +763 -0
- package/SECURITY.md +75 -0
- package/bin/threadshelf-mcp.js +12 -0
- package/bin/threadshelf.js +87 -0
- package/dist/mcp/server.js +388 -0
- package/dist/src/chunking.js +72 -0
- package/dist/src/cli.js +24 -0
- package/dist/src/embedding.js +59 -0
- package/dist/src/env.js +2 -0
- package/dist/src/generation/config.js +344 -0
- package/dist/src/generation/downloader.js +172 -0
- package/dist/src/generation/error-log.js +34 -0
- package/dist/src/generation/filesystem-browser.js +83 -0
- package/dist/src/generation/gguf-metadata.js +179 -0
- package/dist/src/generation/hardware.js +87 -0
- package/dist/src/generation/llama-install.js +563 -0
- package/dist/src/generation/llama-process.js +576 -0
- package/dist/src/generation/llama-profile.js +136 -0
- package/dist/src/generation/master-prompts.js +155 -0
- package/dist/src/generation/model-catalog.js +276 -0
- package/dist/src/generation/model-discovery.js +60 -0
- package/dist/src/generation/model-download.js +151 -0
- package/dist/src/generation/openai-compatible.js +231 -0
- package/dist/src/generation/providers/llama-cpp.js +97 -0
- package/dist/src/generation/providers/openrouter.js +106 -0
- package/dist/src/generation/quick-setup.js +215 -0
- package/dist/src/generation/registry.js +23 -0
- package/dist/src/generation/service.js +100 -0
- package/dist/src/generation/threads.js +311 -0
- package/dist/src/generation/types.js +1 -0
- package/dist/src/ingest-cli.js +95 -0
- package/dist/src/ingest.js +257 -0
- package/dist/src/load-env.js +17 -0
- package/dist/src/model-label.js +15 -0
- package/dist/src/parser.js +811 -0
- package/dist/src/paths.js +79 -0
- package/dist/src/routes/collections.js +97 -0
- package/dist/src/routes/files.js +136 -0
- package/dist/src/routes/generation.js +536 -0
- package/dist/src/routes/health.js +6 -0
- package/dist/src/routes/index.js +21 -0
- package/dist/src/routes/ingest.js +300 -0
- package/dist/src/routes/insights.js +24 -0
- package/dist/src/routes/loopback.js +15 -0
- package/dist/src/routes/model-catalog.js +178 -0
- package/dist/src/routes/search.js +57 -0
- package/dist/src/routes/stream-abort.js +23 -0
- package/dist/src/routes/thread.js +43 -0
- package/dist/src/search-cli.js +93 -0
- package/dist/src/server.js +78 -0
- package/dist/src/services/collections.js +58 -0
- package/dist/src/services/insights.js +111 -0
- package/dist/src/services/search.js +68 -0
- package/dist/src/services/stats.js +35 -0
- package/dist/src/services/thread.js +140 -0
- package/dist/src/store.js +1138 -0
- package/dist/src/validation.js +250 -0
- package/dist/src/watch.js +83 -0
- package/package.json +103 -0
- package/public/assets/index-CIm_Idqi.js +38 -0
- package/public/assets/index-Dv09K2vS.css +1 -0
- package/public/favicon.svg +6 -0
- package/public/index.html +28 -0
- package/scripts/openrouter-export-all.js +228 -0
- package/scripts/openrouter-export-browser.js +153 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark;--bg-0:oklch(15.5% .005 240);--bg-1:oklch(18% .006 240);--bg-2:oklch(21.5% .007 240);--bg-3:oklch(25% .008 240);--bg-hover:oklch(23.5% .008 240);--border-0:oklch(27% .008 240);--border-1:oklch(33% .01 240);--border-2:oklch(42% .012 240);--text-0:oklch(96.5% .005 240);--text-1:oklch(82% .008 240);--text-2:oklch(62% .01 240);--text-3:oklch(46% .01 240);--text-4:oklch(34% .01 240);--accent:oklch(78% .13 215);--accent-soft:oklch(78% .13 215/.14);--accent-border:oklch(78% .13 215/.35);--accent-ink:oklch(18% .04 240);--danger:oklch(70% .16 25);--danger-soft:oklch(70% .16 25/.14);--success:oklch(74% .13 155);--success-soft:oklch(74% .13 155/.14);--warning:oklch(78% .15 75);--warning-soft:oklch(78% .15 75/.14);--role-user:oklch(78% .1 230);--role-reasoning:oklch(80% .13 75);--role-response:oklch(76% .11 155);--p-google:oklch(70% .13 250);--p-openrouter:oklch(72% .15 320);--p-openai:oklch(74% .13 155);--p-claude:oklch(76% .13 55);--p-lmstudio:oklch(72% .12 200);--p-grok:oklch(70% .02 260);--sidebar-bg:oklch(16% .005 240/.6);--sidebar-rail-bg:oklch(15.5% .005 240/.7);--topbar-bg:oklch(16.5% .005 240/.85);--thread-bar-bg:oklch(16% .005 240/.88);--thread-glow-2:oklch(20% .02 240/.4);--empty-bg:oklch(17% .005 240/.5);--overlay-bg:oklch(8% .004 240/.58);--scrim-bg:oklch(10% .005 240/.55);--code-bg:oklch(0% 0 0/.25);--dialog-shadow:0 30px 80px -20px oklch(0% 0 0/.7);--reasoning-bg:oklch(18% .012 75/.3);--reasoning-bg-strong:oklch(18% .012 75/.45);--reasoning-bg-pill:oklch(18% .012 75/.6);--reasoning-border:oklch(80% .13 75/.18);--reasoning-border-strong:oklch(80% .13 75/.35);--reasoning-border-active:oklch(80% .13 75/.5);--glow-1:oklch(22% .04 230/.5);--glow-2:oklch(20% .04 280/.35);--glow-reading:oklch(21% .03 250/.4);--font-sans:Aptos, "Segoe UI Variable", "Segoe UI", ui-sans-serif, system-ui, sans-serif;--font-mono:"Cascadia Code", "SFMono-Regular", Consolas, ui-monospace, monospace;--fs-micro:11px;--fs-meta:11.5px;--r-xs:4px;--r-sm:6px;--r-md:8px;--r-lg:12px;--r-xl:16px;--row-h:32px;--pad-x:14px;--pad-y:10px}[data-theme=light]{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light;--bg-0:oklch(98.5% .002 240);--bg-1:oklch(96.5% .003 240);--bg-2:oklch(94% .004 240);--bg-3:oklch(91% .005 240);--bg-hover:oklch(94.5% .005 240);--border-0:oklch(90% .005 240);--border-1:oklch(84% .007 240);--border-2:oklch(74% .01 240);--text-0:oklch(23% .012 240);--text-1:oklch(34% .012 240);--text-2:oklch(48% .012 240);--text-3:oklch(60% .012 240);--text-4:oklch(72% .01 240);--accent:oklch(60% .13 220);--accent-soft:oklch(60% .13 220/.12);--accent-border:oklch(60% .13 220/.4);--accent-ink:oklch(99% .01 220);--danger:oklch(55% .19 25);--danger-soft:oklch(55% .19 25/.12);--success:oklch(52% .13 155);--success-soft:oklch(52% .13 155/.13);--warning:oklch(60% .15 75);--warning-soft:oklch(60% .15 75/.14);--role-user:oklch(55% .13 230);--role-reasoning:oklch(58% .14 75);--role-response:oklch(52% .12 155);--p-google:oklch(52% .15 250);--p-openrouter:oklch(55% .18 320);--p-openai:oklch(52% .13 155);--p-claude:oklch(55% .14 55);--p-lmstudio:oklch(54% .13 200);--p-grok:oklch(50% .03 260);--sidebar-bg:oklch(97.5% .003 240/.75);--sidebar-rail-bg:oklch(97% .003 240/.82);--topbar-bg:oklch(98.5% .003 240/.85);--thread-bar-bg:oklch(98.5% .003 240/.92);--thread-glow-2:oklch(93% .03 240/.9);--empty-bg:oklch(97% .006 240/.9);--overlay-bg:oklch(38% .02 240/.18);--scrim-bg:oklch(40% .02 240/.18);--code-bg:oklch(94% .01 240/.95);--dialog-shadow:0 24px 64px -28px oklch(38% .02 240/.28);--reasoning-bg:oklch(95% .03 85/.72);--reasoning-bg-strong:oklch(94% .035 85/.84);--reasoning-bg-pill:oklch(91% .05 85/.92);--reasoning-border:oklch(82% .06 85/.45);--reasoning-border-strong:oklch(78% .07 85/.62);--reasoning-border-active:oklch(72% .08 85/.78);--glow-1:oklch(86% .06 230/.5);--glow-2:oklch(86% .06 285/.4);--glow-reading:oklch(88% .05 250/.45)}*,:before,:after{box-sizing:border-box}html,body,#root{height:100%}body{background:var(--bg-0);color:var(--text-0);font-family:var(--font-sans);-webkit-font-smoothing:antialiased;text-rendering:optimizelegibility;margin:0;font-size:15px;line-height:1.5;overflow:hidden}button{cursor:pointer;font-family:inherit}input,textarea,select{color:inherit;font-family:inherit}::selection{background:var(--accent-soft);color:var(--text-0)}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-track{background:0 0}::-webkit-scrollbar-thumb{background:var(--border-0);background-clip:padding-box;border:2px solid #0000;border-radius:99px}::-webkit-scrollbar-thumb:hover{background:var(--border-2);background-clip:padding-box;border:2px solid #0000}.mono{font-family:var(--font-mono)}[hidden]{display:none!important}.app{background:radial-gradient(1200px 600px at 80% -10%, var(--glow-1), transparent 60%), radial-gradient(900px 500px at -10% 110%, var(--glow-2), transparent 60%), var(--bg-0);grid-template-columns:248px 1fr;width:100%;height:100dvh;transition:grid-template-columns .22s cubic-bezier(.4,0,.2,1);display:grid}.app[data-reading=true]{background:radial-gradient(1400px 700px at 50% -10%, var(--glow-reading), transparent 65%), var(--bg-0)}.sidebar-scrim{display:none}.sidebar.rail{background:var(--sidebar-rail-bg);border-right:1px solid var(--border-0);flex-direction:column;padding:0;display:flex}.rail-brand{border-bottom:1px solid var(--border-0);align-items:center;gap:9px;height:52px;padding:0 12px;display:flex}.rail-brand .name{letter-spacing:-.005em;color:var(--text-1);font-size:12.5px;font-weight:500}.rail-nav{flex-direction:column;flex:none;gap:1px;padding:8px 8px 4px;display:flex}.rail-item{border-radius:var(--r-sm);height:30px;color:var(--text-2);cursor:pointer;text-align:left;background:0 0;border:0;grid-template-columns:18px 1fr;align-items:center;gap:9px;padding:0 9px;font-size:12.5px;display:grid;position:relative}.rail-item .ico-wrap{color:var(--text-2);place-items:center;display:grid}.rail-item:hover{background:var(--bg-1);color:var(--text-0)}.rail-item:hover .ico-wrap{color:var(--text-0)}.rail-item[data-active=true]{background:var(--bg-2);color:var(--text-0)}.rail-item[data-active=true] .ico-wrap{color:var(--accent)}.rail-item[data-active=true]:before{content:"";background:var(--accent);border-radius:99px;width:2px;position:absolute;top:6px;bottom:6px;left:-8px}.rail-sep-h{font-family:var(--font-mono);font-size:var(--fs-meta);text-transform:uppercase;letter-spacing:.1em;color:var(--text-4);padding:10px 14px 4px}.rail-colls{flex-direction:column;flex:1;gap:1px;padding:0 8px 12px;display:flex;overflow:auto}.rail-coll-row{grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:4px;display:grid}.rail-coll{border-radius:var(--r-sm);cursor:pointer;text-align:left;height:28px;color:var(--text-2);background:0 0;border:0;grid-template-columns:8px 1fr;align-items:center;gap:10px;padding:0 9px;font-size:12px;display:grid;position:relative}.rail-coll i{background:var(--border-2);border-radius:99px;width:8px;height:8px;display:block}.rail-coll span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.rail-coll:hover{background:var(--bg-1);color:var(--text-0)}.rail-coll[data-active=true]{background:var(--bg-2);color:var(--text-0)}.rail-coll-delete{width:26px;height:26px;color:var(--text-3);background:0 0;border:0;border-radius:4px;place-items:center;padding:0;display:grid}.rail-coll-delete:hover{background:var(--danger-soft);color:var(--danger)}.rail-foot{border-top:1px solid var(--border-0);font-size:var(--fs-meta);color:var(--text-3);font-family:var(--font-mono);justify-content:space-between;align-items:center;margin-top:auto;padding:10px 12px;display:flex}.sidebar{border-right:1px solid var(--border-0);background:var(--sidebar-bg);-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);flex-direction:column;min-width:0;display:flex}.sb-brand{border-bottom:1px solid var(--border-0);align-items:center;gap:9px;height:40px;padding:0 12px;display:flex}.sb-logo{background:linear-gradient(140deg, var(--accent), oklch(55% .16 280));width:26px;height:26px;box-shadow:0 6px 20px -10px var(--accent), inset 0 0 0 1px oklch(100% 0 0/.1);border-radius:7px;flex-shrink:0;place-items:center;display:grid;position:relative}.sb-logo:after{content:"";border:1.5px solid var(--accent-ink);border-bottom-color:#0000;border-radius:99px;width:10px;height:10px;transform:rotate(-30deg)}.sb-name{flex-direction:column;gap:0;min-width:0;line-height:1.15;display:flex}.sb-name b{letter-spacing:-.01em;font-weight:600}.sb-name span{font-size:var(--fs-meta);color:var(--text-3);font-family:var(--font-mono)}.sb-chat-panel{border:1px solid var(--border-0);border-radius:var(--r-lg);background:color-mix(in oklch, var(--bg-1) 82%, transparent);min-width:0;margin:10px 8px 2px;overflow:hidden}.sb-chat-create{grid-template-columns:minmax(0,1fr) 36px;gap:6px;margin:6px;display:grid}.sb-new-chat{border:1px solid var(--accent-border);border-radius:var(--r-md);background:var(--accent);min-height:36px;color:var(--accent-ink);text-align:left;box-shadow:0 10px 28px -18px var(--accent);grid-template-columns:16px minmax(0,1fr);align-items:center;gap:9px;padding:0 10px;font-size:13px;font-weight:600;display:grid}.sb-new-chat span{min-width:0}.sb-new-chat:hover{filter:brightness(1.06)}.sb-private-chat{border:1px solid var(--border-1);border-radius:var(--r-md);background:var(--bg-1);width:36px;height:36px;color:var(--text-1);place-items:center;padding:0;display:grid}.sb-private-chat:hover{border-color:var(--accent-border);background:var(--accent-soft);color:var(--accent-ink)}.sb-chat-history{min-width:0;margin:0 4px 4px}.sb-chat-history-toggle{border-radius:var(--r-sm);width:100%;min-height:34px;color:var(--text-2);text-align:left;background:0 0;border:1px solid #0000;grid-template-columns:18px minmax(0,1fr) auto 14px;align-items:center;gap:7px;padding:0 7px;display:grid}.sb-chat-history-toggle .ico{place-items:center;display:grid}.sb-chat-history-toggle .label{min-width:0;font-size:12.5px;font-weight:500}.sb-chat-history-toggle em{min-width:18px;color:var(--text-3);text-align:right;font:var(--fs-meta) var(--font-mono);font-style:normal}.sb-chat-history-toggle:hover,.sb-chat-history-toggle[aria-expanded=true]{border-color:var(--border-0);background:var(--bg-1);color:var(--text-0)}.sb-chat-chevron{color:var(--text-3);place-items:center;font-size:13px;transition:transform .16s;display:grid}.sb-chat-history-toggle[aria-expanded=true] .sb-chat-chevron{transform:rotate(180deg)}.sb-chat-history-list{flex-direction:column;gap:2px;min-height:0;max-height:min(30dvh,260px);margin-top:2px;padding:3px;display:flex;overflow-y:auto}.sb-chat-item{border-radius:var(--r-sm);min-width:0;color:var(--text-2);text-align:left;background:0 0;border:1px solid #0000;flex-direction:column;gap:3px;padding:7px 8px;display:flex}.sb-chat-item:hover{background:var(--bg-2)}.sb-chat-item[data-active=true]{border-color:var(--accent-border);background:var(--accent-soft)}.sb-chat-item strong{color:var(--text-1);overflow-wrap:anywhere;-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:12.5px;font-weight:500;line-height:1.3;display:-webkit-box;overflow:hidden}.sb-chat-item span{color:var(--text-3);font:var(--fs-micro) var(--font-mono);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.sb-chat-history-empty{color:var(--text-4);font:var(--fs-meta) var(--font-mono);padding:10px 8px}.sb-cmdk{border:1px solid var(--border-0);background:var(--bg-1);border-radius:var(--r-sm);height:30px;color:var(--text-2);white-space:nowrap;align-items:center;gap:8px;margin:8px 12px 4px;padding:0 8px 0 9px;font-size:12px;display:flex}.sb-cmdk>span{text-align:left;text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.sb-cmdk svg{flex:none}.sb-cmdk:hover{border-color:var(--border-1);background:var(--bg-2);color:var(--text-1)}.sb-cmdk kbd{font-family:var(--font-mono);font-size:var(--fs-meta);border:1px solid var(--border-0);background:var(--bg-2);color:var(--text-2);border-radius:4px;margin-left:auto;padding:2px 5px}.sb-section{font-size:var(--fs-meta);font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.08em;color:var(--text-3);justify-content:space-between;align-items:center;padding:12px 14px 4px;display:flex}.sb-section button{color:var(--text-2);background:0 0;border:0;border-radius:4px;place-items:center;width:18px;height:18px;padding:0;display:grid}.sb-section button:hover{background:var(--bg-2);color:var(--text-0)}.sb-list{flex-direction:column;flex:none;gap:1px;padding:2px 8px;display:flex;overflow:auto}.sb-collections{scrollbar-gutter:stable;flex:0 auto;min-height:0;max-height:min(36dvh,360px);padding-bottom:8px;overflow-y:auto}.sb-manage-section{border-top:1px solid var(--border-0);margin-top:auto}.sb-manage-list{padding-bottom:8px}.sb-item{height:var(--row-h);border-radius:var(--r-sm);color:var(--text-1);text-align:left;cursor:pointer;background:0 0;border:0;grid-template-columns:16px 1fr auto;align-items:center;gap:9px;padding:0 8px;font-size:12.8px;display:grid;position:relative}.sb-item:hover{background:var(--bg-1);color:var(--text-0)}.sb-item[data-active=true]{background:var(--bg-2);color:var(--text-0)}.sb-item[data-active=true]:before{content:"";background:var(--accent);border-radius:99px;width:2px;position:absolute;top:6px;bottom:6px;left:-8px}.sb-item[data-active=true] .ico{color:var(--accent)}.sb-item .ico{width:14px;height:14px;color:var(--text-2);display:inline-flex}.sb-item .label{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.sb-item .count{font-family:var(--font-mono);font-size:var(--fs-meta);color:var(--text-3)}.sb-coll-row{grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:4px;display:grid}.sb-coll{border-radius:var(--r-sm);cursor:pointer;text-align:left;color:var(--text-1);background:0 0;border:0;grid-template-columns:14px 1fr auto;align-items:center;gap:9px;width:100%;padding:6px 10px 6px 8px;display:grid;position:relative}.sb-coll:hover{background:var(--bg-1);color:var(--text-0)}.sb-coll[data-active=true]{background:var(--bg-2);color:var(--text-0)}.sb-coll[data-active=true]:before{content:"";background:var(--accent);border-radius:99px;width:2px;position:absolute;top:8px;bottom:8px;left:-8px}.sb-coll-dot{background:var(--border-2);border-radius:99px;flex-shrink:0;width:8px;height:8px}.sb-coll-meta{flex-direction:column;gap:1px;min-width:0;display:flex}.sb-coll-meta b{text-overflow:ellipsis;white-space:nowrap;font-size:12.8px;font-weight:500;overflow:hidden}.sb-coll-meta span{font-size:var(--fs-meta);color:var(--text-3);font-family:var(--font-mono);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.sb-coll-delete{width:26px;height:26px;color:var(--text-3);background:0 0;border:0;border-radius:4px;place-items:center;padding:0;display:grid}.sb-coll-delete:hover{background:var(--danger-soft);color:var(--danger)}.sb-coll-providers{align-items:center;gap:3px;display:flex}.sb-coll-providers i{background:var(--border-2);border-radius:99px;width:6px;height:6px;display:block}.sb-coll-providers i.google{background:var(--p-google)}.sb-coll-providers i.openrouter{background:var(--p-openrouter)}.sb-coll-providers i.openai{background:var(--p-openai)}.sb-coll-providers i.claude{background:var(--p-claude)}.sb-footer{border-top:1px solid var(--border-0);font-size:var(--fs-meta);color:var(--text-3);font-family:var(--font-mono);flex-direction:column;gap:6px;margin-top:auto;padding:10px 12px;display:flex}.sb-footer-row{justify-content:space-between;align-items:center;gap:8px;display:flex}.sb-status{color:var(--text-2);align-items:center;gap:6px;display:inline-flex}.sb-status:before{content:"";background:var(--success);width:6px;height:6px;box-shadow:0 0 0 3px var(--success-soft);border-radius:99px}.sb-status.offline:before{background:var(--danger);box-shadow:0 0 0 3px var(--danger-soft)}.topbar{z-index:10;border-bottom:1px solid var(--border-0);background:var(--topbar-bg);-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);flex:none;align-items:center;gap:12px;height:48px;padding:0 16px;display:flex;position:relative}.crumbs{color:var(--text-2);align-items:center;gap:6px;font-size:12.5px;display:flex}.crumbs b{color:var(--text-0);font-weight:500}.crumbs .sep{color:var(--text-4)}.topbar-spacer{flex:1}.topbar-actions{align-items:center;gap:6px;display:flex}.topbar-action{border:1px solid var(--border-0);border-radius:var(--r-sm);background:var(--bg-1);height:30px;color:var(--text-2);white-space:nowrap;align-items:center;gap:7px;padding:0 10px;font-size:12px;display:inline-flex}.topbar-action em{color:var(--text-4);font:var(--fs-micro) var(--font-mono);font-style:normal}.topbar-action:hover,.topbar-action[aria-expanded=true]{border-color:var(--border-1);background:var(--bg-2);color:var(--text-0)}.topbar-action.primary{border-color:var(--accent-border);background:var(--accent-soft);color:var(--accent)}.topbar-action.icon-only{justify-content:center;width:30px;padding:0}.icon-btn{border-radius:var(--r-sm);width:32px;height:32px;color:var(--text-2);background:0 0;border:1px solid #0000;place-items:center;padding:0;display:grid}.icon-btn:hover{background:var(--bg-2);color:var(--text-0);border-color:var(--border-0)}.icon-btn.mobile-menu-btn{flex:none;display:none}.main{flex-direction:column;min-width:0;height:100%;min-height:0;display:flex;overflow:hidden}.main-scroll{flex:1;min-height:0;overflow:auto}.view{flex-direction:column;gap:18px;width:100%;max-width:1040px;margin:0 auto;padding:clamp(22px,3vw,44px) clamp(24px,4vw,56px) 96px;display:flex}.btn{background:var(--bg-2);height:32px;color:var(--text-0);border:1px solid var(--border-1);border-radius:var(--r-sm);white-space:nowrap;cursor:pointer;align-items:center;gap:7px;padding:0 12px;font-family:inherit;font-size:12.5px;display:inline-flex}.btn:hover{background:var(--bg-3);border-color:var(--border-2)}.btn svg{width:13px;height:13px}.btn.primary{background:var(--accent);color:var(--accent-ink);box-shadow:0 8px 20px -10px var(--accent);border-color:oklch(85% .13 215);font-weight:500}.btn.primary:hover{background:oklch(82% .13 215)}.btn.ghost{color:var(--text-2);background:0 0;border-color:#0000}.btn.ghost:hover{background:var(--bg-2);color:var(--text-0);border-color:var(--border-0)}.btn.danger{color:var(--danger);background:0 0;border-color:oklch(70% .16 25/.3)}.btn.danger:hover{background:var(--danger-soft);border-color:oklch(70% .16 25/.5)}.btn.sm{gap:5px;height:26px;padding:0 9px;font-size:11.5px}.btn[disabled]{opacity:.4;pointer-events:none}.section-h{align-items:baseline;gap:12px;display:flex}.section-h h2{letter-spacing:-.015em;margin:0;font-size:18px;font-weight:500}.section-h .desc{color:var(--text-2);font-size:12.5px}.panel{border:1px solid var(--border-0);background:var(--bg-1);border-radius:var(--r-lg);overflow:hidden}.panel-head{border-bottom:1px solid var(--border-0);background:linear-gradient(180deg, var(--bg-2), transparent);align-items:center;gap:10px;padding:12px 16px;display:flex}.panel-head h3{letter-spacing:-.005em;margin:0;font-size:13.5px;font-weight:500}.panel-head .sub{color:var(--text-3);font-size:11.5px;font-family:var(--font-mono)}.panel-body{padding:16px}.stat-grid{background:var(--border-0);border-bottom:1px solid var(--border-0);grid-template-columns:repeat(4,1fr);gap:1px;display:grid}.stat{background:var(--bg-1);flex-direction:column;gap:4px;padding:14px 16px;display:flex}.stat .k{font-family:var(--font-mono);font-size:var(--fs-meta);text-transform:uppercase;letter-spacing:.08em;color:var(--text-3)}.stat .v{font-family:var(--font-mono);letter-spacing:-.02em;color:var(--text-0);font-variant-numeric:tabular-nums;font-size:22px}.stat .d{color:var(--text-3);font-size:11px;font-family:var(--font-mono)}.banner{border-radius:var(--r-md);border:1px solid;align-items:center;gap:10px;padding:9px 14px;font-size:12.5px;display:flex}.banner.warn{background:var(--warning-soft);color:oklch(85% .1 75);border-color:oklch(78% .15 75/.3)}.banner.info{background:var(--accent-soft);border-color:var(--accent-border);color:var(--text-0)}.banner.err{background:var(--danger-soft);color:oklch(85% .1 25);border-color:oklch(70% .16 25/.35)}.banner .grow{flex:1}.banner code{font-family:var(--font-mono);background:var(--code-bg);border-radius:4px;padding:1px 5px;font-size:11.5px}.scrim{background:var(--scrim-bg);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);z-index:100;place-items:start center;padding-top:14vh;display:grid;position:fixed;inset:0}.scrim[hidden]{display:none}.cmdk{background:var(--bg-1);border:1px solid var(--border-1);border-radius:var(--r-lg);width:min(640px,92vw);box-shadow:var(--dialog-shadow);flex-direction:column;display:flex;overflow:hidden}.cmdk-input{border-bottom:1px solid var(--border-0);grid-template-columns:38px 1fr auto;align-items:center;height:48px;display:grid}.cmdk-input svg{width:17px;height:17px;color:var(--text-2);justify-self:center}.cmdk-input input{color:var(--text-0);background:0 0;border:0;outline:0;font-family:inherit;font-size:15px}.cmdk-input kbd{font-family:var(--font-mono);font-size:var(--fs-meta);border:1px solid var(--border-0);color:var(--text-2);border-radius:4px;margin-right:12px;padding:2px 6px}.cmdk-list{max-height:50vh;padding:6px;overflow:auto}.cmdk-group-h{font-family:var(--font-mono);font-size:var(--fs-meta);text-transform:uppercase;letter-spacing:.08em;color:var(--text-3);padding:8px 10px 4px}.cmdk-item{border-radius:var(--r-sm);text-align:left;width:100%;height:34px;color:var(--text-1);cursor:pointer;background:0 0;border:0;grid-template-columns:18px 1fr auto;align-items:center;gap:10px;padding:0 10px;font-family:inherit;font-size:13px;display:grid}.cmdk-item:hover,.cmdk-item[data-active=true]{background:var(--bg-2);color:var(--text-0)}.cmdk-item svg{color:var(--text-2);width:14px;height:14px}.cmdk-item .meta{font-family:var(--font-mono);font-size:var(--fs-meta);color:var(--text-3)}.modal-card{background:var(--bg-1);border:1px solid var(--border-1);border-radius:var(--r-lg);width:min(480px,92vw);box-shadow:var(--dialog-shadow);overflow:hidden}.modal-head{border-bottom:1px solid var(--border-0);padding:14px 16px}.modal-head h3{margin:0;font-size:15px;font-weight:500}.modal-head p{color:var(--text-2);margin:4px 0 0;font-size:12.5px}.modal-body{flex-direction:column;gap:10px;padding:14px 16px;display:flex}.modal-body label{color:var(--text-2);font-size:12px}.modal-body input{border-radius:var(--r-sm);border:1px solid var(--border-0);background:var(--bg-2);outline:0;height:32px;padding:0 10px;font-size:12.5px}.modal-body input:focus{border-color:var(--accent-border)}.modal-foot{border-top:1px solid var(--border-0);justify-content:flex-end;gap:8px;padding:12px 16px;display:flex}.theme-toggle{border-radius:var(--r-sm);color:var(--text-2);cursor:pointer;background:0 0;border:1px solid #0000;align-items:center;gap:7px;font-family:inherit;display:inline-flex}.theme-toggle .tt-ico{place-items:center;display:grid}.theme-toggle:hover{background:var(--bg-2);color:var(--text-0);border-color:var(--border-0)}.theme-toggle.icon{place-content:center;width:26px;height:26px;padding:0}.theme-toggle.full{height:28px;padding:0 10px;font-size:12px}.toaster{z-index:200;flex-direction:column;gap:8px;max-width:min(380px,92vw);display:flex;position:fixed;bottom:18px;right:18px}.toast{border-radius:var(--r-md);border:1px solid var(--border-1);background:var(--bg-2);color:var(--text-0);text-align:left;grid-template-columns:18px 1fr;align-items:center;gap:10px;padding:11px 14px;font-size:12.5px;animation:.18s cubic-bezier(.2,.8,.2,1) toast-in;display:grid;box-shadow:0 16px 40px -16px oklch(0% 0 0/.6)}.toast .toast-ico{color:var(--text-2);place-items:center;display:grid}.toast .toast-text{min-width:0}.toast[data-type=success]{border-color:var(--success)}.toast[data-type=success] .toast-ico{color:var(--success)}.toast[data-type=error]{border-color:var(--danger)}.toast[data-type=error] .toast-ico{color:var(--danger)}.toast[data-type=info]{border-color:var(--accent-border)}.toast[data-type=info] .toast-ico{color:var(--accent)}@keyframes toast-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.role-dist{border-top:1px solid var(--border-0);padding:12px 16px}.role-bar{border-radius:99px;gap:2px;height:6px;display:flex;overflow:hidden}.role-bar i{min-width:2px;display:block}.role-bar i.user{background:var(--role-user);border-radius:99px 0 0 99px}.role-bar i.thinking{background:var(--role-reasoning)}.role-bar i.ai{background:var(--role-response);border-radius:0 99px 99px 0}.role-legend{font-size:11px;font-family:var(--font-mono);color:var(--text-2);gap:16px;margin-top:8px;display:flex}.role-legend span{align-items:center;gap:5px;display:inline-flex}.role-legend i{border-radius:99px;width:6px;height:6px}.role-legend i.user{background:var(--role-user)}.role-legend i.thinking{background:var(--role-reasoning)}.role-legend i.ai{background:var(--role-response)}.file-list{max-height:300px;overflow:auto}.file-list-empty{color:var(--text-3);padding:16px;font-size:12px}.file-row{border-bottom:1px solid var(--border-0);grid-template-columns:auto 1fr;align-items:center;gap:12px;padding:8px 16px;font-size:12.5px;display:grid}.file-row i{background:var(--border-2);border-radius:99px;width:6px;height:6px}.file-row .name{font-family:var(--font-mono);color:var(--text-1);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.danger-row{border:1px solid var(--border-0);border-radius:var(--r-md);grid-template-columns:1fr auto;align-items:center;gap:16px;padding:12px 14px;display:grid}.danger-row .title{color:var(--text-0);font-size:13px;font-weight:500}.danger-row .desc{color:var(--text-2);margin-top:3px;font-size:12px}.search-card{background:var(--bg-1);border:1px solid var(--border-0);border-radius:var(--r-md);grid-template-columns:38px 1fr auto;align-items:center;min-height:50px;padding-right:6px;transition:border-color .15s,box-shadow .15s;display:grid}.search-card:focus-within{border-color:var(--accent-border);box-shadow:0 0 0 4px var(--accent-soft)}.search-card .search-ico{width:16px;height:16px;color:var(--text-2);justify-self:center}.search-card input{color:var(--text-0);letter-spacing:-.005em;background:0 0;border:0;outline:0;min-width:0;font-family:inherit;font-size:16px}.search-card input::placeholder{color:var(--text-3)}.search-card .search-clear{border-radius:var(--r-sm);width:30px;height:30px;color:var(--text-3);cursor:pointer;background:0 0;border:0;place-items:center;padding:0;display:grid}.search-card .search-clear:hover,.search-card .search-clear:focus-visible{background:var(--bg-2);color:var(--text-0)}.search-toolbar{flex-wrap:wrap;align-items:center;gap:10px;padding:0 2px;display:flex}.mode-toggle{border:1px solid var(--border-0);border-radius:var(--r-sm);background:var(--bg-1);display:inline-flex;overflow:hidden}.mode-btn{min-height:28px;color:var(--text-3);cursor:pointer;background:0 0;border:0;padding:0 12px;font-family:inherit;font-size:12.5px}.mode-btn+.mode-btn{border-left:1px solid var(--border-0)}.mode-btn[data-on=true]{color:var(--text-0);background:var(--bg-2)}.mode-btn:hover{color:var(--text-0)}.role-chips{gap:4px;display:inline-flex}.role-chip{border:1px solid var(--border-0);min-height:28px;color:var(--text-3);cursor:pointer;background:0 0;border-radius:99px;align-items:center;gap:6px;padding:0 10px;font-family:inherit;font-size:12.5px;display:inline-flex}.role-chip .dot{background:var(--text-4);border-radius:99px;width:6px;height:6px}.role-chip[data-on=true]{color:var(--text-0);border-color:var(--border-1);background:var(--bg-1)}.role-chip[data-role=user][data-on=true] .dot{background:var(--role-user)}.role-chip[data-role=reasoning][data-on=true] .dot{background:var(--role-reasoning)}.role-chip[data-role=response][data-on=true] .dot{background:var(--role-response)}.role-chip:hover{color:var(--text-0)}.model-filter{border:1px solid var(--border-0);border-radius:var(--r-sm);background:var(--bg-1);min-height:30px;color:var(--text-3);font-family:var(--font-mono);grid-template-columns:auto minmax(150px,220px);align-items:center;gap:8px;padding:0 8px;font-size:11.5px;display:inline-grid}.model-filter span{text-transform:uppercase;letter-spacing:.06em}.model-filter input{min-width:0;height:26px;color:var(--text-0);font:12.5px var(--font-sans);background:0 0;border:0;outline:0}.model-filter input::placeholder{color:var(--text-4)}.origin-filter{border-radius:var(--r-sm);min-height:30px;color:var(--text-3);font:11px var(--font-mono);background:oklch(74% .16 165/.06);border:1px solid oklch(74% .16 165/.24);grid-template-columns:auto auto;align-items:center;gap:7px;padding:0 8px;display:inline-grid}.origin-filter span{text-transform:uppercase;letter-spacing:.06em}.origin-filter select{height:26px;color:var(--text-0);font:12px var(--font-sans);background:0 0;border:0;outline:0}.date-filter{border:1px solid var(--border-0);border-radius:var(--r-sm);background:var(--bg-1);min-height:30px;color:var(--text-3);font-family:var(--font-mono);grid-template-columns:auto minmax(118px,142px);align-items:center;gap:8px;padding:0 8px;font-size:11.5px;display:inline-grid}.date-filter span{text-transform:uppercase;letter-spacing:.06em}.date-filter input{min-width:0;height:26px;color:var(--text-0);font:12.5px var(--font-sans);background:0 0;border:0;outline:0}.toolbar-spacer{flex:1}.toolbar-hint{color:var(--text-3);font-size:12px;font-family:var(--font-mono)}.toolbar-hint kbd{font-family:var(--font-mono);font-size:var(--fs-meta);border:1px solid var(--border-0);background:var(--bg-2);color:var(--text-2);border-radius:4px;margin:0 2px;padding:1px 5px}.results-meta-bar{justify-content:space-between;align-items:baseline;gap:10px;margin-top:6px;display:flex}.results-meta-bar .conv-sort{font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.06em;color:var(--text-3);align-items:center;gap:6px;font-size:11px;display:inline-flex}.results-meta-bar .conv-sort select{border:1px solid var(--border-0);border-radius:var(--r-sm);background:var(--bg-1);height:28px;color:var(--text-0);font:12.5px var(--font-sans);text-transform:none;letter-spacing:normal;outline:0;padding:0 6px}.results-meta-bar .conv-sort select:focus{border-color:var(--border-1)}.results-meta-bar .h{min-width:0;font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.08em;color:var(--text-3);flex:1;font-size:11px}.results-meta-bar .h b{color:var(--text-1);margin-left:4px;font-weight:500}.results-meta-bar .conv-filter{border:1px solid var(--border-0);border-radius:var(--r-sm);background:var(--bg-1);width:min(240px,40%);min-width:0;height:28px;color:var(--text-0);font:12.5px var(--font-sans);outline:0;padding:0 10px}.results-meta-bar .conv-filter::placeholder{color:var(--text-4)}.results-meta-bar .conv-filter:focus{border-color:var(--border-1)}.result-list{flex-direction:column;gap:8px;display:flex}.load-more-row{justify-content:center;margin-top:4px;display:flex}.load-more-button{border-radius:var(--r-sm);border:1px solid var(--border-0);background:var(--bg-1);min-height:32px;color:var(--text-1);font:12.5px var(--font-sans);cursor:pointer;padding:0 14px}.load-more-button:hover{border-color:var(--border-2);color:var(--text-0);background:var(--bg-2)}.result{border:1px solid var(--border-0);border-radius:var(--r-md);cursor:pointer;text-align:left;width:100%;color:inherit;background:0 0;grid-template-columns:minmax(0,1fr);gap:6px;padding:15px 18px 13px;font-family:inherit;transition:border-color .12s,background .12s;display:grid;position:relative}.result:hover{border-color:var(--border-1);background:var(--bg-1)}.result:hover .r-snippet{color:var(--text-0)}.result[data-active=true]{border-color:var(--accent-border);background:var(--accent-soft)}.result[data-active=true] .r-snippet{color:var(--text-0)}.result[data-selected=true]{border-color:var(--accent-border);background:var(--accent-soft);box-shadow:inset 2px 0 0 var(--accent)}.result[data-selected=true] .r-snippet{color:var(--text-0)}.open-thread{color:var(--text-2);align-items:center;gap:6px;margin-left:auto;display:inline-flex}.saved-searches{flex-wrap:wrap;align-items:center;gap:6px;margin-top:10px;display:flex}.saved-searches .ss-label{font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.07em;color:var(--text-3);align-items:center;gap:5px;margin-right:4px;font-size:11px;display:inline-flex}.saved-searches .ss-chip{border:1px solid var(--border-0);background:var(--bg-1);border-radius:999px;align-items:stretch;display:inline-flex;overflow:hidden}.saved-searches .ss-chip:hover{border-color:var(--border-1)}.saved-searches .ss-run{max-width:320px;color:var(--text-1);font:12px var(--font-sans);cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:3px 4px 3px 10px;display:inline-flex}.saved-searches .ss-run .ss-q{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.saved-searches .ss-run .ss-tag{background:var(--bg-2);font-family:var(--font-mono);font-size:var(--fs-meta);color:var(--text-3);border-radius:999px;flex:none;padding:1px 6px}.saved-searches .ss-del{color:var(--text-4);cursor:pointer;background:0 0;border:0;padding:0 8px 0 4px;font-size:13px}.saved-searches .ss-del:hover{color:var(--danger,#e05555)}.save-search{border:1px solid var(--border-0);background:var(--bg-1);height:28px;color:var(--text-2);font:12px var(--font-sans);cursor:pointer;border-radius:999px;align-items:center;gap:6px;padding:0 10px;display:inline-flex}.save-search:hover{border-color:var(--border-1);color:var(--text-0)}.save-search[data-on=true]{color:var(--accent);border-color:var(--accent-border,var(--border-1))}.pin-toggle{border-radius:var(--r-sm);width:24px;height:24px;color:var(--text-4);cursor:pointer;opacity:0;justify-content:center;align-items:center;margin-left:auto;transition:opacity .12s,color .12s;display:inline-flex}.result:hover .pin-toggle,.result:focus-within .pin-toggle,.pin-toggle[data-on=true]{opacity:1}.pin-toggle:hover,.pin-toggle:focus-visible,.pin-toggle[data-on=true]{color:var(--accent)}.more-like-this{border:1px solid var(--line);color:var(--text-2);cursor:pointer;border-radius:999px;align-items:center;margin-left:auto;padding:2px 8px;transition:color .15s,border-color .15s;display:inline-flex}.more-like-this:hover,.more-like-this:focus-visible{color:var(--accent);border-color:var(--accent)}.more-like-this+.open-thread{margin-left:0}.result-head{align-items:center;gap:10px;min-width:0;display:flex}.r-role{font-size:11px;font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.06em;border:1px solid var(--border-0);color:var(--text-1);background:var(--bg-2);border-radius:4px;align-items:center;gap:6px;padding:2px 7px;display:inline-flex}.r-role[data-role=user]{color:var(--role-user);border-color:oklch(78% .1 230/.3)}.r-role[data-role=thinking]{color:var(--role-reasoning);border-color:oklch(80% .13 75/.3)}.r-role[data-role=ai]{color:var(--role-response);border-color:oklch(76% .11 155/.3)}.r-provider{color:var(--text-1);align-items:center;gap:6px;font-size:11.5px;display:inline-flex}.r-provider .pdot{background:var(--border-2);border-radius:99px;width:6px;height:6px}.r-source{min-width:0;color:var(--text-2);flex:260px;align-items:center;gap:6px;display:inline-flex}.r-source svg{flex:none}.r-source .slash{color:var(--text-4)}.r-source-coll{flex:none}.r-source-file{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.r-meta-right{font-family:var(--font-mono);color:var(--text-3);align-items:center;gap:12px;margin-left:auto;font-size:11px;display:inline-flex}.r-score{color:var(--text-2);align-items:center;gap:6px;display:inline-flex}.r-score-bar{background:var(--bg-3);border-radius:99px;width:36px;height:4px;position:relative;overflow:hidden}.r-score-bar i{background:linear-gradient(90deg, var(--accent), oklch(70% .16 280));border-radius:99px;height:100%;display:block}.r-title{letter-spacing:-.012em;color:var(--text-0);overflow-wrap:anywhere;min-width:0;font-size:16px;font-weight:600;line-height:1.35}.result:hover .r-title,.result:focus-visible .r-title{text-decoration:underline;-webkit-text-decoration-color:var(--accent);text-decoration-color:var(--accent);text-underline-offset:3px;text-decoration-thickness:2px}.r-snippet{color:var(--text-1);letter-spacing:-.005em;overflow-wrap:anywhere;-webkit-line-clamp:5;-webkit-box-orient:vertical;font-size:14.5px;line-height:1.58;display:-webkit-box;overflow:hidden}.r-snippet mark,.r-snippet .highlight{background:var(--accent-soft);color:var(--text-0);box-shadow:inset 0 -1px 0 var(--accent-border);border-radius:3px;padding:0 2px}.r-foot{min-width:0;color:var(--text-3);font-size:12.5px;font-family:var(--font-mono);flex-wrap:wrap;align-items:center;gap:14px;display:flex}.r-foot .dot{background:var(--text-4);border-radius:99px;width:3px;height:3px}.r-foot b{color:var(--text-1);font-weight:400}.empty{border:1px dashed var(--border-1);border-radius:var(--r-lg);background:var(--empty-bg);flex-direction:column;gap:14px;margin-top:20px;padding:36px 28px;display:flex}.empty h3{letter-spacing:-.01em;margin:0;font-size:15px;font-weight:500}.empty p{color:var(--text-2);max-width:560px;margin:0;font-size:13px}.empty .examples{flex-wrap:wrap;gap:6px;display:flex}.example-chip{border:1px solid var(--border-0);background:var(--bg-1);height:28px;color:var(--text-1);cursor:pointer;border-radius:99px;align-items:center;gap:7px;padding:0 10px;font-family:inherit;font-size:12.5px;display:inline-flex}.example-chip:hover{border-color:var(--border-2);background:var(--bg-2);color:var(--text-0)}.example-chip svg{width:12px;height:12px;color:var(--text-3)}@keyframes shimmer{0%{background-position:0 0}to{background-position:-200% 0}}.shimmer-card{opacity:.55;background:linear-gradient(90deg, var(--bg-1), var(--bg-2), var(--bg-1));border:1px solid var(--border-0);border-radius:var(--r-md);background-size:200% 100%;min-height:80px;padding:13px 16px 11px;animation:1.4s linear infinite shimmer}.thread{flex-direction:column;flex:1;min-width:0;height:100%;min-height:0;animation:.22s cubic-bezier(.4,0,.2,1) thread-in;display:flex;position:relative;overflow:hidden}.thread:before{content:"";background:linear-gradient(90deg, transparent 0%, var(--provider-color,var(--accent)) 12%, var(--provider-color,var(--accent)) 88%, transparent 100%);z-index:10;opacity:.9;height:2px;position:absolute;top:0;left:0;right:0}@keyframes thread-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.thread-bar{background:var(--thread-bar-bg);-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);border-bottom:1px solid var(--border-0);z-index:5;flex:none;align-items:center;gap:14px;min-height:56px;padding:0 16px 0 18px;display:flex;position:sticky;top:0}.thread-bar .title-preview{letter-spacing:-.01em;min-width:0;color:var(--text-0);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:14px;font-weight:500;overflow:hidden}.thread-bar .bar-meta{font-family:var(--font-mono);color:var(--text-2);border-right:1px solid var(--border-0);flex:none;align-items:center;gap:7px;height:22px;padding-right:12px;font-size:11px;display:inline-flex}.thread-bar .bar-meta .pdot{background:var(--provider-color,var(--accent));width:6px;height:6px;box-shadow:0 0 0 2px color-mix(in oklch, var(--provider-color,var(--accent)) 25%, transparent);border-radius:99px}.thread-bar .bar-model{color:var(--text-1);white-space:nowrap}.thread-bar .path-crumb{font-family:var(--font-mono);color:var(--text-3);text-overflow:ellipsis;white-space:nowrap;flex:0 auto;max-width:340px;font-size:11px;overflow:hidden}.thread-bar .path-crumb .coll{color:var(--text-2)}.thread-bar .path-crumb .sl{color:var(--text-4);margin:0 5px}.thread-bar kbd{font-family:var(--font-mono);font-size:var(--fs-meta);border:1px solid var(--border-0);background:var(--bg-2);color:var(--text-2);border-radius:4px;padding:2px 5px}.thread-back{background:var(--bg-2);border:1px solid var(--border-1);border-radius:var(--r-sm);height:32px;color:var(--text-0);flex:none;align-items:center;gap:8px;padding:0 12px 0 9px;font-family:inherit;font-size:12.5px;font-weight:500;display:inline-flex}.thread-back:hover{background:var(--bg-3);border-color:var(--border-2)}.thread-back svg{width:14px;height:14px}.thread-inner{background:radial-gradient(900px 380px at 50% 0%, color-mix(in oklch, var(--provider-color,var(--accent)) 14%, transparent), transparent 70%), radial-gradient(800px 400px at 50% 0%, var(--thread-glow-2), transparent 60%);flex-direction:column;flex:auto;align-items:center;min-height:0;display:flex;overflow:auto}.thread-hero{flex-direction:column;gap:16px;width:100%;max-width:960px;padding:clamp(28px,4vw,52px) clamp(24px,4vw,56px) 28px;display:flex}.thread-hero h1{letter-spacing:-.025em;color:var(--text-0);margin:0;font-size:clamp(30px,2.3vw,48px);font-weight:500;line-height:1.18}.thread-hero .meta-row{font-family:var(--font-mono);color:var(--text-2);border-top:1px solid var(--border-0);flex-wrap:wrap;align-items:center;gap:8px 14px;margin-top:6px;padding-top:4px;font-size:11.5px;display:flex}.thread-hero .meta-row .item{align-items:baseline;gap:6px;display:inline-flex}.thread-hero .meta-row .k{color:var(--text-4)}.thread-hero .meta-row .v{color:var(--text-1)}.thread-hero .meta-row .v.match{color:var(--accent)}.thread-hero .meta-row .sep{color:var(--text-4)}.thread-actions-bar{flex-wrap:wrap;align-items:center;gap:8px;width:100%;max-width:960px;padding:0 clamp(24px,4vw,56px) 16px;display:flex}.role-toggles{background:var(--bg-1);border:1px solid var(--border-0);border-radius:var(--r-sm);gap:2px;padding:2px;display:inline-flex}.role-toggle{height:22px;color:var(--text-3);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:4px;align-items:center;gap:6px;padding:0 8px;font-size:11.5px;display:inline-flex;position:relative}.role-toggle input{opacity:0;pointer-events:none;position:absolute}.role-toggle .rt-dot{background:var(--text-4);border-radius:99px;width:6px;height:6px;transition:background .15s}.role-toggle:hover{color:var(--text-1)}.role-toggle[data-on=true]{background:var(--bg-3);color:var(--text-0);box-shadow:inset 0 0 0 1px var(--border-1)}.role-toggle[data-on=true][data-role=user] .rt-dot{background:var(--role-user)}.role-toggle[data-on=true][data-role=thinking] .rt-dot{background:var(--role-reasoning)}.role-toggle[data-on=true][data-role=ai] .rt-dot{background:var(--role-response)}.role-toggle[data-on=true][data-role=threadshelf] .rt-dot{background:oklch(74% .16 165)}.turn-stub{grid-template-columns:44px 1fr;align-items:start}.turn-stub .reasoning-stub{border:1px dashed var(--reasoning-border-strong);height:24px;color:var(--text-3);font-size:11px;font-family:var(--font-mono);cursor:pointer;background:0 0;border-radius:99px;grid-column:2;place-self:start;align-items:center;gap:8px;margin-top:2px;margin-left:0;padding:0 10px 0 4px;display:inline-flex}.turn-stub .reasoning-stub:hover{color:var(--text-1);border-color:var(--reasoning-border-active);background:var(--reasoning-bg)}.turn-stub .reasoning-stub .rs-r{background:var(--reasoning-bg-pill);width:18px;height:18px;color:var(--role-reasoning);font-weight:500;font-size:var(--fs-meta);border:1px solid var(--reasoning-border-strong);border-radius:99px;place-items:center;display:inline-grid}.turn-stub .reasoning-stub .rs-label{text-transform:lowercase;letter-spacing:0}.turn-stub .reasoning-stub .rs-idx{color:var(--text-4)}.turn-stub .reasoning-stub .rs-chevron{color:var(--text-3);text-align:center;width:10px;margin-left:2px;font-size:12px}.turn-stub .reasoning-stub[data-open=true]{background:var(--reasoning-bg);color:var(--text-1);border-style:solid}.turn-stub .reasoning-stub-body{color:var(--text-2);background:var(--reasoning-bg-strong);border:1px solid var(--reasoning-border);border-left-width:2px;border-left-color:var(--reasoning-border-active);border-radius:var(--r-md);white-space:pre-wrap;grid-column:2;margin-top:8px;padding:12px 14px;font-size:13px;font-style:italic;line-height:1.6}.thread-end{font-family:var(--font-mono);font-size:var(--fs-meta);text-transform:uppercase;letter-spacing:.18em;color:var(--text-4);z-index:1;justify-content:center;align-items:center;gap:10px;padding:28px 0 8px;display:flex;position:relative}.thread-end:before,.thread-end:after{content:"";background:linear-gradient(90deg, transparent, var(--border-0), transparent);flex:0 80px;height:1px}.thread-end .dot{background:var(--text-4);border-radius:99px;width:3px;height:3px}.thread-body{flex-direction:column;gap:22px;width:100%;max-width:960px;padding:8px clamp(24px,4vw,56px) 140px;display:flex;position:relative}.thread-body:before{content:"";background:linear-gradient(180deg, transparent, var(--border-0) 8%, var(--border-0) 88%, transparent);width:1px;position:absolute;top:12px;bottom:60px;left:56px}.turn{grid-template-columns:44px 1fr;align-items:start;gap:18px;display:grid;position:relative}.turn[data-standalone=true]{grid-template-columns:minmax(0,1fr);gap:6px;margin:0 0 20px}.turn[data-standalone=true] .turn-content{min-width:0}.turn[data-standalone=true][data-role=user]{justify-items:end}.turn[data-standalone=true][data-role=user] .turn-content{border:1px solid var(--accent-border);background:var(--accent-soft);border-radius:14px 14px 4px;max-width:min(80%,640px);padding:9px 14px}.turn[data-standalone=true][data-role=user] .turn-body{font-size:15.5px}.turn-avatar{background:var(--bg-1);border:1px solid var(--border-0);width:28px;height:28px;color:var(--text-2);z-index:1;font-family:var(--font-mono);border-radius:7px;place-items:center;margin-top:2px;margin-left:8px;font-size:11px;font-weight:500;display:grid;position:relative}.turn[data-role=user] .turn-avatar{color:var(--role-user);border-color:oklch(78% .1 230/.35)}.turn[data-role=thinking] .turn-avatar{color:var(--role-reasoning);border-color:var(--reasoning-border-strong)}.turn[data-role=ai] .turn-avatar{color:var(--role-response);border-color:oklch(76% .11 155/.35)}.turn[data-matched=true] .turn-avatar{background:var(--accent);color:var(--accent-ink);border-color:var(--accent);box-shadow:0 0 0 4px var(--accent-soft)}.turn[data-origin=threadshelf] .turn-avatar{color:oklch(82% .14 165);background:oklch(74% .16 165/.1);border-color:oklch(74% .16 165/.62);box-shadow:0 0 0 3px oklch(74% .16 165/.08)}.turn[data-origin=threadshelf] .turn-body{border-left:2px solid oklch(74% .16 165/.48);padding-left:12px}.threadshelf-turn-badge{color:oklch(82% .14 165);min-height:18px;font:600 9px var(--font-mono);letter-spacing:.03em;text-transform:none;background:oklch(74% .16 165/.1);border:1px solid oklch(74% .16 165/.38);border-radius:99px;align-items:center;padding:1px 7px;display:inline-flex}.turn-content{min-width:0}.turn-head{font-family:var(--font-mono);font-size:var(--fs-meta);color:var(--text-3);text-transform:uppercase;letter-spacing:.08em;align-items:center;gap:10px;height:24px;margin-bottom:6px;display:flex}.turn-head .role-tag{color:var(--text-1);font-weight:500}.turn-head .turn-idx{color:var(--text-4)}.turn-head .turn-date{color:var(--text-3);text-transform:none;letter-spacing:0;margin-left:2px}.turn-head .match-pill{background:var(--accent-soft);color:var(--accent);border:1px solid var(--accent-border);text-transform:uppercase;letter-spacing:.1em;font-size:var(--fs-micro);border-radius:99px;margin-left:auto;padding:2px 8px;font-weight:600}.turn-head .copy-turn{color:var(--text-2);text-transform:none;letter-spacing:0;font-family:var(--font-mono);font-size:var(--fs-meta);opacity:0;cursor:pointer;background:0 0;border:0;border-radius:4px;margin-left:auto;padding:2px 6px;transition:opacity .12s}.turn-head .copy-turn:hover{background:var(--bg-2);color:var(--text-0)}.turn[data-role=user] .turn-head .role-tag{color:var(--role-user)}.turn[data-role=thinking] .turn-head .role-tag{color:var(--role-reasoning)}.turn[data-role=ai] .turn-head .role-tag{color:var(--role-response)}.turn:hover .turn-head .copy-turn{opacity:1;color:var(--text-1)}.turn-body{color:var(--text-0);white-space:pre-wrap;word-break:break-word;letter-spacing:-.003em;font-size:16.5px;line-height:1.7;position:relative}.turn-body[data-collapsed=true]{max-height:18rem;overflow:hidden}.turn-body[data-collapsed=true]:after{content:"";pointer-events:none;background:linear-gradient(180deg, transparent, var(--bg-0) 84%);height:6rem;position:absolute;inset:auto 0 0}.turn[data-role=user] .turn-body{color:var(--text-1);font-size:16px}.turn[data-role=thinking] .turn-body{color:var(--text-2);background:var(--reasoning-bg-strong);border:1px solid var(--reasoning-border);border-radius:var(--r-md);border-left-width:2px;border-left-color:var(--reasoning-border-active);padding:12px 14px 12px 16px;font-size:15px;font-style:italic}.show-more{border-radius:var(--r-sm);border:1px solid var(--border-0);background:var(--bg-1);height:30px;color:var(--text-1);font:500 12.5px var(--font-sans);margin-top:10px;padding:0 11px}.show-more:hover{background:var(--bg-2);border-color:var(--border-1);color:var(--text-0)}.turn[data-matched=true] .turn-body{background:linear-gradient(180deg, var(--accent-soft), transparent 80%);border:1px solid var(--accent-border);border-radius:var(--r-md);box-shadow:0 12px 40px -24px var(--accent);padding:14px 18px}.turn[data-matched=true] mark{color:var(--text-0);box-shadow:inset 0 -1px 0 var(--accent);background:oklch(100% 0 0/.08);border-radius:3px;padding:0 3px;font-weight:500}.drop-zone{border:1.5px dashed var(--border-1);border-radius:var(--r-lg);background:linear-gradient(180deg, var(--bg-1), transparent);text-align:center;flex-direction:column;align-items:center;gap:12px;padding:28px 24px;transition:border-color .12s,background .12s;display:flex}.drop-zone[data-dragging=true]{border-color:var(--accent);background:var(--accent-soft)}.drop-zone .ico-big{border-radius:var(--r-md);background:var(--bg-2);border:1px solid var(--border-0);width:44px;height:44px;color:var(--text-1);place-items:center;display:grid}.drop-zone h3{margin:0;font-size:15px;font-weight:500}.drop-zone p{color:var(--text-2);max-width:480px;margin:0;font-size:12.5px}.drop-zone .path-input{grid-template-columns:1fr auto;gap:8px;width:100%;max-width:480px;display:grid}.drop-zone input[type=text]{border-radius:var(--r-sm);border:1px solid var(--border-0);background:var(--bg-2);height:32px;font-family:var(--font-mono);outline:none;padding:0 10px;font-size:12px}.drop-zone input[type=text]:focus{border-color:var(--accent-border)}.ingest-options{flex-wrap:wrap;align-items:center;gap:16px;padding:12px 0 0;display:flex}.ingest-options label{color:var(--text-1);cursor:pointer;align-items:center;gap:6px;font-size:12.5px;display:inline-flex}.ingest-options input[type=checkbox]{accent-color:var(--accent)}.ingest-options select{border-radius:var(--r-sm);border:1px solid var(--border-0);background:var(--bg-2);outline:none;height:28px;padding:0 8px;font-size:12px}.progress-panel{border:1px solid var(--border-0);border-radius:var(--r-lg);background:var(--bg-1);overflow:hidden}.progress-head{border-bottom:1px solid var(--border-0);align-items:center;gap:10px;padding:12px 16px;display:flex}.progress-head .step{font-family:var(--font-mono);color:var(--text-2);font-size:11px}.progress-head .step b{color:var(--text-0);font-weight:500}.progress-head .pct{font-family:var(--font-mono);color:var(--accent);margin-left:auto;font-size:13px}.progress-bar-new{background:var(--bg-2);height:4px;overflow:hidden}.progress-bar-new i{background:linear-gradient(90deg, var(--accent), oklch(70% .16 280));height:100%;transition:width .18s ease-out;display:block}.progress-details-new{font-family:var(--font-mono);color:var(--text-2);flex-wrap:wrap;gap:16px;padding:10px 14px;font-size:11.5px;display:flex}.progress-details-new strong{color:var(--text-0);font-weight:500}.progress-file{font-family:var(--font-mono);color:var(--text-3);white-space:nowrap;text-overflow:ellipsis;padding:0 14px 10px;font-size:11px;overflow:hidden}.insights-view{flex-direction:column;gap:14px;display:flex}.insights-head{justify-content:space-between;align-items:flex-end;gap:10px;display:flex}.insights-head h2{color:var(--text-0);margin:0;font-size:18px;font-weight:600}.insights-head .insights-range{font-family:var(--font-mono);color:var(--text-3);margin:2px 0 0;font-size:11.5px}.insights-scope{font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.06em;color:var(--text-3);flex:none;align-items:center;gap:6px;font-size:11px;display:inline-flex}.insights-scope select{border:1px solid var(--border-0);border-radius:var(--r-sm);background:var(--bg-1);height:28px;color:var(--text-0);font:12.5px var(--font-sans);text-transform:none;letter-spacing:normal;outline:0;padding:0 6px}.insights-scope select:focus{border-color:var(--border-1)}.stat-tiles{grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:10px;display:grid}.stat-tile{border:1px solid var(--border-0);border-radius:var(--r-md);background:var(--bg-1);flex-direction:column;gap:4px;padding:12px 14px;display:flex}.stat-tile .stat-label{font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.07em;color:var(--text-3);font-size:11px}.stat-tile .stat-value{color:var(--text-0);font-size:24px;font-weight:600}.insight-card{border:1px solid var(--border-0);border-radius:var(--r-md);background:var(--bg-1);min-width:0;padding:14px 16px 16px}.insight-card h3{color:var(--text-1);margin:0;font-size:13.5px;font-weight:600}.insight-card .insight-sub{color:var(--text-3);margin:2px 0 12px;font-size:12px}.insight-grid{grid-template-columns:1fr 1fr;gap:14px;display:grid}@media (width<=860px){.insight-grid{grid-template-columns:1fr}}.chart-empty{color:var(--text-3);margin:8px 0 0;font-size:12.5px}.activity-chart{height:190px;padding-bottom:18px;position:relative}.chart-grid{pointer-events:none;flex-direction:column;justify-content:space-between;display:flex;position:absolute;inset:0 0 18px}.chart-grid .grid-row{align-items:center;gap:6px;height:0;display:flex}.chart-grid .grid-tick{text-align:right;min-width:30px;font-family:var(--font-mono);font-size:var(--fs-meta);color:var(--text-4);flex:none;transform:translateY(-1px)}.chart-grid .grid-line{background:var(--border-0);flex:1;height:1px}.chart-cols{align-items:flex-end;gap:2px;display:flex;position:absolute;inset:0 0 18px 40px}.col-slot{flex:1;justify-content:center;align-items:flex-end;min-width:0;height:100%;display:flex;position:relative}.col-slot .col-bar{background:var(--accent);border-radius:4px 4px 0 0;width:100%;max-width:24px;transition:opacity .1s}.col-slot:hover .col-bar,.col-slot .col-bar[data-hover=true]{opacity:.85}.col-slot .col-peak{font-family:var(--font-mono);font-size:var(--fs-meta);color:var(--text-2);white-space:nowrap;position:absolute;top:-4px;left:50%;transform:translate(-50%,-100%)}.chart-tip{border:1px solid var(--border-1);border-radius:var(--r-sm);background:var(--bg-0);white-space:nowrap;z-index:5;pointer-events:none;flex-direction:column;gap:1px;padding:6px 9px;display:flex;position:absolute;bottom:calc(100% + 6px);left:50%;transform:translate(-50%);box-shadow:0 4px 14px #0000002e}.chart-tip b{color:var(--text-0);font-size:11.5px;font-weight:600}.chart-tip span{font-family:var(--font-mono);color:var(--text-2);font-size:11px}.chart-x{gap:2px;display:flex;position:absolute;inset:auto 0 0 40px}.chart-x .x-slot{text-align:center;min-width:0;font-family:var(--font-mono);font-size:var(--fs-meta);color:var(--text-4);white-space:nowrap;flex:1;overflow:visible}.bar-list{flex-direction:column;gap:8px;display:flex}.bar-row{grid-template-columns:minmax(90px,150px) 1fr auto;align-items:center;gap:10px;min-width:0;display:grid}.bar-row .bar-label{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--text-1);font-size:12px;overflow:hidden}.bar-row .bar-label .mono{font-family:var(--font-mono);font-size:11.5px}.bar-row .provider-label{align-items:center;gap:6px;display:inline-flex}.bar-row .provider-label .pdot{border-radius:99px;flex:none;width:7px;height:7px}.bar-row .bar-track{align-items:center;height:12px;display:flex}.bar-row .bar-fill{background:var(--accent);border-radius:0 4px 4px 0;min-width:2px;height:12px}.bar-row .bar-value{font-family:var(--font-mono);color:var(--text-2);font-variant-numeric:tabular-nums;font-size:11px}.longest-list{flex-direction:column;display:flex}.longest-row{border:0;border-bottom:1px solid var(--border-0);width:100%;color:inherit;text-align:left;cursor:pointer;background:0 0;align-items:center;gap:10px;min-width:0;padding:8px 6px;display:flex}.longest-row:last-child{border-bottom:0}.longest-row:hover{background:var(--bg-2)}.longest-row .rank{font-family:var(--font-mono);color:var(--text-4);text-align:right;flex:0 0 18px;font-size:11px}.longest-row .pdot{border-radius:99px;flex:none;width:7px;height:7px}.longest-row .l-title{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--text-1);flex:1;font-size:13px;overflow:hidden}.longest-row .l-meta{font-family:var(--font-mono);color:var(--text-3);flex:none;font-size:11px}.alpha-badge{background:var(--warning-soft);color:oklch(85% .1 75);width:fit-content;min-height:18px;font:600 9.5px var(--font-mono);letter-spacing:.07em;text-transform:uppercase;border:1px solid oklch(78% .15 75/.38);border-radius:99px;align-items:center;padding:1px 7px;display:inline-flex}.generation-settings{flex-direction:column;gap:14px;display:flex}.generation-panel .generation-form{grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;display:grid}.generation-panel .generation-form>label:not(.check-field){color:var(--text-2);flex-direction:column;gap:6px;font-size:12px;display:flex}.generation-panel .generation-form input:not([type=checkbox]),.generation-panel .generation-form textarea{border:1px solid var(--border-0);border-radius:var(--r-sm);background:var(--bg-2);width:100%;min-height:34px;color:var(--text-0);font:12px var(--font-mono);resize:vertical;outline:none;padding:7px 10px}.generation-panel .generation-form input:not([type=checkbox]):focus,.generation-panel .generation-form textarea:focus{border-color:var(--accent-border)}.generation-panel .generation-form .setup-note,.generation-panel .generation-form .generation-actions,.generation-panel .generation-form .llama-runtime-config{grid-column:1/-1}.generation-panel .generation-form label:has(textarea){grid-column:1/-1}.generation-panel .generation-form .short-field{max-width:220px}.llama-runtime-config{border:1px solid var(--border-0);border-radius:var(--r-md);background:var(--bg-1);grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;padding:12px;display:grid}.llama-runtime-config label{min-width:0;color:var(--text-2);flex-direction:column;gap:6px;font-size:12px;display:flex}.llama-runtime-config select{border:1px solid var(--border-0);border-radius:var(--r-sm);background:var(--bg-2);width:100%;min-height:34px;color:var(--text-0);font:12px var(--font-mono);padding:6px 9px}.llama-runtime-config small{color:var(--text-3);font:var(--fs-meta)/1.45 var(--font-mono)}.directory-picker-launch{align-items:center;gap:8px;margin-top:2px;display:flex}.field-error{color:var(--danger);font:var(--fs-meta)/1.4 var(--font-mono)}.directory-picker{border:1px solid var(--accent-border);border-radius:var(--r-md);background:var(--bg-1);flex-direction:column;gap:8px;margin-top:4px;padding:10px;display:flex}.directory-picker-bar{grid-template-columns:auto minmax(0,1fr) auto auto;gap:6px;display:grid}.directory-picker-roots{flex-wrap:wrap;gap:5px;display:flex}.directory-picker-roots button{border:1px solid var(--border-0);background:var(--bg-2);color:var(--text-2);font:var(--fs-meta) var(--font-mono);cursor:pointer;border-radius:99px;padding:3px 7px}.directory-picker-list{border:1px solid var(--border-0);border-radius:var(--r-sm);background:var(--bg-2);max-height:210px;display:grid;overflow:auto}.directory-picker-list button{border:0;border-bottom:1px solid var(--border-0);color:var(--text-1);text-align:left;font:11px var(--font-mono);cursor:pointer;background:0 0;gap:7px;padding:7px 9px;display:flex}.directory-picker-list button:hover{background:var(--accent-soft)}.directory-picker-list>span{color:var(--text-3);font:11px var(--font-mono);padding:12px}.directory-picker-foot{justify-content:space-between;align-items:center;gap:10px;display:flex}.directory-picker-foot>span{min-width:0;color:var(--text-3);font:var(--fs-meta) var(--font-mono);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.setup-note{color:var(--text-2);font-size:12px;line-height:1.6}.setup-note code{background:var(--code-bg);color:var(--text-1);font:11px var(--font-mono);border-radius:4px;padding:2px 5px}.check-field{color:var(--text-1);align-items:flex-start;gap:8px;font-size:12.5px;line-height:1.45;display:flex}.check-field input{accent-color:var(--accent);margin-top:2px}.openrouter-zdr-option{color:var(--text-2);font:11px var(--font-mono);align-items:center;gap:7px;padding:0 2px;display:flex}.openrouter-zdr-option input{accent-color:var(--accent)}.openrouter-zdr-option span{color:var(--text-4)}.llama-diagnostics{border:1px solid var(--border-0);border-radius:var(--r-md);background:var(--bg-1);margin-top:12px;overflow:hidden}.llama-placement{border-bottom:1px solid var(--border-0);justify-content:space-between;align-items:flex-start;gap:12px;padding:10px 12px;display:flex}.llama-placement>div:first-child{flex-direction:column;gap:3px;min-width:0;display:flex}.llama-placement strong{color:var(--text-1);font:600 11px var(--font-mono)}.llama-placement span{color:var(--text-3);font:var(--fs-meta)/1.45 var(--font-mono)}.chat-create-actions{flex:none;align-items:center;gap:5px;display:flex}.chat-create-actions .btn{height:30px;margin:0}.chat-create-actions .icon-only{width:30px;padding:0}.llama-buffer-split{text-align:right;max-width:46%}.llama-memory-warning{background:var(--warning-soft);color:var(--text-1);border-bottom:1px solid oklch(78% .15 75/.28);padding:9px 12px;font-size:11px;line-height:1.5}.llama-log-details summary{color:var(--text-2);font:var(--fs-meta) var(--font-mono);cursor:pointer;justify-content:space-between;gap:12px;padding:9px 12px;list-style-position:inside;display:flex}.llama-log-details summary span:last-child{color:var(--text-4);text-transform:uppercase;margin-left:auto}.llama-log-details pre{border-top:1px solid var(--border-0);background:var(--code-bg);max-height:360px;color:var(--text-2);font:var(--fs-meta)/1.5 var(--font-mono);white-space:pre-wrap;word-break:break-word;margin:0;padding:12px;overflow:auto}.llama-log-toolbar{border-top:1px solid var(--border-0);color:var(--text-4);font:var(--fs-micro) var(--font-mono);justify-content:space-between;align-items:center;gap:10px;padding:7px 12px;display:flex}.generation-actions{color:var(--text-2);font:11.5px var(--font-mono);flex-wrap:wrap;align-items:center;gap:10px;display:flex}.provider-status{border-left:2px solid var(--danger);padding-left:10px}.provider-status[data-ready=true]{border-left-color:var(--success)}.thread-continuation{display:contents}.turn-model{max-width:min(260px,42vw);color:var(--text-4);font:var(--fs-meta) var(--font-mono);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.generated-reasoning{border:1px solid var(--reasoning-border);border-radius:var(--r-sm);background:var(--reasoning-bg);color:var(--text-2);margin:0 0 10px;padding:8px 10px;font-size:12px}.generated-reasoning summary{cursor:pointer;color:var(--role-reasoning);font-family:var(--font-mono)}.generated-reasoning div{white-space:pre-wrap;margin-top:8px}.stream-fragment{white-space:pre-wrap}.stream-copy-button{border-radius:var(--r-sm);width:max-content;color:var(--text-3);cursor:pointer;font:var(--fs-meta) var(--font-mono);background:0 0;border:0;margin-top:8px;padding:3px 7px}.stream-copy-button:hover,.stream-copy-button:focus-visible{background:var(--bg-2);color:var(--text-1)}.interrupted-generation{border:1px solid color-mix(in oklch, var(--danger) 35%, var(--border-0));border-radius:var(--r-md);background:color-mix(in oklch, var(--danger-soft) 35%, var(--bg-1));margin:4px 0;padding:12px 14px}.interrupted-generation>header{justify-content:space-between;align-items:flex-start;gap:12px;margin-bottom:10px;display:flex}.interrupted-generation>header>div:first-child{flex-direction:column;gap:3px;min-width:0;display:flex}.interrupted-generation>header strong{color:var(--danger);font-size:12px}.interrupted-generation>header span{color:var(--text-4);font:var(--fs-micro) var(--font-mono);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.interrupted-generation>footer{max-height:240px;color:var(--danger);font:var(--fs-meta)/1.45 var(--font-mono);overflow-wrap:anywhere;white-space:pre-wrap;margin-top:10px;overflow:auto}.interrupted-generation-actions{flex:none;gap:6px;display:flex}.interrupted-prompt{margin-bottom:10px}.interrupted-prompt span{color:var(--text-4);font:var(--fs-micro) var(--font-mono);text-transform:uppercase}.interrupted-prompt p{color:var(--text-2);white-space:pre-wrap;margin:3px 0 0;font-size:12px}.interrupted-answer{color:var(--text-1);white-space:pre-wrap}.interrupted-answer em{color:var(--text-4);font-size:11px}.continue-card{border:1px solid var(--border-0);border-radius:var(--r-md);background:var(--bg-1);z-index:1;flex-direction:column;gap:12px;margin-top:10px;padding:12px;display:flex;position:relative}.continue-card>.banner.err{overflow-wrap:anywhere;white-space:pre-wrap;max-height:240px;overflow:auto}.continue-card textarea{resize:vertical;border:1px solid var(--border-1);border-radius:var(--r-md);background:var(--bg-0);width:100%;color:var(--text-0);font:14px/1.55 var(--font-sans);outline:none;padding:11px 12px}.continue-card textarea:focus{border-color:var(--accent)}.continue-head{justify-content:space-between;align-items:center;gap:12px;display:flex}.continue-head>div{align-items:center;gap:8px;display:flex}.continue-head strong{font-size:14px;font-weight:500}.continue-head>span{color:var(--text-3);font:var(--fs-meta) var(--font-mono)}.continue-controls{grid-template-columns:132px minmax(180px,1fr) 30px;gap:8px;display:grid}.continue-controls select,.continue-controls input{border:1px solid var(--border-0);border-radius:var(--r-sm);background:var(--bg-2);min-width:0;height:30px;color:var(--text-1);font:11.5px var(--font-mono);outline:none;padding:0 8px}.continue-controls select:focus,.continue-controls input:focus{border-color:var(--accent-border)}.continue-controls .icon-only{place-items:center;width:30px;padding:0;display:grid}.runtime-details{border:1px solid var(--border-0);border-radius:var(--r-sm);background:color-mix(in oklch, var(--bg-2) 55%, transparent)}.runtime-details[data-state=ready] .runtime-dot,.runtime-details[data-state=external] .runtime-dot{background:var(--success)}.runtime-details[data-state=starting] .runtime-dot,.runtime-details[data-state=loading] .runtime-dot{background:var(--warning);animation:1.2s ease-in-out infinite generation-pulse}.runtime-details[data-state=remote] .runtime-dot{background:var(--accent)}.runtime-details>summary{min-height:34px;color:var(--text-3);cursor:pointer;font:var(--fs-meta) var(--font-mono);grid-template-columns:8px minmax(0,auto) minmax(0,1fr) auto;align-items:center;gap:8px;padding:0 10px;list-style:none;display:grid}.runtime-details>summary::-webkit-details-marker{display:none}.runtime-details>summary strong,.runtime-details>summary span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.runtime-details>summary strong{color:var(--text-1);font-weight:500}.runtime-details>summary em{color:var(--text-4);text-transform:uppercase;font-style:normal}.runtime-details[open]>summary{border-bottom:1px solid var(--border-0)}.runtime-details .model-runtime{border:0;border-bottom:1px solid var(--border-0);background:0 0;border-radius:0;margin:0}.runtime-details .llama-diagnostics{border:0;border-radius:0;margin:0}.turn-generation-metrics{color:var(--text-4);font:var(--fs-micro) var(--font-mono);flex-wrap:wrap;align-items:baseline;gap:7px;margin-top:8px;display:flex}.turn-generation-metrics strong{color:var(--success);font-size:11px}.generation-budget{border-bottom:1px solid var(--border-0);color:var(--text-3);font:var(--fs-meta) var(--font-mono);grid-template-columns:minmax(0,1fr);align-items:center;gap:12px;padding:9px 12px;display:grid}.generation-budget strong{color:var(--text-1);font-weight:500}.generation-budget-field{grid-template-columns:minmax(110px,1fr) 19ch auto;align-items:center;gap:7px;width:100%;display:grid}.generation-budget-field .number-combobox{width:19ch}.generation-context-apply{min-width:52px}.number-combobox{min-width:0;position:relative}.number-combobox>input{border:1px solid var(--border-1);border-radius:var(--r-sm);background:var(--bg-2);width:100%;height:28px;color:var(--text-0);font:11px var(--font-mono);outline:none;padding:0 24px 0 8px}.number-combobox>input:focus{border-color:var(--accent)}.number-combobox>input[aria-invalid=true]{border-color:var(--danger)}.number-combobox-toggle{border-radius:var(--r-sm);width:20px;height:20px;color:var(--text-3);font-size:var(--fs-meta);background:0 0;border:0;place-items:center;padding:0;display:grid;position:absolute;top:50%;right:2px;translate:0 -50%}.number-combobox-toggle:hover{color:var(--text-1)}.number-combobox-popover{z-index:30;scrollbar-gutter:stable;border:1px solid var(--border-1);border-radius:var(--r-sm);background:var(--bg-1);max-height:210px;box-shadow:0 12px 30px -12px var(--bg-0);display:grid;position:absolute;top:calc(100% + 4px);left:0;right:0;overflow:hidden auto}.number-combobox-popover button{color:var(--text-1);text-align:left;font:var(--fs-meta) var(--font-mono);white-space:nowrap;background:0 0;border:0;padding:6px 8px}.number-combobox-popover button[data-active=true]{background:var(--accent-soft)}.number-combobox-popover button[data-selected=true]{color:var(--accent)}.master-prompt{flex:none;position:relative}.master-prompt-chip{border:1px dashed var(--border-1);max-width:130px;height:32px;color:var(--text-3);font:11.5px var(--font-mono);text-overflow:ellipsis;white-space:nowrap;background:0 0;border-radius:99px;padding:0 10px;overflow:hidden}.master-prompt-chip:hover{border-color:var(--accent-border);color:var(--text-1)}.master-prompt-chip[data-active=true]{border-style:solid;border-color:var(--accent-border);background:var(--accent-soft);color:var(--accent)}.master-prompt-popover{z-index:40;width:min(380px,100vw - 24px);max-height:min(520px, var(--master-popover-available-height,520px));overscroll-behavior:contain;scrollbar-gutter:stable;border:1px solid var(--border-1);border-radius:var(--r-md);background:var(--bg-1);box-shadow:0 18px 48px -18px var(--bg-0);transform:translateX(var(--master-popover-shift-x,0));flex-direction:column;gap:8px;padding:10px;display:flex;position:absolute;bottom:calc(100% + 8px);left:0;overflow-y:auto}.master-prompt-popover input,.master-prompt-popover textarea{border:1px solid var(--border-1);border-radius:var(--r-sm);background:var(--bg-2);width:100%;color:var(--text-0);font:11.5px/1.5 var(--font-mono);resize:vertical;outline:none;padding:6px 8px}.master-prompt-popover input:focus,.master-prompt-popover textarea:focus{border-color:var(--accent)}.master-prompt-popover input::placeholder,.master-prompt-popover textarea::placeholder{color:var(--text-4)}.master-prompt[data-popover-placement=down] .master-prompt-popover{top:calc(100% + 8px);bottom:auto}.master-prompt-tabs{flex-wrap:wrap;align-items:center;gap:4px;display:flex}.master-prompt-tabs button{border:1px solid var(--border-0);max-width:120px;color:var(--text-3);font:var(--fs-meta) var(--font-mono);text-overflow:ellipsis;white-space:nowrap;background:0 0;border-radius:99px;padding:3px 8px;overflow:hidden}.master-prompt-tabs button[data-active=true]{border-color:var(--accent-border);background:var(--accent-soft);color:var(--accent)}.master-prompt-foot{color:var(--text-4);font:var(--fs-micro) var(--font-mono);flex-wrap:wrap;align-items:center;gap:8px;display:flex}.master-prompt-foot>span{margin-right:auto}.copyable-runtime-detail{min-width:0;color:var(--text-4);font:var(--fs-meta) var(--font-mono);position:relative}.copyable-runtime-detail>span{text-overflow:ellipsis;white-space:nowrap;cursor:help;max-width:25ch;display:block;overflow:hidden}.copyable-runtime-detail:hover .copyable-runtime-popover,.copyable-runtime-detail:focus-within .copyable-runtime-popover{display:flex}.copyable-runtime-popover{z-index:20;border:1px solid var(--border-1);border-radius:var(--r-sm);background:var(--bg-2);align-items:center;gap:8px;width:min(520px,70vw);padding:8px;display:none;position:absolute;bottom:calc(100% + 7px);left:0;box-shadow:0 10px 30px oklch(0% 0 0/.35)}.copyable-runtime-popover code{overflow-wrap:anywhere;min-width:0;color:var(--text-2);-webkit-user-select:text;user-select:text;flex:1}.model-combobox{min-width:0;position:relative}.model-combobox-input{position:relative}.model-combobox-input input{border:1px solid var(--border-1);border-radius:var(--r-sm);background:var(--bg-2);width:100%;height:32px;color:var(--text-0);font:11.5px var(--font-mono);outline:none;padding:0 28px 0 10px}.model-combobox-input input::placeholder{color:var(--text-4)}.model-combobox-input input:focus{border-color:var(--accent)}.model-combobox-input input:disabled{color:var(--text-3);cursor:not-allowed}.model-combobox-chevron{color:var(--text-3);pointer-events:none;position:absolute;top:50%;right:9px;translate:0 -50%}.model-combobox-popover{z-index:12;border:1px solid var(--accent-border);border-radius:var(--r-md);background:var(--bg-1);max-height:min(420px,58vh);position:absolute;top:calc(100% + 5px);left:0;right:0;overflow:auto;box-shadow:0 16px 45px oklch(0% 0 0/.3)}.model-combobox-summary{z-index:1;border-bottom:1px solid var(--border-0);background:var(--bg-1);color:var(--text-3);font:var(--fs-micro) var(--font-mono);text-transform:uppercase;justify-content:space-between;padding:7px 10px;display:flex;position:sticky;top:0}.model-combobox-empty{color:var(--text-3);text-align:center;font:11px var(--font-mono);padding:18px 12px}.model-option{border-bottom:1px solid var(--border-0);cursor:pointer;grid-template-columns:27px minmax(0,1fr) auto;align-items:center;gap:7px;padding:7px 9px;display:grid}.model-option[data-active=true],.model-option[data-selected=true]{background:var(--accent-soft)}.model-favorite{width:25px;height:25px;color:var(--text-3);cursor:pointer;background:0 0;border:0;place-items:center;padding:0;display:grid}.model-favorite[data-favorite=true]{color:var(--warning)}.model-option-copy{flex-direction:column;gap:2px;min-width:0;display:flex}.model-option-copy strong,.model-option-copy span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.model-option-copy strong{color:var(--text-1);font:11.5px var(--font-mono)}.model-option-copy span{color:var(--text-3);font:var(--fs-micro) var(--font-mono)}.model-option-meta{color:var(--text-3);font:var(--fs-micro) var(--font-mono);white-space:nowrap}.model-catalog-filters{color:var(--text-3);font:var(--fs-meta) var(--font-mono);align-items:center;gap:8px;display:flex}.model-catalog-filters>span{text-transform:uppercase}.model-catalog-filters select{border:1px solid var(--border-0);border-radius:var(--r-sm);background:var(--bg-2);height:27px;color:var(--text-1);font:var(--fs-meta) var(--font-mono);padding:0 7px}.model-catalog-filters label{align-items:center;gap:5px;display:flex}.model-catalog-filters input{accent-color:var(--accent)}.model-runtime,.generation-progress{border:1px solid var(--border-0);border-radius:var(--r-sm);background:var(--bg-2);align-items:flex-start;gap:10px;padding:10px 12px;display:flex}.model-runtime>div,.generation-progress>div{flex-direction:column;gap:3px;min-width:0;display:flex}.model-runtime strong,.generation-progress strong{color:var(--text-1);font:600 11.5px var(--font-mono)}.model-runtime span:not(.runtime-dot,.generation-spinner),.generation-progress span:not(.runtime-dot,.generation-spinner){color:var(--text-3);font:var(--fs-meta)/1.4 var(--font-mono);text-overflow:ellipsis;overflow:hidden}.model-runtime>.btn{margin-left:auto}.global-runtime{border:1px solid var(--border-0);border-radius:var(--r-sm);background:var(--bg-1);grid-template-columns:9px minmax(0,1fr) auto;align-items:center;gap:8px;padding:8px;display:grid}.global-runtime[data-state=ready] .runtime-dot,.global-runtime[data-state=external] .runtime-dot{background:var(--success)}.global-runtime[data-state=starting] .runtime-dot{background:var(--warning);animation:1.2s ease-in-out infinite generation-pulse}.global-runtime button{border:1px solid var(--border-0);color:var(--text-3);font:var(--fs-micro) var(--font-mono);cursor:pointer;background:0 0;border-radius:4px;padding:2px 5px}.global-runtime-copy{flex-direction:column;gap:2px;min-width:0;display:flex}.global-runtime-copy b,.global-runtime-copy span,.global-runtime-copy small{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.global-runtime-copy b{color:var(--text-2);font:600 9.5px var(--font-mono);align-items:center;gap:5px;display:flex}.global-runtime-copy b>span:first-child{min-width:0}.global-runtime-copy b em{border:1px solid var(--border-0);color:var(--text-3);font:8px var(--font-mono);text-transform:uppercase;border-radius:999px;flex:none;padding:1px 4px;font-style:normal}.global-runtime-copy span,.global-runtime-copy small{color:var(--text-4);font:var(--fs-micro) var(--font-mono)}.global-runtime-copy small{white-space:normal;margin-top:2px}.runtime-install-help{border:1px solid var(--border-0);cursor:help;border-radius:50%;flex:0 0 14px;place-items:center;width:14px;height:14px;display:inline-grid;color:var(--text-4)!important;font:8px var(--font-mono)!important}.runtime-install-help:focus-visible{outline:1px solid var(--accent);outline-offset:2px}.runtime-dot{background:var(--text-3);width:8px;height:8px;box-shadow:0 0 0 3px color-mix(in oklch, var(--text-3) 14%, transparent);border-radius:50%;flex:none;margin-top:3px}.model-runtime[data-state=ready] .runtime-dot,.model-runtime[data-state=external] .runtime-dot{background:var(--success);box-shadow:0 0 0 3px color-mix(in oklch, var(--success) 16%, transparent)}.model-runtime[data-state=starting] .runtime-dot,.model-runtime[data-state=loading] .runtime-dot{background:var(--warning);animation:1.2s ease-in-out infinite generation-pulse}.model-runtime[data-state=remote] .runtime-dot{background:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}.generation-progress{border-color:var(--accent-border);background:var(--accent-soft)}.generation-spinner{border:2px solid var(--border-1);border-top-color:var(--accent);border-radius:50%;flex:none;width:14px;height:14px;animation:.8s linear infinite generation-spin}.stream-placeholder{color:var(--text-3);font-style:italic}.stream-cursor{background:var(--accent);width:2px;height:1em;margin-left:3px;animation:.85s step-end infinite generation-pulse;display:inline-block;translate:0 2px}@keyframes generation-spin{to{rotate:360deg}}@keyframes generation-pulse{50%{opacity:.3}}@media (prefers-reduced-motion:reduce){.generation-spinner,.runtime-dot,.stream-cursor{animation:none}}.chat-page{width:100%;min-height:calc(100dvh - 48px);margin:0 auto;position:relative}.chat-workspace{width:100%;min-width:0;min-height:calc(100dvh - 48px);padding:22px clamp(18px,4vw,56px) 48px}.chat-hero{border-bottom:1px solid var(--border-0);flex-direction:column;gap:8px;max-width:760px;margin:0 auto 14px;padding-bottom:12px;display:flex}.chat-hero .chat-title-row,.chat-hero .chat-hero-actions{align-items:center;gap:8px;min-width:0;display:flex}.chat-hero h1{min-width:0;color:var(--text-0);overflow-wrap:anywhere;margin:0;font-size:clamp(19px,2.3vw,24px);font-weight:500;line-height:1.25}.chat-title-row{align-items:flex-start!important}.chat-hero-actions{justify-content:space-between}.chat-storage-status{min-width:0;color:var(--text-4);font:var(--fs-micro) var(--font-mono);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.private-chat-badge{border:1px solid var(--border-1);background:var(--bg-2);color:var(--text-2);font:600 9.5px var(--font-mono);letter-spacing:.02em;border-radius:99px;flex:none;align-items:center;gap:5px;padding:2px 7px;display:inline-flex}.chat-storage-badge{border:1px solid var(--border-1);background:var(--bg-2);color:var(--text-2);font:600 9.5px var(--font-mono);letter-spacing:.02em;border-radius:99px;flex:none;align-items:center;gap:5px;padding:2px 8px;display:inline-flex}.chat-storage-badge.saved{border-color:var(--accent-border);background:var(--accent-soft);color:var(--accent)}.chat-storage-badge svg{flex:none}.saved-chat-actions{flex:none;align-items:center;gap:8px;display:flex}.threadshelf-origin-badge{border:1px solid var(--accent-border);background:var(--accent-soft);color:var(--accent);font:600 9.5px var(--font-mono);letter-spacing:.04em;text-transform:uppercase;border-radius:99px;padding:2px 7px;display:inline-flex}.threadshelf-filter{color:var(--text-2);font:var(--fs-meta) var(--font-mono);align-items:center;gap:7px;display:flex}.threadshelf-filter input{accent-color:oklch(74% .16 165)}.chat-conversation{flex-direction:column;gap:10px;max-width:760px;margin:0 auto;display:flex}.chat-empty{text-align:center;flex-direction:column;justify-content:center;align-items:center;max-width:520px;min-height:58vh;margin:0 auto;display:flex}.chat-empty h1{margin:12px 0 6px;font-size:24px;font-weight:500}.chat-empty p{color:var(--text-3);margin:0 0 18px;line-height:1.6}.chat-empty-icon{border:1px solid var(--accent-border);background:var(--accent-soft);width:42px;height:42px;color:var(--accent);border-radius:50%;place-items:center;display:grid}.chat-empty-alpha{color:var(--text-4);font:var(--fs-meta) var(--font-mono);align-items:center;gap:6px;margin-top:18px;display:inline-flex}.chat-empty-alpha svg{flex:none;width:13px;height:13px}.continue-foot{justify-content:space-between;align-items:center;gap:12px;display:flex}.continue-foot>span{color:var(--text-3);font:var(--fs-meta) var(--font-mono)}@media (width<=760px){.chat-workspace{min-height:calc(100dvh - 52px);padding:14px 12px 32px}.chat-hero{margin-bottom:10px;padding-bottom:10px}.chat-hero .chat-title-row{align-items:flex-start}.chat-hero h1{-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:19px;display:-webkit-box;overflow:hidden}.chat-hero-actions{flex-wrap:wrap;align-items:center}.chat-storage-status{white-space:normal;flex:100%}.saved-chat-actions{margin-left:auto}.generation-panel .generation-form{grid-template-columns:1fr}.generation-panel .generation-form>*{grid-column:1!important}.llama-runtime-config{grid-template-columns:1fr}.directory-picker-bar{grid-template-columns:auto minmax(0,1fr) auto}.directory-picker-bar .btn:last-child{grid-column:1/-1}.continue-controls{grid-template-columns:1fr}.continue-head,.continue-foot{flex-direction:column;align-items:flex-start}}.md-body{white-space:normal}.md-body>:first-child{margin-top:0}.md-body>:last-child{margin-bottom:0}.md-body p{white-space:pre-wrap;margin:0 0 .85em}.md-body h3,.md-body h4,.md-body h5,.md-body h6{color:var(--text-0);margin:1.1em 0 .45em;font-weight:600;line-height:1.3}.md-body h3{font-size:1.12em}.md-body h4{font-size:1.04em}.md-body h5,.md-body h6{color:var(--text-1);font-size:1em}.md-body ul,.md-body ol{margin:0 0 .85em;padding-left:1.5em}.md-body li{margin:.2em 0}.md-body li::marker{color:var(--text-3)}.md-body a{color:var(--accent);text-underline-offset:2px;text-decoration:underline}.md-body strong{color:var(--text-0);font-weight:600}.md-body code{border-radius:var(--r-sm);background:var(--bg-2);font:.88em var(--font-mono);word-break:break-word;padding:.1em .36em}.md-body pre{border:1px solid var(--border-0);border-radius:var(--r-md);background:var(--bg-2);margin:0 0 .85em;padding:12px 14px;overflow-x:auto}.md-body pre code{white-space:pre;background:0 0;padding:0;font-size:.86em;line-height:1.55}.md-body blockquote{border-left:2px solid var(--border-1);color:var(--text-2);margin:0 0 .85em;padding:4px 0 4px 14px}.sb-coll-empty-toggle{border-radius:var(--r-sm);color:var(--text-4);font:var(--fs-meta) var(--font-mono);text-align:left;cursor:pointer;background:0 0;border:0;margin:4px 8px 0;padding:6px 8px}.sb-coll-empty-toggle:hover,.sb-coll-empty-toggle:focus-visible{background:var(--bg-2);color:var(--text-2)}.chat-conversation .continue-card{bottom:max(8px, env(safe-area-inset-bottom));z-index:5;box-shadow:0 -10px 20px -12px var(--bg-0);position:sticky}.composer-bar{justify-content:space-between;align-items:center;gap:10px;display:flex}.model-menu{min-width:0;position:relative}.model-status{border:1px solid var(--border-1);background:var(--bg-2);min-width:0;max-width:100%;height:32px;color:var(--text-1);font:11.5px var(--font-mono);cursor:pointer;border-radius:99px;align-items:center;gap:8px;padding:0 10px;display:inline-flex}.model-status:hover,.model-status[aria-expanded=true]{border-color:var(--accent-border);background:var(--accent-soft)}.model-status .runtime-dot{margin-top:0}.model-status[data-state=ready] .runtime-dot{background:var(--success);box-shadow:0 0 0 3px color-mix(in oklch, var(--success) 16%, transparent)}.model-status[data-state=loading] .runtime-dot{background:var(--warning);animation:1.2s ease-in-out infinite generation-pulse}.model-status[data-state=remote] .runtime-dot{background:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}.model-status-name{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.model-status-chevron{color:var(--text-3)}.off-device-chip{background:var(--accent-soft);color:var(--accent);font-size:var(--fs-micro);letter-spacing:.02em;border-radius:99px;flex:none;padding:1px 6px}.model-popover{z-index:40;width:min(440px,86vw);max-height:min(70dvh, 560px, var(--model-popover-available-height,560px));overscroll-behavior:contain;scrollbar-gutter:stable;border:1px solid var(--border-1);border-radius:var(--r-md);background:var(--bg-1);box-shadow:0 18px 48px -18px var(--bg-0);flex-direction:column;gap:12px;padding:14px 14px 28px;scroll-padding-block:14px 28px;display:flex;position:absolute;bottom:calc(100% + 8px);left:0;overflow-y:auto}.model-menu[data-popover-placement=down] .model-popover{top:calc(100% + 8px);bottom:auto}.model-popover-providers{border-radius:var(--r-sm);background:var(--bg-2);grid-template-columns:1fr 1fr;gap:6px;padding:3px;display:grid}.model-popover-providers button{border-radius:var(--r-sm);height:30px;color:var(--text-3);font:11px var(--font-mono);cursor:pointer;background:0 0;border:0}.model-popover-providers button[data-active=true]{background:var(--bg-0);color:var(--text-0);box-shadow:0 1px 2px var(--bg-0)}.model-popover-pick{grid-template-columns:minmax(0,1fr) auto;gap:8px;display:grid}.model-popover-pick-actions{gap:6px;display:flex}.model-popover-pick-actions .icon-only{place-items:center;width:30px;padding:0;display:grid}.composer-actions{flex:none;align-items:center;gap:10px;display:flex}.composer-hint{color:var(--text-4);font:var(--fs-micro) var(--font-mono)}@media (width<=620px){.generation-budget-field{grid-template-columns:minmax(0,1fr) auto}.generation-budget-field>span:first-child{grid-column:1/-1}.generation-budget-field .number-combobox{width:100%}.composer-hint{display:none}.chat-conversation .continue-card{gap:8px;margin-inline:0;padding:9px}.chat-conversation .continue-card textarea{min-height:62px;max-height:34dvh;padding:9px 10px}.composer-bar,.composer-actions{gap:6px}.model-status{max-width:min(210px,58vw)}}.chat-title-input{border:1px solid var(--accent);border-radius:var(--r-sm);background:var(--bg-0);min-width:0;color:var(--text-0);outline:none;flex:1;padding:4px 8px;font-size:clamp(19px,2.3vw,24px);font-weight:500}.chat-hero h1[title="Double-click to rename"]{cursor:text}.catalog-modal{flex-direction:column;width:min(760px,94vw);max-height:82vh;display:flex}.catalog-head{justify-content:space-between;align-items:flex-start;gap:12px;display:flex}.catalog-origin{font-size:var(--fs-micro);border:1px solid var(--warning);color:var(--warning);background:var(--warning-soft);white-space:nowrap;border-radius:999px;flex:none;padding:2px 7px}.catalog-controls{gap:8px;padding:12px 16px 8px;display:flex}.catalog-controls input{border-radius:var(--r-sm);border:1px solid var(--border-0);background:var(--bg-2);outline:0;flex:1;height:32px;padding:0 10px;font-size:12.5px}.catalog-controls input:focus{border-color:var(--accent-border)}.catalog-controls select{border-radius:var(--r-sm);border:1px solid var(--border-0);background:var(--bg-2);height:32px;font-size:12.5px}.catalog-hardware{font-size:var(--fs-meta);color:var(--text-2);flex-wrap:wrap;gap:4px 10px;padding:0 16px 10px;display:flex}.catalog-hardware b{color:var(--text-1);font-weight:500}.catalog-token-hint{color:var(--warning)}.catalog-body{flex-direction:column;gap:6px;padding:0 16px 12px;display:flex;overflow-y:auto}.catalog-empty,.catalog-error{color:var(--text-2);margin:8px 0;font-size:12.5px}.catalog-error{color:var(--danger)}.catalog-item{border:1px solid var(--border-0);border-radius:var(--r-sm);background:var(--bg-2)}.catalog-item[data-open=true]{border-color:var(--accent-border)}.catalog-item-head{text-align:left;cursor:pointer;width:100%;color:inherit;background:0 0;border:0;justify-content:space-between;align-items:center;gap:12px;padding:9px 11px;display:flex}.catalog-item-head:hover{background:var(--bg-3)}.catalog-item-title{flex-direction:column;gap:2px;min-width:0;display:flex}.catalog-item-title b{overflow-wrap:anywhere;font-size:13px;font-weight:500}.catalog-item-title em{font-style:normal;font-size:var(--fs-meta);color:var(--text-2)}.catalog-item-meta{font-size:var(--fs-meta);color:var(--text-2);font-variant-numeric:tabular-nums;flex:none;align-items:center;gap:8px;display:flex}.catalog-badge{font-size:var(--fs-micro);border:1px solid var(--border-1);border-radius:999px;padding:1px 6px}.catalog-badge.trusted{color:var(--success);border-color:var(--success);background:var(--success-soft)}.catalog-badge.gated{color:var(--warning);border-color:var(--warning);background:var(--warning-soft)}.catalog-quants{border-top:1px solid var(--border-0);flex-direction:column;gap:4px;max-height:320px;padding:8px 11px 10px;display:flex;overflow-y:auto}.catalog-gated-note{font-size:var(--fs-meta);color:var(--warning);margin:0 0 6px}.catalog-quant{grid-template-columns:minmax(0,1fr) auto auto auto;align-items:center;gap:10px;padding:4px 0;font-size:12.5px;display:grid}.catalog-quant button{height:26px;font-size:var(--fs-meta);padding:0 10px}.catalog-quant-name{font-family:var(--mono,monospace);overflow-wrap:anywhere;align-items:baseline;gap:6px;display:flex}.catalog-quant-name em,.catalog-quant-name i{font-style:normal;font-size:var(--fs-micro);color:var(--text-2);font-family:inherit}.catalog-quant-name em{color:var(--accent)}.catalog-quant-size{font-variant-numeric:tabular-nums;color:var(--text-2)}.catalog-quant-fit{font-size:var(--fs-micro);white-space:nowrap;border-radius:999px;padding:1px 6px}.catalog-quant-fit[data-fit=fits]{color:var(--success);background:var(--success-soft)}.catalog-quant-fit[data-fit=tight]{color:var(--warning);background:var(--warning-soft)}.catalog-quant-fit[data-fit=too-large]{color:var(--danger);background:var(--danger-soft)}.catalog-progress{font-size:var(--fs-meta);color:var(--text-2);flex-direction:column;gap:4px;margin-top:8px;display:flex}.catalog-progress span{overflow-wrap:anywhere}.catalog-progress-track{background:var(--bg-3);border-radius:999px;height:5px;overflow:hidden}.catalog-progress-fill{background:var(--accent);height:100%;transition:width .2s}.quick-setup{flex-direction:column;gap:10px;display:flex}.quick-setup-variant{align-items:center;gap:8px;font-size:12.5px;display:flex}.quick-setup-variant select{border-radius:var(--r-sm);border:1px solid var(--border-0);background:var(--bg-2);height:30px;font-size:12.5px}.quick-setup-detected{color:var(--text-2);margin:0;font-size:12.5px}.quick-setup-detected b{color:var(--text-1);font-weight:500}.quick-setup-steps{flex-direction:column;gap:8px;margin:0;padding-left:18px;display:flex}.quick-setup-steps li{font-size:12.5px}.quick-setup-steps li[data-action=reuse],.quick-setup-steps li[data-action=none]{color:var(--text-2)}.quick-setup-step-title{overflow-wrap:anywhere;display:block}.quick-setup-step-title em{font-style:normal;font-size:var(--fs-micro);color:var(--text-2);margin-left:6px}.quick-setup-step-meta{font-size:var(--fs-meta);color:var(--text-2);font-family:var(--mono,monospace);overflow-wrap:anywhere;display:block}.quick-setup-destination{font-size:var(--fs-meta);color:var(--text-2);overflow-wrap:anywhere;margin:0}.quick-setup-warning{font-size:var(--fs-meta);color:var(--warning);margin:0}@media (width>=1800px){body{font-size:16px}.app{grid-template-columns:296px 1fr}.view{max-width:1280px}.thread-hero,.thread-actions-bar,.thread-body{max-width:1120px}.turn-body{font-size:18px}.turn[data-role=user] .turn-body{font-size:17px}.r-title{font-size:17.5px}.r-snippet{font-size:15.5px}}@media (width<=1180px){.app,.app[data-reading=true]{grid-template-columns:1fr}.sidebar,.sidebar.rail{z-index:40;width:min(320px,86vw);transition:transform .2s cubic-bezier(.4,0,.2,1);display:flex;position:fixed;inset:0 auto 0 0;transform:translate(-105%);box-shadow:24px 0 60px -32px oklch(0% 0 0/.8)}.app[data-sidebar-open=true] .sidebar{transform:translate(0)}.sidebar-scrim{z-index:35;background:var(--overlay-bg);opacity:0;pointer-events:none;border:0;transition:opacity .2s;display:block;position:fixed;inset:0}.app[data-sidebar-open=true] .sidebar-scrim{opacity:1;pointer-events:auto}.icon-btn.mobile-menu-btn{display:grid}.thread-bar{gap:10px}.thread-bar .bar-meta,.thread-bar kbd{display:none}.thread-bar .path-crumb{max-width:28vw}.view{max-width:none}}@media (width<=640px){body{font-size:15px}.topbar{gap:8px;height:52px;padding:0 12px}.topbar-actions{gap:4px}.topbar-action{padding:0 8px}.topbar-action.primary span{display:none}.view{gap:14px;padding:16px 14px 72px}.search-card{grid-template-columns:38px 1fr;grid-auto-rows:minmax(42px,auto);padding:0 6px 6px 0}.toolbar-hint{display:none}.model-filter{grid-template-columns:auto 1fr;width:100%}.role-chips{grid-template-columns:repeat(3,minmax(0,1fr));width:100%;display:grid}.role-chip{justify-content:center}.result{padding:13px 12px}.result-head{flex-wrap:wrap}.r-source{flex-basis:100%}.results-meta-bar{flex-wrap:wrap}.results-meta-bar .h{flex:100%}.results-meta-bar .conv-filter{flex:150px;width:auto}.r-foot>span:last-child{width:100%;margin-left:0!important}.thread-hero{padding:22px 16px}.thread-body{gap:18px;padding:8px 16px 80px}.thread-body:before{left:30px}.thread-actions-bar{padding:0 16px 12px}.thread-bar{min-height:54px;padding:0 10px}.thread-back span,.thread-bar .path-crumb{display:none}.turn{grid-template-columns:32px 1fr;gap:12px}.turn-avatar{width:26px;height:26px;margin-left:0}.turn-head{flex-wrap:wrap;height:auto;min-height:24px}.turn-body{font-size:15.5px}.turn[data-role=user] .turn-body{font-size:15px}}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
|
|
2
|
+
<rect width="32" height="32" rx="7" fill="#16242b"/>
|
|
3
|
+
<circle cx="14" cy="14" r="6.5" fill="none" stroke="#4cc9d6" stroke-width="2.4"/>
|
|
4
|
+
<path d="M19 19l5 5" fill="none" stroke="#4cc9d6" stroke-width="2.4" stroke-linecap="round"/>
|
|
5
|
+
<path d="M14 9.5v2M14 16.5v2M9.5 14h2M16.5 14h2" stroke="#9fe8f0" stroke-width="1.5" stroke-linecap="round"/>
|
|
6
|
+
</svg>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
7
|
+
<title>ThreadShelf — local semantic search for AI chats</title>
|
|
8
|
+
<meta
|
|
9
|
+
name="description"
|
|
10
|
+
content="Local-first semantic search and backup tool for AI chat exports (Google AI Studio, OpenRouter, LM Studio, ChatGPT, Claude)."
|
|
11
|
+
/>
|
|
12
|
+
<script type="module" crossorigin src="/assets/index-CIm_Idqi.js"></script>
|
|
13
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Dv09K2vS.css">
|
|
14
|
+
</head>
|
|
15
|
+
<body>
|
|
16
|
+
<div id="root"></div>
|
|
17
|
+
<script>
|
|
18
|
+
// Apply persisted theme before first paint to avoid a flash of the wrong theme.
|
|
19
|
+
try {
|
|
20
|
+
var s = JSON.parse(localStorage.getItem('threadshelf:ui') || '{}');
|
|
21
|
+
var t = s && s.state && s.state.theme;
|
|
22
|
+
document.documentElement.dataset.theme = t === 'light' ? 'light' : 'dark';
|
|
23
|
+
} catch (e) {
|
|
24
|
+
document.documentElement.dataset.theme = 'dark';
|
|
25
|
+
}
|
|
26
|
+
</script>
|
|
27
|
+
</body>
|
|
28
|
+
</html>
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* OpenRouter BULK export (run in browser DevTools console).
|
|
3
|
+
*
|
|
4
|
+
* Exports EVERY chat in your sidebar — one JSON file per chat — so you can drop the
|
|
5
|
+
* whole download into a folder and index it in one go. For a single chat instead,
|
|
6
|
+
* use scripts/openrouter-export-browser.js.
|
|
7
|
+
*
|
|
8
|
+
* How to use:
|
|
9
|
+
* 1) Open https://openrouter.ai/ signed in, with your chat list (sidebar) visible.
|
|
10
|
+
* 2) Open DevTools Console (F12), paste this whole file, press Enter.
|
|
11
|
+
* 3) Allow "multiple downloads" if the browser asks.
|
|
12
|
+
* 4) Move the downloaded *.json files into a folder and index that folder.
|
|
13
|
+
*
|
|
14
|
+
* Each file is compatible with the ThreadShelf parser (platform: "openrouter").
|
|
15
|
+
* Selectors below match OpenRouter's chat UI as of 2026-06; if the UI changes they
|
|
16
|
+
* may need updating (see test/playwright/openrouter-export.spec.js for the contract).
|
|
17
|
+
*/
|
|
18
|
+
(async () => {
|
|
19
|
+
const CONFIG = {
|
|
20
|
+
DOWNLOAD_DELAY_MS: 700,
|
|
21
|
+
NAV_TIMEOUT_MS: 15000,
|
|
22
|
+
SCROLL_PAUSE_MS: 350,
|
|
23
|
+
MAX_SCROLLS: 250,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
27
|
+
|
|
28
|
+
function normalizeText(text) {
|
|
29
|
+
return String(text || '')
|
|
30
|
+
.replace(/\u00a0/g, ' ')
|
|
31
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
32
|
+
.trim();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function safeName(text) {
|
|
36
|
+
return (
|
|
37
|
+
normalizeText(text)
|
|
38
|
+
.replace(/[\\/:*?"<>|]+/g, '-')
|
|
39
|
+
.replace(/\s+/g, '_')
|
|
40
|
+
.slice(0, 60) || 'chat'
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Text of a node with chrome (buttons, icons, avatars) stripped out.
|
|
45
|
+
function cleanText(node) {
|
|
46
|
+
if (!node) return '';
|
|
47
|
+
const clone = node.cloneNode(true);
|
|
48
|
+
clone
|
|
49
|
+
.querySelectorAll('button, svg, picture, img, [role="button"], [aria-hidden="true"]')
|
|
50
|
+
.forEach((n) => n.remove());
|
|
51
|
+
return normalizeText(clone.innerText || clone.textContent || '');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// The rendered message text lives in a privacy-masked panel. For assistant
|
|
55
|
+
// messages with reasoning there are two panels (reasoning first, answer last);
|
|
56
|
+
// we keep the last. Falls back to prose elements, then the whole node.
|
|
57
|
+
function messageBody(el) {
|
|
58
|
+
const panels = el.querySelectorAll('[data-dd-privacy="hidden"]');
|
|
59
|
+
if (panels.length) return cleanText(panels[panels.length - 1]);
|
|
60
|
+
const prose = Array.from(el.querySelectorAll('p, li, pre, h1, h2, h3, h4, blockquote'));
|
|
61
|
+
if (prose.length) return normalizeText(prose.map((n) => n.textContent || '').join('\n'));
|
|
62
|
+
return cleanText(el);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getModel(el) {
|
|
66
|
+
const fav = el.querySelector('img[alt^="Favicon for"], img[alt*="Favicon"]');
|
|
67
|
+
if (fav) {
|
|
68
|
+
const m = (fav.getAttribute('alt') || '').replace(/favicon for/i, '').trim();
|
|
69
|
+
if (m) return m;
|
|
70
|
+
}
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function extractTurns() {
|
|
75
|
+
const els = Array.from(
|
|
76
|
+
document.querySelectorAll('[data-testid="user-message"], [data-testid="assistant-message"]'),
|
|
77
|
+
);
|
|
78
|
+
const turns = [];
|
|
79
|
+
const seen = new Set();
|
|
80
|
+
for (const el of els) {
|
|
81
|
+
const role = el.getAttribute('data-testid') === 'user-message' ? 'user' : 'assistant';
|
|
82
|
+
const content = messageBody(el);
|
|
83
|
+
if (!content) continue;
|
|
84
|
+
const key = `${role}:${content}`;
|
|
85
|
+
if (seen.has(key)) continue;
|
|
86
|
+
seen.add(key);
|
|
87
|
+
const turn = { role, content };
|
|
88
|
+
if (role === 'assistant') {
|
|
89
|
+
const model = getModel(el);
|
|
90
|
+
if (model) turn.model = model;
|
|
91
|
+
}
|
|
92
|
+
turns.push(turn);
|
|
93
|
+
}
|
|
94
|
+
return turns;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Sidebar chat links look like /chat?room=orc-<id>.
|
|
98
|
+
function findChats() {
|
|
99
|
+
const anchors = Array.from(document.querySelectorAll('a[href*="room="]'));
|
|
100
|
+
const byId = new Map();
|
|
101
|
+
for (const a of anchors) {
|
|
102
|
+
const href = a.getAttribute('href') || '';
|
|
103
|
+
const match = href.match(/[?&]room=([^&#]+)/);
|
|
104
|
+
if (!match) continue;
|
|
105
|
+
const id = match[1];
|
|
106
|
+
if (id && !byId.has(id)) byId.set(id, { id, href, title: normalizeText(a.textContent || '') });
|
|
107
|
+
}
|
|
108
|
+
return [...byId.values()];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function findAnchor(id) {
|
|
112
|
+
return Array.from(document.querySelectorAll('a[href*="room="]')).find((a) =>
|
|
113
|
+
(a.getAttribute('href') || '').includes(id),
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function buildPayload(turns, title) {
|
|
118
|
+
return {
|
|
119
|
+
platform: 'openrouter',
|
|
120
|
+
exportedAt: new Date().toISOString(),
|
|
121
|
+
pageTitle: document.title,
|
|
122
|
+
title: title || document.title,
|
|
123
|
+
sourceUrl: location.href,
|
|
124
|
+
turns,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function getScrollContainer() {
|
|
129
|
+
return (
|
|
130
|
+
document.querySelector('[data-testid="message-list-scroll"]') ||
|
|
131
|
+
document.querySelector('[data-testid="message-list-content"]')?.parentElement ||
|
|
132
|
+
document.scrollingElement ||
|
|
133
|
+
document.documentElement
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function autoScrollToLoadAll() {
|
|
138
|
+
const container = getScrollContainer();
|
|
139
|
+
let prev = -1;
|
|
140
|
+
let stable = 0;
|
|
141
|
+
for (let i = 0; i < CONFIG.MAX_SCROLLS && stable < 3; i++) {
|
|
142
|
+
const count = document.querySelectorAll(
|
|
143
|
+
'[data-testid="user-message"], [data-testid="assistant-message"]',
|
|
144
|
+
).length;
|
|
145
|
+
stable = count === prev ? stable + 1 : 0;
|
|
146
|
+
prev = count;
|
|
147
|
+
container.scrollTop = 0;
|
|
148
|
+
await sleep(CONFIG.SCROLL_PAUSE_MS);
|
|
149
|
+
}
|
|
150
|
+
container.scrollTop = container.scrollHeight;
|
|
151
|
+
await sleep(CONFIG.SCROLL_PAUSE_MS);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async function waitForChat(id) {
|
|
155
|
+
const start = Date.now();
|
|
156
|
+
while (Date.now() - start < CONFIG.NAV_TIMEOUT_MS) {
|
|
157
|
+
if (location.href.includes(id) && extractTurns().length > 0) return true;
|
|
158
|
+
await sleep(300);
|
|
159
|
+
}
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function download(payload, fileName) {
|
|
164
|
+
const blob = new Blob([JSON.stringify(payload, null, 2)], { type: 'application/json' });
|
|
165
|
+
const url = URL.createObjectURL(blob);
|
|
166
|
+
const a = document.createElement('a');
|
|
167
|
+
a.href = url;
|
|
168
|
+
a.download = fileName;
|
|
169
|
+
document.body.appendChild(a);
|
|
170
|
+
a.click();
|
|
171
|
+
a.remove();
|
|
172
|
+
URL.revokeObjectURL(url);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Test hook: expose internals and skip side effects when driven by a test.
|
|
176
|
+
if (typeof window !== 'undefined' && window.__OR_TEST__) {
|
|
177
|
+
window.__ORX = { findChats, extractTurns, buildPayload, normalizeText, getModel };
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const chats = findChats();
|
|
182
|
+
if (!chats.length) {
|
|
183
|
+
console.error(
|
|
184
|
+
'No chats found in the sidebar. Open openrouter.ai with your chat list visible, then re-run. ' +
|
|
185
|
+
'For a single open chat use scripts/openrouter-export-browser.js.',
|
|
186
|
+
);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
console.log(`Found ${chats.length} chats. Starting bulk export…`);
|
|
191
|
+
let exported = 0;
|
|
192
|
+
let skipped = 0;
|
|
193
|
+
for (const [i, chat] of chats.entries()) {
|
|
194
|
+
try {
|
|
195
|
+
if (!location.href.includes(chat.id)) {
|
|
196
|
+
const anchor = findAnchor(chat.id);
|
|
197
|
+
if (!anchor) {
|
|
198
|
+
console.warn(`(${i + 1}/${chats.length}) anchor not found, skipping ${chat.id}`);
|
|
199
|
+
skipped++;
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
anchor.click();
|
|
203
|
+
}
|
|
204
|
+
if (!(await waitForChat(chat.id))) {
|
|
205
|
+
console.warn(`(${i + 1}/${chats.length}) timed out loading ${chat.id}, skipping`);
|
|
206
|
+
skipped++;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
await autoScrollToLoadAll();
|
|
210
|
+
const turns = extractTurns();
|
|
211
|
+
if (!turns.length) {
|
|
212
|
+
console.warn(`(${i + 1}/${chats.length}) no messages in ${chat.id}, skipping`);
|
|
213
|
+
skipped++;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
const title = chat.title || document.title;
|
|
217
|
+
download(buildPayload(turns, title), `openrouter-${safeName(title)}-${safeName(chat.id)}.json`);
|
|
218
|
+
exported++;
|
|
219
|
+
console.log(`(${i + 1}/${chats.length}) exported "${title}" (${turns.length} messages)`);
|
|
220
|
+
await sleep(CONFIG.DOWNLOAD_DELAY_MS);
|
|
221
|
+
} catch (err) {
|
|
222
|
+
skipped++;
|
|
223
|
+
console.warn(`(${i + 1}/${chats.length}) failed on ${chat.id}:`, err);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
console.log(`Done. Exported ${exported} chats, skipped ${skipped}. Index the downloaded folder.`);
|
|
228
|
+
})();
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* OpenRouter SINGLE-chat export (run in browser DevTools console).
|
|
3
|
+
*
|
|
4
|
+
* Exports the chat that is currently open into one parser-compatible JSON file.
|
|
5
|
+
* To export EVERY chat at once, use scripts/openrouter-export-all.js instead.
|
|
6
|
+
*
|
|
7
|
+
* How to use:
|
|
8
|
+
* 1) Open the chat you want at https://openrouter.ai/chat?room=...
|
|
9
|
+
* 2) Scroll up so the whole conversation is loaded.
|
|
10
|
+
* 3) Open DevTools Console (F12), paste this whole file, press Enter.
|
|
11
|
+
* 4) A JSON file downloads. Move it into a folder and index that folder.
|
|
12
|
+
*
|
|
13
|
+
* Output format is compatible with the ThreadShelf parser (platform: "openrouter").
|
|
14
|
+
* Selectors match OpenRouter's chat UI as of 2026-06 (see
|
|
15
|
+
* test/playwright/openrouter-export.spec.js for the contract).
|
|
16
|
+
*/
|
|
17
|
+
(async () => {
|
|
18
|
+
const CONFIG = { SCROLL_PAUSE_MS: 350, MAX_SCROLLS: 250 };
|
|
19
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
20
|
+
|
|
21
|
+
function normalizeText(text) {
|
|
22
|
+
return String(text || '')
|
|
23
|
+
.replace(/\u00a0/g, ' ')
|
|
24
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
25
|
+
.trim();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function safeName(text) {
|
|
29
|
+
return (
|
|
30
|
+
normalizeText(text)
|
|
31
|
+
.replace(/[\\/:*?"<>|]+/g, '-')
|
|
32
|
+
.replace(/\s+/g, '_')
|
|
33
|
+
.slice(0, 60) || 'chat'
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function cleanText(node) {
|
|
38
|
+
if (!node) return '';
|
|
39
|
+
const clone = node.cloneNode(true);
|
|
40
|
+
clone
|
|
41
|
+
.querySelectorAll('button, svg, picture, img, [role="button"], [aria-hidden="true"]')
|
|
42
|
+
.forEach((n) => n.remove());
|
|
43
|
+
return normalizeText(clone.innerText || clone.textContent || '');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Message text is in a privacy-masked panel; for assistant messages with
|
|
47
|
+
// reasoning the answer is the last panel (reasoning is first). Fallbacks: prose,
|
|
48
|
+
// then the node itself.
|
|
49
|
+
function messageBody(el) {
|
|
50
|
+
const panels = el.querySelectorAll('[data-dd-privacy="hidden"]');
|
|
51
|
+
if (panels.length) return cleanText(panels[panels.length - 1]);
|
|
52
|
+
const prose = Array.from(el.querySelectorAll('p, li, pre, h1, h2, h3, h4, blockquote'));
|
|
53
|
+
if (prose.length) return normalizeText(prose.map((n) => n.textContent || '').join('\n'));
|
|
54
|
+
return cleanText(el);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function getModel(el) {
|
|
58
|
+
const fav = el.querySelector('img[alt^="Favicon for"], img[alt*="Favicon"]');
|
|
59
|
+
if (fav) {
|
|
60
|
+
const m = (fav.getAttribute('alt') || '').replace(/favicon for/i, '').trim();
|
|
61
|
+
if (m) return m;
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function extractTurns() {
|
|
67
|
+
const els = Array.from(
|
|
68
|
+
document.querySelectorAll('[data-testid="user-message"], [data-testid="assistant-message"]'),
|
|
69
|
+
);
|
|
70
|
+
const turns = [];
|
|
71
|
+
const seen = new Set();
|
|
72
|
+
for (const el of els) {
|
|
73
|
+
const role = el.getAttribute('data-testid') === 'user-message' ? 'user' : 'assistant';
|
|
74
|
+
const content = messageBody(el);
|
|
75
|
+
if (!content) continue;
|
|
76
|
+
const key = `${role}:${content}`;
|
|
77
|
+
if (seen.has(key)) continue;
|
|
78
|
+
seen.add(key);
|
|
79
|
+
const turn = { role, content };
|
|
80
|
+
if (role === 'assistant') {
|
|
81
|
+
const model = getModel(el);
|
|
82
|
+
if (model) turn.model = model;
|
|
83
|
+
}
|
|
84
|
+
turns.push(turn);
|
|
85
|
+
}
|
|
86
|
+
return turns;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function buildPayload(turns, title) {
|
|
90
|
+
return {
|
|
91
|
+
platform: 'openrouter',
|
|
92
|
+
exportedAt: new Date().toISOString(),
|
|
93
|
+
pageTitle: document.title,
|
|
94
|
+
title: title || document.title,
|
|
95
|
+
sourceUrl: location.href,
|
|
96
|
+
turns,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function getScrollContainer() {
|
|
101
|
+
return (
|
|
102
|
+
document.querySelector('[data-testid="message-list-scroll"]') ||
|
|
103
|
+
document.querySelector('[data-testid="message-list-content"]')?.parentElement ||
|
|
104
|
+
document.scrollingElement ||
|
|
105
|
+
document.documentElement
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function autoScrollToLoadAll() {
|
|
110
|
+
const container = getScrollContainer();
|
|
111
|
+
let prev = -1;
|
|
112
|
+
let stable = 0;
|
|
113
|
+
for (let i = 0; i < CONFIG.MAX_SCROLLS && stable < 3; i++) {
|
|
114
|
+
const count = document.querySelectorAll(
|
|
115
|
+
'[data-testid="user-message"], [data-testid="assistant-message"]',
|
|
116
|
+
).length;
|
|
117
|
+
stable = count === prev ? stable + 1 : 0;
|
|
118
|
+
prev = count;
|
|
119
|
+
container.scrollTop = 0;
|
|
120
|
+
await sleep(CONFIG.SCROLL_PAUSE_MS);
|
|
121
|
+
}
|
|
122
|
+
container.scrollTop = container.scrollHeight;
|
|
123
|
+
await sleep(CONFIG.SCROLL_PAUSE_MS);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function download(payload, fileName) {
|
|
127
|
+
const blob = new Blob([JSON.stringify(payload, null, 2)], { type: 'application/json' });
|
|
128
|
+
const url = URL.createObjectURL(blob);
|
|
129
|
+
const a = document.createElement('a');
|
|
130
|
+
a.href = url;
|
|
131
|
+
a.download = fileName;
|
|
132
|
+
document.body.appendChild(a);
|
|
133
|
+
a.click();
|
|
134
|
+
a.remove();
|
|
135
|
+
URL.revokeObjectURL(url);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Test hook: expose internals and skip side effects when driven by a test.
|
|
139
|
+
if (typeof window !== 'undefined' && window.__OR_TEST__) {
|
|
140
|
+
window.__ORX = { extractTurns, buildPayload, normalizeText, getModel };
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
await autoScrollToLoadAll();
|
|
145
|
+
const turns = extractTurns();
|
|
146
|
+
if (!turns.length) {
|
|
147
|
+
console.error('No messages found. Open a chat, scroll it fully, and run again.');
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
151
|
+
download(buildPayload(turns, document.title), `openrouter-${safeName(document.title)}-${stamp}.json`);
|
|
152
|
+
console.log(`Exported ${turns.length} messages (single chat).`);
|
|
153
|
+
})();
|