texlite 0.7.8 → 0.8.1
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/DESIGN.md +463 -0
- package/NPM_TESTING.md +136 -0
- package/OPERATIONS.md +261 -0
- package/README.md +82 -305
- package/README.zh-CN.md +64 -329
- package/dist/client/assets/{GitDialog-CqGyUxfP.js → GitDialog-CZRQPg3O.js} +1 -1
- package/dist/client/assets/{HistoryDialog-BMl2zxBa.js → HistoryDialog-BQtr58Co.js} +1 -1
- package/dist/client/assets/{LatexEditor-C4bFVwJZ.js → LatexEditor-XLwZxO6_.js} +1 -1
- package/dist/client/assets/{PdfPreview-BpP2LnX7.js → PdfPreview-D5CC-vqV.js} +1 -1
- package/dist/client/assets/{ProjectNavigationDialogs-B7mxG8Fz.js → ProjectNavigationDialogs-BdtTldSa.js} +1 -1
- package/dist/client/assets/{SystemMetricsDialog-BK_K3ah8.js → SystemMetricsDialog-CEbYJdj7.js} +1 -1
- package/dist/client/assets/index-BAFR6u6_.js +64 -0
- package/dist/client/assets/index-g5CaToD6.css +1 -0
- package/dist/client/assets/{minus-BwzSZenU.js → minus-KzdrD7TK.js} +1 -1
- package/dist/client/assets/spellCheck-CDZ9ZXo6.js +1 -0
- package/dist/client/index.html +2 -2
- package/dist/server/app.js +8 -3
- package/dist/server/cli.js +170 -32
- package/dist/server/environment.js +168 -38
- package/dist/server/harper.js +210 -119
- package/dist/server/i18n.js +8 -0
- package/dist/server/latexSpellMask.js +257 -0
- package/dist/server/projects.js +0 -12
- package/dist/server/routes/projectShared.js +1 -1
- package/dist/server/routes/projects.js +20 -19
- package/dist/server/routes/wordCount.js +83 -0
- package/dist/server/texcount.js +244 -0
- package/package.json +6 -3
- package/preview-1.png +0 -0
- package/preview-2.png +0 -0
- package/dist/client/assets/index-B9n8hfV0.js +0 -64
- package/dist/client/assets/index-BhyTKMoO.css +0 -1
- package/dist/client/assets/spellCheck-CvOAlLWp.js +0 -4
- package/preview.png +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;color:#202421;background:#f3f4f1;font-synthesis:none}*{box-sizing:border-box}html,body,#root{margin:0;min-height:100%}button,input,select,textarea{font:inherit}button{cursor:pointer}button:disabled{cursor:not-allowed;opacity:.45}.muted{color:#737a75}.error{color:#b3261e;font-size:14px}.dialog-error{margin:0;padding:8px 10px;border:1px solid #e9b6b0;border-radius:6px;background:#fff3f1}.field-hint{color:#778179;font-size:11px;font-weight:400}.primary,.compile{border:0;border-radius:8px;background:#176b44;color:#fff;padding:10px 18px;font-weight:650}.icon-button{display:inline-flex;align-items:center;gap:6px}.ghost{border:0;background:transparent;color:inherit}.page{min-height:100vh;display:flex;flex-direction:column}.login-page{min-height:100vh;display:grid;grid-template-rows:1fr auto;place-items:center;padding-top:44px;background:radial-gradient(circle at 50% 0,#d8e8dd,#f5f5f1 45%)}.login-card{width:min(390px,calc(100vw - 32px));padding:38px;display:flex;flex-direction:column;gap:16px;background:#ffffffeb;border:1px solid #dfe4df;border-radius:16px;box-shadow:0 24px 70px #1d31241f}.login-card h1{text-align:center;margin:0;letter-spacing:-.04em}.login-card>p{text-align:center;margin:-8px 0 8px}.login-card label,.settings label{display:flex;flex-direction:column;gap:7px;font-size:13px;font-weight:650}.login-card input,.settings input,.settings select,.settings textarea{width:100%;border:1px solid #cbd2cc;border-radius:8px;padding:10px 11px;background:#fff;outline:none}.login-card input:focus,.settings input:focus{border-color:#176b44;box-shadow:0 0 0 3px #176b4420}.site-logo{width:40px;height:40px;flex:none;display:inline-flex;align-items:center;justify-content:center}.site-logo img{display:block;width:100%;height:100%}.site-logo.compact{width:34px;height:34px;margin:0 16px 0 10px}.site-logo.auth-logo{width:76px;height:76px;margin:0 auto 2px;filter:drop-shadow(0 10px 18px #1e2a4a25)}.brand-link{display:inline-flex;align-items:center;color:inherit;text-decoration:none}.brand-link:hover .site-title{color:#d9f0df}.compact-brand-link{flex:none}.site-title{margin-right:11px;font-size:20px;font-weight:800;letter-spacing:-.04em}.sr-only{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.support{color:#737a75;text-align:center}.topbar,.editor-topbar{height:62px;display:flex;align-items:center;padding:0 26px;background:#123c2a;color:#fff}.top-actions{margin-left:auto;display:flex;align-items:center;gap:18px;font-size:14px}.top-actions .ghost{display:inline-flex;align-items:center;gap:5px;border:1px solid transparent;border-radius:6px;padding:6px 8px;background:transparent;color:inherit;transition:background .15s ease,border-color .15s ease,box-shadow .15s ease,color .15s ease,transform .08s ease}.top-actions .ghost:hover,.top-actions .ghost:focus-visible{border-color:#ffffff20;background:#ffffff16;color:#d9f0df;box-shadow:0 4px 12px #061c1130;outline:none}.top-actions .ghost:active{transform:translateY(1px);box-shadow:0 1px 4px #061c1126}.top-actions .ghost.top-return-action,.top-actions .ghost.top-return-action:hover,.top-actions .ghost.top-return-action:focus-visible,.top-actions .ghost.top-return-action:active{transform:none;box-shadow:none}.top-user-identity{min-width:0;display:flex;flex-direction:column;line-height:1.15}.top-user-identity strong{overflow:hidden;max-width:180px;font-size:13px;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.top-user-identity small{overflow:hidden;max-width:180px;margin-top:3px;color:#b9d0c2;font-size:10px;text-overflow:ellipsis;white-space:nowrap}.language-switcher{position:fixed;top:18px;right:20px;z-index:5;display:flex;align-items:center;gap:6px;color:#536059;font-size:12px}.language-switcher select{border:1px solid #c9d0ca;border-radius:6px;padding:5px 7px;background:#fff;color:#26342b}.language-switcher.compact{position:static;color:inherit}.language-switcher.compact select{border-color:#ffffff35;background:#ffffff10;color:inherit}.language-switcher.compact option{color:#202421}.dashboard{width:100%;max-width:1180px;flex:1;margin:0 auto;padding:52px 34px}.citation-library-page-shell{padding-top:34px}.citation-library-page{display:flex;flex-direction:column;gap:18px}.citation-library-page-header{display:flex;align-items:flex-start;justify-content:space-between;gap:18px}.citation-library-page-header>div{min-width:0}.citation-library-page-header h1{display:flex;align-items:center;gap:9px;margin:0;color:#202421;font-size:30px;letter-spacing:-.04em}.citation-library-page-header h1 svg{flex:none;color:#315b43}.citation-library-page-header p{max-width:720px;margin:8px 0 0;color:#737a75;font-size:12px;line-height:1.5}.citation-library-page-header>button{display:inline-flex;align-items:center;gap:5px;flex:none;border:1px solid #bfc8c1;border-radius:8px;padding:9px 12px;background:#fff;color:#52685a;font-size:11px}.citation-library-page-header>button:hover{border-color:#8eaa98;background:#edf4ef;color:#176b44}.citation-library-page .citation-library-dialog{padding:18px;border:1px solid #dfe4df;border-radius:12px;background:#fff;box-shadow:0 8px 26px #25352a0f}.citation-library-page .citation-entry-list{max-height:none}.citation-library-pagination{display:flex;align-items:center;justify-content:center;gap:10px;margin-top:6px;color:#66736b;font-size:10px}.citation-library-pagination button{display:inline-flex;align-items:center;gap:4px;border:1px solid #cbd5ce;border-radius:6px;padding:6px 9px;background:#fff;color:#52685a;font-size:10px}.citation-library-pagination button:hover:not(:disabled){border-color:#8eaa98;background:#edf4ef;color:#176b44}.site-footer{width:100%;display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:7px 16px;padding:18px 24px;border-top:1px solid #dfe3df;background:#eef0ed;color:#737b75;font-size:11px;text-align:center}.site-footer a{color:#176b44;text-decoration:none}.site-footer a:hover{text-decoration:underline}.login-page>.site-footer{align-self:end;background:#ffffff50}.section-title{display:flex;justify-content:space-between;align-items:end;margin-bottom:28px}.section-title h1{display:flex;align-items:center;gap:9px;margin:0;font-size:30px;letter-spacing:-.04em}.section-title h1 svg{flex:none;color:#315b43}.section-title p{margin:7px 0 0}.section-actions{display:flex;gap:9px}.section-actions>button{display:inline-flex;align-items:center;gap:6px;border:1px solid #bfc8c1;border-radius:8px;background:#fff;padding:10px 16px}.section-actions>.primary{border-color:#176b44;background:#176b44;color:#fff}.project-toolbar{display:flex;align-items:center;flex-wrap:wrap;gap:12px;margin-bottom:18px;padding:10px;background:#e9ece8;border-radius:10px}.project-toolbar>input{width:220px;border:1px solid #cbd2cc;border-radius:7px;padding:8px 10px;background:#fff}.project-scope{display:flex;flex:none;gap:2px}.project-scope button{display:flex;align-items:center;gap:5px;flex:none;border:1px solid transparent;border-radius:7px;padding:7px 9px;background:transparent;color:#536059;font-size:12px}.project-scope button.active{border-color:#b8c4ba;background:#fff;color:#174b33}.tag-filters{min-width:0;flex:1;display:flex;gap:6px;overflow-x:auto}.tag-filters button,.view-toggle button{display:flex;align-items:center;gap:5px;flex:none;border:1px solid transparent;border-radius:7px;padding:7px 9px;background:transparent;color:#536059;font-size:12px}.tag-filters button.active,.view-toggle button.active{border-color:#b8c4ba;background:#fff;color:#174b33}.project-sort{flex:none;display:flex;align-items:center;gap:5px;color:#536059;font-size:11px}.project-sort>span{white-space:nowrap}.project-sort select{max-width:150px;border:1px solid #c4ccc6;border-radius:7px;padding:7px 25px 7px 8px;background:#fff;color:#34433a;font-size:12px}.view-toggle{display:flex;gap:2px}.project-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(270px,1fr));gap:16px}.project-card{position:relative;min-height:250px;display:flex;flex-direction:column;text-align:left;background:#fff;border:1px solid #dfe2de;border-radius:12px;overflow:hidden;transition:.15s ease}.project-card:hover{border-color:#8bae9a;transform:translateY(-2px);box-shadow:0 10px 30px #25352a10}.project-card-open{all:unset;box-sizing:border-box;min-width:0;flex:1;display:flex;flex-direction:column;align-items:flex-start;gap:10px;padding:20px 20px 14px;cursor:pointer}.project-card-open:focus-visible{outline:3px solid #176b4455;outline-offset:-3px}.project-card strong{font-size:17px}.project-card-main{min-width:0;display:flex;flex-direction:column;gap:7px}.project-tags,.settings-tags{display:flex;flex-wrap:wrap;gap:5px}.owner-badge{max-width:100%;overflow:hidden;padding:6px 9px;border-radius:7px;background:#e2f0e7;color:#176b44;font-size:11px;font-weight:750;text-overflow:ellipsis;white-space:nowrap}.project-grid:not(.list-view) .owned-project .owner-badge{max-width:calc(100% - 94px)}.project-transfer-action{position:absolute;z-index:2;top:17px;right:16px;display:inline-flex;align-items:center;gap:4px;border:1px solid #cbd7cf;border-radius:6px;padding:5px 7px;background:#f7faf8;color:#315c43;font-size:10px}.project-transfer-action:hover{border-color:#8caf99;background:#e8f1eb;color:#176b44}.project-meta{width:100%;display:grid;grid-template-columns:1fr;gap:8px;margin:auto 0 0}.project-meta div{min-width:0}.project-meta dt{display:flex;align-items:center;gap:4px;color:#8a918c;font-size:10px;text-transform:uppercase}.project-meta dt svg{flex:none;color:#6f8e7a}.project-meta dd{overflow:hidden;margin:2px 0 0;color:#555e58;font-size:11px;text-overflow:ellipsis;white-space:nowrap}.project-grid:not(.list-view) .project-meta dd{overflow:visible;text-overflow:clip;white-space:normal;overflow-wrap:anywhere}.project-modified-by{color:#68716b}.project-card-actions{display:flex;flex-wrap:wrap;gap:5px;padding:9px 12px;border-top:1px solid #eceeeb;background:#fafbf9}.project-card-actions button,.project-card-actions a{display:inline-flex;align-items:center;gap:5px;border:0;border-radius:5px;padding:5px 7px;background:transparent;color:#4f5b53;font-size:11px;text-decoration:none}.project-card-actions button:hover,.project-card-actions a:hover{background:#e8eeea;color:#176b44}.project-card-actions .danger-text{margin-left:auto;color:#b3261e}.project-grid:not(.list-view) .project-card-actions{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:4px}.project-grid:not(.list-view) .project-card-actions button,.project-grid:not(.list-view) .project-card-actions a{width:100%;min-width:0;justify-content:flex-start;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.project-grid:not(.list-view) .project-card-actions .danger-text{margin-left:0}.project-grid.list-view{display:flex;flex-direction:column;gap:7px}.project-grid.list-view .project-card{min-height:88px;flex-direction:row;align-items:stretch}.project-grid.list-view .project-card-open{display:grid;grid-template-columns:minmax(90px,140px) minmax(170px,1fr) minmax(390px,2fr);align-items:center;gap:14px;padding:12px 15px}.project-grid.list-view .project-card-main{min-width:170px}.project-grid.list-view .project-meta{grid-template-columns:minmax(145px,.75fr) minmax(0,1.25fr);gap:8px 12px;margin:0}.project-grid.list-view .project-meta>div:last-child dd{overflow:visible;text-overflow:clip;white-space:normal;overflow-wrap:anywhere}.project-grid.list-view .project-card-actions{width:190px;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));align-content:center;gap:4px;border-top:0;border-left:1px solid #eceeeb}.project-grid.list-view .project-card-actions button,.project-grid.list-view .project-card-actions a{width:100%;justify-content:flex-start}.project-grid.list-view .project-card-actions .danger-text{margin-left:0}.project-comments-badge{display:inline-flex;align-items:center;gap:3px;width:fit-content;border-radius:999px;padding:1px 6px;font-size:10px;font-weight:650;line-height:1.4}.project-comments-badge.unresolved{background:#fde8e7;color:#b3261e;border:1px solid #f8c8c5}.tag{display:inline-flex;align-items:center;gap:4px;width:fit-content;border-radius:999px;padding:2px 7px;background:#eef0ee;color:#4a524c;font-size:10px;font-weight:650}.tag-dot{display:inline-block;width:9px;height:9px;border-radius:50%;background:currentColor}.tag-red{--tag-color: #e04b45}.tag-orange{--tag-color: #ef9135}.tag-yellow{--tag-color: #dbb62f}.tag-green{--tag-color: #49a563}.tag-blue{--tag-color: #4c83db}.tag-purple{--tag-color: #9566ce}.tag-gray{--tag-color: #929994}.tag-dot[class*=tag-]{color:var(--tag-color)}.tag[class*=tag-]{border:1px solid color-mix(in srgb,var(--tag-color) 35%,transparent);background:color-mix(in srgb,var(--tag-color) 12%,white)}.empty,.center-card{padding:50px;color:#737a75;text-align:center}.project-empty{grid-column:1 / -1;width:100%;min-height:320px;display:flex;align-items:center;justify-content:center;flex-direction:column;box-sizing:border-box;padding:64px 24px;border:1px dashed #cbd7ce;border-radius:14px;background:linear-gradient(145deg,#fbfcfa,#f2f7f3);text-align:center}.project-empty-icon{width:58px;height:58px;display:grid;place-items:center;margin-bottom:18px;border-radius:18px;background:#dfeee4;color:#176b44}.project-empty h2{margin:0;color:#203f2e;font-size:clamp(27px,3vw,38px);line-height:1.15;letter-spacing:-.035em}.project-empty p{max-width:520px;margin:13px 0 0;color:#6e7b72;font-size:15px;line-height:1.6}.project-pagination{display:flex;align-items:center;justify-content:center;gap:12px;margin:22px 0 4px;color:#66726a;font-size:12px}.project-pagination button{display:inline-flex;align-items:center;gap:5px;border:1px solid #cbd4ce;border-radius:7px;padding:7px 10px;background:#fff;color:#405248;font-size:12px}.project-pagination button:hover:not(:disabled){border-color:#8bae9a;background:#f2f7f3;color:#176b44}.table-card{overflow:hidden;background:#fff;border:1px solid #dfe2de;border-radius:12px}table{width:100%;border-collapse:collapse}th,td{padding:14px 18px;border-bottom:1px solid #eceeeb;text-align:left;font-size:14px}th{background:#f8f9f7;color:#667069;font-size:12px;text-transform:uppercase}td small{display:block;color:#7d837f;margin-top:3px}td button{margin-right:8px;border:1px solid #cdd2ce;background:#fff;border-radius:5px;padding:5px 9px}.danger-text{color:#b3261e}.workspace{height:100vh;display:flex;flex-direction:column;overflow:hidden}.editor-topbar{height:56px;padding:0 14px;flex:none}.back{color:#fff;border:0;background:#ffffff10;width:32px;height:32px;display:grid;place-items:center;border-radius:6px}.project-heading{display:flex;flex-direction:column;min-width:0;margin-right:auto}.project-heading small{color:#b9d0c2;font-size:11px;margin-top:2px}.vim-status-badge{display:inline-flex;align-items:center;gap:5px;margin-right:8px;border:1px solid #7fd39e80;border-radius:999px;padding:5px 9px;background:#1d6b4638;color:#d7ffe3;font-size:10px;font-weight:750;letter-spacing:.04em;white-space:nowrap}.vim-status-badge svg{color:#9df0b5}.collaboration-presence{min-width:0;display:flex;align-items:center;gap:7px;padding-left:8px}.collaboration-status-dot{width:7px;height:7px;flex:none;border-radius:50%;background:#efb84b;box-shadow:0 0 0 2px #efb84b2e}.collaboration-connected .collaboration-status-dot{background:#69d391;box-shadow:0 0 0 2px #69d3912e}.collaboration-disconnected .collaboration-status-dot{background:#e07167;box-shadow:0 0 0 2px #e071672e}.collaboration-avatars{display:flex;align-items:center;padding-left:8px}.collaboration-avatar{--session-color: #1677c8;position:relative;width:28px;height:28px;display:grid;place-items:center;margin-left:-8px;border:2px solid #214d35;border-radius:50%;background:var(--session-color);color:#fff;font-size:11px;font-weight:750;cursor:default;box-shadow:0 1px 4px #061c1145}.collaboration-avatar.editing:after{content:"";position:absolute;right:-2px;bottom:-2px;width:7px;height:7px;border:2px solid #214d35;border-radius:50%;background:#8ff0af}.collaboration-avatar.local{outline:1px solid #ffffff8a;outline-offset:-4px}.collaboration-avatar-overflow{appearance:none;padding:0;border-color:#72877b;background:#f4f7f5;color:#284536;font-family:inherit;font-size:10px;cursor:pointer}.collaboration-avatar-overflow:hover,.collaboration-avatar-overflow:focus-visible{background:#dfe9e3;outline:2px solid #9bc6aa;outline-offset:1px}.collaboration-avatar-tooltip{position:absolute;z-index:80;top:calc(100% + 9px);right:-8px;width:max-content;max-width:280px;display:none;gap:2px;padding:9px 11px;border:1px solid #d7ded9;border-radius:7px;background:#fff;color:#20352a;font-size:12px;font-weight:400;line-height:1.35;text-align:left;box-shadow:0 8px 24px #061c1130}.collaboration-avatar-tooltip:before{content:"";position:absolute;top:-5px;right:15px;width:8px;height:8px;transform:rotate(45deg);border-left:1px solid #d7ded9;border-top:1px solid #d7ded9;background:#fff}.collaboration-avatar-tooltip strong,.collaboration-avatar-tooltip span,.collaboration-avatar-tooltip small{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.collaboration-avatar-tooltip strong{font-size:13px}.collaboration-avatar-tooltip span{color:#526158}.collaboration-avatar-tooltip small{margin-top:3px;color:#77837b;font-size:11px}.collaboration-avatar:hover .collaboration-avatar-tooltip,.collaboration-avatar:focus-visible .collaboration-avatar-tooltip{display:block}.collaboration-recovery{min-width:0;display:inline-flex;align-items:center;gap:7px;margin:0 8px;border:1px solid #e0716780;border-radius:999px;padding:4px 6px 4px 9px;background:#6f2b2b66;color:#ffe0dd;font-size:10px;white-space:nowrap}.collaboration-recovery button{border:1px solid #ffffff55;border-radius:999px;padding:3px 7px;background:#ffffff18;color:inherit;font-size:10px}.collaboration-recovery button:hover{background:#ffffff2c}.compile-status-strip{min-height:31px;display:flex;align-items:center;justify-content:center;gap:7px;padding:6px 14px;background:#fff6dc;color:#72530d;border-bottom:1px solid #e8cd7d;font-size:11px}.compile-status-strip.failed{background:#fff0ee;color:#9a3028;border-bottom-color:#e8aaa4}.editor-actions .compile.cancel-compile{border-color:#c9675f;background:#fff5f3;color:#9b342d}.editor-actions .compile.cancel-compile:hover:not(:disabled){border-color:#a8463f;background:#ffe9e6}.workspace-update-banner{min-height:34px;display:flex;align-items:center;justify-content:center;gap:8px;padding:6px 14px;border-bottom:1px solid #dfb25e;background:#fff3d8;color:#62460e;font-size:11px}.workspace-update-banner>svg{flex:none;color:#b97817}.workspace-update-banner button{flex:none;border:1px solid #c9963d;border-radius:5px;padding:4px 8px;background:#fff;color:inherit;font:inherit;font-weight:650}.workspace-update-banner button:hover{border-color:#9b6b16;background:#fff8e9}.client-tool-recoveries{flex:none;display:flex;flex-direction:column}.client-tool-recovery{min-height:34px;display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:8px;padding:6px 14px;border-bottom:1px solid #e4bf78;background:#fff8e8;color:#6f4d10;font-size:11px}.client-tool-recovery>svg{flex:none;color:#b97817}.client-tool-recovery>span{min-width:0;flex:0 1 auto;line-height:1.35}.client-tool-recovery>span strong{margin-right:3px}.client-tool-recovery-actions{flex:none;display:inline-flex;align-items:center;gap:5px}.client-tool-recovery-actions button{border:1px solid #d5a553;border-radius:5px;padding:4px 8px;background:#fff;color:#6f4d10;font:inherit;cursor:pointer}.client-tool-recovery-actions button:hover:not(:disabled){border-color:#a86b0f;background:#fff1cd}.client-tool-recovery-actions button:disabled{cursor:not-allowed;opacity:.5}.formatter-diagnostics details{min-width:110px;max-width:min(760px,80vw)}.formatter-diagnostics summary{cursor:pointer;color:#8f5b0d;font-weight:650}.formatter-diagnostics details[open]{flex-basis:100%;order:3}.formatter-diagnostics pre{max-height:150px;margin:7px auto 2px;overflow:auto;border:1px solid #e4c88f;border-radius:5px;padding:8px 10px;background:#fffdf7;color:#57451f;font:11px/1.45 SFMono-Regular,Consolas,monospace;white-space:pre-wrap}.formatter-diagnostics-dismiss{width:25px;height:25px;display:grid;place-items:center;flex:none;border:1px solid transparent;border-radius:5px;padding:0;background:transparent;color:#8f5b0d;cursor:pointer}.formatter-diagnostics-dismiss:hover{border-color:#d5a553;background:#fff1cd}.editor-actions{display:flex;align-items:center;gap:8px}.editor-actions button{padding:8px 10px;display:inline-flex;align-items:center;gap:6px;border-radius:6px;border:1px solid #ffffff28;color:#fff;background:#ffffff0d;font-size:12px;white-space:nowrap}.editor-actions .compile{background:#f3b943;border-color:#f3b943;color:#193023;font-weight:700}.editor-actions button.active{background:#d9eadf;color:#164c33}.format-action,.comments-action,.version-action{min-width:112px;display:flex;flex-direction:column;align-self:center;gap:2px}.format-action-label,.comments-action-label,.version-action-label{height:12px;display:flex;align-items:center;justify-content:center;gap:4px;padding:0 5px;color:#b9d0c2;font-size:9px;font-weight:750;letter-spacing:.08em;line-height:1;text-transform:uppercase}.format-action-options,.comments-action-options,.version-action-options{height:27px;display:grid;grid-template-columns:1fr 1fr;overflow:hidden;border:1px solid #ffffff35;border-radius:6px;background:#ffffff0d}.editor-actions .format-action button,.editor-actions .comments-action button,.editor-actions .version-action button{min-width:0;height:25px;justify-content:center;border:0;border-radius:0;padding:0 7px;font-size:11px}.editor-actions .format-action button+button,.editor-actions .comments-action button+button,.editor-actions .version-action button+button{border-left:1px solid #ffffff35}.editor-actions .format-action-file{background:#2f7a58;color:#fff}.editor-actions .format-action-selected{background:#326b91;color:#fff}.editor-actions .format-action-file:hover:not(:disabled){background:#3a946c}.editor-actions .format-action-selected:hover:not(:disabled){background:#3d82ae}.editor-actions .comments-action-add{background:#2f7a58;color:#fff}.editor-actions .comments-action-all{background:#5b648e;color:#fff}.editor-actions .comments-action-add:hover:not(:disabled){background:#3a946c}.editor-actions .comments-action-all:hover:not(:disabled){background:#6e79a8}.editor-actions .comments-action-all.active{border-color:transparent;background:#6e79a8;color:#fff}.editor-actions .version-action-history{background:#5b648e;color:#fff}.editor-actions .version-action-git{background:#765493;color:#fff}.editor-actions .version-action-history:hover:not(:disabled){background:#6e79a8}.editor-actions .version-action-git:hover:not(:disabled){background:#8a65ad}.editor-actions .format-action button:disabled,.editor-actions .comments-action button:disabled,.editor-actions .version-action button:disabled{cursor:not-allowed;opacity:.45}.layout-menu{position:relative}.editor-actions .layout-trigger{min-width:138px;justify-content:flex-start;padding-block:5px}.layout-trigger>span{min-width:0;display:flex;flex:1;flex-direction:column;align-items:flex-start;line-height:1.15}.layout-trigger>span small{color:#b9d0c2;font-size:9px;font-weight:500;letter-spacing:.025em;text-transform:uppercase}.layout-trigger.active>span small{color:#52715f}.layout-popover{position:absolute;z-index:100;top:calc(100% + 8px);right:0;width:290px;padding:7px;border:1px solid #d4dcd6;border-radius:9px;background:#fff;color:#25362c;box-shadow:0 14px 38px #061c1138}.layout-popover-title{padding:6px 8px 8px;color:#768178;font-size:10px;font-weight:700;letter-spacing:.055em;text-transform:uppercase}.editor-actions .layout-option{width:100%;min-height:52px;display:grid;grid-template-columns:25px minmax(0,1fr) 18px;gap:9px;padding:8px 9px;border:0;color:#25362c;background:transparent;text-align:left}.editor-actions .layout-option:hover,.editor-actions .layout-option.selected{background:#edf5ef;color:#185d3d}.layout-option>span{min-width:0;display:flex;flex-direction:column;align-items:flex-start;gap:2px}.layout-option strong{font-size:12px}.layout-option small{color:#748078;font-size:10px;line-height:1.35;white-space:normal}.toast{position:fixed;z-index:10;top:66px;left:50%;transform:translate(-50%);background:#8f271f;color:#fff;padding:9px 16px;border-radius:7px;font-size:13px;box-shadow:0 8px 30px #0003}.toast.success{background:#1d6b46}.work-grid{min-height:0;flex:1;background:#fff}.resize-handle{position:relative;width:6px;flex:0 0 6px;display:grid;place-items:center;background:#e4e7e4;color:#98a09a;outline:none;transition:background .12s ease}.resize-handle:hover,.resize-handle[data-resize-handle-active]{background:#89ad98;color:#fff}.resize-handle svg{pointer-events:none}.sync-resize-handle{z-index:20!important;overflow:visible}.sync-direction-buttons{position:absolute;z-index:21;top:50%;left:50%;display:flex;flex-direction:row;gap:2px;padding:3px;transform:translate(-50%,-50%);border:1px solid #aebdb3;border-radius:7px;background:#fff;box-shadow:0 4px 16px #15251b38}.sync-direction-buttons button{width:27px;height:27px;display:grid;place-items:center;border:0;border-radius:4px;padding:0;background:transparent;color:#214d35;font-size:17px;font-weight:750;line-height:1}.sync-direction-buttons button:hover:not(:disabled){background:#deebe2;color:#176b44}.sync-direction-buttons button:disabled{cursor:not-allowed;opacity:.35}.sync-resize-handle .resize-grip{opacity:0}.cm-ySelectionInfo{opacity:1!important;padding:2px 5px!important;border-radius:4px 4px 4px 0;font-family:Inter,ui-sans-serif,system-ui,sans-serif!important;font-size:10px!important;transform:translateY(-2px);box-shadow:0 2px 5px #0002}.left-panel,.context-panel,.source-panel,.preview-panel{min-width:0;min-height:0;border-right:1px solid #dfe2de}.left-panel,.source-panel,.preview-panel,.context-panel{height:100%}.left-panel{display:flex;flex-direction:column;overflow:hidden}.files-panel{position:relative;min-height:180px;flex:3;overflow:auto;border-bottom:1px solid #dfe2de}.files-panel.drop-active{outline:2px solid #2c9564;outline-offset:-2px}.file-drop-overlay{position:absolute;z-index:8;inset:42px 0 0;min-height:130px;display:flex;align-items:center;justify-content:center;flex-direction:column;gap:6px;padding:16px;background:#e8f4edee;color:#185d3c;text-align:center;pointer-events:none;backdrop-filter:blur(2px)}.file-drop-overlay strong{font-size:13px}.file-drop-overlay span{max-width:90%;overflow:hidden;color:#5e7668;font-size:10px;text-overflow:ellipsis;white-space:nowrap}.outline-panel{min-height:150px;flex:2;overflow:auto}.panel-title{height:42px;display:flex;align-items:center;justify-content:space-between;padding:0 12px;border-bottom:1px solid #e6e8e5;color:#647069;text-transform:uppercase;font-size:11px;font-weight:700}.panel-title>span{min-width:0;display:flex;align-items:center;gap:6px}.outline-heading{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.word-count-actions{flex:none;display:flex;align-items:center;gap:2px;margin-left:auto}.panel-title .word-count-actions button{width:auto;height:26px;display:inline-flex;align-items:center;gap:3px;padding:0 5px;color:#52685a;font-size:9px;text-transform:none;white-space:nowrap}.panel-title .word-count-actions button:hover:not(:disabled){background:#e8f1eb;color:#176b44}.panel-title .word-count-actions button:disabled{opacity:.4}.panel-title button{width:28px;height:28px;display:grid;place-items:center;border:0;border-radius:5px;background:transparent;color:#5d6961}.panel-title button:hover{background:#e8eeea;color:#176b44}.panel-title .file-size-toggle{width:auto;min-width:0;display:inline-flex;padding:0 5px;font:inherit;text-transform:inherit;cursor:pointer}.panel-title .file-size-toggle[aria-pressed=true]{color:#176b44;background:#e4f0e8}.file-tools{flex:none;display:flex;align-items:center;gap:4px;margin-left:8px}.file-tools button{box-sizing:border-box}.file-list{padding:6px 7px 10px}.file-entry{min-width:0;height:calc(1em + 18px);min-height:30px;display:flex;align-items:center;border-radius:5px;color:#4f5952}.file-entry:hover{background:#f0f3f0}.file-entry.active,.file-entry.selected{background:#e2efe7;color:#15583a;font-weight:650}.file-entry-main{min-width:0;height:100%;flex:1;overflow:hidden;display:flex;align-items:center;gap:5px;border:0;padding:0 4px;background:transparent;color:inherit;text-align:left;font-size:inherit}.file-entry-main span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-entry-main svg{flex:none;color:#28724e}.file-entry.root-document .file-entry-main>svg{color:#2d6f9f}.file-entry.compile-target{background:#e9f2ec;box-shadow:inset 2px 0 #28724e}.file-entry-main small{flex:none;padding:1px 4px;border-radius:999px;background:#d9eadf;color:#1d5b3e;font-size:8px;line-height:1.35}.file-entry-size{flex:none;margin-right:5px;color:#78837b;font-size:.86em;font-variant-numeric:tabular-nums;white-space:nowrap}.folder-entry .file-entry-main svg:first-child{color:#78837b}.folder-entry .file-entry-main svg:nth-child(2){color:#d49b2d}.root-entry{padding-left:5px}.root-entry .file-entry-main svg{color:#d49b2d}.file-entry-action{width:26px;height:26px;flex:none;display:none;place-items:center;border:0;border-radius:4px;background:transparent;color:#657069}.file-entry:hover .file-entry-action,.file-entry:focus-within .file-entry-action{display:grid}.file-entry-action:hover{background:#dfe7e1;color:#176b44}.resource-download{display:inline-flex;align-items:center;gap:6px;text-decoration:none}.resource-preview-message{min-height:180px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;color:#536158;text-align:center}.resource-preview-message strong{color:#263d2e;font-size:15px}.resource-preview-message span{max-width:440px;color:#748078;font-size:12px}.resource-image-wrap{display:flex;max-height:min(620px,65vh);align-items:center;justify-content:center;overflow:auto;padding:8px;background:#e9ecea;border-radius:7px}.resource-image{display:block;max-width:100%;max-height:min(590px,62vh);object-fit:contain}.resource-pdf{width:100%;height:min(650px,68vh);border:1px solid #d9dfda;border-radius:6px;background:#69706c}.resource-text{max-height:min(650px,68vh);overflow:auto;margin:0;padding:14px;border:1px solid #d9dfda;border-radius:6px;background:#f7f9f7;color:#26352c;font:12px/1.55 ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.source-panel{position:relative;overflow:hidden;display:flex;flex-direction:column;height:100%;min-height:0}.editor-tabs-bar{flex:none;min-height:35px;background:#eaefe9;border-bottom:1px solid #d4ded7;display:flex;align-items:stretch;padding:4px 6px 0;overflow:hidden}.editor-tabs-scroll{display:flex;align-items:stretch;gap:3px;overflow-x:auto;overflow-y:hidden;scrollbar-width:none}.editor-tabs-scroll::-webkit-scrollbar{display:none}.editor-tab-item{display:inline-flex;align-items:center;max-width:220px;border:1px solid #ccd6ce;border-bottom:0;border-radius:6px 6px 0 0;background:#dce4de;color:#55665c}.editor-tab-item:hover{background:#e6eee8;color:#1e3628}.editor-tab-item.active{background:#fff;border-color:#cad7ce;box-shadow:0 -1px 3px #0000000a}.editor-tab{display:inline-flex;align-items:center;gap:5px;min-width:0;flex:1 1 auto;padding:4px 7px 4px 10px;border:0;border-radius:6px 0 0;background:transparent;color:inherit;font:inherit;font-size:12px;text-align:left;cursor:pointer;user-select:none;white-space:nowrap}.editor-tab:hover{color:#1e3628}.editor-tab.active{color:#184f36;font-weight:600}.editor-tab:focus-visible{position:relative;z-index:1;outline:2px solid #4c9a6d;outline-offset:-2px}.editor-tab-icon{display:inline-flex;align-items:center;color:#697a70}.editor-tab.active .editor-tab-icon{color:#184f36}.editor-tab-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.editor-tab-badge{font-size:9px;padding:1px 4px;border-radius:4px;background:#e3eee6;color:#1a6442;font-weight:600;flex-shrink:0}.editor-tab-close{display:inline-flex;align-items:center;justify-content:center;width:22px;height:24px;border:0;border-radius:0 5px 0 0;background:transparent;color:#76887e;padding:0;cursor:pointer;flex-shrink:0}.editor-tab-close:hover{background:#cbd7cf;color:#153123}.editor-tab-item.active .editor-tab-close:hover{background:#e3ece5;color:#184f36}.editor-tab-close:focus-visible{position:relative;z-index:1;outline:2px solid #4c9a6d;outline-offset:-2px}.editor-content-container{position:relative;flex:1 1 auto;min-height:0;height:100%;overflow:hidden}.editor-centered-notice{position:absolute;z-index:8;top:50%;left:50%;max-width:calc(100% - 32px);transform:translate(-50%,-50%);pointer-events:none;border:1px solid #69a780;border-radius:8px;padding:9px 15px;background:#1d6b46ed;color:#fff;font:600 12px/1.4 inherit;text-align:center;box-shadow:0 8px 26px #071d1238}.editor-shell{height:100%;min-height:0;display:flex;flex-direction:column}.editor-shell .editor-host{height:auto;min-height:0;flex:1 1 auto}.editor-host,.cm-editor{height:100%;min-height:0}.editor-host .cm-editor{font-family:inherit;font-size:inherit;line-height:inherit}.editor-host .cm-editor{font-variant-ligatures:contextual;font-feature-settings:"liga" 1,"calt" 1}.editor-host .cm-scroller{min-height:0;height:auto;flex:1 1 auto;overflow:auto;font-family:inherit;line-height:inherit}.editor-host .cm-panels{flex:none}.editor-host .cm-vim-panel{min-height:25px;display:flex;align-items:center;box-sizing:border-box;width:100%;border-top:1px solid #cbd8ce;padding:3px 10px;background:#f1f6f2;color:#31523e;font:11px/1.3 SFMono-Regular,Consolas,monospace}.vim-editor-status{min-height:25px;flex:0 0 25px;display:flex;align-items:center;box-sizing:border-box;border-top:1px solid #cbd8ce;padding:3px 10px;background:#f1f6f2;color:#31523e;font:11px/1.3 SFMono-Regular,Consolas,monospace}.editor-host .cm-content,.editor-host .cm-gutters{font-family:inherit;font-size:inherit}.cm-editor.cm-focused{outline:none}.editor-host .cm-spell-error-active{border-radius:2px;background:#f6d66f;box-shadow:0 0 0 1px #c99324;color:#3f3010;text-decoration:underline wavy #9b6715 1.5px;text-decoration-skip-ink:none}.editor-host .cm-panel.cm-search{padding:8px 38px 8px 10px;border-top:1px solid #ccd5cf;background:#f7f9f7;color:#35443a;box-shadow:0 -3px 10px #1f382710;font-family:Inter,ui-sans-serif,system-ui,sans-serif;font-size:12px;line-height:1.4}.editor-host .cm-panel.cm-search .cm-textfield{min-width:170px;height:29px;margin:2px 6px 2px 0;border:1px solid #bcc8c0;border-radius:5px;padding:4px 8px;background:#fff;color:#202b24;outline:none;font-family:inherit;font-size:12px}.editor-host .cm-panel.cm-search .cm-textfield:focus{border-color:#3d8a60;box-shadow:0 0 0 2px #3d8a6025}.editor-host .cm-panel.cm-search .cm-button{height:29px;margin:2px 5px 2px 0;border:1px solid #bdc8c0;border-radius:5px;padding:3px 9px;background:#fff;background-image:none;color:#31513d;font-family:inherit;font-size:12px;text-transform:none}.editor-host .cm-panel.cm-search .cm-button:hover{border-color:#7c9f89;background:#e9f1ec}.editor-host .cm-panel.cm-search label{display:inline-flex;align-items:center;gap:3px;margin:3px 9px 3px 0;color:#59665d;font-family:inherit;font-size:12px}.editor-host .cm-panel.cm-search input[type=checkbox]{accent-color:#176b44}.editor-host .cm-panel.cm-search [name=close]{top:8px;right:10px;width:25px;height:25px;border-radius:5px;color:#647069;font-size:19px;line-height:1}.editor-host .cm-panel.cm-search [name=close]:hover{background:#e3e9e5;color:#244d36}.editor-host .cm-search-count{display:inline-flex;align-items:center;min-height:29px;margin:2px 5px 2px 4px;color:#506057;font-size:12px;font-variant-numeric:tabular-nums;white-space:nowrap}.editor-host .cm-searchMatch{background:#f5d76e99;outline:1px solid #d9a91c88}.editor-host .cm-searchMatch.cm-searchMatch-selected{background:#f0a94a99;outline-color:#cc7720}.editor-host .cm-spell-error{text-decoration:underline wavy #c53b32 1.5px;text-decoration-skip-ink:none;text-decoration-thickness:1.5px}.editor-host .cm-grammar-warning{text-decoration:underline wavy #d19a26 1.5px;text-decoration-skip-ink:none;text-decoration-thickness:1.5px}.spell-suggestions-menu{position:fixed;z-index:1200;display:flex;min-width:190px;max-width:250px;flex-direction:column;gap:3px;padding:7px;border:1px solid #b9c8bd;border-radius:7px;background:#fff;box-shadow:0 10px 28px #1930222e;color:#26352c;font-size:12px}.spell-suggestions-title{padding:3px 6px 5px;color:#607067;font-size:10px;font-weight:700;letter-spacing:.02em;text-transform:uppercase}.spell-suggestions-message{padding:3px 6px 6px;border-bottom:1px solid #e2e8e3;color:#58685e;font-size:11px;line-height:1.4}.spell-suggestions-menu button{min-height:29px;border:1px solid transparent;border-radius:5px;padding:4px 8px;background:transparent;color:#214f37;font:inherit;text-align:left;cursor:pointer}.spell-suggestions-menu button:hover:not(:disabled),.spell-suggestions-menu button:focus-visible:not(:disabled){border-color:#a9c9b3;background:#edf6ef;outline:none}.spell-suggestions-menu button:disabled{color:#78847d;cursor:not-allowed;opacity:.7}.spell-suggestions-empty,.spell-suggestions-readonly{display:block;padding:4px 6px;color:#78847d;font-size:10px;line-height:1.35}.spell-suggestions-readonly{border-top:1px solid #e2e8e3;margin-top:3px;padding-top:7px}.cm-source-comment{background:#ffe49b99;border-bottom:2px solid #d68b00;cursor:text}.cm-source-comment-resolved{background:#dce5de99;border-bottom-color:#829087}.cm-comment-pin{color:#d68b00;font-size:9px;padding:0 2px;cursor:pointer}.preview-panel{display:flex;flex-direction:column;background:#6f7471}.preview-tabs{min-height:48px;flex:none;display:flex;align-items:stretch;padding:5px 6px 0;background:#4d544f}.preview-tab-list{min-width:0;flex:1;display:grid;grid-template-columns:minmax(0,1.8fr) minmax(120px,1fr);gap:3px}.preview-tabs button{min-width:0;display:flex;align-items:center;justify-content:center;gap:5px;border:0;border-radius:6px 6px 0 0;background:transparent;color:#d7dcd8;font-size:11px}.preview-tabs button.active{background:#f3f4f1;color:#184f36;font-weight:700}.preview-tabs button span{min-width:17px;padding:1px 4px;border-radius:999px;background:#ffffff20;font-size:9px}.preview-tabs button.active span{background:#dfe8e2}.preview-tabs .pdf-tab{justify-content:flex-start;padding:0 12px;font-size:12px}.preview-tabs button .pdf-tab-label{min-width:0;overflow:hidden;padding:0;border-radius:0;background:transparent;display:flex;flex-direction:column;align-items:flex-start;gap:2px;font-size:12px;line-height:1;text-overflow:ellipsis;white-space:nowrap}.preview-tabs button.active .pdf-tab-label{background:transparent}.preview-tabs .pdf-tab small{max-width:100%;overflow:hidden;color:#bcc4bf;font-size:8px;font-weight:400;line-height:1;text-overflow:ellipsis;white-space:nowrap}.preview-tabs .pdf-tab.active small{color:#65756c}.pdf-download-top{flex:none;display:inline-flex;align-items:center;gap:5px;margin-left:4px;padding:0 11px;border:0;border-radius:6px 6px 0 0;color:#d7dcd8;font-size:10px;text-decoration:none;white-space:nowrap}.pdf-download-top:hover{background:#ffffff1b;color:#fff}.preview-subtabs{height:36px;flex:none;display:flex;align-items:center;gap:3px;padding:4px 7px;border-bottom:1px solid #cfd6d1;background:#e4e9e5}.preview-subtabs button{display:inline-flex;align-items:center;gap:5px;height:28px;padding:0 10px;border:0;border-radius:5px;background:transparent;color:#58665d;font-size:10px}.preview-subtabs button:hover{background:#d8e3db;color:#205c40}.preview-subtabs button.active{background:#fff;color:#184f36;font-weight:700;box-shadow:0 1px 3px #26312b22}.preview-subtabs button span{min-width:16px;padding:1px 4px;border-radius:999px;background:#d5ded7;font-size:9px;text-align:center}.preview-subtabs button.active span{background:#dfe8e2}.preview-content{min-height:0;flex:1}.preview-pdf{overflow:hidden}.pdf-viewer{position:relative;width:100%;height:100%;min-height:0;display:flex;flex-direction:column}.pdf-toolbar{height:36px;flex:none;display:flex;align-items:center;justify-content:flex-end;gap:3px;padding:4px 8px;border-bottom:1px solid #343a36;background:#414843;color:#e4e8e5;font:11px/1 Inter,ui-sans-serif,system-ui,sans-serif}.pdf-toolbar button{height:27px;min-width:27px;display:inline-flex;align-items:center;justify-content:center;gap:5px;border:1px solid #ffffff24;border-radius:5px;padding:0 6px;background:#ffffff0b;color:inherit}.pdf-toolbar button:hover:not(:disabled){border-color:#ffffff48;background:#ffffff1b}.pdf-toolbar button:disabled{opacity:.3}.pdf-zoom-value{min-width:42px;text-align:center;font-variant-numeric:tabular-nums}.pdf-toolbar .pdf-fit-width{margin-left:3px;padding:0 8px}.pdf-compiling-overlay{position:absolute;z-index:4;inset:36px 0 0;display:flex;align-items:flex-start;justify-content:center;gap:8px;padding-top:24px;background:#26312bb8;color:#fff;font-size:13px;pointer-events:none}.pdf-compiling-overlay span{padding:3px 8px;border-radius:5px;background:#17231cdd}.pdf-loading-state{width:100%;height:100%;min-height:220px;display:grid;place-items:center;align-content:center;gap:10px;background:#6f7471;color:#eef2ef;font-size:12px}.pdf-document{position:relative;width:100%;min-width:0;min-height:0;flex:1;overflow-x:scroll;overflow-y:auto;overscroll-behavior:contain;scrollbar-color:#aeb8b1 #4f5652;scrollbar-width:auto;scrollbar-gutter:stable;padding:14px 14px 20px;background:#6f7471}.pdf-document::-webkit-scrollbar{width:12px;height:12px}.pdf-document::-webkit-scrollbar-track{background:#4f5652}.pdf-document::-webkit-scrollbar-thumb{min-width:38px;border:2px solid #4f5652;border-radius:999px;background:#aeb8b1}.pdf-document::-webkit-scrollbar-thumb:hover{background:#d5dcd7}.pdf-document::-webkit-scrollbar-corner{background:#4f5652}.pdf-pages{min-width:100%}.pdf-loading{min-height:220px;display:grid;place-items:center;align-content:center;gap:10px;color:#eef2ef;font-size:12px}.pdf-page{position:relative;flex:none;max-width:none;overflow:hidden;margin:0 auto 16px;background:#fff;box-shadow:0 3px 14px #0004}.pdf-page.loading{background:#f7f8f7}.pdf-page canvas{display:block;width:100%!important;max-width:100%;height:auto!important}.pdf-annotation-layer{position:absolute;inset:0;z-index:3;pointer-events:none}.pdf-annotation-link{position:absolute;display:block;pointer-events:auto;border-radius:2px;background:transparent;cursor:pointer}.pdf-annotation-link:hover{background:#3f9b6426;box-shadow:inset 0 0 0 1px #3f9b6440}.pdf-page figcaption{position:absolute;right:7px;bottom:5px;padding:2px 5px;border-radius:4px;background:#26312bb5;color:#fff;font-size:9px;pointer-events:none}.pdf-sync-marker{position:absolute;z-index:2;width:14px;height:14px;border:3px solid #ef9c24;border-radius:50%;transform:translate(-50%,-50%);background:#ffe0a580;box-shadow:0 0 0 4px #ef9c2435;pointer-events:none;animation:sync-pulse 1.2s ease-out}@keyframes sync-pulse{0%{box-shadow:0 0 0 14px #ef9c2460}to{box-shadow:0 0 0 4px #ef9c2435}}.preview-empty{height:100%;display:grid;place-content:center;gap:8px;color:#e7e9e7;text-align:center}.preview-empty span{font-size:12px;color:#c2c7c4}.preview-log,.preview-warnings,.preview-errors{overflow:auto;background:#202522}.preview-clean{overflow:auto;background:#f4f6f4}.preview-artifacts{overflow:hidden;background:#f4f6f4}.artifact-browser{width:100%;height:100%;min-height:0;display:grid;grid-template-columns:minmax(135px,38%) minmax(0,1fr)}.artifact-list{min-width:0;overflow:auto;border-right:1px solid #d9dedb;background:#fff}.artifact-row{min-width:0;display:flex;align-items:stretch;border-bottom:1px solid #edf0ee}.artifact-row.active{background:#e5f0e9}.artifact-row>button{min-width:0;flex:1;display:flex;align-items:center;gap:7px;padding:8px 6px 8px 9px;border:0;background:transparent;color:#33463b;text-align:left}.artifact-row>button:disabled{cursor:default;opacity:.7}.artifact-row>button>span{min-width:0;display:flex;flex-direction:column;gap:2px}.artifact-row strong{overflow:hidden;font-size:11px;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.artifact-row small{color:#89928c;font-size:9px}.artifact-row>a{width:30px;flex:none;display:grid;place-items:center;color:#52705f}.artifact-row>a:hover{background:#dce8e0;color:#176641}.artifact-preview{min-width:0;min-height:0;display:flex;flex-direction:column;background:#202522;color:#dbe2dd}.artifact-preview>header{height:36px;flex:none;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:0 10px;border-bottom:1px solid #39413c;background:#303732;font-size:11px}.artifact-preview>header strong{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.artifact-preview>header a{flex:none;display:inline-flex;align-items:center;gap:4px;color:#c9ddd1}.artifact-preview>pre{min-height:0;flex:1;margin:0;overflow:auto;padding:13px;white-space:pre-wrap;overflow-wrap:anywhere;font:11px/1.55 SFMono-Regular,Consolas,monospace}.compile-output{min-height:100%;margin:0;padding:16px;color:#dbe2dd;white-space:pre-wrap;overflow-wrap:anywhere;font:11px/1.55 SFMono-Regular,Consolas,monospace}.compile-output.compile-warning{color:#ffdfa0;background:#2d281c}.compile-output.compile-error{color:#ffc2bd;background:#301e1d}.compile-empty{height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:9px;color:#bfc7c1;font-size:12px}.compile-empty.compile-warning{color:#e8c46d;background:#2d281c}.compile-empty.compile-error{color:#e99b94;background:#301e1d}.compile-clean-panel{max-width:820px;margin:0 auto;padding:24px;color:#30453a}.compile-clean-intro{display:flex;align-items:flex-start;gap:12px;padding:15px;border:1px solid #e3d1a7;border-radius:9px;background:#fffaf0;color:#80631f;box-shadow:0 3px 12px #5c48100d}.compile-clean-intro>div{min-width:0}.compile-clean-intro strong{display:block;font-size:14px}.compile-clean-intro p,.compile-clean-actions p{margin:5px 0 0;color:#718078;font-size:11px;line-height:1.5}.compile-clean-actions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin-top:14px}.compile-clean-actions article{display:grid;grid-template-columns:34px minmax(0,1fr);gap:10px;min-width:0;padding:14px;border:1px solid #d4dfd7;border-radius:8px;background:#fff}.compile-clean-actions article.danger{border-color:#e3c9c5}.compile-clean-action-icon{display:grid;place-items:center;width:32px;height:32px;border-radius:7px;background:#e7f2ea;color:#28714a}.compile-clean-actions article.danger .compile-clean-action-icon{background:#f8e8e6;color:#a6433a}.compile-clean-actions strong{color:#2d4638;font-size:12px}.compile-clean-actions article.danger strong{color:#874039}.compile-clean-actions button{display:inline-flex;align-items:center;gap:5px;margin-top:12px;padding:6px 10px;border:1px solid #b8d1bd;border-radius:5px;background:#f0f8f1;color:#21633d;font-size:11px}.compile-clean-actions button:hover:not(:disabled){border-color:#79aa86;background:#e3f2e6}.compile-clean-actions button.danger{border-color:#e2b9b4;background:#fff4f2;color:#a23d35}.compile-clean-actions button.danger:hover:not(:disabled){border-color:#c8837a;background:#fce7e4}.compile-clean-actions button:disabled{cursor:not-allowed;opacity:.45}.compile-diagnostic-list{min-height:100%;padding:8px;background:#202522;overflow:auto}.compile-diagnostic-list.compile-warning{background:#2d281c}.compile-diagnostic-list.compile-error{background:#301e1d}.compile-diagnostic-row{display:grid;grid-template-columns:20px minmax(0,1fr);gap:7px;width:100%;padding:9px 10px;border:0;border-bottom:1px solid #ffffff12;border-radius:4px;background:transparent;color:#eef2ef;text-align:left}.compile-diagnostic-row:not(:disabled):hover{background:#ffffff10;box-shadow:inset 2px 0 #63b889}.compile-diagnostic-row:disabled{opacity:.78;cursor:default}.compile-diagnostic-row>span{min-width:0;display:grid;gap:4px}.compile-diagnostic-row strong{font-size:11px;font-weight:500;white-space:normal}.compile-diagnostic-row small{color:#aeb8b1;font:10px/1.4 SFMono-Regular,Consolas,monospace;overflow-wrap:anywhere}.compile-warning .compile-diagnostic-row>svg{color:#e8c46d}.compile-error .compile-diagnostic-row>svg{color:#e99b94}.context-panel{border-right:0;overflow:auto}.drawer-title{position:sticky;top:0;z-index:2;height:42px;display:flex;align-items:center;justify-content:space-between;padding:0 12px;border-bottom:1px solid #e3e6e3;background:#fff;font-size:13px}.drawer-title button{width:28px;height:28px;display:grid;place-items:center;border:0;border-radius:5px;background:transparent;color:#737a75}.drawer-title button:hover{background:#edf1ee}.tabs{height:42px;display:flex;border-bottom:1px solid #e3e6e3}.tabs button{flex:1;border:0;background:#fff;color:#707872;font-size:12px}.tabs button.active{color:#176b44;border-bottom:2px solid #176b44;font-weight:700}.outline{padding:10px 8px}.outline-item{width:100%;min-width:0;display:flex;align-items:stretch;border:0;padding:6px 0;background:transparent;font-size:12px;text-align:left}.outline-item:hover,.outline-item:focus-visible{background:#edf3ef;color:#176b44;outline:none}.outline-item.current{background:#e2efe7;color:#176b44;font-weight:700}.outline-guides{flex:none;background:repeating-linear-gradient(to right,#dfe5e0 0,#dfe5e0 1px,transparent 1px,transparent 12px)}.outline small{flex:none;min-width:22px;margin-left:8px;color:#a1a7a2}.outline-title{min-width:0;overflow:hidden;color:#3f4942;text-overflow:ellipsis;white-space:nowrap}.padded{padding:14px}.comments{padding:9px}.comments article{margin-bottom:9px;padding:10px;border:1px solid #dde2de;border-radius:7px;font-size:12px;cursor:pointer;user-select:text;-webkit-user-select:text}.comments article.resolved{opacity:.55;background:#f3f5f3}.comments article.orphaned{border-color:#d8847d;background:#fff4f2}.comments header{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}.comments header small{color:#858b87}.comments time{flex:none;color:#8b928d;font-size:9px;white-space:nowrap}.comment-times{flex:none;display:flex;align-items:flex-end;flex-direction:column;gap:2px}.comment-times small{font-size:8px;white-space:nowrap}.comment-author{min-width:0;display:flex;flex-direction:column;gap:1px}.comment-author strong,.comment-author small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.comment-location{margin-top:5px;color:#768079;font-size:10px}.comments blockquote{margin:8px 0;padding:6px 8px;border-left:2px solid #85ad96;background:#f2f6f3;color:#657069;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.comments p{white-space:pre-wrap;user-select:text;-webkit-user-select:text;cursor:text}.comments blockquote,.comments .comment-content{user-select:text;-webkit-user-select:text;cursor:text}.comments .resolve{display:inline-flex;align-items:center;gap:4px;border:0;background:transparent;color:#176b44;padding:0;font-size:11px}.comment-replies{display:flex;flex-direction:column;gap:7px;margin:10px 0 8px;padding-left:9px;border-left:2px solid #d6dfd9}.comment-reply{position:relative;padding:7px 8px;border-radius:6px;background:#f5f7f5}.comment-reply p{margin:7px 0 1px}.comment-actions{display:flex;align-items:center;gap:12px}.comments .reply-action{display:inline-flex;align-items:center;gap:4px;border:0;padding:0;background:transparent;color:#526c5d;font-size:11px}.comment-owner-actions{display:inline-flex;align-items:center;gap:2px;margin-left:auto}.comment-reply>.comment-owner-actions{position:absolute;right:5px;bottom:4px}.comments .comment-owner-actions button{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:0;border-radius:5px;background:transparent;color:#66716a}.comments .comment-owner-actions button:hover{background:#e2e8e3;color:#244c35}.comments .comment-owner-actions button.danger-text:hover{background:#f8e4e2;color:#a7312a}.comment-reply-form{display:flex;flex-direction:column;gap:7px;margin-top:9px}.comment-edit-form{margin:7px 0}.comment-reply-form textarea{width:100%;resize:vertical;border:1px solid #cbd2cc;border-radius:6px;padding:7px 8px;outline:none;font-size:11px}.comment-reply-form textarea:focus{border-color:#176b44;box-shadow:0 0 0 2px #176b4420}.comment-reply-form>div{display:flex;justify-content:flex-end;gap:5px}.comment-reply-form button{display:inline-flex;align-items:center;gap:4px;border:1px solid #cbd2cc;border-radius:5px;padding:5px 7px;background:#fff;font-size:10px}.comment-reply-form button.primary{border-color:#176b44;background:#176b44;color:#fff}.settings{display:flex;flex-direction:column;gap:14px}.settings>section{display:flex;flex-direction:column;gap:14px}.settings button{border:1px solid #c9d0ca;background:#fff;border-radius:6px;padding:7px 9px;font-size:12px}.settings-tabs{display:flex;gap:4px;padding:3px;border:1px solid #d7ded8;border-radius:9px;background:#f4f7f4}.settings-tab{display:inline-flex;flex:1;align-items:center;justify-content:center;gap:6px;min-height:34px;border:1px solid transparent!important;border-radius:7px!important;background:transparent!important;color:#66716a;font-weight:650}.settings-tab:hover{background:#eaf1eb!important;color:#31523e}.settings-tab.active{border-color:#c8d9cb!important;background:#fff!important;color:#176b44;box-shadow:0 1px 2px #233c2a12}.settings-tab:focus-visible{outline:2px solid #176b44;outline-offset:1px}.settings-actions{display:flex;width:100%;justify-content:flex-end;padding-top:2px}.settings-section-title{display:flex;align-items:center;gap:7px;color:#31523e;font-size:13px}.settings-description{margin:0;color:#7b837e;font-size:11px;line-height:1.45}.browser-tool-statuses{display:flex;flex-wrap:wrap;gap:7px}.browser-tool-status{min-width:116px;flex:1;display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:6px;padding:8px 9px;border:1px solid #d9ded9;border-radius:7px;background:#f7f9f7;color:#6d776f;font-size:10px}.browser-tool-status strong{min-width:0;overflow:hidden;color:#344d3c;font-size:11px;text-overflow:ellipsis;white-space:nowrap}.browser-tool-status span{font-weight:700;white-space:nowrap}.browser-tool-status.loading{border-color:#e4d7ad;background:#fffaf0;color:#9a6b18}.browser-tool-status.working{border-color:#bddbc7;background:#f0f8f2;color:#187348}.browser-tool-status.error{border-color:#e7beb9;background:#fff3f1;color:#a3342c}.tex-fmt-options-heading{width:100%;display:flex;align-items:center;justify-content:space-between;gap:8px}.tex-fmt-options-heading>span:first-child{min-width:0}.browser-tool-status.compact{min-width:0;flex:none;display:inline-flex;align-items:center;gap:4px;padding:3px 6px;border-radius:999px;font-size:10px;line-height:1;white-space:nowrap}.browser-tool-status.compact span{font-size:10px}.browser-tool-status.compact .browser-tool-reload{grid-column:auto;display:grid;place-items:center;width:18px;height:18px;min-height:18px;margin:-1px -3px -1px 0;padding:0;border:0;border-radius:50%;background:transparent;color:inherit}.browser-tool-status.compact .browser-tool-reload:hover{background:#0000000d}.browser-tool-reload{grid-column:1 / -1;display:inline-flex;align-items:center;justify-content:center;gap:5px;width:100%;min-height:26px;margin-top:2px;border:1px solid #dca9a3;border-radius:5px;background:#fff;color:#922d27;font-size:10px;font-weight:700}.browser-tool-reload:hover{border-color:#bf7770;background:#fff8f7}.settings .editor-preference{display:flex;flex-direction:column;gap:4px}.settings .editor-preference .field-hint{margin:0 9px;line-height:1.4}.settings .editor-checkbox{flex-direction:row;align-items:center;gap:7px;padding:8px 9px;border:1px solid #d9ded9;border-radius:7px;font-weight:500}.settings .editor-checkbox input{width:auto;margin:0;accent-color:#176b44}.spell-check-result{display:inline-flex;align-items:center;gap:6px;color:#66716a;font-size:11px}.spell-check-result.has-issues{color:#a3342c;font-weight:650}.spell-check-controls{display:inline-flex;align-items:center;gap:2px;margin-left:3px;color:#6f4a45;font-weight:500}.spell-check-controls button{width:24px;height:24px;display:inline-grid;place-items:center;border:1px solid #d7b8b4;border-radius:4px;padding:0;background:#fff8f7;color:#8e4a42}.spell-check-controls button:hover:not(:disabled){border-color:#b98279;background:#fce9e6}.spell-check-controls button:disabled{cursor:not-allowed;opacity:.35}.spell-check-position{min-width:34px;text-align:center;color:#825850;font-variant-numeric:tabular-nums;white-space:nowrap}.password-generator{display:flex;align-items:stretch;gap:7px}.password-generator input{min-width:0;flex:1;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace}.password-generator button{flex:none;display:inline-flex;align-items:center;justify-content:center;gap:5px;padding:0 10px;border:1px solid #c9d0ca;border-radius:6px;background:#f6f8f6;color:#31523e;font-size:11px;white-space:nowrap}.password-generator button:hover{border-color:#8eaa98;background:#edf3ef}.settings-save{width:100%;display:inline-flex;align-items:center;justify-content:center;gap:6px}.latexmkrc-editor,.tex-fmt-options-editor{resize:vertical;font:12px/1.5 SFMono-Regular,Consolas,monospace!important}.tex-fmt-options-editor{min-height:100px}.dictionary-add{display:flex;align-items:stretch;gap:7px}.dictionary-add input{min-width:0;flex:1}.dictionary-add button{flex:none;color:#176b44}.dictionary-words{display:flex;flex-wrap:wrap;gap:6px}.dictionary-word{display:inline-flex;align-items:center;gap:3px;min-height:27px;padding:3px 5px 3px 8px;border:1px solid #d5ded7;border-radius:999px;background:#f1f6f2;color:#31523e;font-size:11px}.dictionary-word code{font:11px/1.2 SFMono-Regular,Consolas,monospace}.dictionary-word button{width:20px;height:20px;display:grid;place-items:center;padding:0;border:0;background:transparent;color:#748078}.dictionary-word button:hover{color:#a7312a}.dictionary-empty{color:#7b837e;font-size:11px}.dictionary-error{margin:-6px 0 0;font-size:11px}.share-dialog{display:flex;flex-direction:column;gap:16px}.share-owner{display:flex;align-items:center;gap:10px;padding:11px 13px;border-radius:8px;background:#edf4ef;color:#18583a}.share-owner>span{display:flex;flex-direction:column;gap:2px}.share-owner small{color:#6f7d74;font-size:10px;text-transform:uppercase}.share-add{display:grid;grid-template-columns:minmax(0,1fr) 150px auto;align-items:end;gap:9px;padding-bottom:16px;border-bottom:1px solid #e4e7e4}.share-add .icon-button{height:39px;display:inline-flex;align-items:center;gap:6px;padding:0 13px;font-size:12px}.shared-members-heading{display:flex;align-items:center;justify-content:space-between;color:#48524b;font-size:13px}.shared-members-heading span{min-width:22px;padding:2px 6px;border-radius:999px;background:#e8ece9;color:#6a746d;font-size:10px;text-align:center}.shared-members{display:flex;flex-direction:column;gap:7px}.shared-member{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:10px;border:1px solid #dfe3df;border-radius:8px}.member-identity{min-width:0;display:flex;align-items:center;gap:9px}.member-identity>span:last-child{min-width:0;display:flex;flex-direction:column}.member-identity strong,.member-identity small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.member-identity small{color:#7c857e;font-size:10px}.member-avatar{width:30px;height:30px;flex:none;display:grid;place-items:center;border-radius:50%;background:#dfece4;color:#176b44;font-size:12px;font-weight:750}.member-controls{display:flex;align-items:center;gap:5px}.member-controls select{border:1px solid #cbd2cc;border-radius:6px;padding:6px 8px;background:#fff;font-size:11px}.icon-only{width:31px;height:31px;display:grid;place-items:center;border:0;border-radius:6px;background:transparent}.icon-only:hover{background:#f8e9e7}.share-empty{min-height:90px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:7px;color:#89928c;font-size:12px}.spin{animation:spin .8s linear infinite}.dialog-overlay{position:fixed;z-index:100;inset:0;background:#101b152e;animation:fade-in .12s ease-out}.dialog-content{position:fixed;z-index:101;top:50%;left:50%;width:min(460px,calc(100vw - 32px));max-height:min(760px,calc(100vh - 40px));overflow:auto;transform:translate(-50%,-50%);background:#fff;border-radius:12px;box-shadow:0 25px 80px #0004;animation:dialog-in .15s ease-out}.dialog-wide{width:min(660px,calc(100vw - 32px))}.dialog-extra-wide{width:min(900px,calc(100vw - 32px))}.dialog-header{display:flex;align-items:flex-start;justify-content:space-between;padding:20px 22px 14px;border-bottom:1px solid #e5e8e5}.dialog-header h2{margin:0;font-size:19px}.dialog-header p{margin:6px 0 0;color:#737a75;font-size:12px;line-height:1.5}.dialog-close{border:0;background:transparent;color:#6d746f;font-size:22px}.dialog-body{padding:20px 22px}.dialog-body .warning{display:flex;align-items:flex-start;gap:8px;margin:0;padding:10px 11px;border:1px solid #e4cf91;border-radius:7px;background:#fff8df;color:#735a18;font-size:11px;line-height:1.5}.dialog-body .warning svg{flex:none;margin-top:1px}.word-count-source{margin:0 0 15px;color:#68766d;font-size:11px}.word-count-source code{color:#315b43;font:11px/1.4 SFMono-Regular,Consolas,monospace}.word-count-source a{margin-left:8px;color:#176b44;font-size:10px}.word-count-template-note{margin:-6px 0 15px;color:#7b7566;font-size:10px;line-height:1.45}.word-count-loading{min-height:150px;display:flex;align-items:center;justify-content:center;gap:9px;color:#52685a;font-size:12px}.word-count-result{display:grid;gap:16px}.word-count-totals{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.word-count-total{display:flex;align-items:baseline;gap:8px;padding:15px 16px;border:1px solid #cfe0d3;border-radius:9px;background:#edf6ef;color:#1e5f3d}.word-count-total svg{align-self:center}.word-count-total strong{font-size:28px;line-height:1;letter-spacing:-.03em}.word-count-total span{color:#52705d;font-size:11px}.word-count-total small{display:block;margin-top:2px;color:#75847a;font-size:9px;font-weight:400;line-height:1.25}.word-count-characters{border-color:#d8ddea;background:#f1f3f9;color:#405989}.word-count-characters span{color:#617092}.word-count-breakdown{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px 16px;margin:0}.word-count-breakdown div{display:flex;align-items:baseline;justify-content:space-between;gap:8px;padding-bottom:6px;border-bottom:1px solid #edf0ed}.word-count-breakdown dt{color:#68766d;font-size:11px}.word-count-breakdown dd{display:inline-flex;align-items:baseline;gap:3px;margin:0;color:#2f4938;font-size:12px;font-variant-numeric:tabular-nums;font-weight:650}.word-count-breakdown dd small{color:#77847c;font-size:9px;font-weight:500}.word-count-warning{margin:0}.system-metrics{display:grid;gap:20px}.metric-summary-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.metric-card{min-width:0;padding:14px 16px;border:1px solid #dfe4df;border-radius:10px;background:#f7f8f6;display:grid;gap:4px}.metric-card>span,.metric-card small{color:var(--muted);font-size:12px}.metric-card strong{font-size:20px;font-weight:650}.metric-section{display:grid;gap:10px}.metric-section h3{margin:0;display:flex;align-items:center;gap:7px;font-size:14px}.metric-section p{margin:0;font-size:13px}.metric-table-wrap{overflow-x:auto;border:1px solid #dfe4df;border-radius:9px}.metric-table{width:100%;border-collapse:collapse;font-size:12px;white-space:nowrap}.metric-table th,.metric-table td{padding:8px 10px;border-bottom:1px solid #e4e8e4;text-align:right}.metric-table th:first-child,.metric-table td:first-child{text-align:left}.metric-table tbody tr:last-child td{border-bottom:0}@media(max-width:640px){.metric-summary-grid{grid-template-columns:1fr}}.dialog-footer{display:flex;justify-content:flex-end;gap:8px;padding:14px 22px;border-top:1px solid #e5e8e5;background:#f8f9f7}.dialog-footer button{border:1px solid #cbd2cc;border-radius:7px;padding:8px 14px;background:#fff}.dialog-footer .primary{display:inline-flex;align-items:center;justify-content:center;gap:6px;border-color:#176b44;background:#176b44;color:#fff}.dialog-footer .danger,button.danger{border-color:#b3261e;background:#b3261e;color:#fff}.citation-library-dialog{display:flex;flex-direction:column;gap:12px}.citation-library-tabs{display:flex;gap:4px;padding:3px;border:1px solid #d7ded8;border-radius:9px;background:#f4f7f4}.citation-library-tabs button{display:inline-flex;flex:1;align-items:center;justify-content:center;gap:6px;min-height:34px;border:1px solid transparent;border-radius:7px;background:transparent;color:#66716a;font-size:12px}.citation-library-tabs button:hover{background:#eaf1eb;color:#31523e}.citation-library-tabs button.active{border-color:#c8d9cb;background:#fff;color:#176b44;box-shadow:0 1px 2px #233c2a12}.citation-library-tabs button span{min-width:18px;padding:1px 5px;border-radius:999px;background:#e7eee8;font-size:10px}.citation-library-search{display:flex;align-items:center;gap:8px;padding:0 10px;border:1px solid #ccd6ce;border-radius:7px;background:#fff;color:#68766d}.citation-library-search-row{display:flex;align-items:stretch;gap:8px}.citation-library-search-row .citation-library-search{min-width:0;flex:1}.citation-add-entry-button{display:inline-flex;align-items:center;gap:5px;flex:none;border:1px solid #176b44;border-radius:7px;padding:0 11px;background:#176b44;color:#fff;font-size:11px}.citation-add-entry-button:hover{background:#125937}.citation-library-search input{min-width:0;flex:1;border:0;padding:9px 0;outline:0;font-size:12px}.citation-library-search span{flex:none;color:#8a958d;font-size:10px}.citation-tag-bar{display:flex;flex-wrap:wrap;align-items:center;gap:8px}.citation-tag-filters{min-width:0;display:flex;flex:1;flex-wrap:wrap;gap:5px}.citation-tag-filters button{display:inline-flex;align-items:center;gap:5px;border:1px solid transparent;border-radius:999px;padding:5px 8px;background:#f1f4f1;color:#5f6e64;font-size:10px}.citation-tag-filters button:hover{background:#e6eee8}.citation-tag-filters button.active{border-color:#9cbea6;background:#e8f2eb;color:#176b44}.citation-tag-create{display:flex;flex:none;gap:5px}.citation-tag-create input,.citation-tag-create select{min-width:0;border:1px solid #cbd4cd;border-radius:6px;padding:6px 7px;background:#fff;font-size:10px}.citation-tag-create input{width:120px}.citation-tag-create select{width:76px}.citation-tag-create button{display:inline-flex;align-items:center;gap:4px;border:1px solid #bdc9c0;border-radius:6px;padding:6px 8px;background:#fff;color:#31523e;font-size:10px;white-space:nowrap}.citation-tag-create button:hover:not(:disabled){border-color:#8eaa98;background:#edf4ef}.citation-entry-list{display:flex;flex-direction:column;gap:8px;max-height:46vh;overflow:auto;padding:1px}.citation-entry-item{display:flex;flex-direction:column;gap:6px}.citation-entry-card{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:10px 11px;border:1px solid #dce3de;border-radius:8px;background:#fbfcfb}.citation-entry-card.already-in-file{border-color:#d7ddd8;background:#f0f2f0;filter:grayscale(.35)}.citation-entry-card.already-in-file .citation-entry-heading code,.citation-entry-card.already-in-file .citation-entry-main>strong,.citation-entry-card.already-in-file .citation-entry-main>p{color:#7c867f}.citation-entry-card.selected{position:relative;z-index:1;border-color:#70a982;background:#f0f8f2;box-shadow:0 0 0 2px #2f7a5824,0 6px 16px #244c3520}.citation-entry-card.selected .citation-entry-heading code{color:#0f633d}.citation-entry-main{min-width:0;display:flex;flex:1;flex-direction:column;gap:3px}.citation-entry-heading{display:flex;align-items:center;flex-wrap:wrap;gap:6px}.citation-entry-heading code{color:#176b44;font:650 11px/1.3 SFMono-Regular,Consolas,monospace}.citation-entry-heading>span{color:#859189;font-size:10px}.citation-entry-heading>.citation-entry-venue{max-width:22rem;overflow:hidden;border-radius:999px;padding:2px 6px;background:#edf0ff;color:#4b5ca8;font-size:9px;font-style:italic;font-synthesis:style;text-overflow:ellipsis;white-space:nowrap}.citation-entry-heading em{display:inline-flex;align-items:center;gap:3px;border-radius:999px;padding:2px 6px;background:#e8f2eb;color:#26704a;font-size:9px;font-style:normal}.citation-entry-heading em.private{background:#edf0ee;color:#69756d}.citation-entry-main>strong{overflow:hidden;color:#2b3b31;font-size:12px;text-overflow:ellipsis;white-space:nowrap}.citation-entry-main>p{margin:0;overflow:hidden;color:#718078;font-size:10px;text-overflow:ellipsis;white-space:nowrap}.citation-entry-tags{display:flex;flex-wrap:wrap;gap:4px;margin-top:3px}.citation-tag-pill{display:inline-flex;align-items:center;gap:4px;border:1px solid color-mix(in srgb,var(--tag-color) 35%,transparent);border-radius:999px;padding:2px 6px;background:color-mix(in srgb,var(--tag-color) 12%,white);color:#526158;font-size:9px}.citation-tag-dot{width:7px;height:7px;flex:none;display:inline-block;border-radius:50%;background:var(--tag-color)}.citation-tag-filters .citation-tag-dot{background:var(--tag-color)}.citation-entry-actions{display:flex;flex:none;flex-wrap:wrap;justify-content:flex-end;gap:5px}.citation-entry-actions button{display:inline-flex;align-items:center;gap:4px;border:1px solid #cbd5ce;border-radius:6px;padding:6px 8px;background:#fff;color:#52685a;font-size:10px;white-space:nowrap}.citation-entry-actions button:hover:not(:disabled){border-color:#8eaa98;background:#edf4ef;color:#176b44}.citation-entry-actions button.primary{border-color:#176b44;background:#176b44;color:#fff}.citation-entry-actions button.saved{border-color:#acd0b8;background:#edf7f0;color:#17623d}.citation-library-empty{min-height:150px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:7px;color:#7b887f;text-align:center}.citation-library-empty strong{color:#526158;font-size:13px}.citation-library-empty span{max-width:360px;font-size:11px;line-height:1.45}.citation-library-notice{display:flex;align-items:center;gap:6px;margin:0;padding:8px 10px;border:1px solid #acd0b8;border-radius:7px;background:#edf7f0;color:#17623d;font-size:11px}.citation-library-notice button{display:grid;place-items:center;width:21px;height:21px;margin-left:auto;border:0;border-radius:4px;background:transparent;color:inherit}.citation-current-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}.citation-current-heading>div{min-width:0;display:flex;flex-direction:column;gap:3px}.citation-current-heading strong{color:#31523e;font-size:13px}.citation-current-heading span{color:#78857c;font-size:10px}.citation-current-heading button{display:inline-flex;align-items:center;gap:4px;border:0;background:transparent;color:#176b44;font-size:10px;white-space:nowrap}.citation-edit-panel,.citation-tag-editor{display:flex;flex-direction:column;gap:9px;padding:10px 11px;border:1px solid #cbd9ce;border-radius:8px;background:#f5f9f6}.citation-edit-header{display:flex;align-items:center;justify-content:space-between;gap:8px;color:#31523e;font-size:11px}.citation-edit-header>div{min-width:0;display:flex;flex-direction:column;gap:3px}.citation-edit-header small{color:#78857c;font-size:10px;font-weight:400;line-height:1.4}.citation-edit-header button{display:grid;place-items:center;width:22px;height:22px;border:0;border-radius:4px;background:transparent;color:#68766d}.citation-edit-header button:hover{background:#e2ece4}.citation-edit-panel textarea{width:100%;resize:vertical;border:1px solid #cbd5ce;border-radius:6px;padding:8px;outline:0;font:11px/1.5 SFMono-Regular,Consolas,monospace}.citation-edit-panel textarea:focus{border-color:#176b44;box-shadow:0 0 0 2px #176b4420}.citation-modal-form{display:flex;flex-direction:column;gap:12px}.citation-modal-form.citation-edit-panel{padding:0;border:0;background:transparent}.citation-entry-item>.citation-edit-panel,.citation-entry-item>.citation-tag-editor{margin:0 7px 0 12px;border-left:3px solid #70a982}.citation-edit-actions{display:flex;justify-content:flex-end;gap:6px}.citation-edit-actions button{display:inline-flex;align-items:center;gap:4px;border:1px solid #bdc9c0;border-radius:6px;padding:6px 9px;background:#fff;color:#52685a;font-size:10px}.citation-edit-actions button.primary{border-color:#176b44;background:#176b44;color:#fff}.citation-tag-choice-list{display:flex;flex-wrap:wrap;gap:7px}.citation-tag-choice-list label{display:inline-flex;align-items:center;gap:5px;border:1px solid #d4ded6;border-radius:999px;padding:5px 7px;background:#fff;color:#526158;font-size:10px}.citation-tag-choice-list input{width:auto;accent-color:#176b44}.form-stack{display:flex;flex-direction:column;gap:14px}.import-error{margin:0;padding:10px 12px;border:1px solid #e3b5b1;border-radius:8px;background:#fff3f2;line-height:1.45}.form-field{display:flex;flex-direction:column;gap:7px;font-size:13px;font-weight:650}.form-field input,.form-field select,.form-field textarea{width:100%;border:1px solid #cbd2cc;border-radius:8px;padding:10px 11px;background:#fff;outline:none}.form-field input:focus,.form-field select:focus,.form-field textarea:focus{border-color:#176b44;box-shadow:0 0 0 3px #176b4420}.upload-picker{position:relative;min-height:116px;display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:14px;padding:20px;border:1.5px dashed #aebbb2;border-radius:10px;background:#f6f8f6;color:#5f6b63;transition:border-color .15s ease,background .15s ease}.upload-picker:hover,.upload-picker:focus-within{border-color:#4f8a68;background:#f0f6f2}.upload-picker.has-file{border-style:solid;border-color:#83aa91;background:#edf5ef;color:#276044}.upload-picker>svg{flex:none;color:#176b44}.upload-picker-copy{min-width:0;display:flex;flex-direction:column;gap:4px}.upload-picker-copy strong,.upload-picker-copy span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.upload-picker-copy strong{color:#29382f;font-size:13px}.upload-picker-copy span{color:#758078;font-size:11px}.upload-picker>button{display:inline-flex;align-items:center;gap:6px;border:1px solid #9fb0a4;border-radius:7px;padding:8px 11px;background:#fff;color:#235c3d;font-size:12px;font-weight:650}.upload-picker>button:hover{border-color:#176b44;background:#e4efe8}.upload-picker>.upload-clear{position:absolute;top:7px;right:7px;width:26px;height:26px;display:grid;place-items:center;border:0;padding:0;background:transparent;color:#6c776f}.upload-picker>.upload-clear:hover{background:#dce9e0;color:#9d2f27}.choice-group{display:flex;flex-direction:column;gap:10px;border:1px solid #dfe3df;border-radius:8px;padding:14px}.choice-group legend{padding:0 5px;font-size:12px;color:#69716b}.choice-group label{font-size:13px}.color-picker{display:grid;grid-template-columns:repeat(2,1fr);gap:7px;border:0;padding:0}.color-picker legend{margin-bottom:8px;font-size:13px;font-weight:650}.color-picker label{display:flex;align-items:center;gap:7px;border:1px solid #dce1dd;border-radius:7px;padding:8px;font-size:12px}.color-picker label.active{border-color:#176b44;background:#edf5f0}.color-picker input{position:absolute;opacity:0;pointer-events:none}.tag-assignment-list{display:flex;flex-direction:column;gap:7px}.tag-assignment-list label,.tag-assignment-list button{display:flex;align-items:center;gap:9px;min-height:38px;border:1px solid #dce1dd;border-radius:7px;padding:8px 10px;background:#fff;color:#38423b;font-size:13px;text-align:left}.tag-assignment-list label:hover,.tag-assignment-list button:hover{border-color:#8bae9a;background:#f4f8f5}.tag-assignment-list input{width:auto;accent-color:#176b44}.checkbox-field{display:flex;align-items:center;gap:8px;font-size:13px}.checkbox-field input{width:auto}.selection-preview{max-height:130px;overflow:auto;margin:14px 0 0;padding:10px 12px;border-left:3px solid #d6a128;background:#fff8e5;white-space:pre-wrap;font:12px/1.5 SFMono-Regular,Consolas,monospace}.git-dialog{display:flex;flex-direction:column;gap:14px}.git-dialog-modal-fullscreen{top:0;left:0;width:100vw;height:100vh;max-height:100vh;transform:none;overflow:hidden;border-radius:0}.git-loading{min-height:120px;display:flex;align-items:center;justify-content:center;gap:8px;color:#6e7871;font-size:13px}.git-message{margin:0;display:flex;align-items:center;gap:7px;padding:9px 11px;border:1px solid;border-radius:7px;font-size:12px}.git-message.error{border-color:#e2b4b0;background:#fff2f1}.git-message.success{border-color:#acd0b8;background:#edf7f0;color:#17623d}.git-section{display:flex;flex-direction:column;gap:11px;padding:14px;border:1px solid #dfe4e0;border-radius:9px;background:#fbfcfb}.git-section-toggle{width:100%;display:flex;align-items:center;justify-content:space-between;gap:10px;border:0;padding:0;background:transparent;color:#607068;text-align:left}.git-section-toggle:hover{color:#176b44}.git-section-heading{min-width:0;display:flex;align-items:flex-start;gap:8px;color:#27533a}.git-section-heading>svg{flex:none;margin-top:1px}.git-section-heading>div,.git-section-heading>span{min-width:0;display:flex;flex-direction:column;gap:3px}.git-section-heading strong{font-size:13px}.git-section-heading small{max-width:650px;overflow:hidden;color:#78817b;font-size:10px;line-height:1.4;text-overflow:ellipsis;white-space:nowrap}.git-section-content{display:flex;flex-direction:column;gap:11px;padding-top:2px}.git-token-guidance{display:flex;flex-direction:column;gap:4px;padding:10px 11px;border:1px solid #c6d9cb;border-left:3px solid #28714b;border-radius:7px;background:#f0f7f2}.git-token-guidance strong{color:#225d3c;font-size:11px}.git-token-guidance span{color:#66756b;font-size:10px;line-height:1.5}.git-account,.git-repository-card{display:flex;align-items:center;gap:8px;padding:9px 10px;border-radius:7px;background:#eaf3ed;color:#23563a;font-size:12px}.git-account>span{min-width:0;flex:1}.git-account button{display:inline-flex;align-items:center;gap:4px;border:0;background:transparent;color:#a3342c;font-size:10px}.git-inline-actions,.git-action-row{display:flex;align-items:center;flex-wrap:wrap;gap:7px}.git-inline-actions{justify-content:space-between}.git-inline-actions a,.git-repository-card a{display:inline-flex;align-items:center;gap:4px;color:#176b44;font-size:11px;text-decoration:none}.git-inline-actions button,.git-action-row button,.git-primary-action{display:inline-flex;align-items:center;justify-content:center;gap:5px;border:1px solid #bdc9c0;border-radius:6px;padding:7px 9px;background:#fff;color:#31523e;font-size:11px}.git-action-row .git-discard-button:not(:disabled){border-color:#d9aaa5;color:#9b332b}.git-action-row .git-discard-button:not(:disabled):hover{background:#fff0ee}.git-primary-action{align-self:flex-start;border-color:#176b44;background:#176b44;color:#fff}.git-repository-card{justify-content:space-between}.git-repository-card>div{min-width:0;display:flex;flex-direction:column;gap:3px}.git-repository-card strong,.git-repository-card small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.git-repository-card small{color:#6e7c73;font-size:10px}.git-count{min-width:17px;padding:1px 5px;border-radius:999px;background:#d9e9df;font-size:9px}.git-diff-section{padding-bottom:0;overflow:hidden}.git-diff-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}.git-diff-controls{display:flex;align-items:center;gap:7px;flex:none}.git-diff-font-controls{display:inline-flex;align-items:center;gap:2px;border:1px solid #cbd5ce;border-radius:6px;padding:2px;background:#fff;color:#52685a}.git-diff-font-button{width:25px;height:25px;display:grid;place-items:center;border:0;border-radius:4px;padding:0;background:transparent;color:inherit}.git-diff-font-button:hover:not(:disabled){background:#edf4ef;color:#176b44}.git-diff-font-value{min-width:34px;color:#52685a;font-size:10px;font-variant-numeric:tabular-nums;text-align:center}.git-diff-fullscreen{width:29px;height:29px;flex:none;display:grid;place-items:center;padding:0!important;border:1px solid #cbd5ce!important;border-radius:6px!important;background:#fff!important;color:#52685a}.git-diff-fullscreen:hover{border-color:#8eaa98!important;background:#edf4ef!important;color:#176b44}.git-diff-section.is-fullscreen,.git-diff-section:fullscreen{position:fixed;z-index:1000;inset:0;width:100vw;height:100vh;max-height:none;box-sizing:border-box;margin:0;padding:20px!important;border:0;border-radius:0;overflow:hidden;background:#fbfcfb}.git-diff-section.is-fullscreen .git-diff,.git-diff-section:fullscreen .git-diff{flex:1;min-height:0;max-height:none;margin:0}.git-diff-section.is-fullscreen .git-diff-empty,.git-diff-section:fullscreen .git-diff-empty{flex:1;min-height:0;margin:0}.git-diff{max-height:360px;margin:0 -14px;overflow:auto;padding:11px 0;background:#202522;color:#d9e1dc;font:10px/1.5 SFMono-Regular,Consolas,monospace;tab-size:4}.git-diff span{display:block;min-width:max-content;padding:0 12px;white-space:pre}.git-diff span.addition{background:#173b28;color:#bfe8cb}.git-diff span.deletion{background:#442421;color:#f1c1bc}.git-diff span.hunk{background:#283a48;color:#b8daf4}.git-diff span.header{color:#e8cf8b;font-weight:650}.git-diff-empty{margin:0 -14px;padding:28px;background:#252a27;color:#b9c0bc;font-size:12px;text-align:center}.git-history{max-height:300px;display:flex;flex-direction:column;gap:5px;overflow:auto}.git-history article{min-width:0;display:grid;grid-template-columns:66px minmax(0,1fr) auto;align-items:center;gap:8px;padding:8px;border:1px solid #e2e6e3;border-radius:6px;background:#fff}.git-history code{color:#176b44;font-size:10px}.git-history article>div{min-width:0;display:flex;flex-direction:column;gap:2px}.git-history article strong,.git-history article small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.git-history article strong{font-size:11px}.git-history article small{color:#7b847e;font-size:9px}.git-history article>span{display:flex;gap:3px}.git-history button{width:27px;height:27px;display:grid;place-items:center;border:0;border-radius:5px;background:transparent;color:#52685a}.git-history button:hover{background:#e8f0eb;color:#176b44}.git-force-checkout{display:flex;align-items:flex-start;gap:9px;padding:11px;border:1px solid #e4b9b5;border-radius:8px;background:#fff6f5}.git-force-checkout input{margin-top:2px;accent-color:#b3261e}.git-force-checkout span{display:flex;flex-direction:column;gap:3px}.git-force-checkout strong{color:#932c25;font-size:12px}.git-force-checkout small{color:#7d6562;font-size:10px;line-height:1.45}.quick-open-dialog>label,.project-search-query{display:flex;align-items:center;gap:8px;border:1px solid #bfcac2;border-radius:7px;padding:0 10px;background:#fff}.quick-open-dialog>label:focus-within,.project-search-query:focus-within{border-color:#418060;box-shadow:0 0 0 2px #41806020}.quick-open-dialog input,.project-search-query input{width:100%;border:0;outline:0;padding:10px 0;background:transparent}.quick-open-results{max-height:420px;overflow:auto;margin-top:8px;border:1px solid #d9e0db;border-radius:7px}.quick-open-results button{display:grid;grid-template-columns:20px minmax(0,1fr) 18px;align-items:center;gap:6px;width:100%;padding:8px 10px;border:0;border-radius:0;background:#fff;text-align:left}.quick-open-results button+button{border-top:1px solid #eef1ef}.quick-open-results button.active{background:#e4efe8;color:#195f3d}.quick-open-results span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:11px/1.4 JetBrains Mono,monospace}.project-search-dialog{display:grid;gap:9px}.project-search-form{display:grid;grid-template-columns:1fr 1fr;gap:8px}.project-search-options{grid-column:1 / -1;display:flex;align-items:center;gap:14px}.project-search-options label{display:inline-flex;align-items:center;gap:5px;color:#55645a;font-size:11px}.project-search-options label input{accent-color:#28734b}.project-search-options button{margin-left:auto;display:inline-flex;align-items:center;gap:5px}.project-search-summary{display:flex;align-items:center;justify-content:space-between;min-height:22px;color:#5e6c63;font-size:11px}.project-search-summary span{display:inline-flex;align-items:center;gap:5px}.project-search-results{max-height:480px;overflow:auto;border:1px solid #d9e0db;border-radius:7px;background:#fff}.project-search-results>button{display:grid;grid-template-columns:20px minmax(0,1fr);gap:7px;width:100%;padding:9px 10px;border:0;border-radius:0;background:#fff;text-align:left}.project-search-results>button+button{border-top:1px solid #e8ece9}.project-search-results>button:hover{background:#edf4ef}.project-search-results>button>span{min-width:0;display:grid;gap:4px}.project-search-results strong{color:#31503d;font-size:11px}.project-search-results strong small{color:#7c877f;font-weight:400}.project-search-results code{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#4e5952;font:10px/1.45 JetBrains Mono,monospace}.project-search-results mark{border-radius:2px;padding:1px;background:#f2d36e;color:#4b3b0b}.history-dialog-modal{width:min(1120px,calc(100vw - 32px))}.history-dialog{display:grid;grid-template-columns:270px minmax(0,1fr);min-height:560px;max-height:min(72vh,760px);border:1px solid #d9e0db;border-radius:8px;overflow:hidden;background:#fff}.history-loading{grid-column:1 / -1;display:flex;align-items:center;justify-content:center;gap:8px;min-height:420px;color:#68736b}.history-message{grid-column:1 / -1;margin:10px}.history-timeline{overflow:auto;border-right:1px solid #d9e0db;background:#f5f7f5}.history-stats{position:sticky;top:0;z-index:2;display:grid;gap:5px;padding:10px 12px;border-bottom:1px solid #d8dfda;background:#edf3ef;color:#33483b}.history-stats header{display:flex;align-items:center;justify-content:space-between;gap:8px}.history-stats header span{display:inline-flex;align-items:center;gap:6px;font-size:11px;font-weight:700}.history-stats header button{width:26px;height:26px;display:grid;place-items:center;border:0;padding:0;background:transparent;color:#9d332b}.history-stats header button:hover:not(:disabled){background:#f5deda}.history-stats strong{font-size:11px}.history-stats small{color:#68766d;font-size:9px;line-height:1.4}.history-stats progress{width:100%;height:6px;border:0;border-radius:999px;overflow:hidden;accent-color:#34845a}.history-stats.exceeded progress{accent-color:#bd483e}.history-stats .history-storage-warning{color:#9d332b}.history-timeline>button{display:grid;grid-template-columns:20px minmax(0,1fr);gap:7px;width:100%;padding:11px 12px;border:0;border-bottom:1px solid #e1e6e2;border-radius:0;background:transparent;text-align:left;color:#34443a}.history-timeline>button:hover{background:#eaf0ec}.history-timeline>button.active{background:#dfece4;box-shadow:inset 3px 0 #28734b}.history-timeline>button span{min-width:0;display:grid;gap:2px}.history-timeline>button strong,.history-timeline>button small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.history-timeline>button small{color:#68736b;font-size:10px}.history-detail{min-width:0;overflow:auto;padding:14px}.history-detail-header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:12px}.history-detail-header>div{display:grid;gap:4px}.history-detail-header small{display:flex;align-items:center;gap:4px;color:#68736b}.history-detail-actions{display:flex;align-items:center;gap:6px}.history-detail-actions button{display:inline-flex;align-items:center;gap:5px;white-space:nowrap}.history-label{display:flex;gap:8px;margin-bottom:12px}.history-label label{flex:1;display:flex;align-items:center;gap:7px;padding:0 9px;border:1px solid #cdd6cf;border-radius:6px;background:#fff}.history-label input{width:100%;border:0;padding:8px 0;outline:0}.history-files{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:start}.history-file-list{display:flex;gap:5px;overflow-x:auto;padding-bottom:5px}.history-file-list button{display:inline-flex;align-items:center;gap:5px;flex:0 0 auto;max-width:230px}.history-file-list button span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.history-file-list button small{padding:1px 4px;border-radius:8px;background:#f2d675;color:#695414;font-size:9px}.history-file-list button.active{border-color:#418060;background:#e7f0ea}.history-file-actions{display:flex;gap:5px}.history-file-actions button{display:inline-flex;align-items:center;gap:5px;white-space:nowrap}.history-comparison{min-height:360px;margin-top:10px;border:1px solid #d8dfda;border-radius:7px;overflow:hidden;background:#fbfcfb}.history-comparison>header{display:flex;align-items:baseline;justify-content:space-between;gap:10px;padding:8px 10px;border-bottom:1px solid #d8dfda;background:#f1f4f2}.history-comparison>header small{color:#68736b}.history-comparison pre{min-height:330px;max-height:430px;margin:0;overflow:auto;padding:11px;white-space:pre-wrap;overflow-wrap:anywhere;font:11px/1.5 JetBrains Mono,Source Code Pro,monospace;color:#26342b}.history-comparison pre .history-removed{background:#f8c9c9;color:#7b2525;text-decoration:line-through}.history-comparison pre .history-added{background:#ccebd5;color:#15552c}.history-comparison-empty{min-height:360px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;color:#78827b}@keyframes fade-in{0%{opacity:0}}@keyframes dialog-in{0%{opacity:0;transform:translate(-50%,-48%) scale(.98)}}@keyframes spin{to{transform:rotate(360deg)}}@media(max-width:1100px){.project-grid.list-view .project-card-open{grid-template-columns:110px minmax(160px,1fr)}.project-grid.list-view .project-meta{grid-column:1 / -1}.editor-actions button{padding:8px}.editor-actions button svg+*{display:none}.editor-actions .format-action button,.editor-actions .comments-action button,.editor-actions .version-action button{padding:7px 6px}.editor-actions .format-action button svg+*,.editor-actions .comments-action button svg+*,.editor-actions .version-action button svg+*{display:inline}}@media(max-width:720px){.citation-library-page-shell{padding-top:24px}.citation-library-page-header{flex-direction:column}.citation-library-page-header h1{font-size:25px}.citation-library-page-header>button{align-self:flex-start}.citation-library-page .citation-library-dialog{padding:12px}.citation-library-search-row{flex-direction:column}.citation-add-entry-button{min-height:34px;justify-content:center}.citation-entry-card{flex-direction:column}.citation-entry-actions{width:100%;justify-content:flex-start}.upload-picker{grid-template-columns:auto 1fr}.upload-picker>button{grid-column:1 / -1;justify-content:center}.share-add{grid-template-columns:1fr}.shared-member{align-items:flex-start}.member-controls{flex:none}.history-dialog{grid-template-columns:1fr;max-height:none}.history-timeline{max-height:180px;border-right:0;border-bottom:1px solid #d9e0db}.history-files,.project-search-form{grid-template-columns:1fr}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as e}from"./index-
|
|
1
|
+
import{j as e}from"./index-BAFR6u6_.js";const n=e("Maximize2",[["polyline",{points:"15 3 21 3 21 9",key:"mznyad"}],["polyline",{points:"9 21 3 21 3 15",key:"1avn1i"}],["line",{x1:"21",x2:"14",y1:"3",y2:"10",key:"ota7mn"}],["line",{x1:"3",x2:"10",y1:"21",y2:"14",key:"1atl0r"}]]);const a=e("Minus",[["path",{d:"M5 12h14",key:"1ays0h"}]]);export{a as M,n as a};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as k}from"./index-BAFR6u6_.js";import"./react-BoEjKzFZ.js";const S=5,u=new Map,x=12;let p=!1,f=null;class h extends Error{constructor(){super("A newer writing check replaced this request."),this.name="HarperLintSupersededError"}}function A(t){return t instanceof h}function v(t){const e=[0];let n=0;for(const r of t)n+=r.length,e.push(n);return e}function L(t){return[...new Set(t.map(e=>e.trim()).filter(Boolean))].sort((e,n)=>e.localeCompare(n)).join("\0")}async function C(t,e,n){return(await k(`/api/projects/${t}/spellcheck`,{method:"POST",body:JSON.stringify({path:e,source:n})})).lints}function R(t,e,n){if(!e.problem)return null;const r={from:e.start,to:e.end},o={from:n[e.start]??-1,to:n[e.end]??-1},i=c=>c.from>=0&&c.to>c.from&&c.to<=t.length,a=c=>i(c)&&t.slice(c.from,c.to)===e.problem;return a(o)?o:a(r)?r:null}function $(t,e,n){const r=R(t,e,n);if(!r)return null;const{from:o,to:i}=r,a=t.slice(o,i);if(!a.trim()||!/[A-Za-z]/.test(a)||e.kind==="Formatting")return null;const c=e.kind==="Spelling"||e.kind==="Typo"?"spelling":"grammar",m=e.suggestions.filter((d,s,l)=>s<S&&l.indexOf(d)===s);return{from:o,to:i,word:a,kind:c,message:e.message,suggestions:m}}function g(t,e){let n=2166136261;for(let r=0;r<e.length;r+=1)n^=e.charCodeAt(r),n=Math.imul(n,16777619);return`${t}\0${e.length}:${n>>>0}`}function y(t,e,n){const r=g(t,e),o=u.get(r);return!o||o.path!==t||o.source!==e||o.dictionary!==n?null:(u.delete(r),u.set(r,o),o.issues)}function j(t,e,n,r){const o=g(t,e);for(u.set(o,{path:t,source:e,dictionary:n,issues:r});u.size>x;){const i=u.keys().next().value;if(i===void 0)break;u.delete(i)}}async function q(t,e,n,r="main.tex"){const o=L(e),i=y(r,t,o);if(i)return i;const a=v(t),c=new Set(e.map(s=>s.trim().toLocaleLowerCase("en-US")).filter(Boolean)),m=new Set,d=n.map(s=>$(t,s,a)).filter(s=>!!s).filter(s=>s.kind!=="spelling"||!c.has(s.word.trim().toLocaleLowerCase("en-US"))).filter(s=>{const l=`${s.from}:${s.to}:${s.kind}`;return m.has(l)?!1:(m.add(l),!0)}).sort((s,l)=>s.from-l.from||s.to-l.to);return j(r,t,o,d),d}async function b(t,e,n,r){const o=L(r),i=y(e,n,o);if(i)return i;const a=await C(t,e,n);return q(n,r,a,e)}async function w(){if(p||!f)return;const t=f;f=null,p=!0;try{t.resolve(await b(t.projectId,t.path,t.source,t.customWords))}catch(e){t.reject(e)}finally{p=!1,w()}}function B(t,e,n,r=[]){return new Promise((o,i)=>{f?.reject(new h),f={projectId:t,path:e,source:n,customWords:[...r],resolve:o,reject:i},w()})}export{h as HarperLintSupersededError,A as isHarperLintSupersededError,B as lintLatex,q as mapLatexLints};
|
package/dist/client/index.html
CHANGED
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource/iosevka@5.2.5/400.css" />
|
|
11
11
|
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
|
|
12
12
|
<title>TexLite</title>
|
|
13
|
-
<script type="module" crossorigin src="/assets/index-
|
|
13
|
+
<script type="module" crossorigin src="/assets/index-BAFR6u6_.js"></script>
|
|
14
14
|
<link rel="modulepreload" crossorigin href="/assets/react-BoEjKzFZ.js">
|
|
15
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
15
|
+
<link rel="stylesheet" crossorigin href="/assets/index-g5CaToD6.css">
|
|
16
16
|
</head>
|
|
17
17
|
<body>
|
|
18
18
|
<div id="root"></div>
|
package/dist/server/app.js
CHANGED
|
@@ -31,7 +31,9 @@ import { registerProjectGitRoutes } from "./routes/projectGit.js";
|
|
|
31
31
|
import { registerProjectCatalogRoutes } from "./routes/projects.js";
|
|
32
32
|
import { registerSystemRoutes } from "./routes/system.js";
|
|
33
33
|
import { registerUserManagementRoutes } from "./routes/users.js";
|
|
34
|
+
import { registerWordCountRoutes } from "./routes/wordCount.js";
|
|
34
35
|
import { HarperService } from "./harper.js";
|
|
36
|
+
import { TexcountService } from "./texcount.js";
|
|
35
37
|
// Retained public helper for callers and tests; implementation lives with the file routes.
|
|
36
38
|
export { escapeGlobPattern } from "./routes/projectShared.js";
|
|
37
39
|
const SESSION_CLEANUP_INTERVAL_MS = 15 * 60_000;
|
|
@@ -50,9 +52,10 @@ export async function buildApp(config, db, options = {}) {
|
|
|
50
52
|
const latexCompletions = new LatexCompletionService(config);
|
|
51
53
|
const projectOutlines = new ProjectOutlineService(config);
|
|
52
54
|
const harper = new HarperService();
|
|
53
|
-
|
|
54
|
-
//
|
|
55
|
-
|
|
55
|
+
const texcount = new TexcountService();
|
|
56
|
+
// Probe the optional host Harper CLI without delaying startup. Its absence is
|
|
57
|
+
// supported: the browser spellchecker remains the writing-check fallback.
|
|
58
|
+
void harper.preload().catch((error) => app.log.info({ err: error }, "Optional Harper CLI is unavailable"));
|
|
56
59
|
const recordHistory = (projectId, userId, reason, paths) => {
|
|
57
60
|
try {
|
|
58
61
|
return history.record(projectId, userId, reason, paths);
|
|
@@ -106,6 +109,7 @@ export async function buildApp(config, db, options = {}) {
|
|
|
106
109
|
app.addHook("onClose", async () => {
|
|
107
110
|
eventLoopDelay.disable();
|
|
108
111
|
await harper.dispose();
|
|
112
|
+
await texcount.dispose();
|
|
109
113
|
});
|
|
110
114
|
await app.register(cookie, { hook: "onRequest" });
|
|
111
115
|
await app.register(websocket, { options: { maxPayload: 6 * 1024 * 1024 } });
|
|
@@ -195,6 +199,7 @@ export async function buildApp(config, db, options = {}) {
|
|
|
195
199
|
harper,
|
|
196
200
|
recordHistory
|
|
197
201
|
});
|
|
202
|
+
registerWordCountRoutes(app, { config, db, projectMutations, texcount });
|
|
198
203
|
registerCompileRoutes(app, { config, db, collaboration, projectMutations, compileCoordinator, metrics, pruneCompileRuns });
|
|
199
204
|
// The factory owns shared services and lifecycle hooks; route modules own endpoint behavior.
|
|
200
205
|
app.addHook("onRequest", async (request) => {
|
package/dist/server/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import { fileURLToPath } from "node:url";
|
|
|
8
8
|
import { CONFIG_DEFAULTS, loadConfig } from "./config.js";
|
|
9
9
|
import { activeAdminCount, openDatabase } from "./db.js";
|
|
10
10
|
import { hashPassword, MIN_PASSWORD_LENGTH } from "./security.js";
|
|
11
|
-
import { assertEnvironment,
|
|
11
|
+
import { assertEnvironment, hostRequirementsSatisfied, inspectHostEnvironment, inspectHostRequirements } from "./environment.js";
|
|
12
12
|
import { serve } from "./index.js";
|
|
13
13
|
import { processStatus, restartManaged, startManaged, stopManaged, streamLogs, waitForOnline } from "./pm2.js";
|
|
14
14
|
import { defaultDataDirectory, resolveConfigPath } from "./runtimePaths.js";
|
|
@@ -18,42 +18,38 @@ Usage:
|
|
|
18
18
|
texlite <command> [options]
|
|
19
19
|
|
|
20
20
|
Commands:
|
|
21
|
-
init
|
|
22
|
-
serve
|
|
23
|
-
start
|
|
24
|
-
status
|
|
25
|
-
stop
|
|
26
|
-
restart
|
|
27
|
-
logs
|
|
28
|
-
doctor
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
init Create the configuration, initialize storage, and create the first administrator.
|
|
22
|
+
serve Run the server in the foreground for debugging, Docker, or systemd.
|
|
23
|
+
start Start the server in the background under PM2.
|
|
24
|
+
status Show the status of the PM2-managed server.
|
|
25
|
+
stop Stop the PM2-managed server.
|
|
26
|
+
restart Restart (or start) the PM2-managed server.
|
|
27
|
+
logs Stream logs from the PM2-managed server.
|
|
28
|
+
doctor Check configuration, application state, and host dependencies.
|
|
29
|
+
requirements Check host software on PATH without loading TexLite configuration.
|
|
30
|
+
config Print the effective configuration as JSON without changing it.
|
|
31
|
+
help Show this help message.
|
|
32
|
+
version Print the installed TexLite version.
|
|
32
33
|
|
|
33
34
|
Options:
|
|
34
35
|
--config PATH Use this configuration file instead of TEXLITE_CONFIG or the XDG default.
|
|
35
|
-
|
|
36
|
-
--json Print status as JSON for scripts
|
|
36
|
+
Requirements does not accept this option.
|
|
37
|
+
--json Print status, doctor, or requirements results as JSON for scripts.
|
|
37
38
|
-h, --help Show this help message.
|
|
38
39
|
-v, --version Print the installed TexLite version.
|
|
39
40
|
`;
|
|
40
41
|
export function parseArgs(args) {
|
|
41
42
|
let command = "help";
|
|
42
43
|
let configPath;
|
|
43
|
-
let checkGit = false;
|
|
44
44
|
let json = false;
|
|
45
45
|
for (let index = 0; index < args.length; index += 1) {
|
|
46
46
|
const argument = args[index];
|
|
47
47
|
if (!argument)
|
|
48
48
|
continue;
|
|
49
49
|
if (argument === "-h" || argument === "--help")
|
|
50
|
-
return { command: "help", configPath,
|
|
50
|
+
return { command: "help", configPath, json };
|
|
51
51
|
if (argument === "-v" || argument === "--version")
|
|
52
|
-
return { command: "version", configPath,
|
|
53
|
-
if (argument === "--git") {
|
|
54
|
-
checkGit = true;
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
52
|
+
return { command: "version", configPath, json };
|
|
57
53
|
if (argument === "--json") {
|
|
58
54
|
json = true;
|
|
59
55
|
continue;
|
|
@@ -78,7 +74,10 @@ export function parseArgs(args) {
|
|
|
78
74
|
throw new Error(`Only one command may be specified (already received ${command})`);
|
|
79
75
|
command = argument;
|
|
80
76
|
}
|
|
81
|
-
|
|
77
|
+
if (command === "requirements" && configPath) {
|
|
78
|
+
throw new Error("`texlite requirements` does not use --config.");
|
|
79
|
+
}
|
|
80
|
+
return { command, configPath, json };
|
|
82
81
|
}
|
|
83
82
|
function output(message) {
|
|
84
83
|
stdout.write(`${message}\n`);
|
|
@@ -209,16 +208,64 @@ async function assertAdmin(config) {
|
|
|
209
208
|
}
|
|
210
209
|
async function doctor(options) {
|
|
211
210
|
const { config, configPath } = await loadValidatedConfig(options);
|
|
212
|
-
const
|
|
213
|
-
await
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
211
|
+
const application = inspectDoctorApplication(config, configPath);
|
|
212
|
+
const hostTools = await inspectHostEnvironment(config);
|
|
213
|
+
const report = {
|
|
214
|
+
configPath,
|
|
215
|
+
dataDir: config.dataDir,
|
|
216
|
+
clientDir: config.clientDir,
|
|
217
|
+
application,
|
|
218
|
+
hostTools,
|
|
219
|
+
ok: application.every((check) => check.status === "passed")
|
|
220
|
+
&& hostRequirementsSatisfied(hostTools)
|
|
221
|
+
};
|
|
222
|
+
output(options.json ? JSON.stringify(report, null, 2) : formatDoctorReport(report, terminalColorsEnabled()));
|
|
223
|
+
if (!report.ok)
|
|
224
|
+
process.exitCode = 2;
|
|
225
|
+
}
|
|
226
|
+
async function requirements(options) {
|
|
227
|
+
const hostTools = await inspectHostRequirements();
|
|
228
|
+
const report = { hostTools, ok: hostRequirementsSatisfied(hostTools) };
|
|
229
|
+
output(options.json ? JSON.stringify(report, null, 2) : formatRequirementsReport(report, terminalColorsEnabled()));
|
|
230
|
+
if (!report.ok)
|
|
231
|
+
process.exitCode = 2;
|
|
232
|
+
}
|
|
233
|
+
function inspectDoctorApplication(config, configPath) {
|
|
234
|
+
const checks = [
|
|
235
|
+
{ name: "Configuration", status: "passed", detail: `Valid: ${configPath}` },
|
|
236
|
+
inspectClientAssets(config)
|
|
237
|
+
];
|
|
238
|
+
let db = null;
|
|
239
|
+
try {
|
|
240
|
+
db = openDatabase(config);
|
|
241
|
+
checks.push({ name: "Data and database", status: "passed", detail: `Opened: ${config.databasePath}` });
|
|
242
|
+
const administrators = activeAdminCount(db);
|
|
243
|
+
checks.push(administrators > 0
|
|
244
|
+
? { name: "Administrator", status: "passed", detail: `${administrators} active administrator${administrators === 1 ? "" : "s"}` }
|
|
245
|
+
: { name: "Administrator", status: "failed", detail: "No active administrator. Run `texlite init`." });
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
const detail = errorMessage(error);
|
|
249
|
+
checks.push({ name: "Data and database", status: "failed", detail });
|
|
250
|
+
checks.push({ name: "Administrator", status: "failed", detail: "Could not inspect because the database is unavailable." });
|
|
251
|
+
}
|
|
252
|
+
finally {
|
|
253
|
+
db?.close();
|
|
254
|
+
}
|
|
255
|
+
return checks;
|
|
256
|
+
}
|
|
257
|
+
function inspectClientAssets(config) {
|
|
258
|
+
const entry = path.join(config.clientDir, "index.html");
|
|
259
|
+
try {
|
|
260
|
+
const stat = fs.statSync(entry);
|
|
261
|
+
if (stat.isFile())
|
|
262
|
+
return { name: "Client assets", status: "passed", detail: `Found: ${entry}` };
|
|
263
|
+
}
|
|
264
|
+
catch { /* Report a concise diagnostic below. */ }
|
|
265
|
+
return { name: "Client assets", status: "failed", detail: `Missing ${entry}; run \`npm run build\` or reinstall TexLite.` };
|
|
266
|
+
}
|
|
267
|
+
function errorMessage(error) {
|
|
268
|
+
return error instanceof Error ? error.message.replace(/\s+/g, " ").slice(0, 240) : String(error).slice(0, 240);
|
|
222
269
|
}
|
|
223
270
|
async function printConfig(options) {
|
|
224
271
|
const { config, configPath } = await loadValidatedConfig(options);
|
|
@@ -282,6 +329,94 @@ function terminalColorsEnabled() {
|
|
|
282
329
|
function colorize(value, color, enabled) {
|
|
283
330
|
return enabled ? `${ANSI[color]}${value}${ANSI.reset}` : value;
|
|
284
331
|
}
|
|
332
|
+
export function formatDoctorReport(report, colors = false) {
|
|
333
|
+
const titleColor = report.ok ? "green" : "red";
|
|
334
|
+
const title = report.ok ? "all required checks passed" : "required checks need attention";
|
|
335
|
+
const applicationRows = report.application.map((check) => [
|
|
336
|
+
{ text: check.name },
|
|
337
|
+
{ text: "Required" },
|
|
338
|
+
{ text: check.status === "passed" ? "Passed" : "Failed", color: check.status === "passed" ? "green" : "red" },
|
|
339
|
+
{ text: shortenDoctorCell(check.detail, 68) }
|
|
340
|
+
]);
|
|
341
|
+
return [
|
|
342
|
+
`${colorize("●", titleColor, colors)} ${colors ? `${ANSI.bold}TexLite doctor${ANSI.reset}` : "TexLite doctor"} — ${colorize(title, titleColor, colors)}`,
|
|
343
|
+
` Config: ${report.configPath}`,
|
|
344
|
+
` Data: ${report.dataDir}`,
|
|
345
|
+
` Client: ${report.clientDir}`,
|
|
346
|
+
"",
|
|
347
|
+
"Application checks",
|
|
348
|
+
formatDoctorTable(["Check", "Need", "Status", "Details"], applicationRows, colors),
|
|
349
|
+
"",
|
|
350
|
+
"Host software",
|
|
351
|
+
formatHostSoftwareTable(report.hostTools, colors),
|
|
352
|
+
"",
|
|
353
|
+
hostRequirementNote(report.hostTools, "start TexLite"),
|
|
354
|
+
"Harper CLI is used by TexLite; harper-ls is reported for host diagnostics and external editor integrations."
|
|
355
|
+
].join("\n");
|
|
356
|
+
}
|
|
357
|
+
export function formatRequirementsReport(report, colors = false) {
|
|
358
|
+
const titleColor = report.ok ? "green" : "red";
|
|
359
|
+
const title = report.ok ? "all host requirements passed" : "host requirements need attention";
|
|
360
|
+
return [
|
|
361
|
+
`${colorize("●", titleColor, colors)} ${colors ? `${ANSI.bold}TexLite requirements${ANSI.reset}` : "TexLite requirements"} — ${colorize(title, titleColor, colors)}`,
|
|
362
|
+
"",
|
|
363
|
+
"Host software (default commands on PATH)",
|
|
364
|
+
formatHostSoftwareTable(report.hostTools, colors),
|
|
365
|
+
"",
|
|
366
|
+
hostRequirementNote(report.hostTools, "compile with TexLite"),
|
|
367
|
+
"This command does not read a TexLite configuration, data directory, database, or administrator state.",
|
|
368
|
+
"Harper CLI is used by TexLite; harper-ls is reported for host diagnostics and external editor integrations."
|
|
369
|
+
].join("\n");
|
|
370
|
+
}
|
|
371
|
+
function formatHostSoftwareTable(hostTools, colors) {
|
|
372
|
+
const hostRows = hostTools.map((tool) => [
|
|
373
|
+
{ text: shortenDoctorCell(tool.command === tool.name ? tool.name : `${tool.name} (${tool.command})`, 32) },
|
|
374
|
+
{ text: requirementLabel(tool.requirement) },
|
|
375
|
+
hostToolStatusCell(tool),
|
|
376
|
+
{ text: shortenDoctorCell(tool.version ?? tool.detail ?? "—", 56) }
|
|
377
|
+
]);
|
|
378
|
+
return formatDoctorTable(["Tool / command", "Need", "Status", "Version / diagnostic"], hostRows, colors);
|
|
379
|
+
}
|
|
380
|
+
function requirementLabel(requirement) {
|
|
381
|
+
if (requirement === "required")
|
|
382
|
+
return "Required";
|
|
383
|
+
if (requirement === "one-of")
|
|
384
|
+
return "One of";
|
|
385
|
+
return "Optional";
|
|
386
|
+
}
|
|
387
|
+
function hostRequirementNote(hostTools, action) {
|
|
388
|
+
const oneOf = hostTools.some((tool) => tool.requirement === "one-of");
|
|
389
|
+
return oneOf
|
|
390
|
+
? `Required tools and at least one tool in every “One of” group must be installed to ${action}. Optional tools enable their named feature without blocking the editor.`
|
|
391
|
+
: `Required tools must be installed to ${action}. Optional tools enable their named feature without blocking the editor.`;
|
|
392
|
+
}
|
|
393
|
+
function hostToolStatusCell(tool) {
|
|
394
|
+
if (tool.status === "installed")
|
|
395
|
+
return { text: "Installed", color: "green" };
|
|
396
|
+
if (tool.status === "missing") {
|
|
397
|
+
return { text: tool.requirement === "required" ? "Missing" : "Not installed", color: tool.requirement === "required" ? "red" : "yellow" };
|
|
398
|
+
}
|
|
399
|
+
return { text: "Failed", color: "red" };
|
|
400
|
+
}
|
|
401
|
+
function shortenDoctorCell(value, maxLength) {
|
|
402
|
+
const normalized = value.replace(/\s+/g, " ").trim();
|
|
403
|
+
return normalized.length > maxLength ? `${normalized.slice(0, Math.max(1, maxLength - 1))}…` : normalized;
|
|
404
|
+
}
|
|
405
|
+
function formatDoctorTable(headers, rows, colors) {
|
|
406
|
+
const widths = headers.map((header, index) => Math.max(header.length, ...rows.map((row) => row[index]?.text.length ?? 0)));
|
|
407
|
+
const line = (left, middle, right, fill) => `${left}${widths.map((width) => fill.repeat(width + 2)).join(middle)}${right}`;
|
|
408
|
+
const renderRow = (cells) => `│${cells.map((cell, index) => {
|
|
409
|
+
const padded = (cell?.text ?? "").padEnd(widths[index] ?? 0);
|
|
410
|
+
return ` ${cell?.color ? colorize(padded, cell.color, colors) : padded} `;
|
|
411
|
+
}).join("│")}│`;
|
|
412
|
+
return [
|
|
413
|
+
line("┌", "┬", "┐", "─"),
|
|
414
|
+
renderRow(headers.map((text) => ({ text }))),
|
|
415
|
+
line("├", "┼", "┤", "─"),
|
|
416
|
+
...rows.map(renderRow),
|
|
417
|
+
line("└", "┴", "┘", "─")
|
|
418
|
+
].join("\n");
|
|
419
|
+
}
|
|
285
420
|
function duration(value) {
|
|
286
421
|
if (value === null)
|
|
287
422
|
return "n/a";
|
|
@@ -371,6 +506,9 @@ async function run(options) {
|
|
|
371
506
|
case "doctor":
|
|
372
507
|
await doctor(options);
|
|
373
508
|
return;
|
|
509
|
+
case "requirements":
|
|
510
|
+
await requirements(options);
|
|
511
|
+
return;
|
|
374
512
|
case "config":
|
|
375
513
|
await printConfig(options);
|
|
376
514
|
return;
|