@zaclinley/dsh-mailharbor 0.7.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/lib/client.js +478 -111
- package/lib/client.js.map +2 -2
- package/lib/index.js +14 -3
- package/lib/index.js.map +2 -2
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -35,7 +35,7 @@ __export(index_exports, {
|
|
|
35
35
|
module.exports = __toCommonJS(index_exports);
|
|
36
36
|
|
|
37
37
|
// src/client/styles.css
|
|
38
|
-
var styles_default = "/* MailHarbor panel + settings.\n Tokens come from the DSH shell (dark by default); fallbacks match the\n default dark theme so the panel also renders in a bare host page.\n Component rules are all scoped under `.mailharbor` and the generic element\n reset lives in `:where()` so it cannot outrank a component class. */\n\n.mailharbor {\n --m-bg: var(--dsw-alias-bg-base, #151517);\n --m-bg-1: var(--dsw-alias-bg-layer-1, #232324);\n --m-bg-2: var(--dsw-alias-bg-layer-2, #2c2c2e);\n --m-bg-3: var(--dsw-alias-bg-layer-3, #353638);\n --m-line: var(--dsw-alias-border-l2, #ffffff1f);\n --m-line-soft: var(--dsw-alias-border-l1, #ffffff0f);\n --m-line-strong: var(--dsw-alias-border-l3, #ffffff29);\n --m-text: var(--dsw-alias-label-primary, #f9fafb);\n --m-text-2: var(--dsw-alias-label-secondary, #cfd3d6);\n --m-text-3: var(--dsw-alias-label-tertiary, #adb2b8);\n --m-caption: var(--dsw-alias-label-caption, #81858c);\n --m-accent: #5686fe;\n --m-accent-soft: rgba(86, 134, 254, 0.14);\n --m-primary-bg: var(--dsw-alias-brand-primary, #f9fafb);\n --m-primary-fg: var(--dsw-alias-label-primary-foreground, #0f1115);\n --m-hover: var(--dsw-alias-interactive-bg-hover, #ffffff14);\n --m-danger: #f25a5a;\n --m-ok: #3fbf7f;\n --m-warn: var(--dsw-alias-state-warn-label, #dd8629);\n --m-radius: 8px;\n --m-shadow: 0 18px 60px rgba(0, 0, 0, 0.5);\n\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n background: var(--m-bg);\n color: var(--m-text);\n font-size: 13px;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n}\n\n.mailharbor *,\n.mailharbor *::before,\n.mailharbor *::after {\n box-sizing: border-box;\n}\n\n/* ---------- base controls ---------- */\n\n.mailharbor :where(button) {\n font: inherit;\n color: inherit;\n background: transparent;\n border: 0;\n margin: 0;\n cursor: pointer;\n}\n\n.mailharbor button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n height: 30px;\n padding: 0 12px;\n border-radius: var(--m-radius);\n border: 1px solid transparent;\n color: var(--m-text-2);\n font-size: 12.5px;\n font-weight: 500;\n white-space: nowrap;\n transition:\n background 120ms ease,\n color 120ms ease,\n border-color 120ms ease;\n}\n\n.mailharbor button:hover:not(:disabled) {\n background: var(--m-hover);\n color: var(--m-text);\n}\n\n.mailharbor button:disabled {\n opacity: 0.45;\n cursor: default;\n}\n\n.mailharbor button.primary {\n background: var(--m-primary-bg);\n color: var(--m-primary-fg);\n border-color: transparent;\n}\n\n.mailharbor button.primary:hover:not(:disabled) {\n background: var(--m-primary-bg);\n filter: brightness(0.94);\n color: var(--m-primary-fg);\n}\n\n.mailharbor button.ghost {\n border-color: var(--m-line);\n color: var(--m-text-2);\n}\n\n.mailharbor button.ghost:hover:not(:disabled) {\n border-color: var(--m-line-strong);\n color: var(--m-text);\n}\n\n.mailharbor button.subtle {\n color: var(--m-text-3);\n padding: 0 8px;\n}\n\n.mailharbor button.icon {\n width: 30px;\n padding: 0;\n}\n\n.mailharbor button.danger {\n color: var(--m-danger);\n}\n\n.mailharbor input,\n.mailharbor select,\n.mailharbor textarea {\n font: inherit;\n color: var(--m-text);\n background: var(--m-bg-1);\n border: 1px solid var(--m-line);\n border-radius: var(--m-radius);\n padding: 0 10px;\n height: 32px;\n min-width: 0;\n}\n\n.mailharbor textarea {\n height: auto;\n padding: 8px 10px;\n resize: vertical;\n line-height: 1.6;\n}\n\n.mailharbor select {\n padding-right: 26px;\n appearance: none;\n background-image:\n linear-gradient(45deg, transparent 50%, var(--m-text-3) 50%),\n linear-gradient(135deg, var(--m-text-3) 50%, transparent 50%);\n background-position:\n calc(100% - 15px) 14px,\n calc(100% - 10px) 14px;\n background-size:\n 5px 5px,\n 5px 5px;\n background-repeat: no-repeat;\n}\n\n.mailharbor ::placeholder {\n color: var(--m-caption);\n}\n\n.mailharbor input:focus-visible,\n.mailharbor select:focus-visible,\n.mailharbor textarea:focus-visible,\n.mailharbor button:focus-visible,\n.mailharbor [contenteditable='true']:focus-visible {\n outline: 2px solid rgba(86, 134, 254, 0.55);\n outline-offset: -1px;\n}\n\n.mailharbor .spacer {\n flex: 1;\n}\n\n.mailharbor .muted {\n color: var(--m-text-3);\n}\n\n.mailharbor .small {\n font-size: 12px;\n}\n\n.mailharbor .badge {\n display: inline-flex;\n align-items: center;\n height: 18px;\n padding: 0 6px;\n border-radius: 999px;\n font-size: 10.5px;\n font-weight: 500;\n background: var(--m-bg-3);\n color: var(--m-text-2);\n}\n\n.mailharbor .badge.ok {\n background: rgba(63, 191, 127, 0.16);\n color: var(--m-ok);\n}\n\n.mailharbor .badge.warn {\n background: rgba(221, 134, 41, 0.16);\n color: var(--m-warn);\n}\n\n.mailharbor .error {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 14px;\n color: var(--m-danger);\n background: rgba(242, 90, 90, 0.1);\n border-bottom: 1px solid rgba(242, 90, 90, 0.2);\n font-size: 12.5px;\n}\n\n/* ---------- shell ---------- */\n\n.mailharbor-topbar {\n display: flex;\n align-items: center;\n gap: 10px;\n height: 52px;\n padding: 0 14px;\n border-bottom: 1px solid var(--m-line-soft);\n background: var(--m-bg);\n flex: none;\n}\n\n.mailharbor-account {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n max-width: 220px;\n padding: 4px 8px 4px 4px;\n border-radius: 999px;\n border: 1px solid transparent;\n cursor: default;\n}\n\n.mailharbor-account:hover {\n background: var(--m-hover);\n}\n\n.mailharbor-account .name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 500;\n}\n\n.mailharbor-account select {\n height: 26px;\n background: transparent;\n border-color: transparent;\n font-weight: 500;\n}\n\n.mailharbor-body {\n display: flex;\n flex: 1;\n min-height: 0;\n position: relative;\n}\n\n.mailharbor button.active {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.mailharbor-list {\n display: flex;\n flex-direction: column;\n width: 360px;\n flex: none;\n border-right: 1px solid var(--m-line-soft);\n min-height: 0;\n}\n\n.mailharbor-reader {\n flex: 1;\n min-width: 0;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n@media (max-width: 1000px) {\n .mailharbor-list {\n width: 300px;\n }\n}\n\n.mailharbor-narrow .mailharbor-body[data-mode='reader'] .mailharbor-list {\n display: none;\n}\n\n.mailharbor-narrow .mailharbor-body[data-mode='list'] .mailharbor-reader {\n display: none;\n}\n\n/* ---------- segmented control ---------- */\n\n.mailharbor-segment {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 2px;\n border-radius: 9px;\n background: var(--m-bg-2);\n}\n\n.mailharbor-segment button {\n height: 26px;\n padding: 0 12px;\n border-radius: 7px;\n color: var(--m-text-3);\n font-size: 12px;\n}\n\n.mailharbor-segment button:hover:not(.active) {\n color: var(--m-text-2);\n background: transparent;\n}\n\n.mailharbor-segment button.active {\n background: var(--m-bg-3);\n color: var(--m-text);\n}\n\n/* ---------- list ---------- */\n\n.mailharbor-filters {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-filters select {\n width: 128px;\n flex: none;\n font-size: 12px;\n}\n\n.mailharbor-filters input[type='search'] {\n flex: 1;\n height: 30px;\n font-size: 12.5px;\n}\n\n.mailharbor-rows {\n flex: 1;\n overflow: auto;\n min-height: 0;\n}\n\n.mailharbor-row {\n display: flex;\n flex-direction: column;\n gap: 3px;\n width: 100%;\n padding: 10px 14px;\n border: 0;\n border-bottom: 1px solid var(--m-line-soft);\n border-left: 2px solid transparent;\n border-radius: 0;\n background: transparent;\n color: inherit;\n text-align: left;\n cursor: pointer;\n user-select: none;\n}\n\n.mailharbor-row:hover {\n background: var(--m-hover);\n}\n\n.mailharbor-row.selected {\n background: var(--m-accent-soft);\n border-left-color: var(--m-accent);\n}\n\n.mailharbor-row .line-1,\n.mailharbor-row .line-2 {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n width: 100%;\n}\n\n.mailharbor-row .from {\n font-weight: 600;\n font-size: 12.5px;\n color: var(--m-text-2);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-row .date {\n margin-left: auto;\n color: var(--m-caption);\n font-size: 11px;\n flex: none;\n}\n\n.mailharbor-row .subject {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--m-text-2);\n font-size: 12.5px;\n}\n\n.mailharbor-row .snippet {\n color: var(--m-caption);\n font-size: 11.5px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n width: 100%;\n}\n\n.mailharbor-row.unread .from,\n.mailharbor-row.unread .subject {\n color: var(--m-text);\n}\n\n.mailharbor-row .dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--m-accent);\n flex: none;\n}\n\n.mailharbor-row .paperclip {\n color: var(--m-caption);\n flex: none;\n display: inline-flex;\n}\n\n.mailharbor-list-foot {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-top: 1px solid var(--m-line-soft);\n color: var(--m-text-3);\n font-size: 11.5px;\n flex: none;\n}\n\n.mailharbor-empty {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 10px;\n padding: 48px 24px;\n color: var(--m-text-3);\n text-align: center;\n}\n\n.mailharbor-empty svg {\n opacity: 0.5;\n}\n\n.mailharbor-empty .title {\n color: var(--m-text-2);\n font-size: 13px;\n font-weight: 500;\n}\n\n/* ---------- reader ---------- */\n\n.mailharbor-reader-head {\n padding: 16px 20px 12px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.mailharbor-reader-title {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n}\n\n.mailharbor-reader-title h2 {\n margin: 0;\n font-size: 17px;\n line-height: 1.35;\n font-weight: 600;\n letter-spacing: -0.01em;\n word-break: break-word;\n}\n\n.mailharbor-reader-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 4px 10px;\n color: var(--m-text-3);\n font-size: 12px;\n}\n\n.mailharbor-reader-meta .who {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n color: var(--m-text-2);\n}\n\n.mailharbor-reader-meta .who strong {\n color: var(--m-text);\n font-weight: 600;\n}\n\n.mailharbor-reader-actions {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.mailharbor-reader-body {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n padding: 14px 18px 18px;\n background: var(--m-bg-2);\n}\n\n.mailharbor-reader-body iframe {\n flex: 1;\n width: 100%;\n border: 0;\n border-radius: 10px;\n background: #fff;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);\n}\n\n.mailharbor-reader-body pre {\n flex: 1;\n overflow: auto;\n margin: 0;\n padding: 20px 22px;\n white-space: pre-wrap;\n word-break: break-word;\n background: #fff;\n border-radius: 10px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);\n color: #171a21;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12.5px;\n line-height: 1.7;\n}\n\n.mailharbor-attachments {\n padding: 10px 18px;\n border-top: 1px solid var(--m-line-soft);\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n flex: none;\n background: var(--m-bg);\n}\n\n.mailharbor-attachment {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n height: 30px;\n padding: 0 10px;\n border: 1px solid var(--m-line);\n border-radius: var(--m-radius);\n font-size: 12px;\n text-decoration: none;\n color: var(--m-text-2);\n max-width: 260px;\n background: var(--m-bg-1);\n}\n\n.mailharbor-attachment:hover {\n border-color: var(--m-line-strong);\n color: var(--m-text);\n}\n\n.mailharbor-attachment .name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* ---------- AI rail ---------- */\n\n.mailharbor-ai {\n display: flex;\n flex-direction: column;\n width: 340px;\n flex: none;\n min-height: 0;\n border-left: 1px solid var(--m-line-soft);\n background: var(--m-bg);\n}\n\n.mailharbor-ai-head {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 46px;\n padding: 0 8px 0 14px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-ai-head strong {\n font-size: 13px;\n font-weight: 600;\n}\n\n.mailharbor-ai-confirm {\n display: inline-flex;\n gap: 2px;\n}\n\n.mailharbor-ai-context {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 9px 14px 10px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-ai-context strong {\n font-size: 12.5px;\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-ai-warn {\n padding: 8px 14px;\n color: var(--m-warn);\n background: rgba(221, 134, 41, 0.1);\n font-size: 12px;\n flex: none;\n}\n\n.mailharbor-ai-quick {\n display: flex;\n gap: 6px;\n padding: 10px 14px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-ai-quick button {\n flex: 1;\n padding: 0 6px;\n}\n\n.mailharbor-ai-list {\n flex: 1;\n min-height: 0;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px 14px;\n}\n\n.mailharbor-ai-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 6px;\n padding: 30px 12px;\n text-align: center;\n color: var(--m-text-3);\n}\n\n.mailharbor-ai-empty .title {\n color: var(--m-text-2);\n font-weight: 500;\n font-size: 12.5px;\n}\n\n.mailharbor-ai-card {\n display: flex;\n flex-direction: column;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n overflow: hidden;\n}\n\n.mailharbor-ai-card.generating {\n opacity: 0.7;\n}\n\n.mailharbor-ai-card-head {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 7px 8px 7px 12px;\n border-bottom: 1px solid var(--m-line-soft);\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.mailharbor-ai-card-head > span:first-child {\n color: var(--m-text-2);\n font-weight: 600;\n}\n\n.mailharbor-ai-summary {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 10px 12px;\n}\n\n.mailharbor-ai-summary section h4 {\n margin: 0 0 3px;\n font-size: 11px;\n color: var(--m-text-3);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.mailharbor-ai-summary section p {\n margin: 0;\n white-space: pre-wrap;\n font-size: 12.5px;\n line-height: 1.65;\n color: var(--m-text);\n}\n\n.mailharbor-ai-text {\n padding: 10px 12px;\n max-height: 320px;\n overflow: auto;\n white-space: pre-wrap;\n font-size: 12.5px;\n line-height: 1.65;\n color: var(--m-text);\n}\n\n.mailharbor-ai-card-actions {\n display: flex;\n align-items: center;\n gap: 4px;\n flex-wrap: wrap;\n padding: 6px 8px;\n border-top: 1px solid var(--m-line-soft);\n}\n\n.mailharbor-ai-card-actions button {\n height: 26px;\n padding: 0 8px;\n font-size: 11.5px;\n}\n\n.mailharbor-ai-ask {\n display: flex;\n gap: 6px;\n padding: 10px 12px;\n border-top: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-ai-ask input {\n flex: 1;\n height: 32px;\n}\n\n.mailharbor-ai-error {\n color: var(--m-danger);\n font-size: 12px;\n padding: 0 2px;\n}\n\n@media (max-width: 1280px) {\n .mailharbor-ai {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n width: min(420px, 94%);\n z-index: 6;\n border-left: 1px solid var(--m-line);\n box-shadow: -12px 0 40px rgba(0, 0, 0, 0.45);\n }\n}\n\n/* ---------- AI summary ---------- */\n\n.mailharbor-divider {\n width: 1px;\n height: 18px;\n margin: 0 4px;\n background: var(--m-line);\n}\n\n.mailharbor-summary {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.mailharbor-summary section h4 {\n margin: 0 0 6px;\n font-size: 11.5px;\n font-weight: 600;\n color: var(--m-text-3);\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n\n.mailharbor-summary section p {\n margin: 0;\n white-space: pre-wrap;\n line-height: 1.75;\n color: var(--m-text);\n}\n\n/* ---------- modal / forms ---------- */\n\n.mailharbor-portal {\n position: fixed;\n inset: 0;\n z-index: 80;\n height: auto;\n background: transparent;\n pointer-events: none;\n}\n\n.mailharbor-portal .mailharbor-modal-mask {\n pointer-events: auto;\n}\n\n.mailharbor-modal-mask {\n position: fixed;\n inset: 0;\n z-index: 60;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n background: rgba(0, 0, 0, 0.55);\n backdrop-filter: blur(2px);\n}\n\n.mailharbor-modal {\n display: flex;\n flex-direction: column;\n width: min(720px, 100%);\n max-height: 86vh;\n overflow: hidden;\n border: 1px solid var(--m-line);\n border-radius: 14px;\n background: var(--m-bg-1);\n color: var(--m-text);\n box-shadow: var(--m-shadow);\n}\n\n.mailharbor-modal > header {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 52px;\n padding: 0 14px 0 18px;\n border-bottom: 1px solid var(--m-line-soft);\n font-size: 14px;\n font-weight: 600;\n}\n\n.mailharbor-modal .content {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 18px;\n overflow: auto;\n}\n\n.mailharbor-modal > footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 18px;\n border-top: 1px solid var(--m-line-soft);\n}\n\n.mailharbor-field {\n display: flex;\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n}\n\n.mailharbor-field > input,\n.mailharbor-field > select,\n.mailharbor-field > textarea,\n.mailharbor-card > textarea {\n width: 100%;\n min-width: 0;\n}\n\n.mailharbor-field > label {\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.mailharbor-grid {\n display: grid;\n grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);\n gap: 10px;\n min-width: 0;\n}\n\n.mailharbor-grid.three {\n grid-template-columns: minmax(0, 2fr) minmax(72px, 90px) auto;\n align-items: end;\n min-width: 0;\n}\n\n.mailharbor-toggle {\n display: inline-flex;\n align-items: center;\n gap: 7px;\n color: var(--m-text-2);\n font-size: 12.5px;\n cursor: pointer;\n white-space: nowrap;\n}\n\n.mailharbor-toggle input[type='checkbox'] {\n width: 14px;\n height: 14px;\n accent-color: var(--m-accent);\n}\n\n/* ---------- composer ---------- */\n\n.mailharbor-toolbar {\n display: flex;\n align-items: center;\n gap: 2px;\n flex-wrap: wrap;\n padding: 6px;\n border: 1px solid var(--m-line-soft);\n border-bottom: 0;\n border-radius: 10px 10px 0 0;\n background: var(--m-bg-2);\n}\n\n.mailharbor-toolbar button {\n height: 26px;\n padding: 0 9px;\n border-radius: 6px;\n color: var(--m-text-2);\n font-size: 12px;\n}\n\n.mailharbor-toolbar button:hover {\n background: var(--m-bg-3);\n color: var(--m-text);\n}\n\n.mailharbor-editor {\n min-height: 240px;\n max-height: 44vh;\n overflow: auto;\n padding: 14px 16px;\n border: 1px solid var(--m-line-soft);\n border-radius: 0 0 10px 10px;\n background: #fff;\n color: #171a21;\n outline: none;\n font-size: 13.5px;\n line-height: 1.7;\n}\n\n.mailharbor-editor:empty::before {\n content: attr(data-placeholder);\n color: #9aa0ab;\n}\n\n/* ---------- inline confirm ---------- */\n\n.mailharbor-confirm {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--m-line);\n background: var(--m-bg-2);\n color: var(--m-text-2);\n font-size: 12.5px;\n}\n\n/* ---------- selection / extraction ---------- */\n\n.mailharbor-selectbar {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n margin: 0 12px 8px;\n border: 1px solid var(--m-accent-soft);\n border-radius: 9px;\n background: var(--m-accent-soft);\n}\n\n.mailharbor-selectbar select {\n height: 28px;\n max-width: 200px;\n}\n\n.mailharbor-row.selectable input[type='checkbox'] {\n width: 15px;\n height: 15px;\n flex: none;\n accent-color: var(--m-accent);\n}\n\n.mailharbor-extract-row {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n padding: 9px 10px;\n border: 1px solid var(--m-line-soft);\n border-radius: 9px;\n background: var(--m-bg-1);\n cursor: pointer;\n}\n\n.mailharbor-extract-row input {\n margin-top: 2px;\n accent-color: var(--m-accent);\n}\n\n.mailharbor-extract-row > span {\n display: flex;\n flex-direction: column;\n gap: 3px;\n min-width: 0;\n}\n\n.mailharbor-kv {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr);\n gap: 6px 12px;\n margin: 0;\n font-size: 12.5px;\n}\n\n.mailharbor-kv dt {\n color: var(--m-text-3);\n}\n\n.mailharbor-kv dd {\n margin: 0;\n overflow-wrap: anywhere;\n}\n\n/* ---------- tasks panel ---------- */\n\n.mailharbor .chip {\n height: 26px;\n padding: 0 10px;\n border: 1px solid var(--m-line);\n border-radius: 999px;\n color: var(--m-text-3);\n font-size: 12px;\n}\n\n.mailharbor .chip.active {\n background: var(--m-accent-soft);\n border-color: transparent;\n color: var(--m-text);\n}\n\n.tasks-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 18px;\n padding: 18px 20px 48px;\n width: 100%;\n max-width: 940px;\n margin: 0 auto;\n}\n\n.tasks-overview {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));\n gap: 12px;\n}\n\n.tasks-progress,\n.tasks-project {\n display: flex;\n flex-direction: column;\n gap: 7px;\n padding: 12px 14px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n min-width: 0;\n}\n\n.tasks-progress-head,\n.tasks-project-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n min-width: 0;\n}\n\n.tasks-project-head .name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12.5px;\n font-weight: 500;\n}\n\n.tasks-bar {\n height: 6px;\n border-radius: 999px;\n background: var(--m-bg-3);\n overflow: hidden;\n}\n\n.tasks-bar span {\n display: block;\n height: 100%;\n border-radius: 999px;\n background: var(--m-accent);\n transition: width 200ms ease;\n}\n\n.tasks-bar.small {\n height: 4px;\n}\n\n.tasks-filters {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n.tasks-list {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.tasks-row {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 9px 12px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n}\n\n.tasks-row input[type='checkbox'] {\n width: 16px;\n height: 16px;\n flex: none;\n accent-color: var(--m-accent);\n}\n\n.tasks-row .tasks-title {\n flex: 1;\n min-width: 0;\n height: auto;\n padding: 0;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n text-align: left;\n border: 0;\n background: transparent;\n}\n\n.tasks-row .tasks-title:hover {\n background: transparent;\n}\n\n.tasks-row .tasks-title > span:first-child {\n font-size: 13px;\n color: var(--m-text);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 100%;\n}\n\n.tasks-row.done .tasks-title > span:first-child {\n color: var(--m-text-3);\n text-decoration: line-through;\n}\n\n.tasks-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.tasks-meta .due.overdue {\n color: var(--m-danger);\n}\n\n.tasks-list-wrap {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n/* ---------- markdown ---------- */\n\n.mailharbor-markdown {\n display: flex;\n flex-direction: column;\n gap: 8px;\n font-size: 12.5px;\n line-height: 1.68;\n overflow-wrap: anywhere;\n}\n\n.mailharbor-markdown > *:first-child {\n margin-top: 0;\n}\n\n.mailharbor-markdown > *:last-child {\n margin-bottom: 0;\n}\n\n.mailharbor-markdown p {\n margin: 0;\n white-space: pre-wrap;\n}\n\n.mailharbor-markdown h1,\n.mailharbor-markdown h2,\n.mailharbor-markdown h3,\n.mailharbor-markdown h4,\n.mailharbor-markdown h5,\n.mailharbor-markdown h6 {\n margin: 4px 0 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--m-text);\n}\n\n.mailharbor-markdown ul,\n.mailharbor-markdown ol {\n margin: 0;\n padding-left: 20px;\n display: flex;\n flex-direction: column;\n gap: 3px;\n}\n\n.mailharbor-markdown li::marker {\n color: var(--m-text-3);\n}\n\n.mailharbor-markdown a {\n color: var(--m-accent);\n text-decoration: none;\n}\n\n.mailharbor-markdown a:hover {\n text-decoration: underline;\n}\n\n.mailharbor-markdown code {\n padding: 1px 4px;\n border-radius: 4px;\n background: var(--m-bg-2);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11.5px;\n}\n\n.mailharbor-markdown pre {\n margin: 0;\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--m-bg);\n border: 1px solid var(--m-line-soft);\n overflow: auto;\n}\n\n.mailharbor-markdown pre code {\n padding: 0;\n background: transparent;\n}\n\n.mailharbor-markdown blockquote {\n margin: 0;\n padding-left: 10px;\n border-left: 2px solid var(--m-line);\n color: var(--m-text-2);\n}\n\n.mailharbor-markdown hr {\n width: 100%;\n margin: 4px 0;\n border: 0;\n border-top: 1px solid var(--m-line-soft);\n}\n\n/* ---------- composer AI ---------- */\n\n.mailharbor-toolbar button.ai {\n color: var(--m-accent);\n}\n\n.mailharbor-compose-foot {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n flex-wrap: wrap;\n}\n\n.mailharbor-versions {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n padding-top: 8px;\n}\n\n.mailharbor-versions .chip {\n height: 22px;\n padding: 0 8px;\n border: 1px solid var(--m-line);\n border-radius: 999px;\n color: var(--m-text-3);\n font-size: 11px;\n}\n\n.mailharbor-versions .chip.active {\n background: var(--m-accent-soft);\n border-color: transparent;\n color: var(--m-text);\n}\n\n/* ---------- settings ---------- */\n\n.mailharbor.mailharbor-settings-page {\n height: auto;\n min-height: 100%;\n overflow: visible;\n}\n\n.mailharbor-settings {\n flex: 0 0 auto;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n padding: 18px 20px 48px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n overflow-x: hidden;\n}\n\n.mailharbor-settings > * {\n min-width: 0;\n}\n\n.mailharbor-settings h2 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n letter-spacing: -0.01em;\n}\n\n.mailharbor-settings h3 {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--m-text-3);\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n\n.mailharbor-card {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n min-width: 0;\n overflow: hidden;\n}\n\n.mailharbor-account-row {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.mailharbor-account-row .meta {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.mailharbor-account-row .meta strong {\n font-weight: 600;\n}\n\n.mailharbor-account-row .meta span {\n color: var(--m-text-3);\n font-size: 11.5px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mailharbor .avatar {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n border-radius: 50%;\n background: var(--m-accent-soft);\n color: var(--m-accent);\n font-weight: 600;\n}\n\n.mailharbor-log {\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--m-bg);\n border: 1px solid var(--m-line-soft);\n color: var(--m-text-2);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11px;\n line-height: 1.6;\n max-height: 220px;\n overflow: auto;\n white-space: pre-wrap;\n}\n\n.mailharbor-kv {\n display: grid;\n grid-template-columns: minmax(120px, 170px) 1fr;\n gap: 6px 14px;\n font-size: 12px;\n margin: 0;\n}\n\n.mailharbor-kv dt {\n color: var(--m-text-3);\n}\n\n.mailharbor-kv dd {\n margin: 0;\n color: var(--m-text-2);\n word-break: break-all;\n}\n\n.mailharbor hr {\n border: 0;\n border-top: 1px solid var(--m-line-soft);\n margin: 2px 0;\n}\n\n/* ---------- conversation rows ---------- */\n\n.mailharbor-thread {\n display: flex;\n flex-direction: column;\n}\n\n.mailharbor-row.compact {\n padding-top: 6px;\n padding-bottom: 6px;\n padding-left: 34px;\n background: var(--m-bg);\n}\n\n.mailharbor-row.compact .line-1 {\n opacity: 0.85;\n}\n\n.mailharbor-row.compact .snippet {\n -webkit-line-clamp: 1;\n}\n\n.mailharbor .to-label {\n font-size: 10.5px;\n color: var(--m-text-3);\n flex: none;\n}\n\n.mailharbor .thread-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n border-radius: 999px;\n background: var(--m-bg-3);\n color: var(--m-text-2);\n font-size: 10.5px;\n flex: none;\n}\n\n.mailharbor .thread-count:hover {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.mailharbor-account {\n height: auto;\n padding: 3px 8px 3px 3px;\n border-radius: 8px;\n gap: 8px;\n}\n\n.mailharbor-account:hover {\n background: var(--m-hover);\n}\n\n/* ---------- mailbox sidebar ---------- */\n\n.mailharbor-side {\n display: flex;\n flex-direction: column;\n gap: 2px;\n width: 214px;\n flex: none;\n padding: 10px 8px;\n overflow: auto;\n border-right: 1px solid var(--m-line-soft);\n background: var(--m-bg);\n}\n\n.mailharbor-side-section {\n padding: 12px 8px 4px;\n font-size: 10.5px;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n color: var(--m-text-3);\n}\n\n.mailharbor-side-item {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n height: 32px;\n padding: 0 8px;\n border-radius: 8px;\n color: var(--m-text-2);\n font-size: 12.5px;\n text-align: left;\n flex: none;\n}\n\n.mailharbor-side-item:hover {\n background: var(--m-hover);\n}\n\n.mailharbor-side-item.active {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.mailharbor-side-item .name {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-side-item .sub {\n display: block;\n font-size: 10.5px;\n color: var(--m-text-3);\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mailharbor-side-item .count {\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.mailharbor-side-item svg {\n flex: none;\n color: var(--m-text-3);\n}\n\n.mailharbor-side-item.active svg {\n color: var(--m-accent);\n}\n\n@media (max-width: 900px) {\n .mailharbor-side {\n display: none;\n }\n}\n\n/* ---------- task board ---------- */\n\n.tasks-board-wrap {\n flex: 1;\n min-height: 0;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 14px;\n padding: 16px 18px 40px;\n}\n\n.tasks-summary {\n display: flex;\n align-items: center;\n gap: 20px;\n padding: 14px 16px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n}\n\n.tasks-summary-main {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 7px;\n}\n\n.tasks-summary-labels {\n display: flex;\n align-items: baseline;\n gap: 10px;\n}\n\n.tasks-stats {\n display: flex;\n gap: 18px;\n}\n\n.tasks-stat {\n display: flex;\n flex-direction: column;\n gap: 1px;\n min-width: 42px;\n}\n\n.tasks-stat strong {\n font-size: 16px;\n font-weight: 600;\n color: var(--m-text);\n}\n\n.tasks-stat span {\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.tasks-stat.danger strong {\n color: var(--m-danger);\n}\n\n.tasks-toolbar {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.tasks-board {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: 14px;\n align-items: start;\n}\n\n.task-column {\n display: flex;\n flex-direction: column;\n gap: 8px;\n min-height: 140px;\n padding: 8px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n}\n\n.task-column-head {\n display: flex;\n align-items: center;\n gap: 7px;\n padding: 2px 4px 6px;\n}\n\n.task-column-head strong {\n font-size: 12.5px;\n font-weight: 600;\n}\n\n.task-column-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n border-radius: 999px;\n background: var(--m-bg-3);\n color: var(--m-text-3);\n font-size: 10.5px;\n}\n\n.task-dot {\n width: 7px;\n height: 7px;\n border-radius: 999px;\n background: var(--m-text-3);\n}\n\n.task-dot.NEEDS-ACTION {\n background: #8a8f98;\n}\n\n.task-dot.IN-PROCESS {\n background: var(--m-accent);\n}\n\n.task-dot.COMPLETED {\n background: var(--m-ok);\n}\n\n.task-dot.CANCELLED {\n background: var(--m-danger);\n opacity: 0.7;\n}\n\n.task-column-body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n min-height: 60px;\n}\n\n.task-column-empty {\n padding: 18px 8px;\n text-align: center;\n color: var(--m-text-3);\n font-size: 11.5px;\n border: 1px dashed var(--m-line-soft);\n border-radius: 9px;\n}\n\n.task-card {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 10px 11px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg);\n cursor: grab;\n transition:\n border-color 120ms ease,\n box-shadow 120ms ease;\n}\n\n.task-card:hover {\n border-color: var(--m-line);\n box-shadow: 0 4px 14px rgba(0, 0, 0, 0.16);\n}\n\n.task-card.dragging {\n opacity: 0.5;\n}\n\n.task-card-top {\n display: flex;\n align-items: flex-start;\n gap: 7px;\n}\n\n.task-card-title {\n flex: 1;\n min-width: 0;\n font-size: 12.5px;\n line-height: 1.45;\n color: var(--m-text);\n overflow-wrap: anywhere;\n}\n\n.task-priority {\n width: 3px;\n height: 14px;\n margin-top: 2px;\n border-radius: 999px;\n background: transparent;\n flex: none;\n}\n\n.task-priority.p5 {\n background: #d9a441;\n}\n\n.task-priority.p9 {\n background: var(--m-danger);\n}\n\n.task-card-delete {\n width: 18px;\n height: 18px;\n flex: none;\n border-radius: 5px;\n color: var(--m-text-3);\n opacity: 0;\n}\n\n.task-card:hover .task-card-delete {\n opacity: 1;\n}\n\n.task-card-notes {\n margin: 0;\n font-size: 11.5px;\n line-height: 1.55;\n color: var(--m-text-3);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.task-card-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n font-size: 10.5px;\n color: var(--m-text-3);\n}\n\n.task-due,\n.task-owner,\n.task-project,\n.task-priority-label {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n padding: 1px 6px;\n border-radius: 5px;\n background: var(--m-bg-2);\n}\n\n.task-due.overdue {\n color: var(--m-danger);\n background: rgba(242, 90, 90, 0.12);\n}\n\n.task-project {\n color: var(--m-accent);\n background: var(--m-accent-soft);\n}\n\n.task-source {\n align-self: flex-start;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n height: 22px;\n padding: 0 6px;\n border-radius: 5px;\n color: var(--m-text-3);\n font-size: 10.5px;\n}\n\n.task-source:hover {\n background: var(--m-hover);\n color: var(--m-text-2);\n}\n\n@media (max-width: 1180px) {\n .tasks-board {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n}\n\n@media (max-width: 720px) {\n .tasks-board {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n/* ---------- AI search ---------- */\n\n.mailharbor-ai-search {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0 12px 8px;\n padding: 7px 10px;\n border-radius: 8px;\n background: var(--m-accent-soft);\n color: var(--m-text-2);\n font-size: 12px;\n}\n\n.mailharbor-ai-search.searching {\n background: var(--m-bg-2);\n color: var(--m-text-3);\n}\n\n/* ---------- task editor ---------- */\n\n.mailharbor-tasks .mailharbor-modal {\n max-width: 760px;\n}\n\n.task-editor {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 230px;\n gap: 18px;\n}\n\n.task-editor-main {\n display: flex;\n flex-direction: column;\n gap: 14px;\n min-width: 0;\n}\n\n.task-editor-title input {\n width: 100%;\n height: 38px;\n font-size: 15px;\n font-weight: 500;\n}\n\n.task-editor-section {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.task-editor-section label,\n.task-editor-field label {\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.task-editor-section textarea {\n width: 100%;\n resize: vertical;\n}\n\n.task-editor-side {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 12px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n align-self: start;\n}\n\n.task-editor-field {\n display: flex;\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n}\n\n.task-editor-field input,\n.task-editor-field select {\n width: 100%;\n}\n\n.task-priority-picker {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 4px;\n padding: 3px;\n border: 1px solid var(--m-line);\n border-radius: 8px;\n background: var(--m-bg);\n}\n\n.task-priority-picker button {\n height: 26px;\n border-radius: 6px;\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.task-priority-picker button.active {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.task-editor-foot {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n}\n\n/* ---------- project manager ---------- */\n\n.project-manager {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.project-manager-row {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 12px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n}\n\n.project-manager-main {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 3px;\n}\n\n.project-manager-main strong {\n font-size: 13px;\n}\n\n.project-manager-main .small {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.project-manager-main input {\n width: 100%;\n height: 28px;\n}\n\n.project-manager-actions {\n display: flex;\n gap: 4px;\n flex: none;\n align-items: center;\n}\n";
|
|
38
|
+
var styles_default = "/* MailHarbor panel + settings.\n Tokens come from the DSH shell (dark by default); fallbacks match the\n default dark theme so the panel also renders in a bare host page.\n Component rules are all scoped under `.mailharbor` and the generic element\n reset lives in `:where()` so it cannot outrank a component class. */\n\n.mailharbor {\n --m-bg: var(--dsw-alias-bg-base, #151517);\n --m-bg-1: var(--dsw-alias-bg-layer-1, #232324);\n --m-bg-2: var(--dsw-alias-bg-layer-2, #2c2c2e);\n --m-bg-3: var(--dsw-alias-bg-layer-3, #353638);\n --m-line: var(--dsw-alias-border-l2, #ffffff1f);\n --m-line-soft: var(--dsw-alias-border-l1, #ffffff0f);\n --m-line-strong: var(--dsw-alias-border-l3, #ffffff29);\n --m-text: var(--dsw-alias-label-primary, #f9fafb);\n --m-text-2: var(--dsw-alias-label-secondary, #cfd3d6);\n --m-text-3: var(--dsw-alias-label-tertiary, #adb2b8);\n --m-caption: var(--dsw-alias-label-caption, #81858c);\n --m-accent: #5686fe;\n --m-accent-soft: rgba(86, 134, 254, 0.14);\n --m-primary-bg: var(--dsw-alias-brand-primary, #f9fafb);\n --m-primary-fg: var(--dsw-alias-label-primary-foreground, #0f1115);\n --m-hover: var(--dsw-alias-interactive-bg-hover, #ffffff14);\n --m-danger: #f25a5a;\n --m-ok: #3fbf7f;\n --m-warn: var(--dsw-alias-state-warn-label, #dd8629);\n --m-radius: 8px;\n --m-shadow: 0 18px 60px rgba(0, 0, 0, 0.5);\n\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n background: var(--m-bg);\n color: var(--m-text);\n font-size: 13px;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n}\n\n.mailharbor *,\n.mailharbor *::before,\n.mailharbor *::after {\n box-sizing: border-box;\n}\n\n/* ---------- base controls ---------- */\n\n.mailharbor :where(button) {\n font: inherit;\n color: inherit;\n background: transparent;\n border: 0;\n margin: 0;\n cursor: pointer;\n}\n\n.mailharbor button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n height: 30px;\n padding: 0 12px;\n border-radius: var(--m-radius);\n border: 1px solid transparent;\n color: var(--m-text-2);\n font-size: 12.5px;\n font-weight: 500;\n white-space: nowrap;\n transition:\n background 120ms ease,\n color 120ms ease,\n border-color 120ms ease;\n}\n\n.mailharbor button:hover:not(:disabled) {\n background: var(--m-hover);\n color: var(--m-text);\n}\n\n.mailharbor button:disabled {\n opacity: 0.45;\n cursor: default;\n}\n\n.mailharbor button.primary {\n background: var(--m-primary-bg);\n color: var(--m-primary-fg);\n border-color: transparent;\n}\n\n.mailharbor button.primary:hover:not(:disabled) {\n background: var(--m-primary-bg);\n filter: brightness(0.94);\n color: var(--m-primary-fg);\n}\n\n.mailharbor button.ghost {\n border-color: var(--m-line);\n color: var(--m-text-2);\n}\n\n.mailharbor button.ghost:hover:not(:disabled) {\n border-color: var(--m-line-strong);\n color: var(--m-text);\n}\n\n.mailharbor button.subtle {\n color: var(--m-text-3);\n padding: 0 8px;\n}\n\n.mailharbor button.icon {\n width: 30px;\n padding: 0;\n}\n\n.mailharbor button.danger {\n color: var(--m-danger);\n}\n\n.mailharbor input,\n.mailharbor select,\n.mailharbor textarea {\n font: inherit;\n color: var(--m-text);\n background: var(--m-bg-1);\n border: 1px solid var(--m-line);\n border-radius: var(--m-radius);\n padding: 0 10px;\n height: 32px;\n min-width: 0;\n}\n\n.mailharbor textarea {\n height: auto;\n padding: 8px 10px;\n resize: vertical;\n line-height: 1.6;\n}\n\n.mailharbor select {\n padding-right: 26px;\n appearance: none;\n background-image:\n linear-gradient(45deg, transparent 50%, var(--m-text-3) 50%),\n linear-gradient(135deg, var(--m-text-3) 50%, transparent 50%);\n background-position:\n calc(100% - 15px) 14px,\n calc(100% - 10px) 14px;\n background-size:\n 5px 5px,\n 5px 5px;\n background-repeat: no-repeat;\n}\n\n.mailharbor ::placeholder {\n color: var(--m-caption);\n}\n\n.mailharbor input:focus-visible,\n.mailharbor select:focus-visible,\n.mailharbor textarea:focus-visible,\n.mailharbor button:focus-visible,\n.mailharbor [contenteditable='true']:focus-visible {\n outline: 2px solid rgba(86, 134, 254, 0.55);\n outline-offset: -1px;\n}\n\n.mailharbor .spacer {\n flex: 1;\n}\n\n.mailharbor .muted {\n color: var(--m-text-3);\n}\n\n.mailharbor .small {\n font-size: 12px;\n}\n\n.mailharbor .badge {\n display: inline-flex;\n align-items: center;\n height: 18px;\n padding: 0 6px;\n border-radius: 999px;\n font-size: 10.5px;\n font-weight: 500;\n background: var(--m-bg-3);\n color: var(--m-text-2);\n}\n\n.mailharbor .badge.ok {\n background: rgba(63, 191, 127, 0.16);\n color: var(--m-ok);\n}\n\n.mailharbor .badge.warn {\n background: rgba(221, 134, 41, 0.16);\n color: var(--m-warn);\n}\n\n.mailharbor .error {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 14px;\n color: var(--m-danger);\n background: rgba(242, 90, 90, 0.1);\n border-bottom: 1px solid rgba(242, 90, 90, 0.2);\n font-size: 12.5px;\n}\n\n/* ---------- shell ---------- */\n\n.mailharbor-topbar {\n display: flex;\n align-items: center;\n gap: 10px;\n height: 52px;\n padding: 0 14px;\n border-bottom: 1px solid var(--m-line-soft);\n background: var(--m-bg);\n flex: none;\n}\n\n.mailharbor-account {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n max-width: 220px;\n padding: 4px 8px 4px 4px;\n border-radius: 999px;\n border: 1px solid transparent;\n cursor: default;\n}\n\n.mailharbor-account:hover {\n background: var(--m-hover);\n}\n\n.mailharbor-account .name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 500;\n}\n\n.mailharbor-account select {\n height: 26px;\n background: transparent;\n border-color: transparent;\n font-weight: 500;\n}\n\n.mailharbor-body {\n display: flex;\n flex: 1;\n min-height: 0;\n position: relative;\n}\n\n.mailharbor button.active {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.mailharbor-list {\n display: flex;\n flex-direction: column;\n width: 360px;\n flex: none;\n border-right: 1px solid var(--m-line-soft);\n min-height: 0;\n}\n\n.mailharbor-reader {\n flex: 1;\n min-width: 0;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n@media (max-width: 1000px) {\n .mailharbor-list {\n width: 300px;\n }\n}\n\n.mailharbor-narrow .mailharbor-body[data-mode='reader'] .mailharbor-list {\n display: none;\n}\n\n.mailharbor-narrow .mailharbor-body[data-mode='list'] .mailharbor-reader {\n display: none;\n}\n\n/* ---------- segmented control ---------- */\n\n.mailharbor-segment {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 2px;\n border-radius: 9px;\n background: var(--m-bg-2);\n}\n\n.mailharbor-segment button {\n height: 26px;\n padding: 0 12px;\n border-radius: 7px;\n color: var(--m-text-3);\n font-size: 12px;\n}\n\n.mailharbor-segment button:hover:not(.active) {\n color: var(--m-text-2);\n background: transparent;\n}\n\n.mailharbor-segment button.active {\n background: var(--m-bg-3);\n color: var(--m-text);\n}\n\n/* ---------- list ---------- */\n\n.mailharbor-filters {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 12px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-filters select {\n width: 128px;\n flex: none;\n font-size: 12px;\n}\n\n.mailharbor-filters input[type='search'] {\n flex: 1;\n height: 30px;\n font-size: 12.5px;\n}\n\n.mailharbor-rows {\n flex: 1;\n overflow: auto;\n min-height: 0;\n}\n\n.mailharbor-row {\n display: flex;\n flex-direction: column;\n gap: 3px;\n width: 100%;\n padding: 10px 14px;\n border: 0;\n border-bottom: 1px solid var(--m-line-soft);\n border-left: 2px solid transparent;\n border-radius: 0;\n background: transparent;\n color: inherit;\n text-align: left;\n cursor: pointer;\n user-select: none;\n}\n\n.mailharbor-row:hover {\n background: var(--m-hover);\n}\n\n.mailharbor-row.selected {\n background: var(--m-accent-soft);\n border-left-color: var(--m-accent);\n}\n\n.mailharbor-row .line-1,\n.mailharbor-row .line-2 {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n width: 100%;\n}\n\n.mailharbor-row .from {\n font-weight: 600;\n font-size: 12.5px;\n color: var(--m-text-2);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-row .date {\n margin-left: auto;\n color: var(--m-caption);\n font-size: 11px;\n flex: none;\n}\n\n.mailharbor-row .subject {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--m-text-2);\n font-size: 12.5px;\n}\n\n.mailharbor-row .snippet {\n color: var(--m-caption);\n font-size: 11.5px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n width: 100%;\n}\n\n.mailharbor-row.unread .from,\n.mailharbor-row.unread .subject {\n color: var(--m-text);\n}\n\n.mailharbor-row .dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--m-accent);\n flex: none;\n}\n\n.mailharbor-row .paperclip {\n color: var(--m-caption);\n flex: none;\n display: inline-flex;\n}\n\n.mailharbor-list-foot {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-top: 1px solid var(--m-line-soft);\n color: var(--m-text-3);\n font-size: 11.5px;\n flex: none;\n}\n\n.mailharbor-empty {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 10px;\n padding: 48px 24px;\n color: var(--m-text-3);\n text-align: center;\n}\n\n.mailharbor-empty svg {\n opacity: 0.5;\n}\n\n.mailharbor-empty .title {\n color: var(--m-text-2);\n font-size: 13px;\n font-weight: 500;\n}\n\n/* ---------- reader ---------- */\n\n.mailharbor-reader-head {\n padding: 16px 20px 12px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.mailharbor-reader-title {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n}\n\n.mailharbor-reader-title h2 {\n margin: 0;\n font-size: 17px;\n line-height: 1.35;\n font-weight: 600;\n letter-spacing: -0.01em;\n word-break: break-word;\n}\n\n.mailharbor-reader-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 4px 10px;\n color: var(--m-text-3);\n font-size: 12px;\n}\n\n.mailharbor-reader-meta .who {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n color: var(--m-text-2);\n}\n\n.mailharbor-reader-meta .who strong {\n color: var(--m-text);\n font-weight: 600;\n}\n\n.mailharbor-reader-actions {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.mailharbor-reader-body {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n padding: 14px 18px 18px;\n background: var(--m-bg-2);\n}\n\n.mailharbor-reader-body iframe {\n flex: 1;\n width: 100%;\n border: 0;\n border-radius: 10px;\n background: #fff;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);\n}\n\n.mailharbor-reader-body pre {\n flex: 1;\n overflow: auto;\n margin: 0;\n padding: 20px 22px;\n white-space: pre-wrap;\n word-break: break-word;\n background: #fff;\n border-radius: 10px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);\n color: #171a21;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12.5px;\n line-height: 1.7;\n}\n\n.mailharbor-attachments {\n padding: 10px 18px;\n border-top: 1px solid var(--m-line-soft);\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n flex: none;\n background: var(--m-bg);\n}\n\n.mailharbor-attachment {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n height: 30px;\n padding: 0 10px;\n border: 1px solid var(--m-line);\n border-radius: var(--m-radius);\n font-size: 12px;\n text-decoration: none;\n color: var(--m-text-2);\n max-width: 260px;\n background: var(--m-bg-1);\n}\n\n.mailharbor-attachment:hover {\n border-color: var(--m-line-strong);\n color: var(--m-text);\n}\n\n.mailharbor-attachment .name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* ---------- AI rail ---------- */\n\n.mailharbor-ai {\n display: flex;\n flex-direction: column;\n width: 340px;\n flex: none;\n min-height: 0;\n border-left: 1px solid var(--m-line-soft);\n background: var(--m-bg);\n}\n\n.mailharbor-ai-head {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 46px;\n padding: 0 8px 0 14px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-ai-head strong {\n font-size: 13px;\n font-weight: 600;\n}\n\n.mailharbor-ai-confirm {\n display: inline-flex;\n gap: 2px;\n}\n\n.mailharbor-ai-context {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 9px 14px 10px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-ai-context strong {\n font-size: 12.5px;\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-ai-warn {\n padding: 8px 14px;\n color: var(--m-warn);\n background: rgba(221, 134, 41, 0.1);\n font-size: 12px;\n flex: none;\n}\n\n.mailharbor-ai-quick {\n display: flex;\n gap: 6px;\n padding: 10px 14px;\n border-bottom: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-ai-quick button {\n flex: 1;\n padding: 0 6px;\n}\n\n.mailharbor-ai-list {\n flex: 1;\n min-height: 0;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 12px 14px;\n}\n\n.mailharbor-ai-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 6px;\n padding: 30px 12px;\n text-align: center;\n color: var(--m-text-3);\n}\n\n.mailharbor-ai-empty .title {\n color: var(--m-text-2);\n font-weight: 500;\n font-size: 12.5px;\n}\n\n.mailharbor-ai-card {\n display: flex;\n flex-direction: column;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n overflow: hidden;\n}\n\n.mailharbor-ai-card.generating {\n opacity: 0.7;\n}\n\n.mailharbor-ai-card-head {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 7px 8px 7px 12px;\n border-bottom: 1px solid var(--m-line-soft);\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.mailharbor-ai-card-head > span:first-child {\n color: var(--m-text-2);\n font-weight: 600;\n}\n\n.mailharbor-ai-summary {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 10px 12px;\n}\n\n.mailharbor-ai-summary section h4 {\n margin: 0 0 3px;\n font-size: 11px;\n color: var(--m-text-3);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.mailharbor-ai-summary section p {\n margin: 0;\n white-space: pre-wrap;\n font-size: 12.5px;\n line-height: 1.65;\n color: var(--m-text);\n}\n\n.mailharbor-ai-text {\n padding: 10px 12px;\n max-height: 320px;\n overflow: auto;\n white-space: pre-wrap;\n font-size: 12.5px;\n line-height: 1.65;\n color: var(--m-text);\n}\n\n.mailharbor-ai-card-actions {\n display: flex;\n align-items: center;\n gap: 4px;\n flex-wrap: wrap;\n padding: 6px 8px;\n border-top: 1px solid var(--m-line-soft);\n}\n\n.mailharbor-ai-card-actions button {\n height: 26px;\n padding: 0 8px;\n font-size: 11.5px;\n}\n\n.mailharbor-ai-ask {\n display: flex;\n gap: 6px;\n padding: 10px 12px;\n border-top: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-ai-ask input {\n flex: 1;\n height: 32px;\n}\n\n.mailharbor-ai-error {\n color: var(--m-danger);\n font-size: 12px;\n padding: 0 2px;\n}\n\n@media (max-width: 1280px) {\n .mailharbor-ai {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n width: min(420px, 94%);\n z-index: 6;\n border-left: 1px solid var(--m-line);\n box-shadow: -12px 0 40px rgba(0, 0, 0, 0.45);\n }\n}\n\n/* ---------- AI summary ---------- */\n\n.mailharbor-divider {\n width: 1px;\n height: 18px;\n margin: 0 4px;\n background: var(--m-line);\n}\n\n.mailharbor-summary {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.mailharbor-summary section h4 {\n margin: 0 0 6px;\n font-size: 11.5px;\n font-weight: 600;\n color: var(--m-text-3);\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n\n.mailharbor-summary section p {\n margin: 0;\n white-space: pre-wrap;\n line-height: 1.75;\n color: var(--m-text);\n}\n\n/* ---------- modal / forms ---------- */\n\n.mailharbor-portal {\n position: fixed;\n inset: 0;\n z-index: 80;\n height: auto;\n background: transparent;\n pointer-events: none;\n}\n\n.mailharbor-portal .mailharbor-modal-mask {\n pointer-events: auto;\n}\n\n.mailharbor-modal-mask {\n position: fixed;\n inset: 0;\n z-index: 60;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n background: rgba(0, 0, 0, 0.55);\n backdrop-filter: blur(2px);\n}\n\n.mailharbor-modal {\n display: flex;\n flex-direction: column;\n width: min(720px, 100%);\n max-height: 86vh;\n overflow: hidden;\n border: 1px solid var(--m-line);\n border-radius: 14px;\n background: var(--m-bg-1);\n color: var(--m-text);\n box-shadow: var(--m-shadow);\n}\n\n.mailharbor-modal > header {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 52px;\n padding: 0 14px 0 18px;\n border-bottom: 1px solid var(--m-line-soft);\n font-size: 14px;\n font-weight: 600;\n}\n\n.mailharbor-modal .content {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 18px;\n overflow: auto;\n}\n\n.mailharbor-modal > footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 18px;\n border-top: 1px solid var(--m-line-soft);\n}\n\n.mailharbor-field {\n display: flex;\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n}\n\n.mailharbor-field > input,\n.mailharbor-field > select,\n.mailharbor-field > textarea,\n.mailharbor-card > textarea {\n width: 100%;\n min-width: 0;\n}\n\n.mailharbor-field > label {\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.mailharbor-grid {\n display: grid;\n grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);\n gap: 10px;\n min-width: 0;\n}\n\n.mailharbor-grid.three {\n grid-template-columns: minmax(0, 2fr) minmax(72px, 90px) auto;\n align-items: end;\n min-width: 0;\n}\n\n.mailharbor-toggle {\n display: inline-flex;\n align-items: center;\n gap: 7px;\n color: var(--m-text-2);\n font-size: 12.5px;\n cursor: pointer;\n white-space: nowrap;\n}\n\n.mailharbor-toggle input[type='checkbox'] {\n width: 14px;\n height: 14px;\n accent-color: var(--m-accent);\n}\n\n/* ---------- composer ---------- */\n\n.mailharbor-toolbar {\n display: flex;\n align-items: center;\n gap: 2px;\n flex-wrap: wrap;\n padding: 6px;\n border: 1px solid var(--m-line-soft);\n border-bottom: 0;\n border-radius: 10px 10px 0 0;\n background: var(--m-bg-2);\n}\n\n.mailharbor-toolbar button {\n height: 26px;\n padding: 0 9px;\n border-radius: 6px;\n color: var(--m-text-2);\n font-size: 12px;\n}\n\n.mailharbor-toolbar button:hover {\n background: var(--m-bg-3);\n color: var(--m-text);\n}\n\n.mailharbor-editor {\n min-height: 240px;\n max-height: 44vh;\n overflow: auto;\n padding: 14px 16px;\n border: 1px solid var(--m-line-soft);\n border-radius: 0 0 10px 10px;\n background: #fff;\n color: #171a21;\n outline: none;\n font-size: 13.5px;\n line-height: 1.7;\n}\n\n.mailharbor-editor:empty::before {\n content: attr(data-placeholder);\n color: #9aa0ab;\n}\n\n/* ---------- inline confirm ---------- */\n\n.mailharbor-confirm {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--m-line);\n background: var(--m-bg-2);\n color: var(--m-text-2);\n font-size: 12.5px;\n}\n\n/* ---------- selection / extraction ---------- */\n\n.mailharbor-selectbar {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n margin: 0 12px 8px;\n border: 1px solid var(--m-accent-soft);\n border-radius: 9px;\n background: var(--m-accent-soft);\n}\n\n.mailharbor-selectbar select {\n height: 28px;\n max-width: 200px;\n}\n\n.mailharbor-row.selectable input[type='checkbox'] {\n width: 15px;\n height: 15px;\n flex: none;\n accent-color: var(--m-accent);\n}\n\n.mailharbor-extract-row {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n padding: 9px 10px;\n border: 1px solid var(--m-line-soft);\n border-radius: 9px;\n background: var(--m-bg-1);\n cursor: pointer;\n}\n\n.mailharbor-extract-row input {\n margin-top: 2px;\n accent-color: var(--m-accent);\n}\n\n.mailharbor-extract-row > span {\n display: flex;\n flex-direction: column;\n gap: 3px;\n min-width: 0;\n}\n\n.mailharbor-kv {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr);\n gap: 6px 12px;\n margin: 0;\n font-size: 12.5px;\n}\n\n.mailharbor-kv dt {\n color: var(--m-text-3);\n}\n\n.mailharbor-kv dd {\n margin: 0;\n overflow-wrap: anywhere;\n}\n\n/* ---------- tasks panel ---------- */\n\n.mailharbor .chip {\n height: 26px;\n padding: 0 10px;\n border: 1px solid var(--m-line);\n border-radius: 999px;\n color: var(--m-text-3);\n font-size: 12px;\n}\n\n.mailharbor .chip.active {\n background: var(--m-accent-soft);\n border-color: transparent;\n color: var(--m-text);\n}\n\n.tasks-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 18px;\n padding: 18px 20px 48px;\n width: 100%;\n max-width: 940px;\n margin: 0 auto;\n}\n\n.tasks-overview {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));\n gap: 12px;\n}\n\n.tasks-progress,\n.tasks-project {\n display: flex;\n flex-direction: column;\n gap: 7px;\n padding: 12px 14px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n min-width: 0;\n}\n\n.tasks-progress-head,\n.tasks-project-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n min-width: 0;\n}\n\n.tasks-project-head .name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12.5px;\n font-weight: 500;\n}\n\n.tasks-bar {\n height: 6px;\n border-radius: 999px;\n background: var(--m-bg-3);\n overflow: hidden;\n}\n\n.tasks-bar span {\n display: block;\n height: 100%;\n border-radius: 999px;\n background: var(--m-accent);\n transition: width 200ms ease;\n}\n\n.tasks-bar.small {\n height: 4px;\n}\n\n.tasks-filters {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n.tasks-list {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.tasks-row {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 9px 12px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n}\n\n.tasks-row input[type='checkbox'] {\n width: 16px;\n height: 16px;\n flex: none;\n accent-color: var(--m-accent);\n}\n\n.tasks-row .tasks-title {\n flex: 1;\n min-width: 0;\n height: auto;\n padding: 0;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n text-align: left;\n border: 0;\n background: transparent;\n}\n\n.tasks-row .tasks-title:hover {\n background: transparent;\n}\n\n.tasks-row .tasks-title > span:first-child {\n font-size: 13px;\n color: var(--m-text);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 100%;\n}\n\n.tasks-row.done .tasks-title > span:first-child {\n color: var(--m-text-3);\n text-decoration: line-through;\n}\n\n.tasks-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.tasks-meta .due.overdue {\n color: var(--m-danger);\n}\n\n.tasks-list-wrap {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n/* ---------- markdown ---------- */\n\n.mailharbor-markdown {\n display: flex;\n flex-direction: column;\n gap: 8px;\n font-size: 12.5px;\n line-height: 1.68;\n overflow-wrap: anywhere;\n}\n\n.mailharbor-markdown > *:first-child {\n margin-top: 0;\n}\n\n.mailharbor-markdown > *:last-child {\n margin-bottom: 0;\n}\n\n.mailharbor-markdown p {\n margin: 0;\n white-space: pre-wrap;\n}\n\n.mailharbor-markdown h1,\n.mailharbor-markdown h2,\n.mailharbor-markdown h3,\n.mailharbor-markdown h4,\n.mailharbor-markdown h5,\n.mailharbor-markdown h6 {\n margin: 4px 0 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--m-text);\n}\n\n.mailharbor-markdown ul,\n.mailharbor-markdown ol {\n margin: 0;\n padding-left: 20px;\n display: flex;\n flex-direction: column;\n gap: 3px;\n}\n\n.mailharbor-markdown li::marker {\n color: var(--m-text-3);\n}\n\n.mailharbor-markdown a {\n color: var(--m-accent);\n text-decoration: none;\n}\n\n.mailharbor-markdown a:hover {\n text-decoration: underline;\n}\n\n.mailharbor-markdown code {\n padding: 1px 4px;\n border-radius: 4px;\n background: var(--m-bg-2);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11.5px;\n}\n\n.mailharbor-markdown pre {\n margin: 0;\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--m-bg);\n border: 1px solid var(--m-line-soft);\n overflow: auto;\n}\n\n.mailharbor-markdown pre code {\n padding: 0;\n background: transparent;\n}\n\n.mailharbor-markdown blockquote {\n margin: 0;\n padding-left: 10px;\n border-left: 2px solid var(--m-line);\n color: var(--m-text-2);\n}\n\n.mailharbor-markdown hr {\n width: 100%;\n margin: 4px 0;\n border: 0;\n border-top: 1px solid var(--m-line-soft);\n}\n\n/* ---------- composer AI ---------- */\n\n.mailharbor-toolbar button.ai {\n color: var(--m-accent);\n}\n\n.mailharbor-compose-foot {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n flex-wrap: wrap;\n}\n\n.mailharbor-versions {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n padding-top: 8px;\n}\n\n.mailharbor-versions .chip {\n height: 22px;\n padding: 0 8px;\n border: 1px solid var(--m-line);\n border-radius: 999px;\n color: var(--m-text-3);\n font-size: 11px;\n}\n\n.mailharbor-versions .chip.active {\n background: var(--m-accent-soft);\n border-color: transparent;\n color: var(--m-text);\n}\n\n/* ---------- settings ---------- */\n\n.mailharbor.mailharbor-settings-page {\n height: auto;\n min-height: 100%;\n overflow: visible;\n}\n\n.mailharbor-settings {\n flex: 0 0 auto;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n padding: 18px 20px 48px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n overflow-x: hidden;\n}\n\n.mailharbor-settings > * {\n min-width: 0;\n}\n\n.mailharbor-settings h2 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n letter-spacing: -0.01em;\n}\n\n.mailharbor-settings h3 {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--m-text-3);\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n\n.mailharbor-card {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n min-width: 0;\n overflow: hidden;\n}\n\n.mailharbor-account-row {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.mailharbor-account-row .meta {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.mailharbor-account-row .meta strong {\n font-weight: 600;\n}\n\n.mailharbor-account-row .meta span {\n color: var(--m-text-3);\n font-size: 11.5px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mailharbor .avatar {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n border-radius: 50%;\n background: var(--m-accent-soft);\n color: var(--m-accent);\n font-weight: 600;\n}\n\n.mailharbor-log {\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--m-bg);\n border: 1px solid var(--m-line-soft);\n color: var(--m-text-2);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11px;\n line-height: 1.6;\n max-height: 220px;\n overflow: auto;\n white-space: pre-wrap;\n}\n\n.mailharbor-kv {\n display: grid;\n grid-template-columns: minmax(120px, 170px) 1fr;\n gap: 6px 14px;\n font-size: 12px;\n margin: 0;\n}\n\n.mailharbor-kv dt {\n color: var(--m-text-3);\n}\n\n.mailharbor-kv dd {\n margin: 0;\n color: var(--m-text-2);\n word-break: break-all;\n}\n\n.mailharbor hr {\n border: 0;\n border-top: 1px solid var(--m-line-soft);\n margin: 2px 0;\n}\n\n/* ---------- conversation rows ---------- */\n\n.mailharbor-thread {\n display: flex;\n flex-direction: column;\n}\n\n.mailharbor-row.compact {\n padding-top: 6px;\n padding-bottom: 6px;\n padding-left: 34px;\n background: var(--m-bg);\n}\n\n.mailharbor-row.compact .line-1 {\n opacity: 0.85;\n}\n\n.mailharbor-row.compact .snippet {\n -webkit-line-clamp: 1;\n}\n\n.mailharbor .to-label {\n font-size: 10.5px;\n color: var(--m-text-3);\n flex: none;\n}\n\n.mailharbor .thread-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n border-radius: 999px;\n background: var(--m-bg-3);\n color: var(--m-text-2);\n font-size: 10.5px;\n flex: none;\n}\n\n.mailharbor .thread-count:hover {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.mailharbor-account {\n height: auto;\n padding: 3px 8px 3px 3px;\n border-radius: 8px;\n gap: 8px;\n}\n\n.mailharbor-account:hover {\n background: var(--m-hover);\n}\n\n/* ---------- mailbox sidebar ---------- */\n\n.mailharbor-side {\n display: flex;\n flex-direction: column;\n gap: 2px;\n width: 214px;\n flex: none;\n padding: 10px 8px;\n overflow: auto;\n border-right: 1px solid var(--m-line-soft);\n background: var(--m-bg);\n}\n\n.mailharbor-side-section {\n padding: 12px 8px 4px;\n font-size: 10.5px;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n color: var(--m-text-3);\n}\n\n.mailharbor-side-item {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n height: 32px;\n padding: 0 8px;\n border-radius: 8px;\n color: var(--m-text-2);\n font-size: 12.5px;\n text-align: left;\n flex: none;\n}\n\n.mailharbor-side-item:hover {\n background: var(--m-hover);\n}\n\n.mailharbor-side-item.active {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.mailharbor-side-item .name {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-side-item .sub {\n display: block;\n font-size: 10.5px;\n color: var(--m-text-3);\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mailharbor-side-item .count {\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.mailharbor-side-item svg {\n flex: none;\n color: var(--m-text-3);\n}\n\n.mailharbor-side-item.active svg {\n color: var(--m-accent);\n}\n\n@media (max-width: 900px) {\n .mailharbor-side {\n display: none;\n }\n}\n\n/* ---------- task board ---------- */\n\n.tasks-board-wrap {\n flex: 1;\n min-height: 0;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 14px;\n padding: 16px 18px 40px;\n}\n\n.tasks-summary {\n display: flex;\n align-items: center;\n gap: 20px;\n padding: 14px 16px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n}\n\n.tasks-summary-main {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 7px;\n}\n\n.tasks-summary-labels {\n display: flex;\n align-items: baseline;\n gap: 10px;\n}\n\n.tasks-stats {\n display: flex;\n gap: 18px;\n}\n\n.tasks-stat {\n display: flex;\n flex-direction: column;\n gap: 1px;\n min-width: 42px;\n}\n\n.tasks-stat strong {\n font-size: 16px;\n font-weight: 600;\n color: var(--m-text);\n}\n\n.tasks-stat span {\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.tasks-stat.danger strong {\n color: var(--m-danger);\n}\n\n.tasks-toolbar {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.tasks-board {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: 14px;\n align-items: start;\n}\n\n.task-column {\n display: flex;\n flex-direction: column;\n gap: 8px;\n min-height: 140px;\n padding: 8px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n}\n\n.task-column-head {\n display: flex;\n align-items: center;\n gap: 7px;\n padding: 2px 4px 6px;\n}\n\n.task-column-head strong {\n font-size: 12.5px;\n font-weight: 600;\n}\n\n.task-column-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n border-radius: 999px;\n background: var(--m-bg-3);\n color: var(--m-text-3);\n font-size: 10.5px;\n}\n\n.task-dot {\n width: 7px;\n height: 7px;\n border-radius: 999px;\n background: var(--m-text-3);\n}\n\n.task-dot.NEEDS-ACTION {\n background: #8a8f98;\n}\n\n.task-dot.IN-PROCESS {\n background: var(--m-accent);\n}\n\n.task-dot.COMPLETED {\n background: var(--m-ok);\n}\n\n.task-dot.CANCELLED {\n background: var(--m-danger);\n opacity: 0.7;\n}\n\n.task-column-body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n min-height: 60px;\n}\n\n.task-column-empty {\n padding: 18px 8px;\n text-align: center;\n color: var(--m-text-3);\n font-size: 11.5px;\n border: 1px dashed var(--m-line-soft);\n border-radius: 9px;\n}\n\n.task-card {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 10px 11px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg);\n cursor: grab;\n transition:\n border-color 120ms ease,\n box-shadow 120ms ease;\n}\n\n.task-card:hover {\n border-color: var(--m-line);\n box-shadow: 0 4px 14px rgba(0, 0, 0, 0.16);\n}\n\n.task-card.dragging {\n opacity: 0.5;\n}\n\n.task-card-top {\n display: flex;\n align-items: flex-start;\n gap: 7px;\n}\n\n.task-card-title {\n flex: 1;\n min-width: 0;\n font-size: 12.5px;\n line-height: 1.45;\n color: var(--m-text);\n overflow-wrap: anywhere;\n}\n\n.task-priority {\n width: 3px;\n height: 14px;\n margin-top: 2px;\n border-radius: 999px;\n background: transparent;\n flex: none;\n}\n\n.task-priority.p5 {\n background: #d9a441;\n}\n\n.task-priority.p9 {\n background: var(--m-danger);\n}\n\n.task-card-delete {\n width: 18px;\n height: 18px;\n flex: none;\n border-radius: 5px;\n color: var(--m-text-3);\n opacity: 0;\n}\n\n.task-card:hover .task-card-delete {\n opacity: 1;\n}\n\n.task-card-notes {\n margin: 0;\n font-size: 11.5px;\n line-height: 1.55;\n color: var(--m-text-3);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.task-card-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n font-size: 10.5px;\n color: var(--m-text-3);\n}\n\n.task-due,\n.task-owner,\n.task-project,\n.task-priority-label {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n padding: 1px 6px;\n border-radius: 5px;\n background: var(--m-bg-2);\n}\n\n.task-due.overdue {\n color: var(--m-danger);\n background: rgba(242, 90, 90, 0.12);\n}\n\n.task-project {\n color: var(--m-accent);\n background: var(--m-accent-soft);\n}\n\n.task-source {\n align-self: flex-start;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n height: 22px;\n padding: 0 6px;\n border-radius: 5px;\n color: var(--m-text-3);\n font-size: 10.5px;\n}\n\n.task-source:hover {\n background: var(--m-hover);\n color: var(--m-text-2);\n}\n\n@media (max-width: 1180px) {\n .tasks-board {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n}\n\n@media (max-width: 720px) {\n .tasks-board {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n/* ---------- AI search ---------- */\n\n.mailharbor-ai-search {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0 12px 8px;\n padding: 7px 10px;\n border-radius: 8px;\n background: var(--m-accent-soft);\n color: var(--m-text-2);\n font-size: 12px;\n}\n\n.mailharbor-ai-search.searching {\n background: var(--m-bg-2);\n color: var(--m-text-3);\n}\n\n/* ---------- task editor ---------- */\n\n.mailharbor-tasks .mailharbor-modal {\n max-width: 760px;\n}\n\n.task-editor {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 230px;\n gap: 18px;\n}\n\n.task-editor-main {\n display: flex;\n flex-direction: column;\n gap: 14px;\n min-width: 0;\n}\n\n.task-editor-title input {\n width: 100%;\n height: 38px;\n font-size: 15px;\n font-weight: 500;\n}\n\n.task-editor-section {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.task-editor-section label,\n.task-editor-field label {\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.task-editor-section textarea {\n width: 100%;\n resize: vertical;\n}\n\n.task-editor-side {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 12px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n align-self: start;\n}\n\n.task-editor-field {\n display: flex;\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n}\n\n.task-editor-field input,\n.task-editor-field select {\n width: 100%;\n}\n\n.task-priority-picker {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 4px;\n padding: 3px;\n border: 1px solid var(--m-line);\n border-radius: 8px;\n background: var(--m-bg);\n}\n\n.task-priority-picker button {\n height: 26px;\n border-radius: 6px;\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.task-priority-picker button.active {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.task-editor-foot {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n}\n\n/* ---------- project manager ---------- */\n\n.project-manager {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.project-manager-row {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 12px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n}\n\n.project-manager-main {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 3px;\n}\n\n.project-manager-main strong {\n font-size: 13px;\n}\n\n.project-manager-main .small {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.project-manager-main input {\n width: 100%;\n height: 28px;\n}\n\n.project-manager-actions {\n display: flex;\n gap: 4px;\n flex: none;\n align-items: center;\n}\n\n/* ---------- task editor v2 ---------- */\n\n.task-editor-v2 {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.task-editor-head {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.task-editor-head .task-title-input {\n width: 100%;\n height: 42px;\n padding: 0 12px;\n border-radius: 10px;\n border: 1px solid var(--m-line);\n background: var(--m-bg);\n color: var(--m-text);\n font-size: 16px;\n font-weight: 500;\n}\n\n.task-editor-head .task-title-input:focus {\n outline: none;\n border-color: var(--m-accent);\n}\n\n.task-status-picker {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: 4px;\n padding: 4px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n}\n\n.task-status-picker button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n height: 30px;\n border-radius: 7px;\n color: var(--m-text-3);\n font-size: 12px;\n}\n\n.task-status-picker button:hover {\n background: var(--m-hover);\n}\n\n.task-status-picker button.active {\n background: var(--m-bg-3);\n color: var(--m-text);\n}\n\n.task-editor-columns {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 250px;\n gap: 18px;\n}\n\n.task-editor-col {\n display: flex;\n flex-direction: column;\n gap: 8px;\n min-width: 0;\n}\n\n.task-editor-col textarea {\n width: 100%;\n resize: vertical;\n min-height: 120px;\n}\n\n.task-editor-col.side {\n padding: 12px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n align-self: start;\n}\n\n.task-label {\n font-size: 11px;\n color: var(--m-text-3);\n margin-top: 2px;\n}\n\n.task-hint {\n margin: 0;\n font-size: 11.5px;\n color: var(--m-text-3);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.task-hint.danger {\n color: var(--m-danger);\n white-space: normal;\n}\n\n.task-source-row {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.task-due {\n position: relative;\n}\n\n.task-due-trigger {\n display: flex;\n align-items: center;\n gap: 7px;\n width: 100%;\n height: 32px;\n padding: 0 10px;\n border: 1px solid var(--m-line);\n border-radius: 8px;\n background: var(--m-bg);\n color: var(--m-text-2);\n font-size: 12.5px;\n}\n\n.task-due-trigger.empty {\n color: var(--m-text-3);\n}\n\n.task-due-trigger span {\n flex: 1;\n text-align: left;\n}\n\n.task-due-popover {\n position: absolute;\n z-index: 20;\n top: calc(100% + 6px);\n left: 0;\n width: 250px;\n padding: 10px;\n border: 1px solid var(--m-line);\n border-radius: 10px;\n background: var(--m-bg-2);\n box-shadow: 0 12px 30px rgba(0, 0, 0, 0.35);\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.task-due-quick {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 5px;\n}\n\n.task-due-quick button {\n height: 28px;\n border-radius: 7px;\n background: var(--m-bg-1);\n border: 1px solid var(--m-line-soft);\n font-size: 11.5px;\n color: var(--m-text-2);\n}\n\n.task-due-quick button.active {\n background: var(--m-accent-soft);\n border-color: transparent;\n color: var(--m-text);\n}\n\n.task-due-popover input[type='date'] {\n width: 100%;\n}\n\n.task-due-foot {\n display: flex;\n justify-content: space-between;\n}\n\n.task-priority-picker {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: 4px;\n padding: 3px;\n border: 1px solid var(--m-line);\n border-radius: 8px;\n background: var(--m-bg);\n}\n\n.task-priority-picker button {\n height: 28px;\n border-radius: 6px;\n font-size: 11.5px;\n color: var(--m-text-3);\n border: 1px solid transparent;\n}\n\n.task-priority-picker button.p3 {\n color: #5aa7f0;\n}\n\n.task-priority-picker button.p5 {\n color: #d9a441;\n}\n\n.task-priority-picker button.p9 {\n color: var(--m-danger);\n}\n\n.task-priority-picker button.active {\n background: var(--m-bg-3);\n border-color: var(--m-line);\n color: var(--m-text);\n}\n\n.task-priority-picker button.p9.active {\n background: rgba(242, 90, 90, 0.16);\n border-color: rgba(242, 90, 90, 0.35);\n color: var(--m-danger);\n}\n\n.task-priority-picker button.p5.active {\n background: rgba(217, 164, 65, 0.16);\n border-color: rgba(217, 164, 65, 0.35);\n color: #d9a441;\n}\n\n.task-priority-picker button.p3.active {\n background: rgba(90, 167, 240, 0.16);\n border-color: rgba(90, 167, 240, 0.35);\n color: #5aa7f0;\n}\n\n.task-priority.p3 {\n background: #5aa7f0;\n}\n\n.task-priority-label.p9 {\n color: var(--m-danger);\n background: rgba(242, 90, 90, 0.12);\n}\n\n.task-priority-label.p5 {\n color: #d9a441;\n background: rgba(217, 164, 65, 0.12);\n}\n\n.task-priority-label.p3 {\n color: #5aa7f0;\n background: rgba(90, 167, 240, 0.12);\n}\n\n@media (max-width: 720px) {\n .task-editor-columns {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n.mailharbor-spinner {\n display: inline-block;\n width: 13px;\n height: 13px;\n border: 2px solid currentColor;\n border-right-color: transparent;\n border-radius: 50%;\n animation: mailharbor-spin 0.7s linear infinite;\n opacity: 0.8;\n vertical-align: -2px;\n flex: none;\n}\n\n@keyframes mailharbor-spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n.extract-body {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.extract-title {\n width: 100%;\n height: 30px;\n font-size: 13px;\n font-weight: 500;\n}\n\n.extract-meta {\n display: grid;\n grid-template-columns: 150px 110px minmax(0, 1fr);\n gap: 6px;\n}\n\n.extract-meta input,\n.extract-meta select {\n height: 28px;\n font-size: 11.5px;\n width: 100%;\n}\n\n.extract-owner {\n width: 100%;\n}\n\n@media (max-width: 720px) {\n .extract-meta {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n/* ---------- conversation reading ---------- */\n\n.mailharbor-thread-view {\n flex: 1;\n min-height: 0;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 14px 18px 32px;\n background: var(--m-bg);\n}\n\n.mailharbor-thread-hint {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 0 4px 2px;\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.mailharbor-thread-msg {\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n overflow: hidden;\n}\n\n.mailharbor-thread-msg.selected {\n border-color: var(--m-accent);\n box-shadow: 0 0 0 1px var(--m-accent-soft);\n}\n\n.mailharbor-thread-head {\n display: flex;\n align-items: center;\n gap: 9px;\n width: 100%;\n height: auto;\n padding: 9px 12px;\n text-align: left;\n border-radius: 0;\n}\n\n.mailharbor-thread-head:hover {\n background: var(--m-hover);\n}\n\n.thread-who {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.thread-who strong {\n font-size: 12.5px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.thread-to {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-thread-preview {\n padding: 0 14px 10px 47px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-thread-body {\n padding: 0 12px 12px;\n}\n\n.mailharbor-thread-frame {\n height: 380px;\n border: 1px solid var(--m-line-soft);\n border-radius: 8px;\n overflow: hidden;\n background: #fff;\n}\n\n.mailharbor-thread-frame iframe {\n display: block;\n width: 100%;\n height: 100%;\n border: 0;\n background: #fff;\n}\n\n.thread-loading {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 4px 12px;\n}\n\n@media (max-width: 900px) {\n .thread-to {\n display: none;\n }\n}\n";
|
|
39
39
|
|
|
40
40
|
// src/client/icon.tsx
|
|
41
41
|
var import_react = require("react");
|
|
@@ -718,6 +718,7 @@ function AiRail({
|
|
|
718
718
|
const [thread, setThread] = (0, import_react5.useState)(null);
|
|
719
719
|
const [loading, setLoading] = (0, import_react5.useState)(false);
|
|
720
720
|
const [generating, setGenerating] = (0, import_react5.useState)(null);
|
|
721
|
+
const [elapsed, setElapsed] = (0, import_react5.useState)(0);
|
|
721
722
|
const [error, setError] = (0, import_react5.useState)("");
|
|
722
723
|
const [question, setQuestion] = (0, import_react5.useState)("");
|
|
723
724
|
const [confirmClear, setConfirmClear] = (0, import_react5.useState)(false);
|
|
@@ -794,6 +795,19 @@ function AiRail({
|
|
|
794
795
|
const element = list.current;
|
|
795
796
|
if (element !== null) element.scrollTop = element.scrollHeight;
|
|
796
797
|
}, [thread, generating]);
|
|
798
|
+
(0, import_react5.useEffect)(() => {
|
|
799
|
+
if (generating === null) {
|
|
800
|
+
setElapsed(0);
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
const started = Date.now();
|
|
804
|
+
const timer = window.setInterval(() => {
|
|
805
|
+
setElapsed(Math.floor((Date.now() - started) / 1e3));
|
|
806
|
+
}, 1e3);
|
|
807
|
+
return () => {
|
|
808
|
+
window.clearInterval(timer);
|
|
809
|
+
};
|
|
810
|
+
}, [generating]);
|
|
797
811
|
(0, import_react5.useEffect)(() => {
|
|
798
812
|
if (detail === null || account === null) {
|
|
799
813
|
setProject(null);
|
|
@@ -1072,7 +1086,15 @@ ${card.output}`
|
|
|
1072
1086
|
"article",
|
|
1073
1087
|
{ className: "mailharbor-ai-card generating" },
|
|
1074
1088
|
(0, import_react5.createElement)("div", { className: "mailharbor-ai-card-head" }, (0, import_react5.createElement)("span", null, KIND_LABEL[generating])),
|
|
1075
|
-
(0, import_react5.createElement)(
|
|
1089
|
+
(0, import_react5.createElement)(
|
|
1090
|
+
"div",
|
|
1091
|
+
{
|
|
1092
|
+
className: "mailharbor-ai-text muted",
|
|
1093
|
+
style: { display: "flex", gap: "8px", alignItems: "center" }
|
|
1094
|
+
},
|
|
1095
|
+
(0, import_react5.createElement)("span", { className: "mailharbor-spinner" }),
|
|
1096
|
+
`\u6B63\u5728\u751F\u6210\u2026 ${String(elapsed)}s`
|
|
1097
|
+
)
|
|
1076
1098
|
) : null,
|
|
1077
1099
|
error === "" ? null : (0, import_react5.createElement)("div", { className: "mailharbor-ai-error" }, error)
|
|
1078
1100
|
),
|
|
@@ -1777,12 +1799,22 @@ function Composer({
|
|
|
1777
1799
|
(0, import_react7.createElement)(
|
|
1778
1800
|
"button",
|
|
1779
1801
|
{ className: "ai", onClick: () => void runAi("polish"), disabled: aiBusy !== null || !hasBody },
|
|
1780
|
-
aiBusy === "polish" ?
|
|
1802
|
+
aiBusy === "polish" ? (0, import_react7.createElement)(
|
|
1803
|
+
"span",
|
|
1804
|
+
{ style: { display: "inline-flex", gap: "5px", alignItems: "center" } },
|
|
1805
|
+
(0, import_react7.createElement)("span", { className: "mailharbor-spinner" }),
|
|
1806
|
+
"\u6DA6\u8272\u4E2D\u2026"
|
|
1807
|
+
) : "\u6DA6\u8272"
|
|
1781
1808
|
),
|
|
1782
1809
|
(0, import_react7.createElement)(
|
|
1783
1810
|
"button",
|
|
1784
1811
|
{ className: "ai", onClick: () => void runAi("shorten"), disabled: aiBusy !== null || !hasBody },
|
|
1785
|
-
aiBusy === "shorten" ?
|
|
1812
|
+
aiBusy === "shorten" ? (0, import_react7.createElement)(
|
|
1813
|
+
"span",
|
|
1814
|
+
{ style: { display: "inline-flex", gap: "5px", alignItems: "center" } },
|
|
1815
|
+
(0, import_react7.createElement)("span", { className: "mailharbor-spinner" }),
|
|
1816
|
+
"\u7F29\u77ED\u4E2D\u2026"
|
|
1817
|
+
) : "\u7F29\u77ED"
|
|
1786
1818
|
),
|
|
1787
1819
|
(0, import_react7.createElement)(
|
|
1788
1820
|
"button",
|
|
@@ -1932,6 +1964,9 @@ function hasRemoteImages(detail) {
|
|
|
1932
1964
|
function addressLine(list) {
|
|
1933
1965
|
return list.map((item) => item.name !== "" ? `${item.name} <${item.address}>` : item.address).join("\u3001");
|
|
1934
1966
|
}
|
|
1967
|
+
function isSentMailbox(mailbox) {
|
|
1968
|
+
return /(^|[/.])(sent|sent items|sent mail|已发送|发件箱)/i.test(mailbox);
|
|
1969
|
+
}
|
|
1935
1970
|
function errorText4(error) {
|
|
1936
1971
|
return error instanceof Error ? error.message : String(error);
|
|
1937
1972
|
}
|
|
@@ -1944,13 +1979,40 @@ function Reader({
|
|
|
1944
1979
|
onAiAction,
|
|
1945
1980
|
onExtractTasks,
|
|
1946
1981
|
onAddToProject,
|
|
1947
|
-
onClose
|
|
1982
|
+
onClose,
|
|
1983
|
+
thread = [],
|
|
1984
|
+
onSelectMessage,
|
|
1985
|
+
loadDetail
|
|
1948
1986
|
}) {
|
|
1949
1987
|
const [plain, setPlain] = (0, import_react8.useState)(false);
|
|
1950
1988
|
const [loadImages, setLoadImages] = (0, import_react8.useState)(false);
|
|
1989
|
+
const [details, setDetails] = (0, import_react8.useState)({});
|
|
1990
|
+
const [expanded, setExpanded] = (0, import_react8.useState)([detail.id]);
|
|
1991
|
+
const selectedCard = (0, import_react8.useRef)(null);
|
|
1951
1992
|
const [busy, setBusy] = (0, import_react8.useState)(false);
|
|
1952
1993
|
const [error, setError] = (0, import_react8.useState)("");
|
|
1953
1994
|
const remoteImages = (0, import_react8.useMemo)(() => hasRemoteImages(detail), [detail]);
|
|
1995
|
+
const conversation = thread.length > 1 ? [...thread].reverse() : [];
|
|
1996
|
+
const threaded = conversation.length > 0 && loadDetail !== void 0;
|
|
1997
|
+
(0, import_react8.useEffect)(() => {
|
|
1998
|
+
setDetails((current) => ({ ...current, [detail.id]: detail }));
|
|
1999
|
+
setExpanded((current) => current.includes(detail.id) ? current : [...current, detail.id]);
|
|
2000
|
+
}, [detail]);
|
|
2001
|
+
(0, import_react8.useEffect)(() => {
|
|
2002
|
+
selectedCard.current?.scrollIntoView({ block: "nearest" });
|
|
2003
|
+
}, [detail.id]);
|
|
2004
|
+
const toggleThread = (item) => {
|
|
2005
|
+
const open = expanded.includes(item.id);
|
|
2006
|
+
if (open) {
|
|
2007
|
+
setExpanded(expanded.filter((id) => id !== item.id));
|
|
2008
|
+
return;
|
|
2009
|
+
}
|
|
2010
|
+
setExpanded([...expanded, item.id]);
|
|
2011
|
+
onSelectMessage?.(item);
|
|
2012
|
+
if (details[item.id] === void 0) {
|
|
2013
|
+
void loadDetail?.(item).then((loaded) => setDetails((current) => ({ ...current, [item.id]: loaded }))).catch(() => void 0);
|
|
2014
|
+
}
|
|
2015
|
+
};
|
|
1954
2016
|
const html = detail.html !== null && detail.html !== "";
|
|
1955
2017
|
const toggleRead = async () => {
|
|
1956
2018
|
setBusy(true);
|
|
@@ -2073,7 +2135,72 @@ function Reader({
|
|
|
2073
2135
|
),
|
|
2074
2136
|
error === "" ? null : (0, import_react8.createElement)("div", { className: "small", style: { color: "var(--m-danger)" } }, error)
|
|
2075
2137
|
),
|
|
2076
|
-
(0, import_react8.createElement)(
|
|
2138
|
+
threaded ? (0, import_react8.createElement)(
|
|
2139
|
+
"div",
|
|
2140
|
+
{ className: "mailharbor-thread-view" },
|
|
2141
|
+
(0, import_react8.createElement)(
|
|
2142
|
+
"div",
|
|
2143
|
+
{ className: "mailharbor-thread-hint" },
|
|
2144
|
+
(0, import_react8.createElement)(Icon, { name: "mail", size: 13 }),
|
|
2145
|
+
`\u5171 ${String(conversation.length)} \u5C01 \xB7 \u70B9\u51FB\u4EFB\u610F\u4E00\u5C01\u5C55\u5F00\u6216\u6536\u8D77`
|
|
2146
|
+
),
|
|
2147
|
+
conversation.map((item) => {
|
|
2148
|
+
const expandedItem = expanded.includes(item.id);
|
|
2149
|
+
const itemDetail = details[item.id];
|
|
2150
|
+
const sentItem = isSentMailbox(mailbox) && item.to.length > 0;
|
|
2151
|
+
const who = sentItem ? item.to[0] ?? item.from : item.from;
|
|
2152
|
+
const selectedItem = item.id === detail.id;
|
|
2153
|
+
return (0, import_react8.createElement)(
|
|
2154
|
+
"div",
|
|
2155
|
+
{
|
|
2156
|
+
key: item.id,
|
|
2157
|
+
ref: selectedItem ? selectedCard : void 0,
|
|
2158
|
+
className: `mailharbor-thread-msg${selectedItem ? " selected" : ""}${expandedItem ? " open" : ""}`
|
|
2159
|
+
},
|
|
2160
|
+
(0, import_react8.createElement)(
|
|
2161
|
+
"button",
|
|
2162
|
+
{ className: "mailharbor-thread-head", onClick: () => toggleThread(item) },
|
|
2163
|
+
(0, import_react8.createElement)(Avatar, { email: who.address, size: 26 }),
|
|
2164
|
+
(0, import_react8.createElement)(
|
|
2165
|
+
"span",
|
|
2166
|
+
{ className: "thread-who" },
|
|
2167
|
+
(0, import_react8.createElement)("strong", null, who.name !== "" ? who.name : who.address),
|
|
2168
|
+
(0, import_react8.createElement)("span", { className: "small muted" }, who.address)
|
|
2169
|
+
),
|
|
2170
|
+
(0, import_react8.createElement)(
|
|
2171
|
+
"span",
|
|
2172
|
+
{ className: "small muted thread-to" },
|
|
2173
|
+
sentItem ? `\u53D1\u7ED9 ${addressLine(item.to)}` : `\u53D1\u7ED9 ${addressLine(item.to)}`
|
|
2174
|
+
),
|
|
2175
|
+
(0, import_react8.createElement)("span", { className: "small muted" }, longDate(item.date)),
|
|
2176
|
+
expandedItem ? (0, import_react8.createElement)(Icon, { name: "chevronLeft", size: 14 }) : (0, import_react8.createElement)(Icon, { name: "chevronRight", size: 14 })
|
|
2177
|
+
),
|
|
2178
|
+
expandedItem ? (0, import_react8.createElement)(
|
|
2179
|
+
"div",
|
|
2180
|
+
{ className: "mailharbor-thread-body" },
|
|
2181
|
+
itemDetail === void 0 ? (0, import_react8.createElement)(
|
|
2182
|
+
"div",
|
|
2183
|
+
{ className: "thread-loading small muted" },
|
|
2184
|
+
(0, import_react8.createElement)("span", { className: "mailharbor-spinner" }),
|
|
2185
|
+
"\u6B63\u5728\u8BFB\u53D6\u2026"
|
|
2186
|
+
) : (0, import_react8.createElement)(
|
|
2187
|
+
"div",
|
|
2188
|
+
{ className: "mailharbor-thread-frame" },
|
|
2189
|
+
(0, import_react8.createElement)("iframe", {
|
|
2190
|
+
title: `\u90AE\u4EF6\u6B63\u6587 ${item.id}`,
|
|
2191
|
+
sandbox: "",
|
|
2192
|
+
srcDoc: srcDoc(itemDetail, loadImages),
|
|
2193
|
+
referrerPolicy: "no-referrer"
|
|
2194
|
+
})
|
|
2195
|
+
)
|
|
2196
|
+
) : (0, import_react8.createElement)(
|
|
2197
|
+
"div",
|
|
2198
|
+
{ className: "mailharbor-thread-preview small muted" },
|
|
2199
|
+
item.snippet !== "" ? item.snippet : "(\u65E0\u9884\u89C8)"
|
|
2200
|
+
)
|
|
2201
|
+
);
|
|
2202
|
+
})
|
|
2203
|
+
) : (0, import_react8.createElement)(
|
|
2077
2204
|
"div",
|
|
2078
2205
|
{ className: "mailharbor-reader-body" },
|
|
2079
2206
|
html && !plain ? (0, import_react8.createElement)("iframe", {
|
|
@@ -2133,6 +2260,8 @@ var EMPTY_PAGE = { items: [], total: 0, offset: 0, limit: 40 };
|
|
|
2133
2260
|
var DRAFTS = "__drafts";
|
|
2134
2261
|
var folderCache = /* @__PURE__ */ new Map();
|
|
2135
2262
|
var pageCache = /* @__PURE__ */ new Map();
|
|
2263
|
+
var detailCache = /* @__PURE__ */ new Map();
|
|
2264
|
+
var DETAIL_TTL = 12e4;
|
|
2136
2265
|
var FOLDER_LABELS = {
|
|
2137
2266
|
INBOX: "\u6536\u4EF6\u7BB1",
|
|
2138
2267
|
"Sent Items": "\u5DF2\u53D1\u9001",
|
|
@@ -2226,6 +2355,9 @@ function MailPanel() {
|
|
|
2226
2355
|
const [managerConfirm, setManagerConfirm] = (0, import_react9.useState)("");
|
|
2227
2356
|
const [managerBusy, setManagerBusy] = (0, import_react9.useState)(false);
|
|
2228
2357
|
const [aiSearching, setAiSearching] = (0, import_react9.useState)(false);
|
|
2358
|
+
const [opening, setOpening] = (0, import_react9.useState)(null);
|
|
2359
|
+
const [aiElapsed, setAiElapsed] = (0, import_react9.useState)(0);
|
|
2360
|
+
const hoverTimer = (0, import_react9.useRef)(null);
|
|
2229
2361
|
const [aiRequest, setAiRequest] = (0, import_react9.useState)(null);
|
|
2230
2362
|
const [tick, setTick] = (0, import_react9.useState)(0);
|
|
2231
2363
|
const accounts = state?.accounts ?? [];
|
|
@@ -2270,6 +2402,19 @@ function MailPanel() {
|
|
|
2270
2402
|
setError(errorText5(caught));
|
|
2271
2403
|
}
|
|
2272
2404
|
};
|
|
2405
|
+
(0, import_react9.useEffect)(() => {
|
|
2406
|
+
if (!aiSearching) {
|
|
2407
|
+
setAiElapsed(0);
|
|
2408
|
+
return;
|
|
2409
|
+
}
|
|
2410
|
+
const started = Date.now();
|
|
2411
|
+
const timer = window.setInterval(() => {
|
|
2412
|
+
setAiElapsed(Math.floor((Date.now() - started) / 1e3));
|
|
2413
|
+
}, 1e3);
|
|
2414
|
+
return () => {
|
|
2415
|
+
window.clearInterval(timer);
|
|
2416
|
+
};
|
|
2417
|
+
}, [aiSearching]);
|
|
2273
2418
|
const runAiSearch = async () => {
|
|
2274
2419
|
const text = query2.trim();
|
|
2275
2420
|
if (text === "" || accountScope === null) return;
|
|
@@ -2445,6 +2590,22 @@ ${projectPicker.subject}`,
|
|
|
2445
2590
|
setExtractBusy(false);
|
|
2446
2591
|
}
|
|
2447
2592
|
};
|
|
2593
|
+
const updateSuggestion = (index, patch) => {
|
|
2594
|
+
setExtraction(
|
|
2595
|
+
(current) => current === null ? null : {
|
|
2596
|
+
...current,
|
|
2597
|
+
items: current.items.map((item, position) => position === index ? { ...item, ...patch } : item)
|
|
2598
|
+
}
|
|
2599
|
+
);
|
|
2600
|
+
};
|
|
2601
|
+
const removeSuggestion = (index) => {
|
|
2602
|
+
setExtraction(
|
|
2603
|
+
(current) => current === null ? null : {
|
|
2604
|
+
items: current.items.filter((_item, position) => position !== index),
|
|
2605
|
+
checked: current.checked.filter((_value, position) => position !== index)
|
|
2606
|
+
}
|
|
2607
|
+
);
|
|
2608
|
+
};
|
|
2448
2609
|
const saveExtraction = async () => {
|
|
2449
2610
|
if (extraction === null || selected === null) return;
|
|
2450
2611
|
setExtractBusy(true);
|
|
@@ -2621,13 +2782,34 @@ ${projectPicker.subject}`,
|
|
|
2621
2782
|
window.clearInterval(timer);
|
|
2622
2783
|
};
|
|
2623
2784
|
}, [showBackup, accountScope, isAll]);
|
|
2785
|
+
const messageKeyOf = (item) => `${item.accountId}:${source}:${item.id}`;
|
|
2786
|
+
const prefetchMessage = (item) => {
|
|
2787
|
+
if (hoverTimer.current !== null) window.clearTimeout(hoverTimer.current);
|
|
2788
|
+
hoverTimer.current = window.setTimeout(() => {
|
|
2789
|
+
const key = messageKeyOf(item);
|
|
2790
|
+
const cached = detailCache.get(key);
|
|
2791
|
+
if (cached !== void 0 && Date.now() - cached.at < DETAIL_TTL) return;
|
|
2792
|
+
void api.message({ id: item.id, accountId: item.accountId, source, mailbox }).then((detail) => {
|
|
2793
|
+
detailCache.set(key, { at: Date.now(), detail });
|
|
2794
|
+
}).catch(() => void 0);
|
|
2795
|
+
}, 160);
|
|
2796
|
+
};
|
|
2624
2797
|
const openMessage = async (item) => {
|
|
2625
2798
|
const owner = item.accountId;
|
|
2626
2799
|
const ownerSource = source;
|
|
2800
|
+
const cacheKey = messageKeyOf(item);
|
|
2801
|
+
const cached = detailCache.get(cacheKey);
|
|
2627
2802
|
setError("");
|
|
2803
|
+
if (cached !== void 0 && Date.now() - cached.at < DETAIL_TTL) {
|
|
2804
|
+
setSelected(cached.detail);
|
|
2805
|
+
} else {
|
|
2806
|
+
setOpening(item.subject);
|
|
2807
|
+
}
|
|
2628
2808
|
try {
|
|
2629
|
-
const detail = await api.message({ id: item.id, accountId: owner, source: ownerSource, mailbox });
|
|
2809
|
+
const detail = cached !== void 0 && Date.now() - cached.at < DETAIL_TTL ? cached.detail : await api.message({ id: item.id, accountId: owner, source: ownerSource, mailbox });
|
|
2810
|
+
detailCache.set(cacheKey, { at: Date.now(), detail });
|
|
2630
2811
|
setSelected(detail);
|
|
2812
|
+
setOpening(null);
|
|
2631
2813
|
if (detail.unread && state?.settings.read.markOnOpen === true) {
|
|
2632
2814
|
try {
|
|
2633
2815
|
await api.setRead({ id: detail.id, accountId: owner, source: ownerSource, mailbox, read: true });
|
|
@@ -2640,6 +2822,7 @@ ${projectPicker.subject}`,
|
|
|
2640
2822
|
}
|
|
2641
2823
|
}
|
|
2642
2824
|
} catch (caught) {
|
|
2825
|
+
setOpening(null);
|
|
2643
2826
|
setError(errorText5(caught));
|
|
2644
2827
|
}
|
|
2645
2828
|
};
|
|
@@ -2805,6 +2988,22 @@ ${projectPicker.subject}`,
|
|
|
2805
2988
|
const loggedIn = isAll ? accounts.some((item) => item.id === state.activeAccountId) : state.loggedIn;
|
|
2806
2989
|
const needsLogin = source === "server" && !isAll && state.loggedIn === false;
|
|
2807
2990
|
const items = page.items;
|
|
2991
|
+
const loadDetailFor = async (item) => {
|
|
2992
|
+
const key = messageKeyOf(item);
|
|
2993
|
+
const cached = detailCache.get(key);
|
|
2994
|
+
if (cached !== void 0 && Date.now() - cached.at < DETAIL_TTL) return cached.detail;
|
|
2995
|
+
const detail = await api.message({
|
|
2996
|
+
id: item.id,
|
|
2997
|
+
accountId: item.accountId,
|
|
2998
|
+
source,
|
|
2999
|
+
mailbox
|
|
3000
|
+
});
|
|
3001
|
+
detailCache.set(key, { at: Date.now(), detail });
|
|
3002
|
+
return detail;
|
|
3003
|
+
};
|
|
3004
|
+
const threadItems = selected === null ? [] : items.filter(
|
|
3005
|
+
(item) => item.accountId === selected.accountId && normalizeSubject(item.subject) === normalizeSubject(selected.subject)
|
|
3006
|
+
);
|
|
2808
3007
|
const isSent = isSentFolder(mailbox);
|
|
2809
3008
|
const groups = groupMessages(items);
|
|
2810
3009
|
const renderMessage = (item, meta = {}) => {
|
|
@@ -2830,6 +3029,12 @@ ${projectPicker.subject}`,
|
|
|
2830
3029
|
if (selectMode) toggleSelect(item);
|
|
2831
3030
|
else void openMessage(item);
|
|
2832
3031
|
}
|
|
3032
|
+
},
|
|
3033
|
+
onMouseEnter: () => {
|
|
3034
|
+
if (!selectMode) prefetchMessage(item);
|
|
3035
|
+
},
|
|
3036
|
+
onMouseLeave: () => {
|
|
3037
|
+
if (hoverTimer.current !== null) window.clearTimeout(hoverTimer.current);
|
|
2833
3038
|
}
|
|
2834
3039
|
},
|
|
2835
3040
|
(0, import_react9.createElement)(
|
|
@@ -3085,7 +3290,12 @@ ${projectPicker.subject}`,
|
|
|
3085
3290
|
"\u6E05\u9664"
|
|
3086
3291
|
)
|
|
3087
3292
|
),
|
|
3088
|
-
aiSearching ? (0, import_react9.createElement)(
|
|
3293
|
+
aiSearching ? (0, import_react9.createElement)(
|
|
3294
|
+
"div",
|
|
3295
|
+
{ className: "mailharbor-ai-search searching" },
|
|
3296
|
+
(0, import_react9.createElement)("span", { className: "mailharbor-spinner" }),
|
|
3297
|
+
`AI \u6B63\u5728\u7406\u89E3\u5E76\u641C\u7D22\u2026 ${String(aiElapsed)}s`
|
|
3298
|
+
) : null,
|
|
3089
3299
|
selectMode ? (0, import_react9.createElement)(
|
|
3090
3300
|
"div",
|
|
3091
3301
|
{ className: "mailharbor-selectbar" },
|
|
@@ -3252,6 +3462,20 @@ ${projectPicker.subject}`,
|
|
|
3252
3462
|
{ className: "small" },
|
|
3253
3463
|
loggedIn ? "\u5DF2\u767B\u5F55\uFF0C\u53EF\u5207\u6362\u300C\u670D\u52A1\u5668\u5B9E\u65F6\u300D\u67E5\u770B\u6700\u65B0\u90AE\u4EF6\u3002" : "\u6D4F\u89C8\u672C\u5730\u5907\u4EFD\u4E0D\u9700\u8981\u767B\u5F55\u3002"
|
|
3254
3464
|
)
|
|
3465
|
+
) : opening !== null && selected === null ? (0, import_react9.createElement)(
|
|
3466
|
+
"div",
|
|
3467
|
+
{ className: "mailharbor-reader" },
|
|
3468
|
+
(0, import_react9.createElement)(
|
|
3469
|
+
"div",
|
|
3470
|
+
{ className: "mailharbor-reader-head" },
|
|
3471
|
+
(0, import_react9.createElement)(
|
|
3472
|
+
"div",
|
|
3473
|
+
{ className: "mailharbor-reader-title" },
|
|
3474
|
+
(0, import_react9.createElement)("h2", null, opening),
|
|
3475
|
+
(0, import_react9.createElement)("span", { className: "mailharbor-spinner", style: { marginLeft: "8px" } })
|
|
3476
|
+
),
|
|
3477
|
+
(0, import_react9.createElement)("div", { className: "small muted" }, "\u6B63\u5728\u8BFB\u53D6\u90AE\u4EF6\u2026")
|
|
3478
|
+
)
|
|
3255
3479
|
) : (0, import_react9.createElement)(Reader, {
|
|
3256
3480
|
detail: selected,
|
|
3257
3481
|
source,
|
|
@@ -3261,7 +3485,10 @@ ${projectPicker.subject}`,
|
|
|
3261
3485
|
onAiAction: requestAi,
|
|
3262
3486
|
onExtractTasks: () => void extractTasks(),
|
|
3263
3487
|
onAddToProject: openProjectPicker,
|
|
3264
|
-
onClose: narrow ? () => setSelected(null) : void 0
|
|
3488
|
+
onClose: narrow ? () => setSelected(null) : void 0,
|
|
3489
|
+
thread: threadItems,
|
|
3490
|
+
onSelectMessage: (item) => void openMessage(item),
|
|
3491
|
+
loadDetail: loadDetailFor
|
|
3265
3492
|
})
|
|
3266
3493
|
),
|
|
3267
3494
|
railOpen ? (0, import_react9.createElement)(AiRail, {
|
|
@@ -3528,7 +3755,7 @@ ${projectPicker.subject}`,
|
|
|
3528
3755
|
{ style: { display: "flex", flexDirection: "column", gap: "8px" } },
|
|
3529
3756
|
extraction.items.map(
|
|
3530
3757
|
(item, index) => (0, import_react9.createElement)(
|
|
3531
|
-
"
|
|
3758
|
+
"div",
|
|
3532
3759
|
{ key: `${item.title}:${String(index)}`, className: "mailharbor-extract-row" },
|
|
3533
3760
|
(0, import_react9.createElement)("input", {
|
|
3534
3761
|
type: "checkbox",
|
|
@@ -3540,18 +3767,49 @@ ${projectPicker.subject}`,
|
|
|
3540
3767
|
}
|
|
3541
3768
|
}),
|
|
3542
3769
|
(0, import_react9.createElement)(
|
|
3543
|
-
"
|
|
3544
|
-
|
|
3545
|
-
(0, import_react9.createElement)("
|
|
3770
|
+
"div",
|
|
3771
|
+
{ className: "extract-body" },
|
|
3772
|
+
(0, import_react9.createElement)("input", {
|
|
3773
|
+
className: "extract-title",
|
|
3774
|
+
value: item.title,
|
|
3775
|
+
onChange: (event) => updateSuggestion(index, { title: event.target.value })
|
|
3776
|
+
}),
|
|
3546
3777
|
(0, import_react9.createElement)(
|
|
3547
|
-
"
|
|
3548
|
-
{ className: "
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3778
|
+
"div",
|
|
3779
|
+
{ className: "extract-meta" },
|
|
3780
|
+
(0, import_react9.createElement)("input", {
|
|
3781
|
+
type: "date",
|
|
3782
|
+
value: item.due,
|
|
3783
|
+
onChange: (event) => updateSuggestion(index, { due: event.target.value })
|
|
3784
|
+
}),
|
|
3785
|
+
(0, import_react9.createElement)(
|
|
3786
|
+
"select",
|
|
3787
|
+
{
|
|
3788
|
+
value: String(item.priority),
|
|
3789
|
+
onChange: (event) => updateSuggestion(index, { priority: Number(event.target.value) })
|
|
3790
|
+
},
|
|
3791
|
+
(0, import_react9.createElement)("option", { value: "0" }, "\u65E0\u4F18\u5148\u7EA7"),
|
|
3792
|
+
(0, import_react9.createElement)("option", { value: "3" }, "\u4F4E"),
|
|
3793
|
+
(0, import_react9.createElement)("option", { value: "5" }, "\u4E2D"),
|
|
3794
|
+
(0, import_react9.createElement)("option", { value: "9" }, "\u9AD8")
|
|
3795
|
+
),
|
|
3796
|
+
(0, import_react9.createElement)("input", {
|
|
3797
|
+
className: "extract-owner",
|
|
3798
|
+
value: item.owner,
|
|
3799
|
+
placeholder: "\u8FD9\u4E2A\u4E8B\u8054\u7CFB\u8C01",
|
|
3800
|
+
onChange: (event) => updateSuggestion(index, { owner: event.target.value })
|
|
3801
|
+
})
|
|
3802
|
+
),
|
|
3803
|
+
item.notes === "" ? null : (0, import_react9.createElement)("span", { className: "small muted" }, item.notes)
|
|
3804
|
+
),
|
|
3805
|
+
(0, import_react9.createElement)(
|
|
3806
|
+
"button",
|
|
3807
|
+
{
|
|
3808
|
+
className: "subtle icon",
|
|
3809
|
+
title: "\u79FB\u9664\u8FD9\u6761",
|
|
3810
|
+
onClick: () => removeSuggestion(index)
|
|
3811
|
+
},
|
|
3812
|
+
(0, import_react9.createElement)(Icon, { name: "close", size: 12 })
|
|
3555
3813
|
)
|
|
3556
3814
|
)
|
|
3557
3815
|
)
|
|
@@ -4249,7 +4507,8 @@ var COLUMNS = [
|
|
|
4249
4507
|
{ status: "COMPLETED", label: "\u5DF2\u5B8C\u6210", hint: "\u6536\u5C3E" },
|
|
4250
4508
|
{ status: "CANCELLED", label: "\u7EC8\u6B62", hint: "\u4E0D\u505A\u4E86" }
|
|
4251
4509
|
];
|
|
4252
|
-
var PRIORITY_LABEL = { 0: "\u65E0", 5: "\u4E2D", 9: "\u9AD8" };
|
|
4510
|
+
var PRIORITY_LABEL = { 0: "\u65E0", 3: "\u4F4E", 5: "\u4E2D", 9: "\u9AD8" };
|
|
4511
|
+
var PRIORITIES = [0, 3, 5, 9];
|
|
4253
4512
|
function errorText7(error) {
|
|
4254
4513
|
return error instanceof ApiError || error instanceof Error ? error.message : String(error);
|
|
4255
4514
|
}
|
|
@@ -4620,7 +4879,7 @@ function TasksPanel() {
|
|
|
4620
4879
|
(0, import_react11.createElement)(Icon, { name: "calendar", size: 12 }),
|
|
4621
4880
|
dueText(task.due)
|
|
4622
4881
|
),
|
|
4623
|
-
task.owner === "" ? null : (0, import_react11.createElement)("span", { className: "task-owner" }, task.owner),
|
|
4882
|
+
task.owner === "" ? null : (0, import_react11.createElement)("span", { className: "task-owner" }, `\u8054\u7CFB ${task.owner}`),
|
|
4624
4883
|
task.projectId === null ? null : (0, import_react11.createElement)(
|
|
4625
4884
|
"span",
|
|
4626
4885
|
{ className: "task-project" },
|
|
@@ -4628,8 +4887,8 @@ function TasksPanel() {
|
|
|
4628
4887
|
),
|
|
4629
4888
|
task.priority > 0 ? (0, import_react11.createElement)(
|
|
4630
4889
|
"span",
|
|
4631
|
-
{ className:
|
|
4632
|
-
|
|
4890
|
+
{ className: `task-priority-label p${String(task.priority)}` },
|
|
4891
|
+
PRIORITY_LABEL[task.priority] ?? String(task.priority)
|
|
4633
4892
|
) : null
|
|
4634
4893
|
),
|
|
4635
4894
|
task.messageKey === "" ? null : (0, import_react11.createElement)(
|
|
@@ -4660,17 +4919,147 @@ function TasksPanel() {
|
|
|
4660
4919
|
setCreating(null);
|
|
4661
4920
|
setEditing(null);
|
|
4662
4921
|
},
|
|
4663
|
-
onSave: (draft) => void save(draft)
|
|
4922
|
+
onSave: (draft) => void save(draft),
|
|
4923
|
+
onDelete: editing === null ? void 0 : () => {
|
|
4924
|
+
void remove(editing);
|
|
4925
|
+
setEditing(null);
|
|
4926
|
+
}
|
|
4664
4927
|
}) : null
|
|
4665
4928
|
);
|
|
4666
4929
|
}
|
|
4930
|
+
function datePickerLabel(value) {
|
|
4931
|
+
if (value === "") return "\u4E0D\u8BBE\u622A\u6B62";
|
|
4932
|
+
const date = /* @__PURE__ */ new Date(`${value}T00:00:00`);
|
|
4933
|
+
if (Number.isNaN(date.getTime())) return value;
|
|
4934
|
+
return date.toLocaleDateString("zh-CN", { month: "long", day: "numeric", weekday: "short" });
|
|
4935
|
+
}
|
|
4936
|
+
function shiftDate(days) {
|
|
4937
|
+
const date = /* @__PURE__ */ new Date();
|
|
4938
|
+
date.setDate(date.getDate() + days);
|
|
4939
|
+
return dateKey(date);
|
|
4940
|
+
}
|
|
4941
|
+
function nextFriday() {
|
|
4942
|
+
const date = /* @__PURE__ */ new Date();
|
|
4943
|
+
const delta = (5 - date.getDay() + 7) % 7;
|
|
4944
|
+
date.setDate(date.getDate() + delta);
|
|
4945
|
+
return dateKey(date);
|
|
4946
|
+
}
|
|
4947
|
+
function nextMonday() {
|
|
4948
|
+
const date = /* @__PURE__ */ new Date();
|
|
4949
|
+
const delta = (8 - date.getDay()) % 7 || 7;
|
|
4950
|
+
date.setDate(date.getDate() + delta);
|
|
4951
|
+
return dateKey(date);
|
|
4952
|
+
}
|
|
4953
|
+
function DuePicker({ value, onChange }) {
|
|
4954
|
+
const [open, setOpen] = (0, import_react11.useState)(false);
|
|
4955
|
+
const choose = (next) => {
|
|
4956
|
+
onChange(next);
|
|
4957
|
+
setOpen(false);
|
|
4958
|
+
};
|
|
4959
|
+
const options = [
|
|
4960
|
+
{ label: "\u4ECA\u5929", value: shiftDate(0) },
|
|
4961
|
+
{ label: "\u660E\u5929", value: shiftDate(1) },
|
|
4962
|
+
{ label: "\u672C\u5468\u4E94", value: nextFriday() },
|
|
4963
|
+
{ label: "\u4E0B\u5468\u4E00", value: nextMonday() }
|
|
4964
|
+
];
|
|
4965
|
+
return (0, import_react11.createElement)(
|
|
4966
|
+
"div",
|
|
4967
|
+
{ className: "task-due" },
|
|
4968
|
+
(0, import_react11.createElement)(
|
|
4969
|
+
"button",
|
|
4970
|
+
{
|
|
4971
|
+
type: "button",
|
|
4972
|
+
className: value === "" ? "task-due-trigger empty" : "task-due-trigger",
|
|
4973
|
+
onClick: () => setOpen(!open)
|
|
4974
|
+
},
|
|
4975
|
+
(0, import_react11.createElement)(Icon, { name: "calendar", size: 14 }),
|
|
4976
|
+
(0, import_react11.createElement)("span", null, datePickerLabel(value)),
|
|
4977
|
+
(0, import_react11.createElement)(Icon, { name: "chevronRight", size: 12 })
|
|
4978
|
+
),
|
|
4979
|
+
open ? (0, import_react11.createElement)(
|
|
4980
|
+
"div",
|
|
4981
|
+
{ className: "task-due-popover" },
|
|
4982
|
+
(0, import_react11.createElement)(
|
|
4983
|
+
"div",
|
|
4984
|
+
{ className: "task-due-quick" },
|
|
4985
|
+
options.map(
|
|
4986
|
+
(option) => (0, import_react11.createElement)(
|
|
4987
|
+
"button",
|
|
4988
|
+
{
|
|
4989
|
+
key: option.label,
|
|
4990
|
+
type: "button",
|
|
4991
|
+
className: value === option.value ? "active" : "",
|
|
4992
|
+
onClick: () => choose(option.value)
|
|
4993
|
+
},
|
|
4994
|
+
option.label
|
|
4995
|
+
)
|
|
4996
|
+
)
|
|
4997
|
+
),
|
|
4998
|
+
(0, import_react11.createElement)("input", {
|
|
4999
|
+
type: "date",
|
|
5000
|
+
value,
|
|
5001
|
+
onChange: (event) => onChange(event.target.value)
|
|
5002
|
+
}),
|
|
5003
|
+
(0, import_react11.createElement)(
|
|
5004
|
+
"div",
|
|
5005
|
+
{ className: "task-due-foot" },
|
|
5006
|
+
(0, import_react11.createElement)("button", { type: "button", className: "subtle small", onClick: () => choose("") }, "\u6E05\u9664\u622A\u6B62"),
|
|
5007
|
+
(0, import_react11.createElement)("button", { type: "button", className: "subtle small", onClick: () => setOpen(false) }, "\u5173\u95ED")
|
|
5008
|
+
)
|
|
5009
|
+
) : null
|
|
5010
|
+
);
|
|
5011
|
+
}
|
|
5012
|
+
function StatusPicker({
|
|
5013
|
+
value,
|
|
5014
|
+
onChange
|
|
5015
|
+
}) {
|
|
5016
|
+
return (0, import_react11.createElement)(
|
|
5017
|
+
"div",
|
|
5018
|
+
{ className: "task-status-picker" },
|
|
5019
|
+
COLUMNS.map(
|
|
5020
|
+
(column) => (0, import_react11.createElement)(
|
|
5021
|
+
"button",
|
|
5022
|
+
{
|
|
5023
|
+
key: column.status,
|
|
5024
|
+
type: "button",
|
|
5025
|
+
className: value === column.status ? "active" : "",
|
|
5026
|
+
onClick: () => onChange(column.status)
|
|
5027
|
+
},
|
|
5028
|
+
(0, import_react11.createElement)("span", { className: `task-dot ${column.status}` }),
|
|
5029
|
+
column.label
|
|
5030
|
+
)
|
|
5031
|
+
)
|
|
5032
|
+
);
|
|
5033
|
+
}
|
|
5034
|
+
function PriorityPicker({
|
|
5035
|
+
value,
|
|
5036
|
+
onChange
|
|
5037
|
+
}) {
|
|
5038
|
+
return (0, import_react11.createElement)(
|
|
5039
|
+
"div",
|
|
5040
|
+
{ className: "task-priority-picker" },
|
|
5041
|
+
PRIORITIES.map(
|
|
5042
|
+
(priority) => (0, import_react11.createElement)(
|
|
5043
|
+
"button",
|
|
5044
|
+
{
|
|
5045
|
+
key: priority,
|
|
5046
|
+
type: "button",
|
|
5047
|
+
className: `p${String(priority)}${value === priority ? " active" : ""}`,
|
|
5048
|
+
onClick: () => onChange(priority)
|
|
5049
|
+
},
|
|
5050
|
+
PRIORITY_LABEL[priority] ?? String(priority)
|
|
5051
|
+
)
|
|
5052
|
+
)
|
|
5053
|
+
);
|
|
5054
|
+
}
|
|
4667
5055
|
function TaskEditor({
|
|
4668
5056
|
task,
|
|
4669
5057
|
status,
|
|
4670
5058
|
projects,
|
|
4671
5059
|
busy,
|
|
4672
5060
|
onClose,
|
|
4673
|
-
onSave
|
|
5061
|
+
onSave,
|
|
5062
|
+
onDelete
|
|
4674
5063
|
}) {
|
|
4675
5064
|
const [draft, setDraft] = (0, import_react11.useState)({
|
|
4676
5065
|
...EMPTY,
|
|
@@ -4686,7 +5075,16 @@ function TaskEditor({
|
|
|
4686
5075
|
projectId: task.projectId ?? ""
|
|
4687
5076
|
}
|
|
4688
5077
|
});
|
|
5078
|
+
const [sourceError, setSourceError] = (0, import_react11.useState)("");
|
|
4689
5079
|
const set = (patch) => setDraft((current) => ({ ...current, ...patch }));
|
|
5080
|
+
const openSource = () => {
|
|
5081
|
+
if (task === null || task.messageKey === "") return;
|
|
5082
|
+
void api.lookupMessage(task.accountId, task.messageKey).then((found) => {
|
|
5083
|
+
requestOpenMail({ accountId: task.accountId, id: found.id, mailbox: found.mailbox });
|
|
5084
|
+
document.querySelector('button[aria-label="MailHarbor"]')?.click();
|
|
5085
|
+
onClose();
|
|
5086
|
+
}).catch((caught) => setSourceError(errorText7(caught)));
|
|
5087
|
+
};
|
|
4690
5088
|
return (0, import_react11.createElement)(
|
|
4691
5089
|
Modal,
|
|
4692
5090
|
{
|
|
@@ -4696,7 +5094,16 @@ function TaskEditor({
|
|
|
4696
5094
|
footer: (0, import_react11.createElement)(
|
|
4697
5095
|
"div",
|
|
4698
5096
|
{ className: "task-editor-foot" },
|
|
4699
|
-
(0, import_react11.createElement)(
|
|
5097
|
+
onDelete === void 0 ? null : (0, import_react11.createElement)(
|
|
5098
|
+
"button",
|
|
5099
|
+
{
|
|
5100
|
+
className: "subtle small danger",
|
|
5101
|
+
onClick: () => {
|
|
5102
|
+
if (window.confirm("\u5220\u9664\u8FD9\u4E2A\u4EFB\u52A1\uFF1F")) onDelete();
|
|
5103
|
+
}
|
|
5104
|
+
},
|
|
5105
|
+
"\u5220\u9664\u4EFB\u52A1"
|
|
5106
|
+
),
|
|
4700
5107
|
(0, import_react11.createElement)("span", { className: "spacer" }),
|
|
4701
5108
|
(0, import_react11.createElement)("button", { className: "ghost", onClick: onClose }, "\u53D6\u6D88"),
|
|
4702
5109
|
(0, import_react11.createElement)(
|
|
@@ -4712,92 +5119,56 @@ function TaskEditor({
|
|
|
4712
5119
|
},
|
|
4713
5120
|
(0, import_react11.createElement)(
|
|
4714
5121
|
"div",
|
|
4715
|
-
{ className: "task-editor" },
|
|
5122
|
+
{ className: "task-editor-v2" },
|
|
4716
5123
|
(0, import_react11.createElement)(
|
|
4717
5124
|
"div",
|
|
4718
|
-
{ className: "task-editor-
|
|
4719
|
-
(0, import_react11.createElement)(
|
|
4720
|
-
"
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
5125
|
+
{ className: "task-editor-head" },
|
|
5126
|
+
(0, import_react11.createElement)("input", {
|
|
5127
|
+
className: "task-title-input",
|
|
5128
|
+
value: draft.title,
|
|
5129
|
+
autoFocus: true,
|
|
5130
|
+
placeholder: "\u8981\u505A\u4EC0\u4E48\uFF1F",
|
|
5131
|
+
onChange: (event) => set({ title: event.target.value })
|
|
5132
|
+
}),
|
|
5133
|
+
(0, import_react11.createElement)(StatusPicker, {
|
|
5134
|
+
value: draft.status,
|
|
5135
|
+
onChange: (next) => set({ status: next })
|
|
5136
|
+
})
|
|
5137
|
+
),
|
|
5138
|
+
(0, import_react11.createElement)(
|
|
5139
|
+
"div",
|
|
5140
|
+
{ className: "task-editor-columns" },
|
|
4729
5141
|
(0, import_react11.createElement)(
|
|
4730
5142
|
"div",
|
|
4731
|
-
{ className: "task-editor-
|
|
4732
|
-
(0, import_react11.createElement)("label",
|
|
5143
|
+
{ className: "task-editor-col" },
|
|
5144
|
+
(0, import_react11.createElement)("label", { className: "task-label" }, "\u5907\u6CE8"),
|
|
4733
5145
|
(0, import_react11.createElement)("textarea", {
|
|
4734
|
-
rows:
|
|
5146
|
+
rows: 6,
|
|
4735
5147
|
value: draft.notes,
|
|
4736
5148
|
placeholder: "\u80CC\u666F\u3001\u4E0B\u4E00\u6B65\u3001\u94FE\u63A5\u2026",
|
|
4737
5149
|
onChange: (event) => set({ notes: event.target.value })
|
|
4738
|
-
})
|
|
4739
|
-
|
|
4740
|
-
(0, import_react11.createElement)(
|
|
4741
|
-
"div",
|
|
4742
|
-
{ className: "task-editor-section" },
|
|
4743
|
-
(0, import_react11.createElement)("label", null, "\u6765\u6E90"),
|
|
4744
|
-
draft.id === void 0 ? (0, import_react11.createElement)("span", { className: "small muted" }, "\u4ECE\u90AE\u4EF6\u63D0\u53D6\u7684\u4EFB\u52A1\u4F1A\u81EA\u52A8\u5173\u8054\u6765\u6E90\u90AE\u4EF6\u3002") : (0, import_react11.createElement)(
|
|
4745
|
-
"span",
|
|
4746
|
-
{ className: "small muted" },
|
|
4747
|
-
task?.messageSubject !== void 0 && task.messageSubject !== "" ? `\u6765\u81EA\u90AE\u4EF6\uFF1A${task.messageSubject}` : "\u65E0\u5173\u8054\u90AE\u4EF6"
|
|
4748
|
-
)
|
|
4749
|
-
)
|
|
4750
|
-
),
|
|
4751
|
-
(0, import_react11.createElement)(
|
|
4752
|
-
"aside",
|
|
4753
|
-
{ className: "task-editor-side" },
|
|
4754
|
-
(0, import_react11.createElement)(
|
|
4755
|
-
"div",
|
|
4756
|
-
{ className: "task-editor-field" },
|
|
4757
|
-
(0, import_react11.createElement)("label", null, "\u72B6\u6001"),
|
|
4758
|
-
(0, import_react11.createElement)(
|
|
4759
|
-
"select",
|
|
4760
|
-
{
|
|
4761
|
-
value: draft.status,
|
|
4762
|
-
onChange: (event) => set({ status: event.target.value })
|
|
4763
|
-
},
|
|
4764
|
-
COLUMNS.map((column) => (0, import_react11.createElement)("option", { key: column.status, value: column.status }, column.label))
|
|
4765
|
-
)
|
|
4766
|
-
),
|
|
4767
|
-
(0, import_react11.createElement)(
|
|
4768
|
-
"div",
|
|
4769
|
-
{ className: "task-editor-field" },
|
|
4770
|
-
(0, import_react11.createElement)("label", null, "\u622A\u6B62\u65E5\u671F"),
|
|
4771
|
-
(0, import_react11.createElement)("input", {
|
|
4772
|
-
type: "date",
|
|
4773
|
-
value: draft.due,
|
|
4774
|
-
onChange: (event) => set({ due: event.target.value })
|
|
4775
|
-
})
|
|
4776
|
-
),
|
|
4777
|
-
(0, import_react11.createElement)(
|
|
4778
|
-
"div",
|
|
4779
|
-
{ className: "task-editor-field" },
|
|
4780
|
-
(0, import_react11.createElement)("label", null, "\u4F18\u5148\u7EA7"),
|
|
4781
|
-
(0, import_react11.createElement)(
|
|
5150
|
+
}),
|
|
5151
|
+
task === null || task.messageKey === "" ? (0, import_react11.createElement)("p", { className: "task-hint" }, "\u4ECE\u90AE\u4EF6\u63D0\u53D6\u7684\u4EFB\u52A1\u4F1A\u81EA\u52A8\u5173\u8054\u6765\u6E90\u90AE\u4EF6\u3002") : (0, import_react11.createElement)(
|
|
4782
5152
|
"div",
|
|
4783
|
-
{ className: "task-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
)
|
|
4794
|
-
)
|
|
4795
|
-
)
|
|
5153
|
+
{ className: "task-source-row" },
|
|
5154
|
+
(0, import_react11.createElement)(
|
|
5155
|
+
"button",
|
|
5156
|
+
{ className: "ghost small", onClick: openSource },
|
|
5157
|
+
(0, import_react11.createElement)(Icon, { name: "mail", size: 13 }),
|
|
5158
|
+
"\u6253\u5F00\u6765\u6E90\u90AE\u4EF6"
|
|
5159
|
+
),
|
|
5160
|
+
(0, import_react11.createElement)("span", { className: "task-hint" }, task.messageSubject === "" ? "" : task.messageSubject)
|
|
5161
|
+
),
|
|
5162
|
+
sourceError === "" ? null : (0, import_react11.createElement)("p", { className: "task-hint danger" }, sourceError)
|
|
4796
5163
|
),
|
|
4797
5164
|
(0, import_react11.createElement)(
|
|
4798
|
-
"
|
|
4799
|
-
{ className: "task-editor-
|
|
4800
|
-
(0, import_react11.createElement)("label",
|
|
5165
|
+
"aside",
|
|
5166
|
+
{ className: "task-editor-col side" },
|
|
5167
|
+
(0, import_react11.createElement)("label", { className: "task-label" }, "\u622A\u6B62\u65E5\u671F"),
|
|
5168
|
+
(0, import_react11.createElement)(DuePicker, { value: draft.due, onChange: (next) => set({ due: next }) }),
|
|
5169
|
+
(0, import_react11.createElement)("label", { className: "task-label" }, "\u4F18\u5148\u7EA7"),
|
|
5170
|
+
(0, import_react11.createElement)(PriorityPicker, { value: draft.priority, onChange: (next) => set({ priority: next }) }),
|
|
5171
|
+
(0, import_react11.createElement)("label", { className: "task-label" }, "\u9879\u76EE"),
|
|
4801
5172
|
(0, import_react11.createElement)(
|
|
4802
5173
|
"select",
|
|
4803
5174
|
{
|
|
@@ -4806,15 +5177,11 @@ function TaskEditor({
|
|
|
4806
5177
|
},
|
|
4807
5178
|
(0, import_react11.createElement)("option", { value: "" }, "\u65E0\u9879\u76EE"),
|
|
4808
5179
|
projects.map((project) => (0, import_react11.createElement)("option", { key: project.id, value: project.id }, project.name))
|
|
4809
|
-
)
|
|
4810
|
-
|
|
4811
|
-
(0, import_react11.createElement)(
|
|
4812
|
-
"div",
|
|
4813
|
-
{ className: "task-editor-field" },
|
|
4814
|
-
(0, import_react11.createElement)("label", null, "\u8D1F\u8D23\u4EBA"),
|
|
5180
|
+
),
|
|
5181
|
+
(0, import_react11.createElement)("label", { className: "task-label" }, "\u8FD9\u4E2A\u4E8B\u8054\u7CFB\u8C01"),
|
|
4815
5182
|
(0, import_react11.createElement)("input", {
|
|
4816
5183
|
value: draft.owner,
|
|
4817
|
-
placeholder: "\u53EF\
|
|
5184
|
+
placeholder: "\u59D3\u540D\u6216\u90AE\u7BB1\uFF0C\u53EF\u7559\u7A7A",
|
|
4818
5185
|
onChange: (event) => set({ owner: event.target.value })
|
|
4819
5186
|
})
|
|
4820
5187
|
)
|
|
@@ -4824,7 +5191,7 @@ function TaskEditor({
|
|
|
4824
5191
|
}
|
|
4825
5192
|
|
|
4826
5193
|
// src/client/index.tsx
|
|
4827
|
-
var VERSION = "0.
|
|
5194
|
+
var VERSION = "0.9.0";
|
|
4828
5195
|
var inject = ["slots"];
|
|
4829
5196
|
var PANEL_ID = "mailharbor";
|
|
4830
5197
|
var TASKS_PANEL_ID = "mailharbor-tasks";
|