@3sln/trove 0.0.4 → 0.0.7
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/README.md +6 -0
- package/package.json +1 -1
- package/packages/core/src/apiKeys.js +326 -0
- package/packages/core/src/collections/index.js +83 -13
- package/packages/core/src/index.js +14 -2
- package/packages/core/src/issues.js +4 -0
- package/packages/core/src/storage/diagnose.js +234 -0
- package/packages/core/src/storage/drivers.js +83 -0
- package/packages/core/src/storage/filesystem.js +22 -0
- package/packages/core/src/storage/registry.js +162 -0
- package/packages/server/src/adapters/bun.js +6 -0
- package/packages/server/src/adapters/node.js +6 -0
- package/packages/server/src/engine/index.js +1 -1
- package/packages/server/src/engine/providers/access.js +47 -5
- package/packages/server/src/engine/providers/core.js +105 -11
- package/packages/server/src/index.js +123 -11
- package/packages/server/src/mcp/tools.js +40 -8
- package/packages/server/src/router.js +1 -1
- package/packages/server/src/routes.js +135 -32
- package/packages/server/src/scope.js +2 -2
- package/packages/web/dist/assets/main-f0f2tfhp.js +356 -0
- package/packages/web/dist/assets/{main-4cxs7prw.js.map → main-f0f2tfhp.js.map} +17 -16
- package/packages/web/dist/assets/{styles-kcx1x337.css → styles-d3cyysgp.css} +1 -1
- package/packages/web/dist/index.html +2 -2
- package/packages/web/dist/sw.js +58 -9
- package/packages/web/src/bl/actions.js +112 -13
- package/packages/web/src/bl/activity.js +32 -0
- package/packages/web/src/bl/commands.js +41 -2
- package/packages/web/src/bl/index.js +9 -4
- package/packages/web/src/bl/services.js +78 -1
- package/packages/web/src/platform/api.js +57 -14
- package/packages/web/src/platform/pluginRpc.js +7 -4
- package/packages/web/src/styles.css +137 -0
- package/packages/web/src/ui/components/activityPanel.js +28 -1
- package/packages/web/src/ui/components/collectionGate.js +81 -0
- package/packages/web/src/ui/components/overlays.js +64 -34
- package/packages/web/src/ui/components/phoneChrome.js +2 -2
- package/packages/web/src/ui/components/settingsView.js +197 -1
- package/packages/web/src/ui/components/statusBar.js +19 -2
- package/packages/web/src/ui/compositions/workbench.js +9 -2
- package/packages/web/dist/assets/main-4cxs7prw.js +0 -356
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{--font-ui:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;--font-mono:"SF Mono","JetBrains Mono","Fira Code",ui-monospace,Menlo,Consolas,monospace;--radius:8px;--radius-sm:5px;--activity-w:52px;--sidebar-w:280px;--statusbar-h:24px;--ease:cubic-bezier(.2,.7,.2,1);--focus:var(--accent);--focus-halo:color-mix(in srgb,var(--accent)32%,transparent)}:root,:root[data-theme=dark]{--bg:#181a1f;--bg-elevated:#1f2228;--bg-sidebar:#1b1d23;--bg-activity:#16181d;--bg-input:#12141a;--bg-hover:#ffffff0d;--bg-active:#ffffff14;--bg-selected:#2d6fd128;--border:#ffffff14;--border-strong:#ffffff26;--text:#d7dce5;--text-dim:#9aa4b2;--text-faint:#6b7280;--accent:#6ea8fe;--accent-2:#a679f0;--accent-text:#0b1020;--danger:#f2607a;--warn:#e5b567;--success:#6cc48a;--shadow:0 12px 40px -8px #000000a8,0 2px 8px -2px #0008;--scrollbar:#fff2}:root[data-theme=midnight]{--bg:#0c0e14;--bg-elevated:#12151e;--bg-sidebar:#0e111a;--bg-activity:#090b11;--bg-input:#080a10;--bg-hover:#ffffff0a;--bg-active:#ffffff12;--bg-selected:#4b7bff22;--border:#ffffff10;--border-strong:#ffffff1f;--text:#cdd6f4;--text-dim:#8b95b0;--text-faint:#5a6482;--accent:#89b4fa;--accent-2:#cba6f7;--danger:#f38ba8;--warn:#f9e2af;--success:#a6e3a1;--shadow:0 16px 50px -10px #000c,0 2px 10px -2px #000a;--scrollbar:#ffffff1a}:root[data-theme=light]{--bg:#f6f7f9;--bg-elevated:#fff;--bg-sidebar:#eef0f3;--bg-activity:#e6e9ee;--bg-input:#fff;--bg-hover:#0000000a;--bg-active:#00000012;--bg-selected:#2d6fd11f;--border:#00000014;--border-strong:#00000024;--text:#1c2430;--text-dim:#55606f;--text-faint:#8a95a4;--accent:#2d6fd1;--accent-2:#7c50c8;--accent-text:#fff;--danger:#d63b5b;--warn:#b3801f;--success:#2f9e57;--shadow:0 12px 40px -10px #0000002e,0 2px 8px -3px #0000001f;--scrollbar:#00000026}*{box-sizing:border-box}html,body{height:100%;margin:0}*,*:before,*:after{-webkit-tap-highlight-color:transparent}body{font-family:var(--font-ui);color:var(--text);background:var(--bg);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;overflow:hidden;font-size:13px}button{font:inherit;color:inherit;cursor:pointer;text-align:inherit;background:0 0;border:0}input,select,textarea{font:inherit;color:inherit}::selection{background:var(--accent);color:var(--accent-text)}:focus-visible{outline:2px solid var(--focus);outline-offset:2px}:focus:not(:focus-visible){outline:none}.btn:focus-visible{outline:none;border-color:var(--focus);box-shadow:0 0 0 3px var(--focus-halo)}.btn.primary:focus-visible{box-shadow:0 0 0 3px var(--focus-halo)}.iconbtn:focus-visible{outline:none;color:var(--text);background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}.act-action:focus-visible{outline:none;color:var(--text);background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}.launch-clear:focus-visible{outline:none;color:var(--text);background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}.pb-status:focus-visible{outline:none;color:var(--text);background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}.pb-brand:focus-visible{outline:none;color:var(--text);background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}.vn-back:focus-visible{outline:none;color:var(--text);background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}.c-link:focus-visible{outline:none;color:var(--text);background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}.react:focus-visible{outline:none;color:var(--text);background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}.launch-box:focus-within{border-color:var(--focus);box-shadow:var(--shadow),0 0 0 3px var(--focus-halo)}.launch-input:focus-visible{outline:none}.launch-item:focus-visible{outline:none;background:var(--bg-selected);box-shadow:inset 3px 0 0 0 var(--focus),0 0 0 1px var(--focus-halo)}.sheet-row:focus-visible{outline:none;background:var(--bg-selected);box-shadow:inset 3px 0 0 0 var(--focus),0 0 0 1px var(--focus-halo)}.inbox-item:focus-visible{outline:none;background:var(--bg-selected);box-shadow:inset 3px 0 0 0 var(--focus),0 0 0 1px var(--focus-halo)}.activitybar .item:focus-visible{outline:none;color:var(--text);background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}.activitybar .item:focus-visible:before{content:"";position:absolute;background:linear-gradient(var(--accent),var(--accent-2));border-radius:0 3px 3px 0;width:3px;top:8px;bottom:8px;left:-6px}.activitybar .brand-mark:focus-visible{outline:none;background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}.pb-tab:focus-visible{outline:none;color:var(--accent);box-shadow:inset 0 3px 0 0 var(--focus)}.statusbar .seg:focus-visible{outline:none;background:var(--bg-active);color:var(--text);box-shadow:inset 0 -2px 0 0 var(--focus)}.md a:focus-visible{outline:2px solid var(--focus);outline-offset:3px;border-radius:3px}.link:focus-visible{outline:2px solid var(--focus);outline-offset:3px;border-radius:3px}.launch-up:focus-visible{outline:2px solid var(--focus);outline-offset:3px;border-radius:3px}.lh-example:focus-visible{outline:none;border-color:var(--focus);box-shadow:0 0 0 3px var(--focus-halo)}::-webkit-scrollbar{width:11px;height:11px}::-webkit-scrollbar-thumb{background:var(--scrollbar);background-clip:content-box;border:3px solid #0000;border-radius:6px}::-webkit-scrollbar-thumb:hover{background:var(--border-strong);background-clip:content-box}.workbench{height:100%}.shell{display:grid;grid-template-rows:1fr var(--statusbar-h);height:100vh;height:100dvh}.body{display:grid;grid-template-columns:var(--activity-w)1fr;overflow:hidden;min-height:0}kbd{font-family:var(--font-ui);color:var(--text-dim);background:var(--bg-hover);border:1px solid var(--border);text-align:center;border-radius:4px;min-width:16px;padding:1px 5px;font-size:10.5px}.kbd-edit{display:inline-flex;color:var(--text-dim);font:inherit;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:6px;align-items: center;gap:6px;padding:2px 4px}.kbd-edit:hover{border-color:var(--border);background:var(--bg-hover)}.kbd-edit:focus-visible{outline:none;border-color:var(--focus);box-shadow:0 0 0 3px var(--focus-halo)}.kbd-clash{display:inline-flex;color:var(--warn);align-items: center;margin-right:4px}.kbd-edit.clash kbd{border-color:color-mix(in srgb,var(--warn)50%,transparent);color:var(--warn)}.kbd-edit.listening{border-color:var(--accent);background:var(--bg-active);color:var(--accent);padding:3px 8px;font-size:11px}.activitybar{display:flex;background:var(--bg-activity);border-right:1px solid var(--border);flex-direction:column;align-items: center;gap:4px;padding:8px 0 10px}.activitybar .brand-mark{display:grid;cursor:pointer;transition:background .12s var(--ease),transform .12s var(--ease);background:0 0;border:0;border-radius:10px;place-items: center;width:40px;height:40px;margin-bottom:6px}.activitybar .brand-mark img{width:24px;height:24px}.activitybar .brand-mark:hover{background:var(--bg-hover)}.activitybar .brand-mark:active{transform:translateY(1px)}.activitybar .item{position:relative;color:var(--text-faint);display:grid;transition:color .12s var(--ease),background .12s var(--ease);background:0 0;border:0;border-radius:9px;place-items: center;width:40px;height:40px}.activitybar .item:hover{color:var(--text);background:var(--bg-hover)}.activitybar .item.active{color:var(--text);background:var(--bg-active)}.activitybar .item.active:before{content:"";position:absolute;background:linear-gradient(var(--accent),var(--accent-2));border-radius:0 3px 3px 0;width:3px;top:8px;bottom:8px;left:-6px}.activitybar .item .badge{position:absolute;background:var(--accent);color:var(--accent-text);display:grid;border-radius:8px;place-items: center;min-width:15px;height:15px;padding:0 3px;font-size:9.5px;font-weight:700;top:3px;right:3px}.activitybar .spacer{flex:1}.activitybar .bell-wrap{display:grid;place-items: center}.activitybar .iconbtn{color:var(--text-faint);border-radius:9px;width:40px;height:40px}.activitybar .iconbtn:hover{color:var(--text);background:var(--bg-hover)}.activitybar .principal{cursor:default;margin:4px 0 0}.sidebar{width:var(--sidebar-w);background:var(--bg-sidebar);border-right:1px solid var(--border);display:flex;overflow:hidden;flex-direction:column;min-width:0}.sidebar .head{display:flex;text-transform:uppercase;letter-spacing:.6px;color:var(--text-dim);align-items: center;gap:6px;padding:10px 12px 8px;font-size:11px;font-weight:600}.sidebar .head .actions{display:flex;gap:2px;margin-left:auto}.sidebar .scroll{overflow-y:auto;overflow-x:hidden;flex:1}.iconbtn{color:var(--text-dim);display:grid;transition:all .12s var(--ease);background:0 0;border:0;border-radius:6px;place-items: center;width:26px;height:26px}.iconbtn:hover{background:var(--bg-hover);color:var(--text)}.iconbtn:active{transform:translateY(1px)}.iconbtn.danger:hover{color:var(--danger)}.collection-switch{display:flex;border:1px solid var(--border);background:var(--bg-elevated);color:var(--text);transition:border-color .12s var(--ease);border-radius:8px;align-items: center;gap:8px;width:calc(100% - 16px);margin:4px 8px 0;padding:7px 10px}.collection-switch:hover{border-color:var(--accent)}.collection-switch .cs-name{text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;font-weight:550}.collection-switch svg:last-child{color:var(--text-faint)}.breadcrumb{display:flex;border-bottom:1px solid var(--border);color:var(--text-dim);flex-wrap:wrap;align-items: center;gap:2px;padding:6px 10px;font-size:12px}.breadcrumb .crumb{color:inherit;background:0 0;border:0;border-radius:5px;padding:2px 6px}.breadcrumb .crumb:hover{background:var(--bg-hover);color:var(--text)}.breadcrumb .sep{opacity:.4}.breadcrumb .crumb.current{color:var(--text);font-weight:500}.filelist{padding:4px}.row{display:flex;cursor:default;user-select:none;color:var(--text);transition:background 80ms var(--ease);border-radius:6px;align-items: center;gap:9px;height:30px;padding:0 8px}.compact .row{height:26px}.row:hover{background:var(--bg-hover)}.row.selected{background:var(--bg-selected);box-shadow:inset 0 0 0 1px var(--accent)}.row.drop-target{box-shadow:inset 0 0 0 2px var(--accent);background:var(--bg-selected)}.row .ico{color:var(--text-dim);display:grid;flex:none;place-items: center}.row .ico.folder{color:var(--accent)}.row .name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.row .meta{color:var(--text-faint);font-variant-numeric:tabular-nums;font-size:11px}.row .pin-dot{color:var(--success);display:grid;flex:none;place-items: center}.statusbar .offline-badge,.statusbar .offline-badge span{color:var(--warn)}.row .rename-input{background:var(--bg-input);border:1px solid var(--accent);outline:none;color:var(--text);border-radius:4px;flex:1;padding:2px 6px}.empty{display:flex;color:var(--text-faint);text-align:center;flex-direction:column;justify-content:center;align-items: center;gap:10px;height:100%;padding:32px}.empty .big{opacity:.5;font-size:34px}.empty .cta{border:1px dashed var(--border-strong);color:var(--text-dim);background:0 0;border-radius:8px;margin-top:4px;padding:7px 14px}.empty .cta:hover{border-color:var(--accent);color:var(--text)}.editor{display:flex;background:var(--bg);overflow:hidden;flex-direction:column;min-width:0}.tabs{display:flex;background:var(--bg-activity);border-bottom:1px solid var(--border);overflow-x:auto;align-items:stretch;height:36px}.tab{display:flex;border:0;border-right:1px solid var(--border);color:var(--text-dim);position:relative;white-space:nowrap;background:0 0;align-items: center;gap:8px;max-width:220px;padding:0 10px 0 14px}.tab.active{background:var(--bg);color:var(--text)}.tab.active:before{content:"";position:absolute;background:linear-gradient(90deg,var(--accent),var(--accent-2));height:2px;top:0;left:0;right:0}.tab .label{overflow:hidden;text-overflow:ellipsis}.tab .close{display:grid;opacity:.5;border-radius:4px;place-items: center;width:18px;height:18px}.tab .close:hover{background:var(--bg-hover);opacity:1}.editor .stage{overflow:auto;position:relative;flex:1;min-height:0}.welcome{display:grid;place-items: center;height:100%}.welcome .card{text-align:center;max-width:460px;padding:40px}.welcome h1{margin:12px 0 6px;font-size:26px;font-weight:650}.welcome .logo{font-size:46px}.welcome p{color:var(--text-dim);line-height:1.6}.welcome .hints{display:grid;text-align:left;gap:8px;margin-top:22px}.welcome .hint{display:flex;color:var(--text-dim);align-items: center;gap:10px}.statusbar{display:flex;background:linear-gradient(90deg,color-mix(in srgb,var(--accent)20%,var(--bg-activity)),var(--bg-activity));border-top:1px solid var(--border);color:var(--text-dim);align-items: center;gap:2px;padding:0 8px;font-size:11.5px}.statusbar .seg{display:flex;color:inherit;background:0 0;border:0;align-items: center;gap:5px;height:100%;padding:0 8px}.statusbar .seg:hover{background:var(--bg-hover);color:var(--text)}.statusbar .spacer{flex:1}.btn{display:inline-flex;border:1px solid var(--border-strong);background:var(--bg-elevated);color:var(--text);transition:all .12s var(--ease);border-radius:7px;align-items: center;gap:7px;padding:7px 13px}.btn:hover{border-color:var(--accent)}.btn.primary{background:linear-gradient(180deg,var(--accent),color-mix(in srgb,var(--accent)82%,black));color:var(--accent-text);border:0;font-weight:600}.btn.small{border-radius:6px;gap:5px;padding:4px 9px;font-size:12px}.btn.ghost{color:var(--text-dim);background:0 0;border-color:#0000}.btn.ghost:hover{background:var(--bg-hover);border-color:var(--border);color:var(--text)}.btn.on{border-color:var(--accent);color:var(--accent);background:var(--bg-active)}.btn.primary:hover{filter:brightness(1.08)}.btn.danger{color:var(--danger);border-color:color-mix(in srgb,var(--danger)40%,var(--border))}.btn.danger:hover{background:color-mix(in srgb,var(--danger)14%,transparent)}.btn:disabled{opacity:.45;pointer-events:none}.field{display:flex;flex-direction:column;gap:6px}.field label{color:var(--text-dim);font-size:12px}.input,select.input{background:var(--bg-input);color:var(--text);border:1px solid var(--border-strong);outline:none;transition:border-color .12s var(--ease),box-shadow .12s var(--ease);border-radius:7px;width:100%;padding:8px 11px}.input:focus{border-color:var(--accent);box-shadow:0 0 0 3px color-mix(in srgb,var(--accent)22%,transparent)}.switch{position:relative;flex:none;width:38px;height:22px}.switch input{position:absolute;opacity:0;cursor:pointer;z-index:1;width:100%;height:100%;margin:0;inset:0}.switch .track{position:absolute;background:var(--border-strong);transition:background .15s var(--ease);border-radius:22px;inset:0}.switch .track:before{content:"";position:absolute;transition:transform .16s var(--ease);background:#fff;border-radius:50%;width:16px;height:16px;top:3px;left:3px}.switch input:focus-visible+.track{box-shadow:0 0 0 3px var(--focus-halo);outline:1px solid var(--focus)}.switch input:checked+.track{background:var(--accent)}.switch input:checked+.track:before{transform:translate(16px)}.scrim{position:fixed;backdrop-filter:blur(1.5px);z-index:40;background:#0006;inset:0}.palette{position:fixed;background:var(--bg-elevated);border:1px solid var(--border-strong);box-shadow:var(--shadow);z-index:50;overflow:hidden;animation:pop .13s var(--ease);border-radius:12px;width:min(640px,92vw);top:12vh;left:50%;transform:translate(-50%)}@keyframes pop{0%{opacity:0;transform:translate(-50%,-6px)scale(.98)}to{opacity:1;transform:translate(-50%)scale(1)}}.palette .search{display:flex;border-bottom:1px solid var(--border);align-items: center;gap:9px;padding:12px 14px}.palette .search input{outline:none;color:var(--text);background:0 0;border:0;flex:1;font-size:15px}.palette .results{overflow-y:auto;max-height:52vh;padding:6px}.palette .opt{display:flex;cursor:default;border-radius:7px;align-items: center;gap:10px;padding:8px 10px}.palette .opt.active{background:var(--bg-active)}.palette .opt .ico{color:var(--text-dim)}.palette .opt .title{flex:1}.palette .opt .cat{color:var(--text-faint);font-size:11px}.palette .opt .kbd{margin-left:auto}.palette .opt .sub{color:var(--text-faint);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px}.palette .opt.unavailable{opacity:.5}.palette .opt.unavailable .title{text-decoration:line-through;text-decoration-color:var(--text-faint)}.offline-tag{text-transform:uppercase;letter-spacing:.5px;color:var(--warn);border:1px solid color-mix(in srgb,var(--warn)40%,transparent);border-radius:5px;padding:1px 5px;font-size:9.5px}.plugin-features{border-top:1px solid var(--border);margin-top:12px;padding-top:10px}.pf-head{display:flex;text-transform:uppercase;letter-spacing:.5px;color:var(--text-dim);justify-content:space-between;margin-bottom:8px;font-size:11px}.pf-list{display:flex;flex-direction:column;gap:4px}.pf-row{display:flex;border-radius:6px;align-items: center;gap:8px;padding:4px 6px;font-size:12.5px}.pf-row.off{opacity:.55}.pf-row .pf-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.pf-row .pf-kind{color:var(--text-faint);font-size:10px}.pf-badge{color:var(--text-faint);border:1px solid var(--border);white-space:nowrap;border-radius:5px;margin-left:auto;padding:1px 5px;font-size:9.5px}.pf-badge.offline-ok{color:var(--success);border:1px solid color-mix(in srgb,var(--success)40%,transparent);border-radius:5px;padding:1px 5px;font-size:9.5px}.pf-dot{border-radius:50%;flex:none;width:8px;height:8px}.pf-dot.on{background:var(--success)}.pf-dot.no{background:var(--text-faint)}.palette .none{text-align:center;color:var(--text-faint);display:flex;justify-content:center;align-items: center;gap:8px;padding:22px}.palette .none.error{color:var(--danger,#e5534b)}.palette .none .spinner{width:13px;height:13px}.dialog{position:fixed;background:var(--bg-elevated);border:1px solid var(--border-strong);box-shadow:var(--shadow);z-index:50;animation:pop .13s var(--ease);border-radius:12px;width:min(440px,92vw);padding:20px;top:50%;left:50%;transform:translate(-50%,-50%)}.dialog h3{margin:0 0 12px;font-size:16px}.dialog .body{display:block;color:var(--text-dim);margin-bottom:16px;line-height:1.5}.dialog .row-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}.opener-chooser .opener-list{display:flex;flex-direction:column;gap:6px;margin:4px 0 12px}.opener-opt{display:flex;border:1px solid var(--border);cursor:pointer;border-radius:9px;align-items: center;gap:10px;padding:9px 11px}.opener-opt:hover{background:var(--bg-hover)}.opener-opt.sel{border-color:var(--accent);background:color-mix(in srgb,var(--accent)10%,transparent)}.opener-opt input{accent-color:var(--accent)}.opener-opt .oo-main{display:flex;flex-direction:column;gap:1px}.opener-opt .oo-title{font-size:13px;font-weight:500}.opener-opt .oo-src{color:var(--text-dim);font-size:11px}.opener-remember{display:flex;color:var(--text-dim);cursor:pointer;align-items: center;gap:8px;font-size:12.5px}.opener-remember input{accent-color:var(--accent)}.menu{overflow-y:auto;overscroll-behavior:contain;position:fixed;z-index:60;background:var(--bg-elevated);border:1px solid var(--border-strong);box-shadow:var(--shadow);animation:pop .1s var(--ease);border-radius:9px;min-width:200px;max-height:calc(100vh - 24px);padding:5px}.menu .mi{display:flex;cursor:default;border-radius:6px;align-items: center;gap:10px;padding:7px 9px}.menu .mi:hover{background:var(--bg-active)}.menu .mi.danger:hover{background:color-mix(in srgb,var(--danger)16%,transparent);color:var(--danger)}.menu .mi .kbd{color:var(--text-faint);margin-left:auto}.menu .sep{background:var(--border);height:1px;margin:5px 2px}.toasts{position:fixed;bottom:calc(var(--statusbar-h) + 12px);z-index:70;display:flex;flex-direction:column;gap:8px;width:340px;right:14px}.toast{display:flex;background:var(--bg-elevated);border:1px solid var(--border-strong);box-shadow:var(--shadow);animation:slidein .16s var(--ease);border-radius:10px;gap:10px;padding:11px 13px}@keyframes slidein{0%{opacity:0;transform:translate(12px)}}.toast .bar{border-radius:3px;flex:none;width:3px}.toast.info .bar{background:var(--accent)}.toast.success .bar{background:var(--success)}.toast.warn .bar{background:var(--warn)}.toast.error .bar{background:var(--danger)}.toast .msg{flex:1;line-height:1.4}.toast .x{color:var(--text-faint);align-self: flex-start}.tray{position:fixed;bottom:calc(var(--statusbar-h) + 12px);left:calc(var(--activity-w) + 12px);z-index:65;background:var(--bg-elevated);border:1px solid var(--border-strong);box-shadow:var(--shadow);overflow:hidden;border-radius:12px;width:320px}.tray .head{display:flex;border-bottom:1px solid var(--border);align-items: center;padding:10px 12px;font-size:12px;font-weight:600}.tray .head .actions{margin-left:auto}.tray .items{overflow-y:auto;max-height:300px}.xfer{border-bottom:1px solid var(--border);padding:9px 12px}.xfer:last-child{border-bottom:0}.xfer .top{display:flex;align-items: center;gap:8px}.xfer .top .name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:12px}.xfer .pct{color:var(--text-faint);font-variant-numeric:tabular-nums;font-size:11px}.progress{background:var(--bg-hover);overflow:hidden;border-radius:3px;height:4px;margin-top:7px}.progress>div{background:linear-gradient(90deg,var(--accent),var(--accent-2));transition:width .2s var(--ease);height:100%}.xfer.error .progress>div{background:var(--danger)}.xfer.cancelled{opacity:.55}.searchview{display:flex;flex-direction:column;gap:10px;height:100%;padding:10px}.searchview .box{display:flex;gap:6px}.searchview .modes{display:flex;gap:4px}.chip{border:1px solid var(--border);color:var(--text-dim);background:0 0;border-radius:20px;padding:4px 10px;font-size:11.5px}.chip.active{background:var(--bg-selected);border-color:var(--accent);color:var(--text)}.results{overflow-y:auto;display:flex;flex-direction:column;flex:1;gap:6px}.result{border:1px solid var(--border);background:var(--bg-elevated);cursor:default;border-radius:9px;padding:10px 11px}.result:hover{border-color:var(--border-strong)}.result .top{display:flex;align-items: center;gap:8px}.result .top .name{font-weight:550}.result .top .score{color:var(--text-faint);margin-left:auto;font-size:10.5px}.result .path{color:var(--text-faint);margin:2px 0 0 24px;font-size:11px}.result .snippet{color:var(--text-dim);margin:6px 0 0 24px;font-size:12px;line-height:1.5}.result .snippet mark{background:color-mix(in srgb,var(--accent)32%,transparent);color:var(--text);border-radius:3px;padding:0 2px}.result .badge{background:var(--bg-hover);color:var(--text-dim);border-radius:5px;padding:1px 6px;font-size:10px}.settings{max-width:720px;margin:0 auto;padding:26px 24px 60px}.settings h2{margin:0 0 4px;font-size:20px}.settings .sub{color:var(--text-dim);margin-bottom:22px}.settings .group{margin-bottom:28px}.settings .group h3{text-transform:uppercase;letter-spacing:.6px;color:var(--accent);margin:0 0 10px;font-size:12px}.setting{display:flex;border-bottom:1px solid var(--border);align-items: center;gap:16px;padding:12px 0}.setting .info{flex:1}.setting .info .t{font-weight:550}.setting .info .d{color:var(--text-faint);margin-top:2px;font-size:12px;line-height:1.4}.setting .control{display:flex;flex:none;justify-content:flex-end;width:200px}.plugins{display:flex;flex-direction:column;gap:12px;padding:16px}.plugin-card{border:1px solid var(--border);background:var(--bg-elevated);border-radius:11px;padding:14px}.plugin-card .top{display:flex;align-items: center;gap:10px}.plugin-card .avatar{background:linear-gradient(135deg,var(--accent),var(--accent-2));display:grid;color:var(--accent-text);border-radius:9px;place-items: center;width:38px;height:38px;font-weight:700}.plugin-card .name{font-weight:600}.plugin-card .status{border-radius:12px;margin-left:auto;padding:2px 8px;font-size:11px}.plugin-card .status.active{background:color-mix(in srgb,var(--success)20%,transparent);color:var(--success)}.plugin-card .status.error{background:color-mix(in srgb,var(--danger)20%,transparent);color:var(--danger)}.plugin-card .status.loading{background:var(--bg-hover);color:var(--text-dim)}.plugin-card .caps{display:flex;flex-wrap:wrap;gap:5px;margin:10px 0 0}.plugin-card .cap{background:var(--bg-hover);color:var(--text-dim);border-radius:6px;padding:2px 7px;font-size:10.5px}.plugin-card .desc{color:var(--text-dim);margin-top:8px;font-size:12px;line-height:1.5}.plugin-card .actions{display:flex;gap:8px;margin-top:12px}.plugin-panel{position:fixed;z-index:55;background:var(--bg-elevated);border:1px solid var(--border-strong);box-shadow:var(--shadow);overflow:hidden;animation:pop .13s var(--ease);border-radius:12px;top:12px;right:12px}.plugin-panel .head{display:flex;border-bottom:1px solid var(--border);align-items: center;gap:8px;padding:9px 12px;font-size:12px;font-weight:600}.plugin-panel .head .x{margin-left:auto}.plugin-panel .host{display:block}.plugin-install{display:flex;gap:8px;margin-top:10px}.trust{display:inline-flex;border:1px solid var(--border);white-space:nowrap;border-radius:12px;align-items: center;gap:4px;padding:2px 7px;font-size:10.5px}.trust.verified{color:var(--success);border-color:color-mix(in srgb,var(--success)45%,transparent);background:color-mix(in srgb,var(--success)12%,transparent)}.trust.signed{color:var(--text-dim)}.trust.unverified{color:var(--warn);border-color:color-mix(in srgb,var(--warn)40%,transparent)}.trust.invalid{color:var(--danger,#e5484d);border-color:color-mix(in srgb,var(--danger,#e5484d)55%,transparent);background:color-mix(in srgb,var(--danger,#e5484d)14%,transparent);font-weight:600}.dialog.review{overflow:hidden;padding:0}.review-head{display:flex;border-bottom:1px solid var(--border);align-items: center;gap:12px;padding:16px 18px}.review-head .avatar{border-radius:11px;width:44px;height:44px}.review-head .rh-main{flex:1}.review-head .rh-name{display:flex;align-items:baseline;gap:8px;font-size:16px;font-weight:650}.review-head .rh-ver{color:var(--text-faint);font-size:11px;font-weight:400}.review-head .rh-author{color:var(--text-dim);margin-top:2px;font-size:12px}.review-body{overflow-y:auto;max-height:60vh;padding:14px 18px}.review-desc{color:var(--text-dim);margin:0 0 14px;line-height:1.55}.review-section{margin-bottom:16px}.review-section .rs-title{text-transform:uppercase;letter-spacing:.5px;color:var(--accent);margin-bottom:8px;font-size:11px}.cap-list{display:flex;flex-direction:column;gap:8px}.cap-row{display:flex;border:1px solid var(--border);cursor:pointer;border-radius:9px;align-items: flex-start;gap:10px;padding:8px 10px}.cap-row:hover{border-color:var(--border-strong)}.cap-row.blocked,.contrib-row.blocked{opacity:.6;cursor:not-allowed}.contrib-row.blocked .pf-title{text-decoration:line-through}.cap-row input{accent-color:var(--accent);margin-top:2px}.cap-row .cap-name{font-size:13px;font-weight:600}.cap-row .cap-desc{color:var(--text-dim);margin-top:2px;font-size:12px;line-height:1.4}.contrib-list{display:flex;flex-direction:column;gap:3px}.contrib-row{display:flex;align-items: center;gap:8px;padding:3px 4px;font-size:12.5px}.contrib-row .cr-title{color:var(--text)}.contrib-row .cr-detail{color:var(--text-faint);font-size:11px}.contrib-row .pf-kind{color:var(--text-faint);margin-left:auto;font-size:10px}.review-meta{color:var(--text-faint);margin-top:6px;font-size:11px}.dialog.review .row-actions{border-top:1px solid var(--border);margin:0;padding:14px 18px}.viewer{display:flex;flex-direction:column;height:100%}.viewer.text pre{font-family:var(--font-mono);white-space:pre-wrap;word-break:break-word;color:var(--text);margin:0;padding:18px 20px;font-size:12.5px;line-height:1.65}.viewer.image{display:grid;background:repeating-conic-gradient(var(--bg-elevated)0% 25%,var(--bg)0% 50%)50%/22px 22px;place-items: center}.viewer.image img{object-fit:contain;box-shadow:var(--shadow);max-width:100%;max-height:100%}.viewer .loading,.viewer .fallback{color:var(--text-faint);display:flex;text-align:center;flex-direction:column;align-items: center;gap:12px;margin:auto;padding:40px}.viewer.plugin-viewer{display:block;position:relative}.viewer.plugin-viewer .pv-host{width:100%;height:100%}.viewer.plugin-viewer .pv-status{position:absolute;z-index:2;display:grid;background:var(--bg);place-items: center;inset:0}.viewer.plugin-viewer .pv-status .loading,.viewer.plugin-viewer .pv-status .fallback{color:var(--text-faint);display:flex;text-align:center;flex-direction:column;align-items: center;gap:12px;padding:40px}.viewer-dock{position:fixed;z-index:60;display:none;box-shadow:var(--shadow);background:0 0;border-radius:12px;flex-direction:column;bottom:18px;right:18px}.viewer-dock .vd-bar{display:flex;background:var(--bg-elevated);border:1px solid var(--border-strong);border-bottom:0;border-radius:12px 12px 0 0;align-items: center;gap:6px;height:26px;padding:0 4px 0 10px}.viewer-dock .vd-title{color:var(--text-dim);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0;font-size:11.5px}.viewer-dock .vd-bar button{color:var(--text-dim);cursor:pointer;display:grid;background:0 0;border:0;border-radius:5px;place-items: center;width:20px;height:20px;padding:0;font-size:12px}.viewer-dock .vd-bar button:hover{background:var(--bg-hover);color:var(--text)}.viewer-dock .vd-body{border:1px solid var(--border-strong);background:0 0;border-top:0;border-radius:0 0 12px 12px;flex:1;min-height:0}.audiobook-host{height:100%;min-height:0}.audiobook{display:grid;grid-template-columns:300px 1fr;height:100%;min-height:0}.audiobook .cover-pane{background:var(--bg-elevated);border-right:1px solid var(--border);display:flex;overflow-y:auto;flex-direction:column;align-items: center;gap:18px;padding:26px}.audiobook .cover{box-shadow:var(--shadow);object-fit:cover;background:linear-gradient(135deg,var(--accent),var(--accent-2));display:grid;color:#fff;border-radius:14px;place-items: center;width:220px;height:220px;font-size:60px}.audiobook .meta{text-align:center}.audiobook .meta .title{font-size:17px;font-weight:650}.audiobook .meta .author{color:var(--text-dim);margin-top:3px}.audiobook .meta .narrator{color:var(--text-faint);margin-top:2px;font-size:12px}.audiobook .transport{display:flex;flex-direction:column;gap:12px;width:100%}.audiobook .scrub{display:flex;align-items: center;gap:10px}.audiobook .scrub input[type=range]{accent-color:var(--accent);flex:1}.audiobook .time{font-variant-numeric:tabular-nums;color:var(--text-faint);min-width:42px;font-size:11px}.audiobook .buttons{display:flex;justify-content:center;align-items: center;gap:14px}.audiobook .buttons .play{background:linear-gradient(180deg,var(--accent),var(--accent-2));color:var(--accent-text);display:grid;box-shadow:var(--shadow);border:0;border-radius:50%;place-items: center;width:54px;height:54px}.audiobook .buttons .play:hover{filter:brightness(1.08)}.audiobook .buttons .skip{background:var(--bg-hover);color:var(--text);display:grid;border:0;border-radius:50%;place-items: center;width:40px;height:40px}.audiobook .buttons .rate{background:var(--bg-hover);color:var(--text-dim);font-variant-numeric:tabular-nums;border:0;border-radius:8px;min-width:46px;padding:6px 8px}.audiobook .chapters{overflow-y:auto;padding:10px}.audiobook .chapters .ch-head{text-transform:uppercase;letter-spacing:.6px;color:var(--text-dim);display:flex;padding:8px 10px;font-size:11px}.audiobook .chapters .ch-head .count{color:var(--text-faint);margin-left:auto}.audiobook .chapter{display:flex;cursor:default;border-radius:8px;align-items: center;gap:10px;padding:9px 11px}.audiobook .chapter:hover{background:var(--bg-hover)}.audiobook .chapter.current{background:var(--bg-selected)}.audiobook .chapter .n{text-align:right;color:var(--text-faint);font-variant-numeric:tabular-nums;width:22px;font-size:12px}.audiobook .chapter .t{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.audiobook .chapter .d{color:var(--text-faint);font-variant-numeric:tabular-nums;font-size:11px}.audiobook .chapter.current .n{color:var(--accent)}.spinner{border:2px solid var(--border-strong);border-top-color:var(--accent);animation:spin .7s linear infinite;border-radius:50%;width:20px;height:20px}@keyframes spin{to{transform:rotate(360deg)}}.dragging-file .editor:after,.dragging-file .sidebar:after{content:"Drop to upload";position:absolute;border:2px dashed var(--accent);display:grid;color:var(--accent);background:color-mix(in srgb,var(--accent)8%,transparent);pointer-events:none;z-index:30;border-radius:12px;place-items: center;font-weight:600;inset:8px}.editor,.sidebar{position:relative}.principal{overflow:hidden;display:grid;background:linear-gradient(135deg,var(--accent),var(--accent-2));color:#fff;border-radius:50%;place-items: center;width:30px;height:30px;font-size:12px;font-weight:700}.principal .avatar-img{object-fit:cover;width:100%;height:100%}.bell-wrap{position:relative}.bell-badge{position:absolute;background:var(--danger);color:#fff;display:grid;border-radius:8px;place-items: center;min-width:15px;height:15px;padding:0 3px;font-size:9.5px;font-weight:700;top:3px;right:3px}.inbox{position:fixed;left:calc(var(--activity-w) + 8px);background:var(--bg-elevated);border:1px solid var(--border-strong);box-shadow:var(--shadow);z-index:55;overflow:hidden;animation:pop .12s var(--ease);border-radius:12px;width:340px;bottom:8px}.inbox-head{display:flex;border-bottom:1px solid var(--border);justify-content:space-between;align-items: center;padding:11px 13px;font-size:12px;font-weight:600}.inbox-head .link,.link{color:var(--accent);background:0 0;border:0;font-size:12px}.inbox-head .muted,.muted{color:var(--text-faint)}.inbox-items{overflow-y:auto;max-height:380px}.inbox-item{border-bottom:1px solid var(--border);cursor:default;padding:10px 13px}.inbox-item:hover{background:var(--bg-hover)}.inbox-item.unread{border-left:2px solid var(--accent)}.inbox-item .ii-title{font-size:12.5px;font-weight:550}.inbox-item .ii-excerpt{color:var(--text-dim);margin-top:2px;font-size:12px}.inbox-item .ii-time{color:var(--text-faint);margin-top:3px;font-size:10.5px}.inbox-empty{display:flex;color:var(--text-faint);flex-direction:column;align-items: center;gap:8px;padding:30px}.editor-split{display:grid;grid-template-columns:1fr 340px;overflow:hidden;min-width:0}.infopanel{border-left:1px solid var(--border);background:var(--bg-sidebar);display:flex;flex-direction:column;min-width:0;min-height:0}.infopanel>*{min-width:0}.ip-head{display:flex;border-bottom:1px solid var(--border);align-items: center;gap:8px;padding:10px 12px;font-size:12px;font-weight:600}.ip-head .iconbtn{margin-left:auto}.ip-body{overflow-y:auto;flex:1}.ip-empty{color:var(--text-faint);text-align:center;padding:30px}.ip-file{border-bottom:1px solid var(--border);padding:12px}.ip-file .ip-name{font-weight:600}.ip-file .ip-path{color:var(--text-faint);margin-top:2px;font-size:11px}.ip-section{border-bottom:1px solid var(--border);padding:12px}.ip-body>:last-child{border-bottom:0}.ip-label{text-transform:uppercase;letter-spacing:.5px;color:var(--text-dim);margin-bottom:9px;font-size:11px}.tags{display:flex;flex-wrap:wrap;align-items: center;gap:6px}.tag{display:inline-flex;background:var(--bg-selected);border:1px solid var(--border);border-radius:14px;align-items: center;gap:5px;padding:3px 4px 3px 9px;font-size:12px}.tag-x{color:var(--text-faint);display:grid;background:0 0;border:0;border-radius:50%;place-items: center;width:16px;height:16px}.tag-x:hover{background:var(--bg-active);color:var(--danger)}.tag-input{background:var(--bg-input);border:1px solid var(--border);outline:none;color:var(--text);border-radius:14px;width:84px;padding:4px 10px;font-size:12px}.tag-input:focus{border-color:var(--accent);width:120px}.conv .thread{display:flex;flex-direction:column;gap:12px;margin-bottom:12px}.conv-empty{color:var(--text-faint);margin-bottom:12px;font-size:12px;line-height:1.5}.conv-signin{display:flex;color:var(--text-faint);flex-wrap:wrap;align-items:baseline;gap:6px;padding:8px 0;font-size:12px}.comment{font-size:13px}.c-head{display:flex;align-items: center;gap:7px}.c-avatar{background:linear-gradient(135deg,var(--accent-2),var(--accent));color:#fff;display:grid;border-radius:50%;flex:none;place-items: center;width:22px;height:22px;font-size:11px;font-weight:700}.c-author{font-size:12.5px;font-weight:600}.c-time{color:var(--text-faint);font-size:11px}.c-body{white-space:pre-wrap;word-break:break-word;margin:4px 0 4px 29px;line-height:1.5}.c-body.deleted{color:var(--text-faint);font-style:italic}.c-body .mention{color:var(--accent);background:color-mix(in srgb,var(--accent)14%,transparent);border-radius:4px;padding:0 3px;font-weight:600}.c-actions{display:flex;flex-wrap:wrap;align-items: center;gap:4px;margin-left:29px}.react{display:inline-flex;background:0 0;border:0;border-radius:12px;align-items: center;gap:3px;padding:2px 6px;font-size:12px}.react:hover{background:var(--bg-hover)}.react.on{background:var(--bg-selected)}.react .rc{color:var(--text-dim);font-size:10px}.c-link{color:var(--text-faint);background:0 0;border:0;border-radius:5px;padding:2px 5px;font-size:11.5px}.c-link:hover{color:var(--text);background:var(--bg-hover)}.c-link.danger:hover{color:var(--danger)}.replies{border-left:2px solid var(--border);margin-top:10px}.composer{display:flex;flex-direction:column;gap:6px}.composer .replying{color:var(--text-dim);display:flex;align-items: center;gap:8px;font-size:11px}.composer-input{background:var(--bg-input);border:1px solid var(--border-strong);resize:vertical;outline:none;color:var(--text);border-radius:9px;padding:8px 10px;font-family:inherit}.composer-input:focus{border-color:var(--accent)}.composer-actions{display:flex;justify-content:space-between;align-items: center}.composer-actions .btn{padding:5px 12px}@media (max-width:720px){:root{--sidebar-w:220px}.audiobook{grid-template-columns:1fr;grid-template-rows:auto 1fr}.audiobook .cover-pane{border-right:0;border-bottom:1px solid var(--border)}.editor-split{grid-template-columns:1fr}.editor-split .infopanel{display:none}}.launcher{display:flex;flex-direction:column;width:100%;max-width:820px;height:100%;margin:0 auto;padding:0 20px}.launch-box{display:flex;background:var(--bg-input);border:1px solid var(--border-strong);box-shadow:var(--shadow);border-radius:12px;align-items: center;gap:10px;margin:min(12vh,90px) 0 4px;padding:12px 16px}.launch-box>svg{color:var(--text-dim);flex:none}.launch-box button>svg{flex:none}.launch-resolved{display:flex;color:var(--text-dim);flex-wrap:wrap;align-items: center;gap:7px;margin:8px 4px 0;font-size:12px}.launch-resolved .rq-label{text-transform:uppercase;letter-spacing:.05em;color:var(--text-faint);font-size:10px;font-weight:600}.launch-resolved .rq-text{color:var(--text)}.launch-resolved .rq-chip{display:inline-flex;background:var(--bg-hover);border:1px solid var(--border);color:var(--text-dim);border-radius:12px;align-items: center;gap:4px;padding:2px 8px}.launch-input{outline:none;color:var(--text);font:500 17px/1.3 var(--font-ui);background:0 0;border:0;flex:1}.launch-input::placeholder{color:var(--text-faint);font-weight:400}.launch-clear{display:inline-flex;color:var(--text-faint);cursor:pointer;background:0 0;border:0;border-radius:6px;justify-content:center;align-items: center;width:24px;height:24px}.launch-clear:hover{background:var(--bg-hover);color:var(--text)}.launch-mic{display:inline-flex;color:var(--text-faint);cursor:pointer;background:0 0;border:0;border-radius:7px;flex:none;justify-content:center;align-items: center;width:26px;height:26px}.launch-mic:hover{background:var(--bg-hover);color:var(--text)}.launch-mic.on{color:var(--accent-text);background:var(--accent);animation:mic-pulse 1.4s var(--ease)infinite}@keyframes mic-pulse{0%,to{box-shadow:0 0 0 0 var(--focus-halo)}50%{box-shadow:0 0 0 5px #0000}}@media (prefers-reduced-motion:reduce){.launch-mic.on{animation:none}}.launch-body{overflow-y:auto;flex:1;padding:8px 0 40px}.launch-group{margin-top:14px}.launch-h{display:flex;letter-spacing:.04em;text-transform:uppercase;color:var(--text-faint);justify-content:space-between;align-items: center;gap:8px;padding:4px 10px;font-size:11px;font-weight:600}.launch-list{display:flex;flex-direction:column}.launch-item{display:flex;cursor:pointer;color:var(--text);border-radius:8px;align-items: center;gap:10px;padding:8px 10px}.launch-item svg{color:var(--text-dim);flex:none}.launch-item .name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:0}.launch-item:hover{background:var(--bg-hover)}.launch-item.active{background:var(--bg-selected);box-shadow:inset 3px 0 0 0 var(--focus)}.launch-detail{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text-faint);flex:0 auto;min-width:0;font-size:12.5px}.launch-more{display:inline-flex;color:var(--text-faint);cursor:pointer;opacity:0;transition:opacity .1s var(--ease),background .1s var(--ease);background:0 0;border:0;border-radius:7px;flex:none;justify-content:center;align-items: center;width:26px;height:26px;margin:-4px -4px -4px 0}.launch-item:hover .launch-more,.launch-item.active .launch-more{opacity:1}.launch-more:focus-visible{opacity:1}.launch-more:hover{background:var(--bg-active);color:var(--text)}.launch-more:focus-visible{outline:none;color:var(--text);background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}@media (hover:none){.launch-more{opacity:1}}.launch-kind{color:var(--text-faint);border:1px solid var(--border);border-radius:5px;flex:none;padding:1px 6px;font-size:11px}.launch-up{display:inline-flex;color:var(--text-dim);cursor:pointer;background:0 0;border:0;border-radius:5px;align-items: center;gap:3px;padding:2px 4px;font-size:12px}.launch-up:hover{background:var(--bg-hover);color:var(--text)}.launch-empty{color:var(--text-faint);padding:8px 12px;font-size:13px}.view-switch{display:inline-flex;border-left:1px solid var(--border);flex:none;align-items: center;gap:2px;margin-left:2px;padding-left:4px}.vs-btn{display:inline-flex;color:var(--text-faint);cursor:pointer;background:0 0;border:0;border-radius:7px;justify-content:center;align-items: center;width:26px;height:26px}.vs-btn:hover{background:var(--bg-hover);color:var(--text)}.vs-btn.on{background:var(--bg-active);color:var(--text)}.vs-btn:focus-visible{outline:none;color:var(--text);box-shadow:0 0 0 2px var(--focus-halo)}.view-error{display:flex;border:1px solid var(--border);background:var(--bg-hover);color:var(--text-dim);border-radius:8px;align-items: center;gap:6px;margin:8px 10px 0;padding:7px 10px;font-size:12.5px}.view-error svg{color:var(--warn);flex:none}.grid-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(132px,1fr));gap:10px;padding:4px 10px}.grid-tile{display:flex;cursor:pointer;color:var(--text);border-radius:10px;flex-direction:column;gap:6px;padding:6px}.grid-tile:hover{background:var(--bg-hover)}.grid-tile.active{background:var(--bg-selected);box-shadow:inset 0 0 0 2px var(--focus)}.gt-media{position:relative;display:grid;aspect-ratio:1;background:var(--bg-hover);overflow:hidden;border-radius:8px;place-items: center}.gt-media>svg{color:var(--text-faint)}.gt-img{position:absolute;object-fit:cover;width:100%;height:100%;inset:0}.gt-badge{position:absolute;color:#fff;background:#0009;border-radius:5px;padding:1px 6px;font-size:10.5px;bottom:5px;left:5px}.gt-media .launch-more{position:absolute;background:var(--bg-elevated);margin:0;top:3px;right:3px}.grid-tile:hover .launch-more,.grid-tile.active .launch-more{opacity:1}.gt-name{overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;word-break:break-word;-webkit-box-orient:vertical;font-size:12.5px;line-height:1.35}.viewer-nav{display:flex;background:var(--bg-activity);border-bottom:1px solid var(--border);align-items: center;gap:6px;height:40px;padding:0 8px}.vn-back{display:inline-flex;border:1px solid var(--border);background:var(--bg-elevated);color:var(--text-dim);border-radius:7px;justify-content:center;align-items: center;width:30px;height:28px}.vn-back:hover{color:var(--text);background:var(--bg-hover)}.vn-trail{display:flex;overflow-x:auto;flex:1;align-items: center;gap:2px;min-width:0}.vn-crumb{display:inline-flex;color:var(--text-dim);white-space:nowrap;background:0 0;border:0;border-radius:6px;align-items: center;gap:5px;max-width:240px;padding:4px 8px}.vn-crumb .label{overflow:hidden;text-overflow:ellipsis}.vn-crumb:hover{background:var(--bg-hover);color:var(--text)}.vn-crumb.active{color:var(--text);font-weight:550}.vn-crumb:not(:last-child):after{content:"›";color:var(--text-faint);margin-left:6px}.vn-actions{display:flex;gap:2px}.search-modal{position:fixed;z-index:60;inset:0}.search-modal .scrim{position:absolute;z-index:0;background:#00000073;inset:0}.search-modal-panel{z-index:1;position:absolute;background:var(--bg-elevated);border:1px solid var(--border-strong);box-shadow:var(--shadow);overflow:hidden;display:flex;border-radius:12px;width:min(680px,94vw);max-height:72vh;top:12vh;left:50%;transform:translate(-50%)}.search-modal-panel .launcher{max-width:none;height:100%;padding:0 12px}.search-modal-panel .launch-box{margin:12px 0 4px}.search-modal-panel .launch-body{max-height:56vh}.ip-uri{display:flex;border:1px solid var(--border);background:var(--bg-elevated);color:var(--text-dim);font:11px/1.4 var(--font-mono,ui-monospace,monospace);text-align:left;cursor:pointer;overflow:hidden;border-radius:6px;align-items: center;gap:6px;width:100%;min-width:0;padding:6px 8px}.ip-uri>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.ip-uri:hover{color:var(--text);border-color:var(--accent)}.ip-backlinks{display:flex;flex-direction:column;gap:4px}.ip-backlink{display:flex;color:var(--text-dim);text-align:left;cursor:pointer;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background:0 0;border:1px solid #0000;border-radius:6px;align-items: center;gap:6px;width:100%;padding:5px 8px;font-size:12px}.ip-backlink:hover{background:var(--bg-elevated);color:var(--text)}.ip-muted{color:var(--text-faint);padding:2px 0;font-size:12px}.ip-muted.error{color:var(--danger,#e5534b)}.viewer.markdown{overflow:auto;padding:32px 40px}.md{color:var(--text);max-width:760px;margin:0 auto;font-size:14px;line-height:1.65}.md-h{margin:1.6em 0 .6em;font-weight:650;line-height:1.3}.md-h:first-child{margin-top:0}.md-h1{font-size:1.7em}.md-h2{font-size:1.35em}.md-h3{font-size:1.12em}.md-h4{font-size:1em}.md-h5{color:var(--text-dim);font-size:.92em}.md-h6{color:var(--text-dim);text-transform:uppercase;letter-spacing:.04em;font-size:.88em}.md-p{margin:0 0 1em}.md-list{margin:0 0 1em;padding-left:1.4em}.md-li{margin:.25em 0}.md-quote{border-left:3px solid var(--border);color:var(--text-dim);margin:0 0 1em;padding:.1em 0 .1em 1em}.md-hr{border:none;border-top:1px solid var(--border);margin:1.8em 0}.md-code{overflow-x:auto;background:var(--bg-elevated);border:1px solid var(--border);font:12px/1.55 var(--font-mono,ui-monospace,monospace);border-radius:8px;margin:0 0 1em;padding:12px 14px}.md-inline-code{background:var(--bg-elevated);font:.9em var(--font-mono,ui-monospace,monospace);border-radius:4px;padding:.12em .35em}.md-link{color:var(--accent);text-decoration:none;border-bottom:1px solid #0000}.md-link:hover{border-bottom-color:currentColor}.md-trove{border-bottom:1px dashed color-mix(in srgb,var(--accent)55%,transparent)}.md-deadlink{color:var(--text-faint);text-decoration:line-through;cursor:not-allowed}.md-truncated{border:1px dashed var(--border);color:var(--text-faint);border-radius:8px;margin:1.5em 0 0;padding:10px 12px;font-size:12.5px}.activity-panel{position:fixed;right:12px;bottom:calc(var(--statusbar-h) + 10px);z-index:60;overflow-y:auto;background:var(--bg-elevated);border:1px solid var(--border-strong);border-radius:var(--radius);box-shadow:var(--shadow);display:flex;flex-direction:column;width:380px;max-height:62vh}.act-head{display:flex;border-bottom:1px solid var(--border);justify-content:space-between;align-items: center;padding:10px 12px}.act-head h3{margin:0;font-size:13px;font-weight:600}.act-section{border-bottom:1px solid var(--border);padding:10px 12px}.act-section:last-of-type{border-bottom:none}.act-section-title{text-transform:uppercase;letter-spacing:.06em;color:var(--text-faint);margin-bottom:8px;font-size:10.5px}.act-empty{color:var(--text-faint);margin:0;font-size:12.5px}.act-row{display:flex;align-items: flex-start;gap:8px}.act-body{flex:1;min-width:0}.act-title{overflow-wrap:anywhere;font-size:12.5px}.act-detail,.act-meta{color:var(--text-dim);overflow-wrap:anywhere;margin-top:2px;font-size:11.5px}.act-meta{color:var(--text-faint)}.act-error{color:var(--danger);overflow-wrap:anywhere;margin-top:2px;font-size:11.5px}.act-amount{color:var(--text-faint);margin-top:3px;font-size:11px}.act-action{color:var(--text-faint);cursor:pointer;background:0 0;border:none;border-radius:4px;padding:2px}.act-action:hover{background:var(--bg-hover);color:var(--text)}.act-task,.act-issue{padding:7px 0}.act-task+.act-task,.act-issue+.act-issue{border-top:1px solid var(--border)}.act-actions{display:flex;gap:6px;margin:6px 0 0 21px}.act-done .act-title,.act-cancelled .act-title{color:var(--text-dim)}.act-failed .act-title{color:var(--danger)}.act-sev-warning .act-title{color:var(--warn)}.act-offline{display:flex;color:var(--warn);background:var(--bg-hover);align-items: center;gap:6px;padding:8px 12px;font-size:11.5px}.act-foot{padding:10px 12px}.act-bar{background:var(--bg-input);overflow:hidden;border-radius:2px;height:3px;margin:6px 0 0 21px}.act-fill{background:var(--accent);transition:width .25s var(--ease);border-radius:2px;height:100%}.act-bar.indeterminate .act-fill{animation:act-slide 1.1s var(--ease)infinite;width:35%}@keyframes act-slide{0%{margin-left:-35%}to{margin-left:100%}}.sb-attention,.sb-attention:hover{color:var(--warn)}.sb-usage{gap:6px}.usage-bar{background:var(--bg-input);overflow:hidden;border-radius:2px;width:42px;height:4px}.usage-fill{background:var(--text-dim);transition:width .3s var(--ease);border-radius:2px;height:100%}.sb-usage.low .usage-fill{background:var(--warn)}.sb-usage.low{color:var(--warn)}.sb-usage.critical .usage-fill{background:var(--danger)}.sb-usage.critical{color:var(--danger)}:root{--phonebar-h:46px;--phonetabs-h:56px}.shell.phone{grid-template-rows:calc(var(--phonebar-h) + env(safe-area-inset-top))1fr calc(var(--phonetabs-h) + env(safe-area-inset-bottom))}.shell.phone .body{grid-template-columns:1fr}.phonebar{display:flex;background:var(--bg-activity);color:var(--text-dim);align-items: center}.phonebar.top{padding:env(safe-area-inset-top)6px 0;border-bottom:1px solid var(--border);gap:8px}.pb-brand{display:grid;background:0 0;border:0;border-radius:9px;flex:none;place-items: center;width:34px;height:34px}.pb-brand img{width:21px;height:21px}.pb-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text);flex:1;min-width:0;font-size:15px;font-weight:600}.pb-status{position:relative;display:grid;color:var(--text-dim);background:0 0;border:0;border-radius:10px;flex:none;place-items: center;width:38px;height:38px}.pb-status:active{background:var(--bg-hover)}.pb-status.warn{color:var(--warn)}.pb-status.danger{color:var(--danger)}.pb-badge{position:absolute;background:var(--danger);color:#fff;display:grid;border-radius:8px;place-items: center;min-width:15px;height:15px;padding:0 3px;font-size:9.5px;font-weight:700;top:2px;right:2px}.phonebar.bottom{padding:0 4px env(safe-area-inset-bottom);border-top:1px solid var(--border);background:color-mix(in srgb,var(--accent)6%,var(--bg-activity));justify-content:space-around}.pb-tab{position:relative;height:var(--phonetabs-h);color:var(--text-faint);display:flex;background:0 0;border:0;border-radius:10px;flex-direction:column;flex:1;justify-content:center;align-items: center;gap:3px}.pb-tab .pb-label{font-size:10.5px;font-weight:550}.pb-tab.active{color:var(--accent)}.pb-tab:active{background:var(--bg-hover)}.pb-tab .pb-badge{background:var(--accent);color:var(--accent-text);top:6px;right:22%}.sheet-wrap{position:fixed;z-index:58;inset:0}.sheet-wrap .scrim{position:absolute;z-index:0;background:#00000080;inset:0}.sheet{position:absolute;z-index:41;overflow-y:auto;background:var(--bg-elevated);border-top:1px solid var(--border-strong);box-shadow:var(--shadow);padding-bottom:calc(12px + env(safe-area-inset-bottom));animation:sheet-up .18s var(--ease);border-radius:16px 16px 0 0;max-height:82vh;bottom:0;left:0;right:0}@keyframes sheet-up{0%{transform:translateY(18px);opacity:.4}to{transform:none;opacity:1}}.sheet-grip{display:grid;background:0 0;border:0;place-items: center;width:100%;height:22px}.sheet-grip:before{content:"";background:var(--border-strong);border-radius:2px;width:38px;height:4px}.sheet-body{display:flex;flex-direction:column;padding:2px 10px 6px}.sheet-title{letter-spacing:.04em;text-transform:uppercase;color:var(--text-faint);padding:4px 8px 10px;font-size:12px;font-weight:600}.sheet-row{display:flex;color:var(--text);text-align:left;background:0 0;border:0;border-radius:10px;align-items: center;gap:12px;width:100%;min-height:46px;padding:0 8px;font-size:14.5px}.sheet-row:active{background:var(--bg-hover)}.sheet-row.static{color:var(--text-dim)}.sheet-row.danger{color:var(--danger)}.sheet-row svg{color:var(--text-dim);flex:none}.sheet-row.danger svg{color:var(--danger)}.sheet-row .sr-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0}.sheet-row .sr-value{color:var(--text-dim);font-size:13px}.sheet-row .sr-go{color:var(--text-faint)}.sheet-row .sb-usage{padding:0}.sheet-actions{display:flex;border-top:1px solid var(--border);gap:8px;margin-top:8px;padding:12px 8px 4px}.sheet-actions .btn{flex:1;justify-content:center}.sheet-me{display:flex;border-bottom:1px solid var(--border);align-items: center;gap:10px;margin-bottom:6px;padding:4px 8px 12px}.sheet-me .avatar-img,.sheet-me .avatar-txt{display:grid;background:linear-gradient(135deg,var(--accent-2),var(--accent));color:#fff;border-radius:50%;flex:none;place-items: center;width:36px;height:36px;font-weight:700}.sheet-me .sm-name{color:var(--text);font-size:14.5px;font-weight:600}.sheet-me .sm-sub{color:var(--text-faint);font-size:12px}.shell.phone .editor-split{grid-template-columns:1fr}.shell.phone .infopanel{border-left:0}.shell.phone .launcher{padding:0 12px}.shell.phone .launch-box{margin-top:14px;padding:10px 12px}.shell.phone .launch-input{font-size:16px}.shell.phone .search-modal-panel{border-radius:0;width:100vw;height:100dvh;max-height:100dvh;top:0}.shell.phone .activity-panel{left:8px;right:8px;bottom:calc(var(--phonetabs-h) + env(safe-area-inset-bottom) + 8px);width:auto;max-height:68vh}.shell.phone .inbox,.shell.phone .toasts,.shell.phone .tray{left:8px;right:8px;bottom:calc(var(--phonetabs-h) + env(safe-area-inset-bottom) + 8px);width:auto}.shell.phone .viewer-dock{left:8px;right:8px;bottom:calc(var(--phonetabs-h) + env(safe-area-inset-bottom) + 8px);width:auto!important}.shell.tv{--activity-w:84px;--statusbar-h:34px;padding:2.2% 2.6%;font-size:17px}.shell.tv .activitybar{gap:10px;padding:16px 0 18px}.shell.tv .activitybar .item,.shell.tv .activitybar .iconbtn,.shell.tv .activitybar .brand-mark{border-radius:14px;width:64px;height:64px}.shell.tv .statusbar{font-size:15px}.shell.tv .launcher{max-width:1100px}.shell.tv .launch-input{font-size:24px}.shell.tv .launch-box{border-radius:16px;padding:16px 22px}.shell.tv .launch-mic{border-radius:11px;width:40px;height:40px}.shell.tv .launch-item{border-radius:12px;padding:14px 16px;font-size:18px}.shell.tv .launch-item .name{max-width:none}.shell.tv .launch-h{font-size:14px}.shell.tv .btn{padding:11px 20px;font-size:16px}.shell.tv .viewer.text pre{padding:28px 34px;font-size:19px;line-height:1.7}.shell.tv .md{max-width:1000px;font-size:21px}.shell.tv .viewer.markdown{padding:40px 52px}.shell.tv .viewer-nav{height:54px;padding:0 14px}.shell.tv .vn-crumb{max-width:420px;padding:8px 12px;font-size:17px}.shell.tv .vn-back{width:44px;height:40px}.shell.tv .settings{max-width:1000px;font-size:17px}.shell.tv .settings .setting .info .d{font-size:15px}.shell.tv .infopanel{font-size:16px}.shell.tv .toasts,.shell.tv .activity-panel{right:2.6%;bottom:calc(var(--statusbar-h) + 2.2%)}.shell.tv .plugin-panel{top:2.2%;right:2.6%}.shell.tv .tray{left:calc(var(--activity-w) + 2.6%);bottom:calc(var(--statusbar-h) + 2.2%)}.shell.tv .inbox{left:calc(var(--activity-w) + 2.6%);bottom:2.2%}.shell.tv .viewer-dock{right:2.6%;bottom:calc(var(--statusbar-h) + 2.2%)}.shell.tv :focus{outline:3px solid var(--accent);outline-offset:3px}.shell.tv :focus-visible{outline:3px solid var(--accent);outline-offset:3px}.shell.tv .launch-item:focus-visible{box-shadow:none}.shell.tv .sheet-row:focus-visible{box-shadow:none}.shell.tv .inbox-item:focus-visible{box-shadow:none}.shell.tv .activitybar .item:focus-visible{box-shadow:none}.shell.tv .activitybar .brand-mark:focus-visible{box-shadow:none}.shell.tv .statusbar .seg:focus-visible{box-shadow:none}.shell.tv .pb-tab:focus-visible{box-shadow:none}.shell.tv .btn:focus-visible{box-shadow:none}.shell.tv .iconbtn:focus-visible{box-shadow:none}.shell.tv .act-action:focus-visible{box-shadow:none}.shell.tv .launch-clear:focus-visible{box-shadow:none}.shell.tv .vn-back:focus-visible{box-shadow:none}.shell.tv .c-link:focus-visible{box-shadow:none}.shell.tv .react:focus-visible{box-shadow:none}.shell.tv .lh-example:focus-visible{box-shadow:none}.shell.tv .kbd-edit:focus-visible{box-shadow:none}.shell.tv .activitybar .item:focus-visible:before{content:none}.shell.tv .launch-input:focus{outline:none}.shell.tv .launch-input:focus-visible{outline:none}.shell.tv .launch-box:focus-within{outline:3px solid var(--accent);outline-offset:3px;border-color:var(--border-strong);box-shadow:var(--shadow)}.shell.tv .launch-item:focus,.shell.tv .sheet-row:focus{background:var(--bg-selected)}.shell.tv .launch-item.active{outline:3px solid var(--accent);outline-offset:3px;background:var(--bg-selected);box-shadow:none}.shell.tv .launch-body:focus-within .launch-item.active:not(:focus){outline:none;background:var(--bg-hover)}.shell.tv .launch-body{padding-left:8px;padding-right:8px}.launch-help{border-top:1px solid var(--border);margin:6px 10px 0;padding:12px 0 0}.lh-hint{display:flex;color:var(--text-dim);align-items: flex-start;gap:8px;font-size:12.5px;line-height:1.55}.lh-hint svg{color:var(--text-faint);flex:none;margin-top:2px}.lh-examples{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}.lh-example{display:inline-flex;border:1px solid var(--border);background:var(--bg-hover);color:var(--text);border-radius:8px;align-items:baseline;gap:7px;padding:5px 10px;font-size:12.5px}.lh-example:hover{border-color:var(--accent)}.lh-example .lh-q{font-family:var(--font-mono);font-size:12px}.lh-example .lh-label{color:var(--text-faint);font-size:11.5px}.mcp-url{display:flex;align-items: center;gap:8px;min-width:0}.mcp-url .mono{font-family:var(--font-mono);color:var(--text);background:var(--bg-input);border:1px solid var(--border);overflow-x:auto;white-space:nowrap;border-radius:6px;max-width:100%;padding:5px 9px;font-size:12.5px}.mcp-url .mono.small{color:var(--text-dim);font-size:11.5px}.settings .control .mono{font-family:var(--font-mono);color:var(--text-dim);font-size:12.5px}.mcp-warn{display:flex;color:var(--warn);background:color-mix(in srgb,var(--warn)10%,transparent);border:1px solid color-mix(in srgb,var(--warn)34%,transparent);border-radius:9px;align-items: flex-start;gap:9px;margin:4px 0 10px;padding:10px 12px;font-size:12.5px;line-height:1.55}.mcp-warn svg{flex:none;margin-top:1px}.shell.phone .settings{padding:18px 14px 40px}.shell.phone .setting{flex-direction:column;align-items:stretch;gap:8px}.shell.phone .setting .control{justify-content:stretch;width:100%}.shell.phone .setting .control>*{flex:1}.shell.phone .setting .control .switch,.shell.phone .setting .control .iconbtn,.shell.phone .mcp-url .btn{flex:none}.shell.phone .setting .control .switch{align-self: flex-start}.shell.phone .mcp-url .mono{flex:1;min-width:0}.shell.phone .setting:has(.control>.iconbtn:only-child){flex-direction:row;align-items: center}.shell.phone .setting:has(.control>.iconbtn:only-child) .control{justify-content:flex-end;width:auto}.launch-h .lh-title{display:flex;align-items:baseline;gap:8px;min-width:0}.launch-h .lh-actions{display:flex;flex:none;align-items: center;gap:2px}.launch-h .lh-verbatim{text-transform:none;color:var(--text-dim);letter-spacing:0;font-weight:500}
|
|
1
|
+
:root{--font-ui:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;--font-mono:"SF Mono","JetBrains Mono","Fira Code",ui-monospace,Menlo,Consolas,monospace;--radius:8px;--radius-sm:5px;--activity-w:52px;--sidebar-w:280px;--statusbar-h:24px;--ease:cubic-bezier(.2,.7,.2,1);--focus:var(--accent);--focus-halo:color-mix(in srgb,var(--accent)32%,transparent)}:root,:root[data-theme=dark]{--bg:#181a1f;--bg-elevated:#1f2228;--bg-sidebar:#1b1d23;--bg-activity:#16181d;--bg-input:#12141a;--bg-hover:#ffffff0d;--bg-active:#ffffff14;--bg-selected:#2d6fd128;--border:#ffffff14;--border-strong:#ffffff26;--text:#d7dce5;--text-dim:#9aa4b2;--text-faint:#6b7280;--accent:#6ea8fe;--accent-2:#a679f0;--accent-text:#0b1020;--danger:#f2607a;--warn:#e5b567;--success:#6cc48a;--shadow:0 12px 40px -8px #000000a8,0 2px 8px -2px #0008;--scrollbar:#fff2}:root[data-theme=midnight]{--bg:#0c0e14;--bg-elevated:#12151e;--bg-sidebar:#0e111a;--bg-activity:#090b11;--bg-input:#080a10;--bg-hover:#ffffff0a;--bg-active:#ffffff12;--bg-selected:#4b7bff22;--border:#ffffff10;--border-strong:#ffffff1f;--text:#cdd6f4;--text-dim:#8b95b0;--text-faint:#5a6482;--accent:#89b4fa;--accent-2:#cba6f7;--danger:#f38ba8;--warn:#f9e2af;--success:#a6e3a1;--shadow:0 16px 50px -10px #000c,0 2px 10px -2px #000a;--scrollbar:#ffffff1a}:root[data-theme=light]{--bg:#f6f7f9;--bg-elevated:#fff;--bg-sidebar:#eef0f3;--bg-activity:#e6e9ee;--bg-input:#fff;--bg-hover:#0000000a;--bg-active:#00000012;--bg-selected:#2d6fd11f;--border:#00000014;--border-strong:#00000024;--text:#1c2430;--text-dim:#55606f;--text-faint:#8a95a4;--accent:#2d6fd1;--accent-2:#7c50c8;--accent-text:#fff;--danger:#d63b5b;--warn:#b3801f;--success:#2f9e57;--shadow:0 12px 40px -10px #0000002e,0 2px 8px -3px #0000001f;--scrollbar:#00000026}*{box-sizing:border-box}html,body{height:100%;margin:0}*,*:before,*:after{-webkit-tap-highlight-color:transparent}body{font-family:var(--font-ui);color:var(--text);background:var(--bg);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;overflow:hidden;font-size:13px}button{font:inherit;color:inherit;cursor:pointer;text-align:inherit;background:0 0;border:0}input,select,textarea{font:inherit;color:inherit}::selection{background:var(--accent);color:var(--accent-text)}:focus-visible{outline:2px solid var(--focus);outline-offset:2px}:focus:not(:focus-visible){outline:none}.btn:focus-visible{outline:none;border-color:var(--focus);box-shadow:0 0 0 3px var(--focus-halo)}.btn.primary:focus-visible{box-shadow:0 0 0 3px var(--focus-halo)}.iconbtn:focus-visible{outline:none;color:var(--text);background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}.act-action:focus-visible{outline:none;color:var(--text);background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}.launch-clear:focus-visible{outline:none;color:var(--text);background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}.pb-status:focus-visible{outline:none;color:var(--text);background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}.pb-brand:focus-visible{outline:none;color:var(--text);background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}.vn-back:focus-visible{outline:none;color:var(--text);background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}.c-link:focus-visible{outline:none;color:var(--text);background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}.react:focus-visible{outline:none;color:var(--text);background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}.launch-box:focus-within{border-color:var(--focus);box-shadow:var(--shadow),0 0 0 3px var(--focus-halo)}.launch-input:focus-visible{outline:none}.launch-item:focus-visible{outline:none;background:var(--bg-selected);box-shadow:inset 3px 0 0 0 var(--focus),0 0 0 1px var(--focus-halo)}.sheet-row:focus-visible{outline:none;background:var(--bg-selected);box-shadow:inset 3px 0 0 0 var(--focus),0 0 0 1px var(--focus-halo)}.inbox-item:focus-visible{outline:none;background:var(--bg-selected);box-shadow:inset 3px 0 0 0 var(--focus),0 0 0 1px var(--focus-halo)}.activitybar .item:focus-visible{outline:none;color:var(--text);background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}.activitybar .item:focus-visible:before{content:"";position:absolute;background:linear-gradient(var(--accent),var(--accent-2));border-radius:0 3px 3px 0;width:3px;top:8px;bottom:8px;left:-6px}.activitybar .brand-mark:focus-visible{outline:none;background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}.pb-tab:focus-visible{outline:none;color:var(--accent);box-shadow:inset 0 3px 0 0 var(--focus)}.statusbar .seg:focus-visible{outline:none;background:var(--bg-active);color:var(--text);box-shadow:inset 0 -2px 0 0 var(--focus)}.md a:focus-visible{outline:2px solid var(--focus);outline-offset:3px;border-radius:3px}.link:focus-visible{outline:2px solid var(--focus);outline-offset:3px;border-radius:3px}.launch-up:focus-visible{outline:2px solid var(--focus);outline-offset:3px;border-radius:3px}.lh-example:focus-visible{outline:none;border-color:var(--focus);box-shadow:0 0 0 3px var(--focus-halo)}::-webkit-scrollbar{width:11px;height:11px}::-webkit-scrollbar-thumb{background:var(--scrollbar);background-clip:content-box;border:3px solid #0000;border-radius:6px}::-webkit-scrollbar-thumb:hover{background:var(--border-strong);background-clip:content-box}.workbench{height:100%}.shell{display:grid;grid-template-rows:1fr var(--statusbar-h);height:100vh;height:100dvh}.body{display:grid;grid-template-columns:var(--activity-w)1fr;overflow:hidden;min-height:0}kbd{font-family:var(--font-ui);color:var(--text-dim);background:var(--bg-hover);border:1px solid var(--border);text-align:center;border-radius:4px;min-width:16px;padding:1px 5px;font-size:10.5px}.kbd-edit{display:inline-flex;color:var(--text-dim);font:inherit;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:6px;align-items: center;gap:6px;padding:2px 4px}.kbd-edit:hover{border-color:var(--border);background:var(--bg-hover)}.kbd-edit:focus-visible{outline:none;border-color:var(--focus);box-shadow:0 0 0 3px var(--focus-halo)}.kbd-clash{display:inline-flex;color:var(--warn);align-items: center;margin-right:4px}.kbd-edit.clash kbd{border-color:color-mix(in srgb,var(--warn)50%,transparent);color:var(--warn)}.kbd-edit.listening{border-color:var(--accent);background:var(--bg-active);color:var(--accent);padding:3px 8px;font-size:11px}.activitybar{display:flex;background:var(--bg-activity);border-right:1px solid var(--border);flex-direction:column;align-items: center;gap:4px;padding:8px 0 10px}.activitybar .brand-mark{display:grid;cursor:pointer;transition:background .12s var(--ease),transform .12s var(--ease);background:0 0;border:0;border-radius:10px;place-items: center;width:40px;height:40px;margin-bottom:6px}.activitybar .brand-mark img{width:24px;height:24px}.activitybar .brand-mark:hover{background:var(--bg-hover)}.activitybar .brand-mark:active{transform:translateY(1px)}.activitybar .item{position:relative;color:var(--text-faint);display:grid;transition:color .12s var(--ease),background .12s var(--ease);background:0 0;border:0;border-radius:9px;place-items: center;width:40px;height:40px}.activitybar .item:hover{color:var(--text);background:var(--bg-hover)}.activitybar .item.active{color:var(--text);background:var(--bg-active)}.activitybar .item.active:before{content:"";position:absolute;background:linear-gradient(var(--accent),var(--accent-2));border-radius:0 3px 3px 0;width:3px;top:8px;bottom:8px;left:-6px}.activitybar .item .badge{position:absolute;background:var(--accent);color:var(--accent-text);display:grid;border-radius:8px;place-items: center;min-width:15px;height:15px;padding:0 3px;font-size:9.5px;font-weight:700;top:3px;right:3px}.activitybar .spacer{flex:1}.activitybar .bell-wrap{display:grid;place-items: center}.activitybar .iconbtn{color:var(--text-faint);border-radius:9px;width:40px;height:40px}.activitybar .iconbtn:hover{color:var(--text);background:var(--bg-hover)}.activitybar .principal{cursor:default;margin:4px 0 0}.sidebar{width:var(--sidebar-w);background:var(--bg-sidebar);border-right:1px solid var(--border);display:flex;overflow:hidden;flex-direction:column;min-width:0}.sidebar .head{display:flex;text-transform:uppercase;letter-spacing:.6px;color:var(--text-dim);align-items: center;gap:6px;padding:10px 12px 8px;font-size:11px;font-weight:600}.sidebar .head .actions{display:flex;gap:2px;margin-left:auto}.sidebar .scroll{overflow-y:auto;overflow-x:hidden;flex:1}.iconbtn{color:var(--text-dim);display:grid;transition:all .12s var(--ease);background:0 0;border:0;border-radius:6px;place-items: center;width:26px;height:26px}.iconbtn:hover{background:var(--bg-hover);color:var(--text)}.iconbtn:active{transform:translateY(1px)}.iconbtn.danger:hover{color:var(--danger)}.collection-switch{display:flex;border:1px solid var(--border);background:var(--bg-elevated);color:var(--text);transition:border-color .12s var(--ease);border-radius:8px;align-items: center;gap:8px;width:calc(100% - 16px);margin:4px 8px 0;padding:7px 10px}.collection-switch:hover{border-color:var(--accent)}.collection-switch .cs-name{text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;font-weight:550}.collection-switch svg:last-child{color:var(--text-faint)}.breadcrumb{display:flex;border-bottom:1px solid var(--border);color:var(--text-dim);flex-wrap:wrap;align-items: center;gap:2px;padding:6px 10px;font-size:12px}.breadcrumb .crumb{color:inherit;background:0 0;border:0;border-radius:5px;padding:2px 6px}.breadcrumb .crumb:hover{background:var(--bg-hover);color:var(--text)}.breadcrumb .sep{opacity:.4}.breadcrumb .crumb.current{color:var(--text);font-weight:500}.filelist{padding:4px}.row{display:flex;cursor:default;user-select:none;color:var(--text);transition:background 80ms var(--ease);border-radius:6px;align-items: center;gap:9px;height:30px;padding:0 8px}.compact .row{height:26px}.row:hover{background:var(--bg-hover)}.row.selected{background:var(--bg-selected);box-shadow:inset 0 0 0 1px var(--accent)}.row.drop-target{box-shadow:inset 0 0 0 2px var(--accent);background:var(--bg-selected)}.row .ico{color:var(--text-dim);display:grid;flex:none;place-items: center}.row .ico.folder{color:var(--accent)}.row .name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.row .meta{color:var(--text-faint);font-variant-numeric:tabular-nums;font-size:11px}.row .pin-dot{color:var(--success);display:grid;flex:none;place-items: center}.statusbar .offline-badge,.statusbar .offline-badge span{color:var(--warn)}.row .rename-input{background:var(--bg-input);border:1px solid var(--accent);outline:none;color:var(--text);border-radius:4px;flex:1;padding:2px 6px}.empty{display:flex;color:var(--text-faint);text-align:center;flex-direction:column;justify-content:center;align-items: center;gap:10px;height:100%;padding:32px}.empty .big{opacity:.5;font-size:34px}.empty .cta{border:1px dashed var(--border-strong);color:var(--text-dim);background:0 0;border-radius:8px;margin-top:4px;padding:7px 14px}.empty .cta:hover{border-color:var(--accent);color:var(--text)}.editor{display:flex;background:var(--bg);overflow:hidden;flex-direction:column;min-width:0}.tabs{display:flex;background:var(--bg-activity);border-bottom:1px solid var(--border);overflow-x:auto;align-items:stretch;height:36px}.tab{display:flex;border:0;border-right:1px solid var(--border);color:var(--text-dim);position:relative;white-space:nowrap;background:0 0;align-items: center;gap:8px;max-width:220px;padding:0 10px 0 14px}.tab.active{background:var(--bg);color:var(--text)}.tab.active:before{content:"";position:absolute;background:linear-gradient(90deg,var(--accent),var(--accent-2));height:2px;top:0;left:0;right:0}.tab .label{overflow:hidden;text-overflow:ellipsis}.tab .close{display:grid;opacity:.5;border-radius:4px;place-items: center;width:18px;height:18px}.tab .close:hover{background:var(--bg-hover);opacity:1}.editor .stage{overflow:auto;position:relative;flex:1;min-height:0}.welcome{display:grid;place-items: center;height:100%}.welcome .card{text-align:center;max-width:460px;padding:40px}.welcome h1{margin:12px 0 6px;font-size:26px;font-weight:650}.welcome .logo{font-size:46px}.welcome p{color:var(--text-dim);line-height:1.6}.welcome .hints{display:grid;text-align:left;gap:8px;margin-top:22px}.welcome .hint{display:flex;color:var(--text-dim);align-items: center;gap:10px}.statusbar{display:flex;background:linear-gradient(90deg,color-mix(in srgb,var(--accent)20%,var(--bg-activity)),var(--bg-activity));border-top:1px solid var(--border);color:var(--text-dim);align-items: center;gap:2px;padding:0 8px;font-size:11.5px}.statusbar .seg{display:flex;color:inherit;background:0 0;border:0;align-items: center;gap:5px;height:100%;padding:0 8px}.statusbar .seg:hover{background:var(--bg-hover);color:var(--text)}.statusbar .spacer{flex:1}.btn{display:inline-flex;border:1px solid var(--border-strong);background:var(--bg-elevated);color:var(--text);transition:all .12s var(--ease);border-radius:7px;align-items: center;gap:7px;padding:7px 13px}.btn:hover{border-color:var(--accent)}.btn.primary{background:linear-gradient(180deg,var(--accent),color-mix(in srgb,var(--accent)82%,black));color:var(--accent-text);border:0;font-weight:600}.btn.small{border-radius:6px;gap:5px;padding:4px 9px;font-size:12px}.btn.ghost{color:var(--text-dim);background:0 0;border-color:#0000}.btn.ghost:hover{background:var(--bg-hover);border-color:var(--border);color:var(--text)}.btn.on{border-color:var(--accent);color:var(--accent);background:var(--bg-active)}.btn.primary:hover{filter:brightness(1.08)}.btn.danger{color:var(--danger);border-color:color-mix(in srgb,var(--danger)40%,var(--border))}.btn.danger:hover{background:color-mix(in srgb,var(--danger)14%,transparent)}.btn:disabled{opacity:.45;pointer-events:none}.field{display:flex;flex-direction:column;gap:6px}.field label{color:var(--text-dim);font-size:12px}.input,select.input{background:var(--bg-input);color:var(--text);border:1px solid var(--border-strong);outline:none;transition:border-color .12s var(--ease),box-shadow .12s var(--ease);border-radius:7px;width:100%;padding:8px 11px}.input:focus{border-color:var(--accent);box-shadow:0 0 0 3px color-mix(in srgb,var(--accent)22%,transparent)}.switch{position:relative;flex:none;width:38px;height:22px}.switch input{position:absolute;opacity:0;cursor:pointer;z-index:1;width:100%;height:100%;margin:0;inset:0}.switch .track{position:absolute;background:var(--border-strong);transition:background .15s var(--ease);border-radius:22px;inset:0}.switch .track:before{content:"";position:absolute;transition:transform .16s var(--ease);background:#fff;border-radius:50%;width:16px;height:16px;top:3px;left:3px}.switch input:focus-visible+.track{box-shadow:0 0 0 3px var(--focus-halo);outline:1px solid var(--focus)}.switch input:checked+.track{background:var(--accent)}.switch input:checked+.track:before{transform:translate(16px)}.scrim{position:fixed;backdrop-filter:blur(1.5px);z-index:40;background:#0006;inset:0}.palette{position:fixed;background:var(--bg-elevated);border:1px solid var(--border-strong);box-shadow:var(--shadow);z-index:50;overflow:hidden;animation:pop .13s var(--ease);border-radius:12px;width:min(640px,92vw);top:12vh;left:50%;transform:translate(-50%)}@keyframes pop{0%{opacity:0;transform:translate(-50%,-6px)scale(.98)}to{opacity:1;transform:translate(-50%)scale(1)}}.palette .search{display:flex;border-bottom:1px solid var(--border);align-items: center;gap:9px;padding:12px 14px}.palette .search input{outline:none;color:var(--text);background:0 0;border:0;flex:1;font-size:15px}.palette .results{overflow-y:auto;max-height:52vh;padding:6px}.palette .opt{display:flex;cursor:default;border-radius:7px;align-items: center;gap:10px;padding:8px 10px}.palette .opt.active{background:var(--bg-active)}.palette .opt .ico{color:var(--text-dim)}.palette .opt .title{flex:1}.palette .opt .cat{color:var(--text-faint);font-size:11px}.palette .opt .kbd{margin-left:auto}.palette .opt .sub{color:var(--text-faint);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px}.palette .opt.unavailable{opacity:.5}.palette .opt.unavailable .title{text-decoration:line-through;text-decoration-color:var(--text-faint)}.offline-tag{text-transform:uppercase;letter-spacing:.5px;color:var(--warn);border:1px solid color-mix(in srgb,var(--warn)40%,transparent);border-radius:5px;padding:1px 5px;font-size:9.5px}.plugin-features{border-top:1px solid var(--border);margin-top:12px;padding-top:10px}.pf-head{display:flex;text-transform:uppercase;letter-spacing:.5px;color:var(--text-dim);justify-content:space-between;margin-bottom:8px;font-size:11px}.pf-list{display:flex;flex-direction:column;gap:4px}.pf-row{display:flex;border-radius:6px;align-items: center;gap:8px;padding:4px 6px;font-size:12.5px}.pf-row.off{opacity:.55}.pf-row .pf-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.pf-row .pf-kind{color:var(--text-faint);font-size:10px}.pf-badge{color:var(--text-faint);border:1px solid var(--border);white-space:nowrap;border-radius:5px;margin-left:auto;padding:1px 5px;font-size:9.5px}.pf-badge.offline-ok{color:var(--success);border:1px solid color-mix(in srgb,var(--success)40%,transparent);border-radius:5px;padding:1px 5px;font-size:9.5px}.pf-dot{border-radius:50%;flex:none;width:8px;height:8px}.pf-dot.on{background:var(--success)}.pf-dot.no{background:var(--text-faint)}.palette .none{text-align:center;color:var(--text-faint);display:flex;justify-content:center;align-items: center;gap:8px;padding:22px}.palette .none.error{color:var(--danger,#e5534b)}.palette .none .spinner{width:13px;height:13px}.dialog{position:fixed;background:var(--bg-elevated);border:1px solid var(--border-strong);box-shadow:var(--shadow);z-index:50;animation:pop .13s var(--ease);border-radius:12px;width:min(440px,92vw);padding:20px;top:50%;left:50%;transform:translate(-50%,-50%)}.dialog h3{margin:0 0 12px;font-size:16px}.dialog .body{display:block;color:var(--text-dim);margin-bottom:16px;line-height:1.5}.dialog .row-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}.opener-chooser .opener-list{display:flex;flex-direction:column;gap:6px;margin:4px 0 12px}.opener-opt{display:flex;border:1px solid var(--border);cursor:pointer;border-radius:9px;align-items: center;gap:10px;padding:9px 11px}.opener-opt:hover{background:var(--bg-hover)}.opener-opt.sel{border-color:var(--accent);background:color-mix(in srgb,var(--accent)10%,transparent)}.opener-opt input{accent-color:var(--accent)}.opener-opt .oo-main{display:flex;flex-direction:column;gap:1px}.opener-opt .oo-title{font-size:13px;font-weight:500}.opener-opt .oo-src{color:var(--text-dim);font-size:11px}.opener-remember{display:flex;color:var(--text-dim);cursor:pointer;align-items: center;gap:8px;font-size:12.5px}.opener-remember input{accent-color:var(--accent)}.menu{overflow-y:auto;overscroll-behavior:contain;position:fixed;z-index:60;background:var(--bg-elevated);border:1px solid var(--border-strong);box-shadow:var(--shadow);animation:pop .1s var(--ease);border-radius:9px;min-width:200px;max-height:calc(100vh - 24px);padding:5px}.menu .mi{display:flex;cursor:default;border-radius:6px;align-items: center;gap:10px;padding:7px 9px}.menu .mi:hover{background:var(--bg-active)}.menu .mi.danger:hover{background:color-mix(in srgb,var(--danger)16%,transparent);color:var(--danger)}.menu .mi .kbd{color:var(--text-faint);margin-left:auto}.menu .sep{background:var(--border);height:1px;margin:5px 2px}.toasts{position:fixed;bottom:calc(var(--statusbar-h) + 12px);z-index:70;display:flex;flex-direction:column;gap:8px;width:340px;right:14px}.toast{display:flex;background:var(--bg-elevated);border:1px solid var(--border-strong);box-shadow:var(--shadow);animation:slidein .16s var(--ease);border-radius:10px;gap:10px;padding:11px 13px}@keyframes slidein{0%{opacity:0;transform:translate(12px)}}.toast .bar{border-radius:3px;flex:none;width:3px}.toast.info .bar{background:var(--accent)}.toast.success .bar{background:var(--success)}.toast.warn .bar{background:var(--warn)}.toast.error .bar{background:var(--danger)}.toast .msg{flex:1;line-height:1.4}.toast .x{color:var(--text-faint);align-self: flex-start}.tray{position:fixed;bottom:calc(var(--statusbar-h) + 12px);left:calc(var(--activity-w) + 12px);z-index:65;background:var(--bg-elevated);border:1px solid var(--border-strong);box-shadow:var(--shadow);overflow:hidden;border-radius:12px;width:320px}.tray .head{display:flex;border-bottom:1px solid var(--border);align-items: center;padding:10px 12px;font-size:12px;font-weight:600}.tray .head .actions{margin-left:auto}.tray .items{overflow-y:auto;max-height:300px}.xfer{border-bottom:1px solid var(--border);padding:9px 12px}.xfer:last-child{border-bottom:0}.xfer .top{display:flex;align-items: center;gap:8px}.xfer .top .name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:12px}.xfer .pct{color:var(--text-faint);font-variant-numeric:tabular-nums;font-size:11px}.progress{background:var(--bg-hover);overflow:hidden;border-radius:3px;height:4px;margin-top:7px}.progress>div{background:linear-gradient(90deg,var(--accent),var(--accent-2));transition:width .2s var(--ease);height:100%}.xfer.error .progress>div{background:var(--danger)}.xfer.cancelled{opacity:.55}.searchview{display:flex;flex-direction:column;gap:10px;height:100%;padding:10px}.searchview .box{display:flex;gap:6px}.searchview .modes{display:flex;gap:4px}.chip{border:1px solid var(--border);color:var(--text-dim);background:0 0;border-radius:20px;padding:4px 10px;font-size:11.5px}.chip.active{background:var(--bg-selected);border-color:var(--accent);color:var(--text)}.results{overflow-y:auto;display:flex;flex-direction:column;flex:1;gap:6px}.result{border:1px solid var(--border);background:var(--bg-elevated);cursor:default;border-radius:9px;padding:10px 11px}.result:hover{border-color:var(--border-strong)}.result .top{display:flex;align-items: center;gap:8px}.result .top .name{font-weight:550}.result .top .score{color:var(--text-faint);margin-left:auto;font-size:10.5px}.result .path{color:var(--text-faint);margin:2px 0 0 24px;font-size:11px}.result .snippet{color:var(--text-dim);margin:6px 0 0 24px;font-size:12px;line-height:1.5}.result .snippet mark{background:color-mix(in srgb,var(--accent)32%,transparent);color:var(--text);border-radius:3px;padding:0 2px}.result .badge{background:var(--bg-hover);color:var(--text-dim);border-radius:5px;padding:1px 6px;font-size:10px}.settings{max-width:720px;margin:0 auto;padding:26px 24px 60px}.settings h2{margin:0 0 4px;font-size:20px}.settings .sub{color:var(--text-dim);margin-bottom:22px}.settings .group{margin-bottom:28px}.settings .group h3{text-transform:uppercase;letter-spacing:.6px;color:var(--accent);margin:0 0 10px;font-size:12px}.setting{display:flex;border-bottom:1px solid var(--border);align-items: center;gap:16px;padding:12px 0}.setting .info{flex:1}.setting .info .t{font-weight:550}.setting .info .d{color:var(--text-faint);margin-top:2px;font-size:12px;line-height:1.4}.setting .control{display:flex;flex:none;justify-content:flex-end;width:200px}.plugins{display:flex;flex-direction:column;gap:12px;padding:16px}.plugin-card{border:1px solid var(--border);background:var(--bg-elevated);border-radius:11px;padding:14px}.plugin-card .top{display:flex;align-items: center;gap:10px}.plugin-card .avatar{background:linear-gradient(135deg,var(--accent),var(--accent-2));display:grid;color:var(--accent-text);border-radius:9px;place-items: center;width:38px;height:38px;font-weight:700}.plugin-card .name{font-weight:600}.plugin-card .status{border-radius:12px;margin-left:auto;padding:2px 8px;font-size:11px}.plugin-card .status.active{background:color-mix(in srgb,var(--success)20%,transparent);color:var(--success)}.plugin-card .status.error{background:color-mix(in srgb,var(--danger)20%,transparent);color:var(--danger)}.plugin-card .status.loading{background:var(--bg-hover);color:var(--text-dim)}.plugin-card .caps{display:flex;flex-wrap:wrap;gap:5px;margin:10px 0 0}.plugin-card .cap{background:var(--bg-hover);color:var(--text-dim);border-radius:6px;padding:2px 7px;font-size:10.5px}.plugin-card .desc{color:var(--text-dim);margin-top:8px;font-size:12px;line-height:1.5}.plugin-card .actions{display:flex;gap:8px;margin-top:12px}.plugin-panel{position:fixed;z-index:55;background:var(--bg-elevated);border:1px solid var(--border-strong);box-shadow:var(--shadow);overflow:hidden;animation:pop .13s var(--ease);border-radius:12px;top:12px;right:12px}.plugin-panel .head{display:flex;border-bottom:1px solid var(--border);align-items: center;gap:8px;padding:9px 12px;font-size:12px;font-weight:600}.plugin-panel .head .x{margin-left:auto}.plugin-panel .host{display:block}.plugin-install{display:flex;gap:8px;margin-top:10px}.trust{display:inline-flex;border:1px solid var(--border);white-space:nowrap;border-radius:12px;align-items: center;gap:4px;padding:2px 7px;font-size:10.5px}.trust.verified{color:var(--success);border-color:color-mix(in srgb,var(--success)45%,transparent);background:color-mix(in srgb,var(--success)12%,transparent)}.trust.signed{color:var(--text-dim)}.trust.unverified{color:var(--warn);border-color:color-mix(in srgb,var(--warn)40%,transparent)}.trust.invalid{color:var(--danger,#e5484d);border-color:color-mix(in srgb,var(--danger,#e5484d)55%,transparent);background:color-mix(in srgb,var(--danger,#e5484d)14%,transparent);font-weight:600}.dialog.review{overflow:hidden;padding:0}.review-head{display:flex;border-bottom:1px solid var(--border);align-items: center;gap:12px;padding:16px 18px}.review-head .avatar{border-radius:11px;width:44px;height:44px}.review-head .rh-main{flex:1}.review-head .rh-name{display:flex;align-items:baseline;gap:8px;font-size:16px;font-weight:650}.review-head .rh-ver{color:var(--text-faint);font-size:11px;font-weight:400}.review-head .rh-author{color:var(--text-dim);margin-top:2px;font-size:12px}.review-body{overflow-y:auto;max-height:60vh;padding:14px 18px}.review-desc{color:var(--text-dim);margin:0 0 14px;line-height:1.55}.review-section{margin-bottom:16px}.review-section .rs-title{text-transform:uppercase;letter-spacing:.5px;color:var(--accent);margin-bottom:8px;font-size:11px}.cap-list{display:flex;flex-direction:column;gap:8px}.cap-row{display:flex;border:1px solid var(--border);cursor:pointer;border-radius:9px;align-items: flex-start;gap:10px;padding:8px 10px}.cap-row:hover{border-color:var(--border-strong)}.cap-row.blocked,.contrib-row.blocked{opacity:.6;cursor:not-allowed}.contrib-row.blocked .pf-title{text-decoration:line-through}.cap-row input{accent-color:var(--accent);margin-top:2px}.cap-row .cap-name{font-size:13px;font-weight:600}.cap-row .cap-desc{color:var(--text-dim);margin-top:2px;font-size:12px;line-height:1.4}.contrib-list{display:flex;flex-direction:column;gap:3px}.contrib-row{display:flex;align-items: center;gap:8px;padding:3px 4px;font-size:12.5px}.contrib-row .cr-title{color:var(--text)}.contrib-row .cr-detail{color:var(--text-faint);font-size:11px}.contrib-row .pf-kind{color:var(--text-faint);margin-left:auto;font-size:10px}.review-meta{color:var(--text-faint);margin-top:6px;font-size:11px}.dialog.review .row-actions{border-top:1px solid var(--border);margin:0;padding:14px 18px}.viewer{display:flex;flex-direction:column;height:100%}.viewer.text pre{font-family:var(--font-mono);white-space:pre-wrap;word-break:break-word;color:var(--text);margin:0;padding:18px 20px;font-size:12.5px;line-height:1.65}.viewer.image{display:grid;background:repeating-conic-gradient(var(--bg-elevated)0% 25%,var(--bg)0% 50%)50%/22px 22px;place-items: center}.viewer.image img{object-fit:contain;box-shadow:var(--shadow);max-width:100%;max-height:100%}.viewer .loading,.viewer .fallback{color:var(--text-faint);display:flex;text-align:center;flex-direction:column;align-items: center;gap:12px;margin:auto;padding:40px}.viewer.plugin-viewer{display:block;position:relative}.viewer.plugin-viewer .pv-host{width:100%;height:100%}.viewer.plugin-viewer .pv-status{position:absolute;z-index:2;display:grid;background:var(--bg);place-items: center;inset:0}.viewer.plugin-viewer .pv-status .loading,.viewer.plugin-viewer .pv-status .fallback{color:var(--text-faint);display:flex;text-align:center;flex-direction:column;align-items: center;gap:12px;padding:40px}.viewer-dock{position:fixed;z-index:60;display:none;box-shadow:var(--shadow);background:0 0;border-radius:12px;flex-direction:column;bottom:18px;right:18px}.viewer-dock .vd-bar{display:flex;background:var(--bg-elevated);border:1px solid var(--border-strong);border-bottom:0;border-radius:12px 12px 0 0;align-items: center;gap:6px;height:26px;padding:0 4px 0 10px}.viewer-dock .vd-title{color:var(--text-dim);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0;font-size:11.5px}.viewer-dock .vd-bar button{color:var(--text-dim);cursor:pointer;display:grid;background:0 0;border:0;border-radius:5px;place-items: center;width:20px;height:20px;padding:0;font-size:12px}.viewer-dock .vd-bar button:hover{background:var(--bg-hover);color:var(--text)}.viewer-dock .vd-body{border:1px solid var(--border-strong);background:0 0;border-top:0;border-radius:0 0 12px 12px;flex:1;min-height:0}.audiobook-host{height:100%;min-height:0}.audiobook{display:grid;grid-template-columns:300px 1fr;height:100%;min-height:0}.audiobook .cover-pane{background:var(--bg-elevated);border-right:1px solid var(--border);display:flex;overflow-y:auto;flex-direction:column;align-items: center;gap:18px;padding:26px}.audiobook .cover{box-shadow:var(--shadow);object-fit:cover;background:linear-gradient(135deg,var(--accent),var(--accent-2));display:grid;color:#fff;border-radius:14px;place-items: center;width:220px;height:220px;font-size:60px}.audiobook .meta{text-align:center}.audiobook .meta .title{font-size:17px;font-weight:650}.audiobook .meta .author{color:var(--text-dim);margin-top:3px}.audiobook .meta .narrator{color:var(--text-faint);margin-top:2px;font-size:12px}.audiobook .transport{display:flex;flex-direction:column;gap:12px;width:100%}.audiobook .scrub{display:flex;align-items: center;gap:10px}.audiobook .scrub input[type=range]{accent-color:var(--accent);flex:1}.audiobook .time{font-variant-numeric:tabular-nums;color:var(--text-faint);min-width:42px;font-size:11px}.audiobook .buttons{display:flex;justify-content:center;align-items: center;gap:14px}.audiobook .buttons .play{background:linear-gradient(180deg,var(--accent),var(--accent-2));color:var(--accent-text);display:grid;box-shadow:var(--shadow);border:0;border-radius:50%;place-items: center;width:54px;height:54px}.audiobook .buttons .play:hover{filter:brightness(1.08)}.audiobook .buttons .skip{background:var(--bg-hover);color:var(--text);display:grid;border:0;border-radius:50%;place-items: center;width:40px;height:40px}.audiobook .buttons .rate{background:var(--bg-hover);color:var(--text-dim);font-variant-numeric:tabular-nums;border:0;border-radius:8px;min-width:46px;padding:6px 8px}.audiobook .chapters{overflow-y:auto;padding:10px}.audiobook .chapters .ch-head{text-transform:uppercase;letter-spacing:.6px;color:var(--text-dim);display:flex;padding:8px 10px;font-size:11px}.audiobook .chapters .ch-head .count{color:var(--text-faint);margin-left:auto}.audiobook .chapter{display:flex;cursor:default;border-radius:8px;align-items: center;gap:10px;padding:9px 11px}.audiobook .chapter:hover{background:var(--bg-hover)}.audiobook .chapter.current{background:var(--bg-selected)}.audiobook .chapter .n{text-align:right;color:var(--text-faint);font-variant-numeric:tabular-nums;width:22px;font-size:12px}.audiobook .chapter .t{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.audiobook .chapter .d{color:var(--text-faint);font-variant-numeric:tabular-nums;font-size:11px}.audiobook .chapter.current .n{color:var(--accent)}.spinner{border:2px solid var(--border-strong);border-top-color:var(--accent);animation:spin .7s linear infinite;border-radius:50%;width:20px;height:20px}@keyframes spin{to{transform:rotate(360deg)}}.dragging-file .editor:after,.dragging-file .sidebar:after{content:"Drop to upload";position:absolute;border:2px dashed var(--accent);display:grid;color:var(--accent);background:color-mix(in srgb,var(--accent)8%,transparent);pointer-events:none;z-index:30;border-radius:12px;place-items: center;font-weight:600;inset:8px}.editor,.sidebar{position:relative}.principal{overflow:hidden;display:grid;background:linear-gradient(135deg,var(--accent),var(--accent-2));color:#fff;border-radius:50%;place-items: center;width:30px;height:30px;font-size:12px;font-weight:700}.principal .avatar-img{object-fit:cover;width:100%;height:100%}.bell-wrap{position:relative}.bell-badge{position:absolute;background:var(--danger);color:#fff;display:grid;border-radius:8px;place-items: center;min-width:15px;height:15px;padding:0 3px;font-size:9.5px;font-weight:700;top:3px;right:3px}.inbox{position:fixed;left:calc(var(--activity-w) + 8px);background:var(--bg-elevated);border:1px solid var(--border-strong);box-shadow:var(--shadow);z-index:55;overflow:hidden;animation:pop .12s var(--ease);border-radius:12px;width:340px;bottom:8px}.inbox-head{display:flex;border-bottom:1px solid var(--border);justify-content:space-between;align-items: center;padding:11px 13px;font-size:12px;font-weight:600}.inbox-head .link,.link{color:var(--accent);background:0 0;border:0;font-size:12px}.inbox-head .muted,.muted{color:var(--text-faint)}.inbox-items{overflow-y:auto;max-height:380px}.inbox-item{border-bottom:1px solid var(--border);cursor:default;padding:10px 13px}.inbox-item:hover{background:var(--bg-hover)}.inbox-item.unread{border-left:2px solid var(--accent)}.inbox-item .ii-title{font-size:12.5px;font-weight:550}.inbox-item .ii-excerpt{color:var(--text-dim);margin-top:2px;font-size:12px}.inbox-item .ii-time{color:var(--text-faint);margin-top:3px;font-size:10.5px}.inbox-empty{display:flex;color:var(--text-faint);flex-direction:column;align-items: center;gap:8px;padding:30px}.editor-split{display:grid;grid-template-columns:1fr 340px;overflow:hidden;min-width:0}.infopanel{border-left:1px solid var(--border);background:var(--bg-sidebar);display:flex;flex-direction:column;min-width:0;min-height:0}.infopanel>*{min-width:0}.ip-head{display:flex;border-bottom:1px solid var(--border);align-items: center;gap:8px;padding:10px 12px;font-size:12px;font-weight:600}.ip-head .iconbtn{margin-left:auto}.ip-body{overflow-y:auto;flex:1}.ip-empty{color:var(--text-faint);text-align:center;padding:30px}.ip-file{border-bottom:1px solid var(--border);padding:12px}.ip-file .ip-name{font-weight:600}.ip-file .ip-path{color:var(--text-faint);margin-top:2px;font-size:11px}.ip-section{border-bottom:1px solid var(--border);padding:12px}.ip-body>:last-child{border-bottom:0}.ip-label{text-transform:uppercase;letter-spacing:.5px;color:var(--text-dim);margin-bottom:9px;font-size:11px}.tags{display:flex;flex-wrap:wrap;align-items: center;gap:6px}.tag{display:inline-flex;background:var(--bg-selected);border:1px solid var(--border);border-radius:14px;align-items: center;gap:5px;padding:3px 4px 3px 9px;font-size:12px}.tag-x{color:var(--text-faint);display:grid;background:0 0;border:0;border-radius:50%;place-items: center;width:16px;height:16px}.tag-x:hover{background:var(--bg-active);color:var(--danger)}.tag-input{background:var(--bg-input);border:1px solid var(--border);outline:none;color:var(--text);border-radius:14px;width:84px;padding:4px 10px;font-size:12px}.tag-input:focus{border-color:var(--accent);width:120px}.conv .thread{display:flex;flex-direction:column;gap:12px;margin-bottom:12px}.conv-empty{color:var(--text-faint);margin-bottom:12px;font-size:12px;line-height:1.5}.conv-signin{display:flex;color:var(--text-faint);flex-wrap:wrap;align-items:baseline;gap:6px;padding:8px 0;font-size:12px}.comment{font-size:13px}.c-head{display:flex;align-items: center;gap:7px}.c-avatar{background:linear-gradient(135deg,var(--accent-2),var(--accent));color:#fff;display:grid;border-radius:50%;flex:none;place-items: center;width:22px;height:22px;font-size:11px;font-weight:700}.c-author{font-size:12.5px;font-weight:600}.c-time{color:var(--text-faint);font-size:11px}.c-body{white-space:pre-wrap;word-break:break-word;margin:4px 0 4px 29px;line-height:1.5}.c-body.deleted{color:var(--text-faint);font-style:italic}.c-body .mention{color:var(--accent);background:color-mix(in srgb,var(--accent)14%,transparent);border-radius:4px;padding:0 3px;font-weight:600}.c-actions{display:flex;flex-wrap:wrap;align-items: center;gap:4px;margin-left:29px}.react{display:inline-flex;background:0 0;border:0;border-radius:12px;align-items: center;gap:3px;padding:2px 6px;font-size:12px}.react:hover{background:var(--bg-hover)}.react.on{background:var(--bg-selected)}.react .rc{color:var(--text-dim);font-size:10px}.c-link{color:var(--text-faint);background:0 0;border:0;border-radius:5px;padding:2px 5px;font-size:11.5px}.c-link:hover{color:var(--text);background:var(--bg-hover)}.c-link.danger:hover{color:var(--danger)}.replies{border-left:2px solid var(--border);margin-top:10px}.composer{display:flex;flex-direction:column;gap:6px}.composer .replying{color:var(--text-dim);display:flex;align-items: center;gap:8px;font-size:11px}.composer-input{background:var(--bg-input);border:1px solid var(--border-strong);resize:vertical;outline:none;color:var(--text);border-radius:9px;padding:8px 10px;font-family:inherit}.composer-input:focus{border-color:var(--accent)}.composer-actions{display:flex;justify-content:space-between;align-items: center}.composer-actions .btn{padding:5px 12px}@media (max-width:720px){:root{--sidebar-w:220px}.audiobook{grid-template-columns:1fr;grid-template-rows:auto 1fr}.audiobook .cover-pane{border-right:0;border-bottom:1px solid var(--border)}.editor-split{grid-template-columns:1fr}.editor-split .infopanel{display:none}}.launcher{display:flex;flex-direction:column;width:100%;max-width:820px;height:100%;margin:0 auto;padding:0 20px}.launch-box{display:flex;background:var(--bg-input);border:1px solid var(--border-strong);box-shadow:var(--shadow);border-radius:12px;align-items: center;gap:10px;margin:min(12vh,90px) 0 4px;padding:12px 16px}.launch-box>svg{color:var(--text-dim);flex:none}.launch-box button>svg{flex:none}.launch-resolved{display:flex;color:var(--text-dim);flex-wrap:wrap;align-items: center;gap:7px;margin:8px 4px 0;font-size:12px}.launch-resolved .rq-label{text-transform:uppercase;letter-spacing:.05em;color:var(--text-faint);font-size:10px;font-weight:600}.launch-resolved .rq-text{color:var(--text)}.launch-resolved .rq-chip{display:inline-flex;background:var(--bg-hover);border:1px solid var(--border);color:var(--text-dim);border-radius:12px;align-items: center;gap:4px;padding:2px 8px}.launch-input{outline:none;color:var(--text);font:500 17px/1.3 var(--font-ui);background:0 0;border:0;flex:1}.launch-input::placeholder{color:var(--text-faint);font-weight:400}.launch-clear{display:inline-flex;color:var(--text-faint);cursor:pointer;background:0 0;border:0;border-radius:6px;justify-content:center;align-items: center;width:24px;height:24px}.launch-clear:hover{background:var(--bg-hover);color:var(--text)}.launch-mic{display:inline-flex;color:var(--text-faint);cursor:pointer;background:0 0;border:0;border-radius:7px;flex:none;justify-content:center;align-items: center;width:26px;height:26px}.launch-mic:hover{background:var(--bg-hover);color:var(--text)}.launch-mic.on{color:var(--accent-text);background:var(--accent);animation:mic-pulse 1.4s var(--ease)infinite}@keyframes mic-pulse{0%,to{box-shadow:0 0 0 0 var(--focus-halo)}50%{box-shadow:0 0 0 5px #0000}}@media (prefers-reduced-motion:reduce){.launch-mic.on{animation:none}}.launch-body{overflow-y:auto;flex:1;padding:8px 0 40px}.launch-group{margin-top:14px}.launch-h{display:flex;letter-spacing:.04em;text-transform:uppercase;color:var(--text-faint);justify-content:space-between;align-items: center;gap:8px;padding:4px 10px;font-size:11px;font-weight:600}.launch-list{display:flex;flex-direction:column}.launch-item{display:flex;cursor:pointer;color:var(--text);border-radius:8px;align-items: center;gap:10px;padding:8px 10px}.launch-item svg{color:var(--text-dim);flex:none}.launch-item .name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:0}.launch-item:hover{background:var(--bg-hover)}.launch-item.active{background:var(--bg-selected);box-shadow:inset 3px 0 0 0 var(--focus)}.launch-detail{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text-faint);flex:0 auto;min-width:0;font-size:12.5px}.launch-more{display:inline-flex;color:var(--text-faint);cursor:pointer;opacity:0;transition:opacity .1s var(--ease),background .1s var(--ease);background:0 0;border:0;border-radius:7px;flex:none;justify-content:center;align-items: center;width:26px;height:26px;margin:-4px -4px -4px 0}.launch-item:hover .launch-more,.launch-item.active .launch-more{opacity:1}.launch-more:focus-visible{opacity:1}.launch-more:hover{background:var(--bg-active);color:var(--text)}.launch-more:focus-visible{outline:none;color:var(--text);background:var(--bg-active);box-shadow:0 0 0 2px var(--focus-halo)}@media (hover:none){.launch-more{opacity:1}}.launch-kind{color:var(--text-faint);border:1px solid var(--border);border-radius:5px;flex:none;padding:1px 6px;font-size:11px}.launch-up{display:inline-flex;color:var(--text-dim);cursor:pointer;background:0 0;border:0;border-radius:5px;align-items: center;gap:3px;padding:2px 4px;font-size:12px}.launch-up:hover{background:var(--bg-hover);color:var(--text)}.launch-empty{color:var(--text-faint);padding:8px 12px;font-size:13px}.view-switch{display:inline-flex;border-left:1px solid var(--border);flex:none;align-items: center;gap:2px;margin-left:2px;padding-left:4px}.vs-btn{display:inline-flex;color:var(--text-faint);cursor:pointer;background:0 0;border:0;border-radius:7px;justify-content:center;align-items: center;width:26px;height:26px}.vs-btn:hover{background:var(--bg-hover);color:var(--text)}.vs-btn.on{background:var(--bg-active);color:var(--text)}.vs-btn:focus-visible{outline:none;color:var(--text);box-shadow:0 0 0 2px var(--focus-halo)}.view-error{display:flex;border:1px solid var(--border);background:var(--bg-hover);color:var(--text-dim);border-radius:8px;align-items: center;gap:6px;margin:8px 10px 0;padding:7px 10px;font-size:12.5px}.view-error svg{color:var(--warn);flex:none}.grid-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(132px,1fr));gap:10px;padding:4px 10px}.grid-tile{display:flex;cursor:pointer;color:var(--text);border-radius:10px;flex-direction:column;gap:6px;padding:6px}.grid-tile:hover{background:var(--bg-hover)}.grid-tile.active{background:var(--bg-selected);box-shadow:inset 0 0 0 2px var(--focus)}.gt-media{position:relative;display:grid;aspect-ratio:1;background:var(--bg-hover);overflow:hidden;border-radius:8px;place-items: center}.gt-media>svg{color:var(--text-faint)}.gt-img{position:absolute;object-fit:cover;width:100%;height:100%;inset:0}.gt-badge{position:absolute;color:#fff;background:#0009;border-radius:5px;padding:1px 6px;font-size:10.5px;bottom:5px;left:5px}.gt-media .launch-more{position:absolute;background:var(--bg-elevated);margin:0;top:3px;right:3px}.grid-tile:hover .launch-more,.grid-tile.active .launch-more{opacity:1}.gt-name{overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;word-break:break-word;-webkit-box-orient:vertical;font-size:12.5px;line-height:1.35}.viewer-nav{display:flex;background:var(--bg-activity);border-bottom:1px solid var(--border);align-items: center;gap:6px;height:40px;padding:0 8px}.vn-back{display:inline-flex;border:1px solid var(--border);background:var(--bg-elevated);color:var(--text-dim);border-radius:7px;justify-content:center;align-items: center;width:30px;height:28px}.vn-back:hover{color:var(--text);background:var(--bg-hover)}.vn-trail{display:flex;overflow-x:auto;flex:1;align-items: center;gap:2px;min-width:0}.vn-crumb{display:inline-flex;color:var(--text-dim);white-space:nowrap;background:0 0;border:0;border-radius:6px;align-items: center;gap:5px;max-width:240px;padding:4px 8px}.vn-crumb .label{overflow:hidden;text-overflow:ellipsis}.vn-crumb:hover{background:var(--bg-hover);color:var(--text)}.vn-crumb.active{color:var(--text);font-weight:550}.vn-crumb:not(:last-child):after{content:"›";color:var(--text-faint);margin-left:6px}.vn-actions{display:flex;gap:2px}.search-modal{position:fixed;z-index:60;inset:0}.search-modal .scrim{position:absolute;z-index:0;background:#00000073;inset:0}.search-modal-panel{z-index:1;position:absolute;background:var(--bg-elevated);border:1px solid var(--border-strong);box-shadow:var(--shadow);overflow:hidden;display:flex;border-radius:12px;width:min(680px,94vw);max-height:72vh;top:12vh;left:50%;transform:translate(-50%)}.search-modal-panel .launcher{max-width:none;height:100%;padding:0 12px}.search-modal-panel .launch-box{margin:12px 0 4px}.search-modal-panel .launch-body{max-height:56vh}.ip-uri{display:flex;border:1px solid var(--border);background:var(--bg-elevated);color:var(--text-dim);font:11px/1.4 var(--font-mono,ui-monospace,monospace);text-align:left;cursor:pointer;overflow:hidden;border-radius:6px;align-items: center;gap:6px;width:100%;min-width:0;padding:6px 8px}.ip-uri>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.ip-uri:hover{color:var(--text);border-color:var(--accent)}.ip-backlinks{display:flex;flex-direction:column;gap:4px}.ip-backlink{display:flex;color:var(--text-dim);text-align:left;cursor:pointer;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background:0 0;border:1px solid #0000;border-radius:6px;align-items: center;gap:6px;width:100%;padding:5px 8px;font-size:12px}.ip-backlink:hover{background:var(--bg-elevated);color:var(--text)}.ip-muted{color:var(--text-faint);padding:2px 0;font-size:12px}.ip-muted.error{color:var(--danger,#e5534b)}.viewer.markdown{overflow:auto;padding:32px 40px}.md{color:var(--text);max-width:760px;margin:0 auto;font-size:14px;line-height:1.65}.md-h{margin:1.6em 0 .6em;font-weight:650;line-height:1.3}.md-h:first-child{margin-top:0}.md-h1{font-size:1.7em}.md-h2{font-size:1.35em}.md-h3{font-size:1.12em}.md-h4{font-size:1em}.md-h5{color:var(--text-dim);font-size:.92em}.md-h6{color:var(--text-dim);text-transform:uppercase;letter-spacing:.04em;font-size:.88em}.md-p{margin:0 0 1em}.md-list{margin:0 0 1em;padding-left:1.4em}.md-li{margin:.25em 0}.md-quote{border-left:3px solid var(--border);color:var(--text-dim);margin:0 0 1em;padding:.1em 0 .1em 1em}.md-hr{border:none;border-top:1px solid var(--border);margin:1.8em 0}.md-code{overflow-x:auto;background:var(--bg-elevated);border:1px solid var(--border);font:12px/1.55 var(--font-mono,ui-monospace,monospace);border-radius:8px;margin:0 0 1em;padding:12px 14px}.md-inline-code{background:var(--bg-elevated);font:.9em var(--font-mono,ui-monospace,monospace);border-radius:4px;padding:.12em .35em}.md-link{color:var(--accent);text-decoration:none;border-bottom:1px solid #0000}.md-link:hover{border-bottom-color:currentColor}.md-trove{border-bottom:1px dashed color-mix(in srgb,var(--accent)55%,transparent)}.md-deadlink{color:var(--text-faint);text-decoration:line-through;cursor:not-allowed}.md-truncated{border:1px dashed var(--border);color:var(--text-faint);border-radius:8px;margin:1.5em 0 0;padding:10px 12px;font-size:12.5px}.activity-panel{position:fixed;right:12px;bottom:calc(var(--statusbar-h) + 10px);z-index:60;overflow-y:auto;background:var(--bg-elevated);border:1px solid var(--border-strong);border-radius:var(--radius);box-shadow:var(--shadow);display:flex;flex-direction:column;width:380px;max-height:62vh}.act-head{display:flex;border-bottom:1px solid var(--border);justify-content:space-between;align-items: center;padding:10px 12px}.act-head h3{margin:0;font-size:13px;font-weight:600}.act-section{border-bottom:1px solid var(--border);padding:10px 12px}.act-section:last-of-type{border-bottom:none}.act-section-title{text-transform:uppercase;letter-spacing:.06em;color:var(--text-faint);margin-bottom:8px;font-size:10.5px}.act-empty{color:var(--text-faint);margin:0;font-size:12.5px}.act-row{display:flex;align-items: flex-start;gap:8px}.act-body{flex:1;min-width:0}.act-title{overflow-wrap:anywhere;font-size:12.5px}.act-detail,.act-meta{color:var(--text-dim);overflow-wrap:anywhere;margin-top:2px;font-size:11.5px}.act-meta{color:var(--text-faint)}.act-error{color:var(--danger);overflow-wrap:anywhere;margin-top:2px;font-size:11.5px}.act-remedy{font-family:var(--font-mono,ui-monospace,monospace);color:var(--text-dim);background:var(--bg-inset,var(--bg-hover));border:1px solid var(--border);overflow:auto;white-space:pre;tab-size:2;border-radius:6px;max-height:220px;margin:6px 0 2px;padding:8px 10px;font-size:10.5px;line-height:1.5}.act-amount{color:var(--text-faint);margin-top:3px;font-size:11px}.act-action{color:var(--text-faint);cursor:pointer;background:0 0;border:none;border-radius:4px;padding:2px}.act-action:hover{background:var(--bg-hover);color:var(--text)}.act-task,.act-issue{padding:7px 0}.act-task+.act-task,.act-issue+.act-issue{border-top:1px solid var(--border)}.act-actions{display:flex;gap:6px;margin:6px 0 0 21px}.act-done .act-title,.act-cancelled .act-title{color:var(--text-dim)}.act-failed .act-title{color:var(--danger)}.act-sev-warning .act-title{color:var(--warn)}.act-offline{display:flex;color:var(--warn);background:var(--bg-hover);align-items: center;gap:6px;padding:8px 12px;font-size:11.5px}.act-foot{padding:10px 12px}.act-bar{background:var(--bg-input);overflow:hidden;border-radius:2px;height:3px;margin:6px 0 0 21px}.act-fill{background:var(--accent);transition:width .25s var(--ease);border-radius:2px;height:100%}.act-bar.indeterminate .act-fill{animation:act-slide 1.1s var(--ease)infinite;width:35%}@keyframes act-slide{0%{margin-left:-35%}to{margin-left:100%}}.sb-attention,.sb-attention:hover{color:var(--warn)}.sb-usage{gap:6px}.usage-bar{background:var(--bg-input);overflow:hidden;border-radius:2px;width:42px;height:4px}.usage-fill{background:var(--text-dim);transition:width .3s var(--ease);border-radius:2px;height:100%}.sb-usage.low .usage-fill{background:var(--warn)}.sb-usage.low{color:var(--warn)}.sb-usage.critical .usage-fill{background:var(--danger)}.sb-usage.critical{color:var(--danger)}:root{--phonebar-h:46px;--phonetabs-h:56px}.shell.phone{grid-template-rows:calc(var(--phonebar-h) + env(safe-area-inset-top))1fr calc(var(--phonetabs-h) + env(safe-area-inset-bottom))}.shell.phone .body{grid-template-columns:1fr}.phonebar{display:flex;background:var(--bg-activity);color:var(--text-dim);align-items: center}.phonebar.top{padding:env(safe-area-inset-top)6px 0;border-bottom:1px solid var(--border);gap:8px}.pb-brand{display:grid;background:0 0;border:0;border-radius:9px;flex:none;place-items: center;width:34px;height:34px}.pb-brand img{width:21px;height:21px}.pb-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text);flex:1;min-width:0;font-size:15px;font-weight:600}.pb-status{position:relative;display:grid;color:var(--text-dim);background:0 0;border:0;border-radius:10px;flex:none;place-items: center;width:38px;height:38px}.pb-status:active{background:var(--bg-hover)}.pb-status.warn{color:var(--warn)}.pb-status.danger{color:var(--danger)}.pb-badge{position:absolute;background:var(--danger);color:#fff;display:grid;border-radius:8px;place-items: center;min-width:15px;height:15px;padding:0 3px;font-size:9.5px;font-weight:700;top:2px;right:2px}.phonebar.bottom{padding:0 4px env(safe-area-inset-bottom);border-top:1px solid var(--border);background:color-mix(in srgb,var(--accent)6%,var(--bg-activity));justify-content:space-around}.pb-tab{position:relative;height:var(--phonetabs-h);color:var(--text-faint);display:flex;background:0 0;border:0;border-radius:10px;flex-direction:column;flex:1;justify-content:center;align-items: center;gap:3px}.pb-tab .pb-label{font-size:10.5px;font-weight:550}.pb-tab.active{color:var(--accent)}.pb-tab:active{background:var(--bg-hover)}.pb-tab .pb-badge{background:var(--accent);color:var(--accent-text);top:6px;right:22%}.sheet-wrap{position:fixed;z-index:58;inset:0}.sheet-wrap .scrim{position:absolute;z-index:0;background:#00000080;inset:0}.sheet{position:absolute;z-index:41;overflow-y:auto;background:var(--bg-elevated);border-top:1px solid var(--border-strong);box-shadow:var(--shadow);padding-bottom:calc(12px + env(safe-area-inset-bottom));animation:sheet-up .18s var(--ease);border-radius:16px 16px 0 0;max-height:82vh;bottom:0;left:0;right:0}@keyframes sheet-up{0%{transform:translateY(18px);opacity:.4}to{transform:none;opacity:1}}.sheet-grip{display:grid;background:0 0;border:0;place-items: center;width:100%;height:22px}.sheet-grip:before{content:"";background:var(--border-strong);border-radius:2px;width:38px;height:4px}.sheet-body{display:flex;flex-direction:column;padding:2px 10px 6px}.sheet-title{letter-spacing:.04em;text-transform:uppercase;color:var(--text-faint);padding:4px 8px 10px;font-size:12px;font-weight:600}.sheet-row{display:flex;color:var(--text);text-align:left;background:0 0;border:0;border-radius:10px;align-items: center;gap:12px;width:100%;min-height:46px;padding:0 8px;font-size:14.5px}.sheet-row:active{background:var(--bg-hover)}.sheet-row.static{color:var(--text-dim)}.sheet-row.danger{color:var(--danger)}.sheet-row svg{color:var(--text-dim);flex:none}.sheet-row.danger svg{color:var(--danger)}.sheet-row .sr-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0}.sheet-row .sr-value{color:var(--text-dim);font-size:13px}.sheet-row .sr-go{color:var(--text-faint)}.sheet-row .sb-usage{padding:0}.sheet-actions{display:flex;border-top:1px solid var(--border);gap:8px;margin-top:8px;padding:12px 8px 4px}.sheet-actions .btn{flex:1;justify-content:center}.sheet-me{display:flex;border-bottom:1px solid var(--border);align-items: center;gap:10px;margin-bottom:6px;padding:4px 8px 12px}.sheet-me .avatar-img,.sheet-me .avatar-txt{display:grid;background:linear-gradient(135deg,var(--accent-2),var(--accent));color:#fff;border-radius:50%;flex:none;place-items: center;width:36px;height:36px;font-weight:700}.sheet-me .sm-name{color:var(--text);font-size:14.5px;font-weight:600}.sheet-me .sm-sub{color:var(--text-faint);font-size:12px}.shell.phone .editor-split{grid-template-columns:1fr}.shell.phone .infopanel{border-left:0}.shell.phone .launcher{padding:0 12px}.shell.phone .launch-box{margin-top:14px;padding:10px 12px}.shell.phone .launch-input{font-size:16px}.shell.phone .search-modal-panel{border-radius:0;width:100vw;height:100dvh;max-height:100dvh;top:0}.shell.phone .activity-panel{left:8px;right:8px;bottom:calc(var(--phonetabs-h) + env(safe-area-inset-bottom) + 8px);width:auto;max-height:68vh}.shell.phone .inbox,.shell.phone .toasts,.shell.phone .tray{left:8px;right:8px;bottom:calc(var(--phonetabs-h) + env(safe-area-inset-bottom) + 8px);width:auto}.shell.phone .viewer-dock{left:8px;right:8px;bottom:calc(var(--phonetabs-h) + env(safe-area-inset-bottom) + 8px);width:auto!important}.shell.tv{--activity-w:84px;--statusbar-h:34px;padding:2.2% 2.6%;font-size:17px}.shell.tv .activitybar{gap:10px;padding:16px 0 18px}.shell.tv .activitybar .item,.shell.tv .activitybar .iconbtn,.shell.tv .activitybar .brand-mark{border-radius:14px;width:64px;height:64px}.shell.tv .statusbar{font-size:15px}.shell.tv .launcher{max-width:1100px}.shell.tv .launch-input{font-size:24px}.shell.tv .launch-box{border-radius:16px;padding:16px 22px}.shell.tv .launch-mic{border-radius:11px;width:40px;height:40px}.shell.tv .launch-item{border-radius:12px;padding:14px 16px;font-size:18px}.shell.tv .launch-item .name{max-width:none}.shell.tv .launch-h{font-size:14px}.shell.tv .btn{padding:11px 20px;font-size:16px}.shell.tv .viewer.text pre{padding:28px 34px;font-size:19px;line-height:1.7}.shell.tv .md{max-width:1000px;font-size:21px}.shell.tv .viewer.markdown{padding:40px 52px}.shell.tv .viewer-nav{height:54px;padding:0 14px}.shell.tv .vn-crumb{max-width:420px;padding:8px 12px;font-size:17px}.shell.tv .vn-back{width:44px;height:40px}.shell.tv .settings{max-width:1000px;font-size:17px}.shell.tv .settings .setting .info .d{font-size:15px}.shell.tv .infopanel{font-size:16px}.shell.tv .toasts,.shell.tv .activity-panel{right:2.6%;bottom:calc(var(--statusbar-h) + 2.2%)}.shell.tv .plugin-panel{top:2.2%;right:2.6%}.shell.tv .tray{left:calc(var(--activity-w) + 2.6%);bottom:calc(var(--statusbar-h) + 2.2%)}.shell.tv .inbox{left:calc(var(--activity-w) + 2.6%);bottom:2.2%}.shell.tv .viewer-dock{right:2.6%;bottom:calc(var(--statusbar-h) + 2.2%)}.shell.tv :focus{outline:3px solid var(--accent);outline-offset:3px}.shell.tv :focus-visible{outline:3px solid var(--accent);outline-offset:3px}.shell.tv .launch-item:focus-visible{box-shadow:none}.shell.tv .sheet-row:focus-visible{box-shadow:none}.shell.tv .inbox-item:focus-visible{box-shadow:none}.shell.tv .activitybar .item:focus-visible{box-shadow:none}.shell.tv .activitybar .brand-mark:focus-visible{box-shadow:none}.shell.tv .statusbar .seg:focus-visible{box-shadow:none}.shell.tv .pb-tab:focus-visible{box-shadow:none}.shell.tv .btn:focus-visible{box-shadow:none}.shell.tv .iconbtn:focus-visible{box-shadow:none}.shell.tv .act-action:focus-visible{box-shadow:none}.shell.tv .launch-clear:focus-visible{box-shadow:none}.shell.tv .vn-back:focus-visible{box-shadow:none}.shell.tv .c-link:focus-visible{box-shadow:none}.shell.tv .react:focus-visible{box-shadow:none}.shell.tv .lh-example:focus-visible{box-shadow:none}.shell.tv .kbd-edit:focus-visible{box-shadow:none}.shell.tv .activitybar .item:focus-visible:before{content:none}.shell.tv .launch-input:focus{outline:none}.shell.tv .launch-input:focus-visible{outline:none}.shell.tv .launch-box:focus-within{outline:3px solid var(--accent);outline-offset:3px;border-color:var(--border-strong);box-shadow:var(--shadow)}.shell.tv .launch-item:focus,.shell.tv .sheet-row:focus{background:var(--bg-selected)}.shell.tv .launch-item.active{outline:3px solid var(--accent);outline-offset:3px;background:var(--bg-selected);box-shadow:none}.shell.tv .launch-body:focus-within .launch-item.active:not(:focus){outline:none;background:var(--bg-hover)}.shell.tv .launch-body{padding-left:8px;padding-right:8px}.launch-help{border-top:1px solid var(--border);margin:6px 10px 0;padding:12px 0 0}.lh-hint{display:flex;color:var(--text-dim);align-items: flex-start;gap:8px;font-size:12.5px;line-height:1.55}.lh-hint svg{color:var(--text-faint);flex:none;margin-top:2px}.lh-examples{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}.lh-example{display:inline-flex;border:1px solid var(--border);background:var(--bg-hover);color:var(--text);border-radius:8px;align-items:baseline;gap:7px;padding:5px 10px;font-size:12.5px}.lh-example:hover{border-color:var(--accent)}.lh-example .lh-q{font-family:var(--font-mono);font-size:12px}.lh-example .lh-label{color:var(--text-faint);font-size:11.5px}.mcp-url{display:flex;align-items: center;gap:8px;min-width:0}.mcp-url .mono{font-family:var(--font-mono);color:var(--text);background:var(--bg-input);border:1px solid var(--border);overflow-x:auto;white-space:nowrap;border-radius:6px;max-width:100%;padding:5px 9px;font-size:12.5px}.mcp-url .mono.small{color:var(--text-dim);font-size:11.5px}.settings .control .mono{font-family:var(--font-mono);color:var(--text-dim);font-size:12.5px}.mcp-warn{display:flex;color:var(--warn);background:color-mix(in srgb,var(--warn)10%,transparent);border:1px solid color-mix(in srgb,var(--warn)34%,transparent);border-radius:9px;align-items: flex-start;gap:9px;margin:4px 0 10px;padding:10px 12px;font-size:12.5px;line-height:1.55}.mcp-warn svg{flex:none;margin-top:1px}.shell.phone .settings{padding:18px 14px 40px}.shell.phone .setting{flex-direction:column;align-items:stretch;gap:8px}.shell.phone .setting .control{justify-content:stretch;width:100%}.shell.phone .setting .control>*{flex:1}.shell.phone .setting .control .switch,.shell.phone .setting .control .iconbtn,.shell.phone .mcp-url .btn{flex:none}.shell.phone .setting .control .switch{align-self: flex-start}.shell.phone .mcp-url .mono{flex:1;min-width:0}.shell.phone .setting:has(.control>.iconbtn:only-child){flex-direction:row;align-items: center}.shell.phone .setting:has(.control>.iconbtn:only-child) .control{justify-content:flex-end;width:auto}.launch-h .lh-title{display:flex;align-items:baseline;gap:8px;min-width:0}.launch-h .lh-actions{display:flex;flex:none;align-items: center;gap:2px}.launch-h .lh-verbatim{text-transform:none;color:var(--text-dim);letter-spacing:0;font-weight:500}.keys-actions{display:flex;align-items: center;gap:8px;padding:12px 0 2px}.keys-empty{color:var(--text-faint);padding:10px 0;font-size:12.5px}.keys-list{display:flex;flex-direction:column;gap:8px;margin-top:12px}.key-row{display:flex;border:1px solid var(--border);background:var(--bg-elevated);border-radius:10px;align-items: flex-start;gap:12px;padding:12px 13px}.key-row-main{flex:1;min-width:0}.key-row-name{display:flex;align-items: center;gap:8px}.key-row-name .t{font-weight:550}.key-row.dead{opacity:.55}.key-row.dead .key-row-name .t{text-decoration:line-through}.key-tag{text-transform:uppercase;letter-spacing:.5px;background:var(--bg-hover);color:var(--text-dim);border-radius:6px;padding:2px 7px;font-size:10.5px}.key-row-scopes{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}.key-chip{display:inline-flex;border:1px solid var(--border);overflow:hidden;border-radius:6px;align-items: center;gap:6px;font-size:11px}.key-chip .where{background:var(--bg-hover);color:var(--text-dim);padding:2px 7px}.key-chip .what{color:var(--accent);font-family:var(--font-mono);padding:2px 7px;font-size:10.5px}.key-row-meta{color:var(--text-faint);margin-top:7px;font-size:11.5px}.key-form{border:1px solid var(--border);background:var(--bg-elevated);border-radius:11px;margin-top:12px;padding:4px 14px 14px}.key-form .setting:last-of-type{border-bottom:0}.key-scopes{padding:12px 0 4px}.key-scopes-head .t{font-weight:550}.key-scopes-head .d{color:var(--text-faint);margin-top:2px;font-size:12px;line-height:1.4}.key-scope{display:flex;border-bottom:1px solid var(--border);align-items: center;gap:12px;padding:9px 0}.key-scope:last-child{border-bottom:0}.key-scope.wildcard{background:color-mix(in srgb,var(--warn)8%,transparent);border-bottom:0;border:1px solid color-mix(in srgb,var(--warn)26%,transparent);border-radius:9px;margin-bottom:4px;padding:10px 11px}.key-scope-name{display:flex;flex:1;align-items: center;gap:8px;min-width:0;font-size:13px}.key-scope-name span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.key-scope-name svg{color:var(--text-dim);flex:none}.key-scope.wildcard .key-scope-name svg{color:var(--warn)}.key-scope-caps{display:flex;flex:none;gap:6px}.key-scope-caps .cap{display:inline-flex;cursor:pointer;user-select:none;border:1px solid var(--border);color:var(--text-dim);background:0 0;border-radius:7px;align-items: center;gap:5px;padding:4px 9px;font-size:11.5px}.key-scope-caps .cap:hover{background:var(--bg-hover)}.key-scope-caps .cap.on{color:var(--accent);border-color:color-mix(in srgb,var(--accent)45%,var(--border));background:color-mix(in srgb,var(--accent)12%,transparent)}.key-scope-caps .cap input{accent-color:var(--accent);margin:0}.key-minted{background:color-mix(in srgb,var(--warn)9%,transparent);border:1px solid color-mix(in srgb,var(--warn)32%,transparent);border-radius:11px;margin:12px 0 4px;padding:13px 14px}.key-minted-head{display:flex;color:var(--warn);align-items: center;gap:9px;font-weight:550}.key-minted-head svg{flex:none}.key-minted-note{color:var(--text-dim);margin:8px 0 11px;font-size:12.5px;line-height:1.55}.key-secret{display:flex;align-items: center;gap:8px;min-width:0}.key-secret code{font-family:var(--font-mono);color:var(--text);background:var(--bg-input);border:1px solid var(--border);overflow-x:auto;white-space:nowrap;border-radius:6px;flex:1;min-width:0;padding:7px 10px;font-size:12.5px}@media (max-width:560px){.key-scope{flex-direction:column;align-items:stretch;gap:8px}.key-scope-caps{flex-wrap:wrap}.key-row{flex-direction:column}}.gate{display:grid;place-items: center;min-height:100%;padding:40px 20px}.gate-card{text-align:center;width:min(520px,100%)}.gate-icon{display:grid;color:var(--accent);background:color-mix(in srgb,var(--accent)13%,transparent);border:1px solid color-mix(in srgb,var(--accent)28%,transparent);border-radius:15px;place-items: center;width:56px;height:56px;margin:0 auto 16px}.gate-card h2{margin:0 0 8px;font-size:19px}.gate-sub{color:var(--text-dim);margin:0 0 20px;font-size:13px;line-height:1.6}.gate-actions{display:flex;justify-content:center;gap:8px;margin-top:18px}.gate-list{display:flex;text-align:left;flex-direction:column;gap:8px}.gate-choice{display:flex;cursor:pointer;font:inherit;color:inherit;border:1px solid var(--border);background:var(--bg-elevated);border-radius:10px;align-items: center;gap:12px;width:100%;padding:12px 14px}.gate-choice:hover{border-color:color-mix(in srgb,var(--accent)45%,var(--border));background:var(--bg-hover)}.gate-choice:focus-visible{outline:none;box-shadow:0 0 0 3px var(--focus-halo)}.gate-choice-main{display:flex;flex-direction:column;flex:1;gap:2px;min-width:0}.gate-choice-main .n{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:550}.gate-choice-main .d{color:var(--text-faint);font-size:11.5px}.gate-caps{font-family:var(--font-mono);color:var(--text-dim);background:var(--bg-hover);border-radius:6px;flex:none;padding:2px 8px;font-size:10.5px}
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
<title>Trove</title>
|
|
8
8
|
<link rel="icon" href="/icon.svg" />
|
|
9
9
|
<link rel="manifest" href="/manifest.webmanifest" />
|
|
10
|
-
<link rel="stylesheet" href="/assets/styles-
|
|
10
|
+
<link rel="stylesheet" href="/assets/styles-d3cyysgp.css" />
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
|
13
13
|
<div class="workbench"></div>
|
|
14
|
-
<script type="module" src="/assets/main-
|
|
14
|
+
<script type="module" src="/assets/main-f0f2tfhp.js"></script>
|
|
15
15
|
</body>
|
|
16
16
|
</html>
|
package/packages/web/dist/sw.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// API and FILES deliberately do NOT rotate. API is data, not code, and FILES holds the
|
|
19
19
|
// bytes of files the user pinned for offline use — naming it per build would throw away
|
|
20
20
|
// someone's offline library every time the app was redeployed.
|
|
21
|
-
const SHELL = 'trove-shell-
|
|
21
|
+
const SHELL = 'trove-shell-50eaa0a24f';
|
|
22
22
|
const API = 'trove-api-v1';
|
|
23
23
|
const FILES = 'trove-files-v1';
|
|
24
24
|
const KEEP = new Set([SHELL, API, FILES]);
|
|
@@ -53,6 +53,51 @@ self.addEventListener('fetch', (event) => {
|
|
|
53
53
|
event.respondWith(staleWhileRevalidate(req));
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
+
/**
|
|
57
|
+
* What a failed fetch actually means — which is not "offline" unless the browser says so.
|
|
58
|
+
*
|
|
59
|
+
* Every arm of this worker used to answer a rejected fetch with a synthesised 504 whose
|
|
60
|
+
* body said "Offline". Both halves of that were wrong, and together they cost a day of
|
|
61
|
+
* debugging: a bucket with no CORS policy rejects the fetch, so an online drive with a
|
|
62
|
+
* misconfigured store reported itself as a gateway timeout while offline, and the tab was
|
|
63
|
+
* neither. A worker cannot diagnose why a fetch failed, so it must not claim to.
|
|
64
|
+
*
|
|
65
|
+
* 503, not 504 — a made-up 504 is indistinguishable from a real proxy timeout, and
|
|
66
|
+
* that is exactly the wrong tree to send someone up.
|
|
67
|
+
* `x-trove-sw` — so a client (and a person reading the network panel) can tell this
|
|
68
|
+
* response was invented here and never reached a server.
|
|
69
|
+
* The real error, and `navigator.onLine`, because those are the two facts available.
|
|
70
|
+
*
|
|
71
|
+
* `kind` is how far the guess is allowed to go. A file request is the one that leaves this
|
|
72
|
+
* origin — the server answers it with a redirect to the store — so a store that refuses
|
|
73
|
+
* the browser is the likely cause there and nowhere else. For everything else the honest
|
|
74
|
+
* statement is that the server did not answer; naming CORS would send someone to check a
|
|
75
|
+
* bucket policy when their drive is simply down.
|
|
76
|
+
*/
|
|
77
|
+
function failed(err, kind) {
|
|
78
|
+
const offline = self.navigator.onLine === false;
|
|
79
|
+
const detail = err?.message || String(err || 'the request failed');
|
|
80
|
+
const cause = kind === 'file'
|
|
81
|
+
? 'The browser reports it is online, so this is usually the backing store refusing it — '
|
|
82
|
+
+ 'check Activity → Needs attention for the store’s CORS policy.'
|
|
83
|
+
: 'The browser reports it is online, so the server did not answer.';
|
|
84
|
+
const message = offline
|
|
85
|
+
? 'You are offline, and this is not available offline.'
|
|
86
|
+
: `This request could not be completed (${detail}). ${cause}`;
|
|
87
|
+
const json = kind === 'api';
|
|
88
|
+
return new Response(
|
|
89
|
+
json ? JSON.stringify({ error: { code: offline ? 'offline' : 'unavailable', message } }) : message,
|
|
90
|
+
{
|
|
91
|
+
status: 503,
|
|
92
|
+
statusText: offline ? 'Offline' : 'Request Failed',
|
|
93
|
+
headers: {
|
|
94
|
+
'content-type': json ? 'application/json' : 'text/plain; charset=utf-8',
|
|
95
|
+
'x-trove-sw': offline ? 'offline' : 'fetch-failed',
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
56
101
|
// Pinned files live in trove-files (keyed by the full download URL). If present,
|
|
57
102
|
// serve from cache (works offline and avoids re-downloading); else go to network.
|
|
58
103
|
async function pinnedFirst(req) {
|
|
@@ -61,8 +106,8 @@ async function pinnedFirst(req) {
|
|
|
61
106
|
if (hit) return sliceForRange(hit, req.headers.get('range'));
|
|
62
107
|
try {
|
|
63
108
|
return await fetch(req);
|
|
64
|
-
} catch {
|
|
65
|
-
return
|
|
109
|
+
} catch (err) {
|
|
110
|
+
return failed(err, 'file');
|
|
66
111
|
}
|
|
67
112
|
}
|
|
68
113
|
|
|
@@ -108,12 +153,10 @@ async function networkFirst(req) {
|
|
|
108
153
|
const res = await fetch(req);
|
|
109
154
|
if (res.ok) cache.put(req, res.clone());
|
|
110
155
|
return res;
|
|
111
|
-
} catch {
|
|
156
|
+
} catch (err) {
|
|
112
157
|
const hit = await cache.match(req);
|
|
113
158
|
if (hit) return hit;
|
|
114
|
-
return
|
|
115
|
-
status: 503, headers: { 'content-type': 'application/json' },
|
|
116
|
-
});
|
|
159
|
+
return failed(err, 'api');
|
|
117
160
|
}
|
|
118
161
|
}
|
|
119
162
|
|
|
@@ -140,13 +183,19 @@ function typeMatches(req, res) {
|
|
|
140
183
|
async function staleWhileRevalidate(req) {
|
|
141
184
|
const cache = await caches.open(SHELL);
|
|
142
185
|
const cached = await cache.match(req, { ignoreSearch: true });
|
|
186
|
+
// The error is kept rather than discarded: it is the only description of what went
|
|
187
|
+
// wrong that anyone will ever see, and `failed` needs it to avoid inventing a reason.
|
|
188
|
+
let reason = null;
|
|
143
189
|
const network = fetch(req).then((res) => {
|
|
144
190
|
// Let a mismatch through — the browser's own error is clearer than anything we
|
|
145
191
|
// could synthesise — but never keep it.
|
|
146
192
|
if (res.ok && typeMatches(req, res)) cache.put(req, res.clone());
|
|
147
193
|
return res;
|
|
148
|
-
}).catch(() =>
|
|
149
|
-
|
|
194
|
+
}).catch((err) => {
|
|
195
|
+
reason = err;
|
|
196
|
+
return null;
|
|
197
|
+
});
|
|
198
|
+
return cached || (await network) || failed(reason, 'asset');
|
|
150
199
|
}
|
|
151
200
|
|
|
152
201
|
// --- web push (bodyless → pull inbox) --------------------------------------
|
|
@@ -25,7 +25,14 @@ export class NavigateAction extends AppAction {
|
|
|
25
25
|
}
|
|
26
26
|
async execute({ app }) {
|
|
27
27
|
const { explorer, platform } = app;
|
|
28
|
-
|
|
28
|
+
// No `|| 'default'`. Navigating nowhere in particular used to land on a collection
|
|
29
|
+
// that may not exist and may not be readable; now it is a bug in the caller, said out
|
|
30
|
+
// loud rather than papered over with a guess.
|
|
31
|
+
const collectionId = this.collectionId || explorer.state.collectionId;
|
|
32
|
+
if (!collectionId) {
|
|
33
|
+
explorer.set({ loading: false, gate: 'choose' });
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
29
36
|
const switching = collectionId !== explorer.state.collectionId;
|
|
30
37
|
// A collection's trash belongs to that collection. Carrying it across a switch
|
|
31
38
|
// listed the OLD collection's deleted files under the new one — above an "Empty
|
|
@@ -35,7 +42,7 @@ export class NavigateAction extends AppAction {
|
|
|
35
42
|
try {
|
|
36
43
|
const sort = platform.settings.get('explorer.sort');
|
|
37
44
|
const order = platform.settings.get('explorer.sortOrder');
|
|
38
|
-
const res = await platform.api.list({ sort, order
|
|
45
|
+
const res = await platform.api.list(collectionId, { sort, order });
|
|
39
46
|
explorer.set({
|
|
40
47
|
items: res.items, loading: false, selection: [], sort, order,
|
|
41
48
|
collectionId: res.collectionId || collectionId,
|
|
@@ -47,6 +54,7 @@ export class NavigateAction extends AppAction {
|
|
|
47
54
|
});
|
|
48
55
|
// Remember where they were, so the next visit opens there rather than guessing.
|
|
49
56
|
platform.settings.set?.('explorer.lastCollection', collectionId);
|
|
57
|
+
explorer.set({ gate: null });
|
|
50
58
|
// Explorer→context projection (collectionId/hasSelection) lives in bl/index.js
|
|
51
59
|
// so it stays in sync with selection too — nothing to mirror here.
|
|
52
60
|
} catch (err) {
|
|
@@ -82,28 +90,46 @@ export class OpenInitialCollectionAction extends AppAction {
|
|
|
82
90
|
// dispatch() returns an event feed, not the action's value, so awaiting it would
|
|
83
91
|
// hand back an EventTarget and this would fail in a way nothing reports.
|
|
84
92
|
let collections = [];
|
|
93
|
+
let canCreate = false;
|
|
85
94
|
try {
|
|
86
95
|
const res = await app.platform.api.collections();
|
|
87
96
|
collections = res.collections || [];
|
|
88
|
-
|
|
97
|
+
canCreate = !!res.canCreate;
|
|
98
|
+
app.explorer.set({ collections, canCreateCollection: canCreate });
|
|
89
99
|
} catch (err) {
|
|
90
100
|
app.explorer.set({ loading: false, error: `Couldn't load your collections: ${err.message}` });
|
|
91
101
|
return;
|
|
92
102
|
}
|
|
103
|
+
|
|
93
104
|
const ids = collections.map((c) => c.id);
|
|
94
105
|
const remembered = app.platform.settings.get('explorer.lastCollection');
|
|
106
|
+
|
|
107
|
+
// Nothing exists yet. Two different situations that used to read as one:
|
|
95
108
|
if (!ids.length) {
|
|
96
|
-
// A signed-in user with no grants at all. Say so; an empty file list with no
|
|
97
|
-
// explanation reads as "your drive is empty", which is a different and much worse
|
|
98
|
-
// thing to believe.
|
|
99
109
|
app.explorer.set({
|
|
100
110
|
loading: false, items: [], collections: [],
|
|
101
|
-
|
|
111
|
+
// Someone who may create one is on a fresh drive and should be asked to. Someone
|
|
112
|
+
// who may not has no grants, and telling them to create a collection they cannot
|
|
113
|
+
// create is worse than telling them nothing.
|
|
114
|
+
gate: canCreate ? 'create' : null,
|
|
115
|
+
error: canCreate
|
|
116
|
+
? null
|
|
117
|
+
: 'You do not have access to any collections yet. Ask an administrator to grant you one.',
|
|
102
118
|
});
|
|
103
119
|
return;
|
|
104
120
|
}
|
|
105
|
-
|
|
106
|
-
|
|
121
|
+
|
|
122
|
+
// There is no fallback to a first or a favourite. Landing somewhere the user did not
|
|
123
|
+
// pick is how the old 'default' behaved, and on a shared drive it opened a collection
|
|
124
|
+
// plenty of people could not read — a permission error presented as their drive.
|
|
125
|
+
// A remembered choice is theirs; anything else is a question.
|
|
126
|
+
if (!remembered || !ids.includes(remembered)) {
|
|
127
|
+
app.explorer.set({ loading: false, items: [], gate: 'choose', error: null });
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
app.explorer.set({ gate: null });
|
|
132
|
+
return app.engine.dispatch(new NavigateAction(remembered));
|
|
107
133
|
}
|
|
108
134
|
}
|
|
109
135
|
|
|
@@ -132,9 +158,8 @@ export class LoadMoreAction extends AppAction {
|
|
|
132
158
|
if (!cursor || explorer.state.loadingMore) return;
|
|
133
159
|
explorer.set({ loadingMore: true });
|
|
134
160
|
try {
|
|
135
|
-
const res = await platform.api.list({
|
|
136
|
-
sort: explorer.state.sort, order: explorer.state.order,
|
|
137
|
-
collection: explorer.state.collectionId, cursor,
|
|
161
|
+
const res = await platform.api.list(explorer.state.collectionId, {
|
|
162
|
+
sort: explorer.state.sort, order: explorer.state.order, cursor,
|
|
138
163
|
});
|
|
139
164
|
explorer.set({
|
|
140
165
|
items: [...explorer.state.items, ...res.items],
|
|
@@ -267,7 +292,13 @@ export class UploadFilesAction extends AppAction {
|
|
|
267
292
|
this.collectionId = collectionId;
|
|
268
293
|
}
|
|
269
294
|
async execute({ app }) {
|
|
270
|
-
const collection = this.collectionId || app.explorer.state.collectionId
|
|
295
|
+
const collection = this.collectionId || app.explorer.state.collectionId;
|
|
296
|
+
// Uploading with no collection open has nowhere to put the bytes. Refused visibly:
|
|
297
|
+
// the old fallback sent them to whatever 'default' happened to be.
|
|
298
|
+
if (!collection) {
|
|
299
|
+
app.platform.notifications.error('Open a collection before uploading');
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
271
302
|
const concurrency = app.platform.settings.get('uploads.concurrency');
|
|
272
303
|
const uploads = [...this.files].map((file) => this.#one(app, file, collection, concurrency));
|
|
273
304
|
await Promise.allSettled(uploads);
|
|
@@ -408,3 +439,71 @@ export class SearchAction extends AppAction {
|
|
|
408
439
|
}
|
|
409
440
|
}
|
|
410
441
|
}
|
|
442
|
+
|
|
443
|
+
// --- API keys (admin) ----------------------------------------------------------
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Load the key list.
|
|
447
|
+
*
|
|
448
|
+
* Silent on failure rather than noisy: this fires when Settings opens, and a non-admin
|
|
449
|
+
* opening Settings gets a 403 that is the correct answer, not an error worth a toast.
|
|
450
|
+
* The section simply does not render.
|
|
451
|
+
*/
|
|
452
|
+
export class LoadApiKeysAction extends AppAction {
|
|
453
|
+
async execute({ app }) {
|
|
454
|
+
app.apiKeys.set({ loading: true, error: null });
|
|
455
|
+
try {
|
|
456
|
+
const res = await app.platform.api.apiKeys();
|
|
457
|
+
app.apiKeys.set({ keys: res.keys || [], loading: false, loaded: true, error: null });
|
|
458
|
+
} catch (err) {
|
|
459
|
+
app.apiKeys.set({ loading: false, loaded: true, error: err?.message || 'Could not load API keys' });
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Mint a key and hold the secret for display.
|
|
466
|
+
*
|
|
467
|
+
* The secret is the whole point of the round trip and cannot be fetched again, so it is
|
|
468
|
+
* put into state before anything else can fail. A refresh of the list afterwards is a
|
|
469
|
+
* convenience; losing the secret because the refresh threw would not be.
|
|
470
|
+
*/
|
|
471
|
+
export class MintApiKeyAction extends AppAction {
|
|
472
|
+
constructor(spec) {
|
|
473
|
+
super();
|
|
474
|
+
this.spec = spec;
|
|
475
|
+
}
|
|
476
|
+
async execute({ app }) {
|
|
477
|
+
app.apiKeys.set({ busy: 'mint', error: null });
|
|
478
|
+
try {
|
|
479
|
+
const { key, secret } = await app.platform.api.mintApiKey(this.spec);
|
|
480
|
+
app.apiKeys.set({ minted: { key, secret }, busy: null });
|
|
481
|
+
const res = await app.platform.api.apiKeys().catch(() => null);
|
|
482
|
+
if (res) app.apiKeys.set({ keys: res.keys || [] });
|
|
483
|
+
return key;
|
|
484
|
+
} catch (err) {
|
|
485
|
+
app.apiKeys.set({ busy: null, error: err?.message || 'Could not create the key' });
|
|
486
|
+
app.platform.notifications.error(err?.message || 'Could not create the key');
|
|
487
|
+
return null;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
export class RevokeApiKeyAction extends AppAction {
|
|
493
|
+
constructor(id) {
|
|
494
|
+
super();
|
|
495
|
+
this.id = id;
|
|
496
|
+
}
|
|
497
|
+
async execute({ app }) {
|
|
498
|
+
app.apiKeys.set({ busy: this.id, error: null });
|
|
499
|
+
try {
|
|
500
|
+
await app.platform.api.revokeApiKey(this.id);
|
|
501
|
+
const res = await app.platform.api.apiKeys().catch(() => null);
|
|
502
|
+
app.apiKeys.set({ busy: null, ...(res ? { keys: res.keys || [] } : {}) });
|
|
503
|
+
app.platform.notifications.success('Key revoked');
|
|
504
|
+
} catch (err) {
|
|
505
|
+
app.apiKeys.set({ busy: null });
|
|
506
|
+
app.platform.notifications.error(err?.message || 'Could not revoke the key');
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|