@zaclinley/dsh-mailharbor 0.7.1 → 0.8.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/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";
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";
39
39
 
40
40
  // src/client/icon.tsx
41
41
  var import_react = require("react");
@@ -187,6 +187,15 @@ var api = {
187
187
  syncTasks: (accountId) => request("tasks/sync", { method: "POST", body: JSON.stringify({ accountId }) }),
188
188
  projects: () => request("projects"),
189
189
  pickDirectory: () => request("projects/pick-directory", { method: "POST" }),
190
+ updateProject: (id, name) => request(`projects/${encodeURIComponent(id)}`, {
191
+ method: "PATCH",
192
+ body: JSON.stringify({ name })
193
+ }),
194
+ deleteProject: (id) => request(
195
+ `projects/${encodeURIComponent(id)}`,
196
+ { method: "DELETE" }
197
+ ),
198
+ openProject: (id) => request(`projects/${encodeURIComponent(id)}/open`, { method: "POST" }),
190
199
  projectFor: (accountId, key) => request(`projects/for${query({ accountId: accountId ?? null, key })}`),
191
200
  createProject: (payload) => request("projects", {
192
201
  method: "POST",
@@ -709,6 +718,7 @@ function AiRail({
709
718
  const [thread, setThread] = (0, import_react5.useState)(null);
710
719
  const [loading, setLoading] = (0, import_react5.useState)(false);
711
720
  const [generating, setGenerating] = (0, import_react5.useState)(null);
721
+ const [elapsed, setElapsed] = (0, import_react5.useState)(0);
712
722
  const [error, setError] = (0, import_react5.useState)("");
713
723
  const [question, setQuestion] = (0, import_react5.useState)("");
714
724
  const [confirmClear, setConfirmClear] = (0, import_react5.useState)(false);
@@ -785,6 +795,19 @@ function AiRail({
785
795
  const element = list.current;
786
796
  if (element !== null) element.scrollTop = element.scrollHeight;
787
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]);
788
811
  (0, import_react5.useEffect)(() => {
789
812
  if (detail === null || account === null) {
790
813
  setProject(null);
@@ -1063,7 +1086,15 @@ ${card.output}`
1063
1086
  "article",
1064
1087
  { className: "mailharbor-ai-card generating" },
1065
1088
  (0, import_react5.createElement)("div", { className: "mailharbor-ai-card-head" }, (0, import_react5.createElement)("span", null, KIND_LABEL[generating])),
1066
- (0, import_react5.createElement)("div", { className: "mailharbor-ai-text muted" }, "\u6B63\u5728\u751F\u6210\u2026")
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
+ )
1067
1098
  ) : null,
1068
1099
  error === "" ? null : (0, import_react5.createElement)("div", { className: "mailharbor-ai-error" }, error)
1069
1100
  ),
@@ -1768,12 +1799,22 @@ function Composer({
1768
1799
  (0, import_react7.createElement)(
1769
1800
  "button",
1770
1801
  { className: "ai", onClick: () => void runAi("polish"), disabled: aiBusy !== null || !hasBody },
1771
- aiBusy === "polish" ? "\u6DA6\u8272\u4E2D\u2026" : "\u6DA6\u8272"
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"
1772
1808
  ),
1773
1809
  (0, import_react7.createElement)(
1774
1810
  "button",
1775
1811
  { className: "ai", onClick: () => void runAi("shorten"), disabled: aiBusy !== null || !hasBody },
1776
- aiBusy === "shorten" ? "\u7F29\u77ED\u4E2D\u2026" : "\u7F29\u77ED"
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"
1777
1818
  ),
1778
1819
  (0, import_react7.createElement)(
1779
1820
  "button",
@@ -2124,6 +2165,8 @@ var EMPTY_PAGE = { items: [], total: 0, offset: 0, limit: 40 };
2124
2165
  var DRAFTS = "__drafts";
2125
2166
  var folderCache = /* @__PURE__ */ new Map();
2126
2167
  var pageCache = /* @__PURE__ */ new Map();
2168
+ var detailCache = /* @__PURE__ */ new Map();
2169
+ var DETAIL_TTL = 12e4;
2127
2170
  var FOLDER_LABELS = {
2128
2171
  INBOX: "\u6536\u4EF6\u7BB1",
2129
2172
  "Sent Items": "\u5DF2\u53D1\u9001",
@@ -2210,7 +2253,16 @@ function MailPanel() {
2210
2253
  const [pickerTarget, setPickerTarget] = (0, import_react9.useState)("");
2211
2254
  const [pickerNewName, setPickerNewName] = (0, import_react9.useState)("");
2212
2255
  const [pickerBusy, setPickerBusy] = (0, import_react9.useState)(false);
2256
+ const [pickerMode, setPickerMode] = (0, import_react9.useState)("existing");
2257
+ const [managerOpen, setManagerOpen] = (0, import_react9.useState)(false);
2258
+ const [managerProjects, setManagerProjects] = (0, import_react9.useState)([]);
2259
+ const [managerRename, setManagerRename] = (0, import_react9.useState)(null);
2260
+ const [managerConfirm, setManagerConfirm] = (0, import_react9.useState)("");
2261
+ const [managerBusy, setManagerBusy] = (0, import_react9.useState)(false);
2213
2262
  const [aiSearching, setAiSearching] = (0, import_react9.useState)(false);
2263
+ const [opening, setOpening] = (0, import_react9.useState)(null);
2264
+ const [aiElapsed, setAiElapsed] = (0, import_react9.useState)(0);
2265
+ const hoverTimer = (0, import_react9.useRef)(null);
2214
2266
  const [aiRequest, setAiRequest] = (0, import_react9.useState)(null);
2215
2267
  const [tick, setTick] = (0, import_react9.useState)(0);
2216
2268
  const accounts = state?.accounts ?? [];
@@ -2255,6 +2307,19 @@ function MailPanel() {
2255
2307
  setError(errorText5(caught));
2256
2308
  }
2257
2309
  };
2310
+ (0, import_react9.useEffect)(() => {
2311
+ if (!aiSearching) {
2312
+ setAiElapsed(0);
2313
+ return;
2314
+ }
2315
+ const started = Date.now();
2316
+ const timer = window.setInterval(() => {
2317
+ setAiElapsed(Math.floor((Date.now() - started) / 1e3));
2318
+ }, 1e3);
2319
+ return () => {
2320
+ window.clearInterval(timer);
2321
+ };
2322
+ }, [aiSearching]);
2258
2323
  const runAiSearch = async () => {
2259
2324
  const text = query2.trim();
2260
2325
  if (text === "" || accountScope === null) return;
@@ -2294,9 +2359,11 @@ function MailPanel() {
2294
2359
  });
2295
2360
  setPickerNewName(selected.subject.replace(/^(re|fwd):\s*/i, "").slice(0, 80));
2296
2361
  setPickerTarget("");
2297
- void api.projects().then((list) => {
2362
+ void Promise.all([api.projects(), api.projectFor(selected.accountId, key)]).then(([list, linked]) => {
2298
2363
  setPickerProjects(list.items);
2299
- setPickerTarget(list.items[0]?.id ?? "");
2364
+ const current = linked.project?.id ?? list.items[0]?.id ?? "";
2365
+ setPickerTarget(current);
2366
+ setPickerMode(current === "" ? "new" : "existing");
2300
2367
  }).catch((caught) => setError(errorText5(caught)));
2301
2368
  };
2302
2369
  const saveProjectPick = async () => {
@@ -2304,7 +2371,7 @@ function MailPanel() {
2304
2371
  setPickerBusy(true);
2305
2372
  setError("");
2306
2373
  try {
2307
- if (pickerTarget !== "") {
2374
+ if (pickerMode === "existing" && pickerTarget !== "") {
2308
2375
  await api.addProjectMessage(pickerTarget, {
2309
2376
  accountId: projectPicker.accountId,
2310
2377
  key: projectPicker.key,
@@ -2314,7 +2381,7 @@ function MailPanel() {
2314
2381
  notice("\u5DF2\u52A0\u5165\u9879\u76EE");
2315
2382
  } else {
2316
2383
  const name = pickerNewName.trim();
2317
- if (name === "") throw new Error("\u5148\u9009\u62E9\u4E00\u4E2A\u9879\u76EE\uFF0C\u6216\u586B\u5199\u65B0\u9879\u76EE\u540D\u79F0");
2384
+ if (name === "") throw new Error("\u8BF7\u586B\u5199\u65B0\u9879\u76EE\u540D\u79F0");
2318
2385
  const settings = await api.settings();
2319
2386
  const created = await api.createProject({
2320
2387
  accountId: projectPicker.accountId,
@@ -2339,6 +2406,28 @@ ${projectPicker.subject}`,
2339
2406
  setPickerBusy(false);
2340
2407
  }
2341
2408
  };
2409
+ const openManager = () => {
2410
+ setManagerOpen(true);
2411
+ setManagerConfirm("");
2412
+ setManagerRename(null);
2413
+ void api.projects().then((list) => setManagerProjects(list.items)).catch((caught) => setError(errorText5(caught)));
2414
+ };
2415
+ const managerAction = async (operation) => {
2416
+ setManagerBusy(true);
2417
+ setError("");
2418
+ try {
2419
+ await operation();
2420
+ const list = await api.projects();
2421
+ setManagerProjects(list.items);
2422
+ setManagerRename(null);
2423
+ setManagerConfirm("");
2424
+ setTick((value) => value + 1);
2425
+ } catch (caught) {
2426
+ setError(errorText5(caught));
2427
+ } finally {
2428
+ setManagerBusy(false);
2429
+ }
2430
+ };
2342
2431
  const toggleSide = () => {
2343
2432
  setSideOpen((open) => {
2344
2433
  try {
@@ -2406,6 +2495,22 @@ ${projectPicker.subject}`,
2406
2495
  setExtractBusy(false);
2407
2496
  }
2408
2497
  };
2498
+ const updateSuggestion = (index, patch) => {
2499
+ setExtraction(
2500
+ (current) => current === null ? null : {
2501
+ ...current,
2502
+ items: current.items.map((item, position) => position === index ? { ...item, ...patch } : item)
2503
+ }
2504
+ );
2505
+ };
2506
+ const removeSuggestion = (index) => {
2507
+ setExtraction(
2508
+ (current) => current === null ? null : {
2509
+ items: current.items.filter((_item, position) => position !== index),
2510
+ checked: current.checked.filter((_value, position) => position !== index)
2511
+ }
2512
+ );
2513
+ };
2409
2514
  const saveExtraction = async () => {
2410
2515
  if (extraction === null || selected === null) return;
2411
2516
  setExtractBusy(true);
@@ -2582,13 +2687,34 @@ ${projectPicker.subject}`,
2582
2687
  window.clearInterval(timer);
2583
2688
  };
2584
2689
  }, [showBackup, accountScope, isAll]);
2690
+ const messageKeyOf = (item) => `${item.accountId}:${source}:${item.id}`;
2691
+ const prefetchMessage = (item) => {
2692
+ if (hoverTimer.current !== null) window.clearTimeout(hoverTimer.current);
2693
+ hoverTimer.current = window.setTimeout(() => {
2694
+ const key = messageKeyOf(item);
2695
+ const cached = detailCache.get(key);
2696
+ if (cached !== void 0 && Date.now() - cached.at < DETAIL_TTL) return;
2697
+ void api.message({ id: item.id, accountId: item.accountId, source, mailbox }).then((detail) => {
2698
+ detailCache.set(key, { at: Date.now(), detail });
2699
+ }).catch(() => void 0);
2700
+ }, 160);
2701
+ };
2585
2702
  const openMessage = async (item) => {
2586
2703
  const owner = item.accountId;
2587
2704
  const ownerSource = source;
2705
+ const cacheKey = messageKeyOf(item);
2706
+ const cached = detailCache.get(cacheKey);
2588
2707
  setError("");
2708
+ if (cached !== void 0 && Date.now() - cached.at < DETAIL_TTL) {
2709
+ setSelected(cached.detail);
2710
+ } else {
2711
+ setOpening(item.subject);
2712
+ }
2589
2713
  try {
2590
- const detail = await api.message({ id: item.id, accountId: owner, source: ownerSource, mailbox });
2714
+ const detail = cached !== void 0 && Date.now() - cached.at < DETAIL_TTL ? cached.detail : await api.message({ id: item.id, accountId: owner, source: ownerSource, mailbox });
2715
+ detailCache.set(cacheKey, { at: Date.now(), detail });
2591
2716
  setSelected(detail);
2717
+ setOpening(null);
2592
2718
  if (detail.unread && state?.settings.read.markOnOpen === true) {
2593
2719
  try {
2594
2720
  await api.setRead({ id: detail.id, accountId: owner, source: ownerSource, mailbox, read: true });
@@ -2601,6 +2727,7 @@ ${projectPicker.subject}`,
2601
2727
  }
2602
2728
  }
2603
2729
  } catch (caught) {
2730
+ setOpening(null);
2604
2731
  setError(errorText5(caught));
2605
2732
  }
2606
2733
  };
@@ -2791,6 +2918,12 @@ ${projectPicker.subject}`,
2791
2918
  if (selectMode) toggleSelect(item);
2792
2919
  else void openMessage(item);
2793
2920
  }
2921
+ },
2922
+ onMouseEnter: () => {
2923
+ if (!selectMode) prefetchMessage(item);
2924
+ },
2925
+ onMouseLeave: () => {
2926
+ if (hoverTimer.current !== null) window.clearTimeout(hoverTimer.current);
2794
2927
  }
2795
2928
  },
2796
2929
  (0, import_react9.createElement)(
@@ -2889,6 +3022,12 @@ ${projectPicker.subject}`,
2889
3022
  (0, import_react9.createElement)(Icon, { name: "archive" }),
2890
3023
  "\u5907\u4EFD"
2891
3024
  ),
3025
+ (0, import_react9.createElement)(
3026
+ "button",
3027
+ { className: "ghost", onClick: openManager, title: "\u9879\u76EE\u7BA1\u7406" },
3028
+ (0, import_react9.createElement)(Icon, { name: "folder" }),
3029
+ "\u9879\u76EE"
3030
+ ),
2892
3031
  (0, import_react9.createElement)(
2893
3032
  "button",
2894
3033
  {
@@ -3040,7 +3179,12 @@ ${projectPicker.subject}`,
3040
3179
  "\u6E05\u9664"
3041
3180
  )
3042
3181
  ),
3043
- aiSearching ? (0, import_react9.createElement)("div", { className: "mailharbor-ai-search searching" }, "AI \u6B63\u5728\u7406\u89E3\u5E76\u641C\u7D22\u2026") : null,
3182
+ aiSearching ? (0, import_react9.createElement)(
3183
+ "div",
3184
+ { className: "mailharbor-ai-search searching" },
3185
+ (0, import_react9.createElement)("span", { className: "mailharbor-spinner" }),
3186
+ `AI \u6B63\u5728\u7406\u89E3\u5E76\u641C\u7D22\u2026 ${String(aiElapsed)}s`
3187
+ ) : null,
3044
3188
  selectMode ? (0, import_react9.createElement)(
3045
3189
  "div",
3046
3190
  { className: "mailharbor-selectbar" },
@@ -3207,6 +3351,20 @@ ${projectPicker.subject}`,
3207
3351
  { className: "small" },
3208
3352
  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"
3209
3353
  )
3354
+ ) : opening !== null && selected === null ? (0, import_react9.createElement)(
3355
+ "div",
3356
+ { className: "mailharbor-reader" },
3357
+ (0, import_react9.createElement)(
3358
+ "div",
3359
+ { className: "mailharbor-reader-head" },
3360
+ (0, import_react9.createElement)(
3361
+ "div",
3362
+ { className: "mailharbor-reader-title" },
3363
+ (0, import_react9.createElement)("h2", null, opening),
3364
+ (0, import_react9.createElement)("span", { className: "mailharbor-spinner", style: { marginLeft: "8px" } })
3365
+ ),
3366
+ (0, import_react9.createElement)("div", { className: "small muted" }, "\u6B63\u5728\u8BFB\u53D6\u90AE\u4EF6\u2026")
3367
+ )
3210
3368
  ) : (0, import_react9.createElement)(Reader, {
3211
3369
  detail: selected,
3212
3370
  source,
@@ -3263,6 +3421,120 @@ ${projectPicker.subject}`,
3263
3421
  backup.output.length === 0 ? "\uFF08\u7B49\u5F85\u8F93\u51FA\u2026\uFF09" : backup.output.join("\n")
3264
3422
  )
3265
3423
  ) : null,
3424
+ managerOpen ? (0, import_react9.createElement)(
3425
+ Modal,
3426
+ {
3427
+ title: "\u9879\u76EE\u7BA1\u7406",
3428
+ onClose: () => setManagerOpen(false),
3429
+ wide: true,
3430
+ footer: (0, import_react9.createElement)(
3431
+ "div",
3432
+ { className: "task-editor-foot" },
3433
+ (0, import_react9.createElement)(
3434
+ "span",
3435
+ { className: "small muted" },
3436
+ "\u5220\u9664\u53EA\u79FB\u9664 MailHarbor \u7684\u9879\u76EE\u8BB0\u5F55\uFF0C\u6587\u4EF6\u5939\u4E0E DSH \u5DE5\u4F5C\u7A7A\u95F4\u4F1A\u4FDD\u7559\u3002"
3437
+ ),
3438
+ (0, import_react9.createElement)("span", { className: "spacer" }),
3439
+ (0, import_react9.createElement)("button", { className: "ghost", onClick: () => setManagerOpen(false) }, "\u5173\u95ED")
3440
+ )
3441
+ },
3442
+ managerProjects.length === 0 ? (0, import_react9.createElement)(
3443
+ "p",
3444
+ { className: "small muted" },
3445
+ "\u8FD8\u6CA1\u6709\u9879\u76EE\u3002\u53EF\u4EE5\u4ECE\u4E00\u5C01\u90AE\u4EF6\u7684\u300C\u52A0\u5165\u9879\u76EE \u2192 \u65B0\u5EFA\u9879\u76EE\u300D\u5F00\u59CB\u3002"
3446
+ ) : (0, import_react9.createElement)(
3447
+ "div",
3448
+ { className: "project-manager" },
3449
+ managerProjects.map(
3450
+ (project) => (0, import_react9.createElement)(
3451
+ "div",
3452
+ { key: project.id, className: "project-manager-row" },
3453
+ (0, import_react9.createElement)(
3454
+ "div",
3455
+ { className: "project-manager-main" },
3456
+ managerRename?.id === project.id ? (0, import_react9.createElement)("input", {
3457
+ value: managerRename.name,
3458
+ autoFocus: true,
3459
+ onChange: (event) => setManagerRename({ id: project.id, name: event.target.value }),
3460
+ onKeyDown: (event) => {
3461
+ if (event.key === "Enter" && managerRename.name.trim() !== "") {
3462
+ void managerAction(
3463
+ () => api.updateProject(project.id, managerRename.name.trim())
3464
+ );
3465
+ }
3466
+ }
3467
+ }) : (0, import_react9.createElement)("strong", null, project.name),
3468
+ (0, import_react9.createElement)(
3469
+ "span",
3470
+ { className: "small muted" },
3471
+ `${String(project.messages.length)} \u5C01\u6765\u6E90\u90AE\u4EF6 \xB7 ${project.path}`
3472
+ )
3473
+ ),
3474
+ (0, import_react9.createElement)(
3475
+ "div",
3476
+ { className: "project-manager-actions" },
3477
+ managerRename?.id === project.id ? (0, import_react9.createElement)(
3478
+ "button",
3479
+ {
3480
+ className: "primary small",
3481
+ disabled: managerBusy || managerRename.name.trim() === "",
3482
+ onClick: () => void managerAction(
3483
+ () => api.updateProject(project.id, managerRename.name.trim())
3484
+ )
3485
+ },
3486
+ "\u4FDD\u5B58\u540D\u79F0"
3487
+ ) : (0, import_react9.createElement)(
3488
+ "button",
3489
+ {
3490
+ className: "ghost small",
3491
+ onClick: () => setManagerRename({ id: project.id, name: project.name })
3492
+ },
3493
+ "\u91CD\u547D\u540D"
3494
+ ),
3495
+ (0, import_react9.createElement)(
3496
+ "button",
3497
+ {
3498
+ className: "ghost small",
3499
+ onClick: () => {
3500
+ void api.openProject(project.id).catch((caught) => setError(errorText5(caught)));
3501
+ }
3502
+ },
3503
+ "\u6253\u5F00\u6587\u4EF6\u5939"
3504
+ ),
3505
+ managerConfirm === project.id ? (0, import_react9.createElement)(
3506
+ "span",
3507
+ { style: { display: "inline-flex", gap: "6px" } },
3508
+ (0, import_react9.createElement)(
3509
+ "button",
3510
+ {
3511
+ className: "ghost small danger",
3512
+ disabled: managerBusy,
3513
+ onClick: () => void managerAction(async () => {
3514
+ await api.deleteProject(project.id);
3515
+ notice("\u9879\u76EE\u5DF2\u5220\u9664\uFF08\u6587\u4EF6\u5939\u4FDD\u7559\uFF09");
3516
+ })
3517
+ },
3518
+ "\u786E\u8BA4\u5220\u9664"
3519
+ ),
3520
+ (0, import_react9.createElement)(
3521
+ "button",
3522
+ { className: "ghost small", onClick: () => setManagerConfirm("") },
3523
+ "\u53D6\u6D88"
3524
+ )
3525
+ ) : (0, import_react9.createElement)(
3526
+ "button",
3527
+ {
3528
+ className: "ghost small danger",
3529
+ onClick: () => setManagerConfirm(project.id)
3530
+ },
3531
+ "\u5220\u9664"
3532
+ )
3533
+ )
3534
+ )
3535
+ )
3536
+ )
3537
+ ) : null,
3266
3538
  projectPicker !== null ? (0, import_react9.createElement)(
3267
3539
  Modal,
3268
3540
  {
@@ -3271,30 +3543,50 @@ ${projectPicker.subject}`,
3271
3543
  footer: (0, import_react9.createElement)(
3272
3544
  "div",
3273
3545
  { style: { display: "flex", gap: "8px", width: "100%", alignItems: "center" } },
3274
- (0, import_react9.createElement)("span", { className: "small muted" }, "\u628A\u8FD9\u5C01\u90AE\u4EF6\u5173\u8054\u5230\u4E00\u4E2A\u9879\u76EE"),
3546
+ (0, import_react9.createElement)("button", { className: "subtle", onClick: openManager }, "\u7BA1\u7406\u9879\u76EE\u2026"),
3275
3547
  (0, import_react9.createElement)("span", { className: "spacer" }),
3276
3548
  (0, import_react9.createElement)("button", { className: "ghost", onClick: () => setProjectPicker(null) }, "\u53D6\u6D88"),
3277
3549
  (0, import_react9.createElement)(
3278
3550
  "button",
3279
3551
  { className: "primary", disabled: pickerBusy, onClick: () => void saveProjectPick() },
3280
- pickerBusy ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58"
3552
+ pickerBusy ? "\u4FDD\u5B58\u4E2D\u2026" : pickerMode === "new" ? "\u521B\u5EFA\u5E76\u52A0\u5165" : "\u52A0\u5165\u9879\u76EE"
3281
3553
  )
3282
3554
  )
3283
3555
  },
3284
3556
  (0, import_react9.createElement)(
3285
3557
  "div",
3286
- { style: { display: "flex", flexDirection: "column", gap: "10px" } },
3287
- pickerProjects.length === 0 ? (0, import_react9.createElement)("p", { className: "small muted" }, "\u8FD8\u6CA1\u6709\u9879\u76EE\uFF0C\u5728\u4E0B\u9762\u65B0\u5EFA\u4E00\u4E2A\u3002") : (0, import_react9.createElement)(
3558
+ { style: { display: "flex", flexDirection: "column", gap: "12px" } },
3559
+ (0, import_react9.createElement)(
3560
+ "div",
3561
+ { className: "mailharbor-segment", role: "tablist" },
3562
+ (0, import_react9.createElement)(
3563
+ "button",
3564
+ {
3565
+ className: pickerMode === "existing" ? "active" : "",
3566
+ disabled: pickerProjects.length === 0,
3567
+ onClick: () => setPickerMode("existing")
3568
+ },
3569
+ "\u52A0\u5165\u5DF2\u6709\u9879\u76EE"
3570
+ ),
3571
+ (0, import_react9.createElement)(
3572
+ "button",
3573
+ {
3574
+ className: pickerMode === "new" ? "active" : "",
3575
+ onClick: () => setPickerMode("new")
3576
+ },
3577
+ "\u65B0\u5EFA\u9879\u76EE"
3578
+ )
3579
+ ),
3580
+ pickerMode === "existing" ? (0, import_react9.createElement)(
3288
3581
  "div",
3289
3582
  { className: "mailharbor-field" },
3290
- (0, import_react9.createElement)("label", null, "\u9009\u62E9\u5DF2\u6709\u9879\u76EE"),
3583
+ (0, import_react9.createElement)("label", null, "\u9879\u76EE"),
3291
3584
  (0, import_react9.createElement)(
3292
3585
  "select",
3293
3586
  {
3294
3587
  value: pickerTarget,
3295
3588
  onChange: (event) => setPickerTarget(event.target.value)
3296
3589
  },
3297
- (0, import_react9.createElement)("option", { value: "" }, "\u4E0D\u52A0\u5165\u5DF2\u6709\u9879\u76EE"),
3298
3590
  pickerProjects.map(
3299
3591
  (project) => (0, import_react9.createElement)(
3300
3592
  "option",
@@ -3302,23 +3594,24 @@ ${projectPicker.subject}`,
3302
3594
  `${project.name} \xB7 ${project.messages.length} \u5C01`
3303
3595
  )
3304
3596
  )
3305
- )
3306
- ),
3307
- (0, import_react9.createElement)(
3597
+ ),
3598
+ (0, import_react9.createElement)("p", { className: "small muted" }, "\u53EA\u4F1A\u628A\u5F53\u524D\u90AE\u4EF6\u52A0\u5165\u8FD9\u4E2A\u9879\u76EE\uFF0C\u4E0D\u4F1A\u65B0\u5EFA\u9879\u76EE\u3002")
3599
+ ) : (0, import_react9.createElement)(
3308
3600
  "div",
3309
3601
  { className: "mailharbor-field" },
3310
- (0, import_react9.createElement)("label", null, pickerProjects.length === 0 ? "\u65B0\u5EFA\u9879\u76EE" : "\u6216\u65B0\u5EFA\u9879\u76EE"),
3602
+ (0, import_react9.createElement)("label", null, "\u65B0\u9879\u76EE\u540D\u79F0"),
3311
3603
  (0, import_react9.createElement)("input", {
3312
3604
  value: pickerNewName,
3313
3605
  placeholder: "\u9879\u76EE\u540D\u79F0",
3314
3606
  onChange: (event) => setPickerNewName(event.target.value)
3315
- })
3607
+ }),
3608
+ (0, import_react9.createElement)(
3609
+ "p",
3610
+ { className: "small muted" },
3611
+ "\u4F1A\u521B\u5EFA\u65B0\u7684\u9879\u76EE\u6587\u4EF6\u5939\uFF0C\u5E76\u628A\u5F53\u524D\u90AE\u4EF6\u4F5C\u4E3A\u7B2C\u4E00\u5C01\u6765\u6E90\u90AE\u4EF6\u3002"
3612
+ )
3316
3613
  ),
3317
- (0, import_react9.createElement)(
3318
- "p",
3319
- { className: "small muted" },
3320
- pickerTarget === "" ? "\u4FDD\u5B58\u65F6\u4F1A\u7528\u4E0A\u9762\u7684\u540D\u79F0\u521B\u5EFA\u9879\u76EE\uFF0C\u5E76\u628A\u5F53\u524D\u90AE\u4EF6\u52A0\u8FDB\u53BB\u3002" : "\u4FDD\u5B58\u540E\u8FD9\u5C01\u90AE\u4EF6\u4F1A\u51FA\u73B0\u5728\u9879\u76EE\u7684\u6765\u6E90\u90AE\u4EF6\u5217\u8868\u91CC\u3002"
3321
- )
3614
+ (0, import_react9.createElement)("p", { className: "small muted" }, `\u6765\u6E90\u90AE\u4EF6\uFF1A${projectPicker.subject}`)
3322
3615
  )
3323
3616
  ) : null,
3324
3617
  extraction !== null ? (0, import_react9.createElement)(
@@ -3348,7 +3641,7 @@ ${projectPicker.subject}`,
3348
3641
  { style: { display: "flex", flexDirection: "column", gap: "8px" } },
3349
3642
  extraction.items.map(
3350
3643
  (item, index) => (0, import_react9.createElement)(
3351
- "label",
3644
+ "div",
3352
3645
  { key: `${item.title}:${String(index)}`, className: "mailharbor-extract-row" },
3353
3646
  (0, import_react9.createElement)("input", {
3354
3647
  type: "checkbox",
@@ -3360,18 +3653,49 @@ ${projectPicker.subject}`,
3360
3653
  }
3361
3654
  }),
3362
3655
  (0, import_react9.createElement)(
3363
- "span",
3364
- null,
3365
- (0, import_react9.createElement)("strong", null, item.title),
3656
+ "div",
3657
+ { className: "extract-body" },
3658
+ (0, import_react9.createElement)("input", {
3659
+ className: "extract-title",
3660
+ value: item.title,
3661
+ onChange: (event) => updateSuggestion(index, { title: event.target.value })
3662
+ }),
3366
3663
  (0, import_react9.createElement)(
3367
- "span",
3368
- { className: "small muted" },
3369
- [
3370
- item.due === "" ? "" : `\u622A\u6B62 ${item.due}`,
3371
- item.owner === "" ? "" : `\u8D1F\u8D23\u4EBA ${item.owner}`,
3372
- item.notes
3373
- ].filter((part) => part !== "").join(" \xB7 ")
3374
- )
3664
+ "div",
3665
+ { className: "extract-meta" },
3666
+ (0, import_react9.createElement)("input", {
3667
+ type: "date",
3668
+ value: item.due,
3669
+ onChange: (event) => updateSuggestion(index, { due: event.target.value })
3670
+ }),
3671
+ (0, import_react9.createElement)(
3672
+ "select",
3673
+ {
3674
+ value: String(item.priority),
3675
+ onChange: (event) => updateSuggestion(index, { priority: Number(event.target.value) })
3676
+ },
3677
+ (0, import_react9.createElement)("option", { value: "0" }, "\u65E0\u4F18\u5148\u7EA7"),
3678
+ (0, import_react9.createElement)("option", { value: "3" }, "\u4F4E"),
3679
+ (0, import_react9.createElement)("option", { value: "5" }, "\u4E2D"),
3680
+ (0, import_react9.createElement)("option", { value: "9" }, "\u9AD8")
3681
+ ),
3682
+ (0, import_react9.createElement)("input", {
3683
+ className: "extract-owner",
3684
+ value: item.owner,
3685
+ placeholder: "\u8FD9\u4E2A\u4E8B\u8054\u7CFB\u8C01",
3686
+ onChange: (event) => updateSuggestion(index, { owner: event.target.value })
3687
+ })
3688
+ ),
3689
+ item.notes === "" ? null : (0, import_react9.createElement)("span", { className: "small muted" }, item.notes)
3690
+ ),
3691
+ (0, import_react9.createElement)(
3692
+ "button",
3693
+ {
3694
+ className: "subtle icon",
3695
+ title: "\u79FB\u9664\u8FD9\u6761",
3696
+ onClick: () => removeSuggestion(index)
3697
+ },
3698
+ (0, import_react9.createElement)(Icon, { name: "close", size: 12 })
3375
3699
  )
3376
3700
  )
3377
3701
  )
@@ -4069,7 +4393,8 @@ var COLUMNS = [
4069
4393
  { status: "COMPLETED", label: "\u5DF2\u5B8C\u6210", hint: "\u6536\u5C3E" },
4070
4394
  { status: "CANCELLED", label: "\u7EC8\u6B62", hint: "\u4E0D\u505A\u4E86" }
4071
4395
  ];
4072
- var PRIORITY_LABEL = { 0: "\u65E0", 5: "\u4E2D", 9: "\u9AD8" };
4396
+ var PRIORITY_LABEL = { 0: "\u65E0", 3: "\u4F4E", 5: "\u4E2D", 9: "\u9AD8" };
4397
+ var PRIORITIES = [0, 3, 5, 9];
4073
4398
  function errorText7(error) {
4074
4399
  return error instanceof ApiError || error instanceof Error ? error.message : String(error);
4075
4400
  }
@@ -4440,7 +4765,7 @@ function TasksPanel() {
4440
4765
  (0, import_react11.createElement)(Icon, { name: "calendar", size: 12 }),
4441
4766
  dueText(task.due)
4442
4767
  ),
4443
- task.owner === "" ? null : (0, import_react11.createElement)("span", { className: "task-owner" }, task.owner),
4768
+ task.owner === "" ? null : (0, import_react11.createElement)("span", { className: "task-owner" }, `\u8054\u7CFB ${task.owner}`),
4444
4769
  task.projectId === null ? null : (0, import_react11.createElement)(
4445
4770
  "span",
4446
4771
  { className: "task-project" },
@@ -4448,8 +4773,8 @@ function TasksPanel() {
4448
4773
  ),
4449
4774
  task.priority > 0 ? (0, import_react11.createElement)(
4450
4775
  "span",
4451
- { className: "task-priority-label" },
4452
- `\u4F18\u5148\u7EA7 ${PRIORITY_LABEL[task.priority] ?? String(task.priority)}`
4776
+ { className: `task-priority-label p${String(task.priority)}` },
4777
+ PRIORITY_LABEL[task.priority] ?? String(task.priority)
4453
4778
  ) : null
4454
4779
  ),
4455
4780
  task.messageKey === "" ? null : (0, import_react11.createElement)(
@@ -4480,17 +4805,147 @@ function TasksPanel() {
4480
4805
  setCreating(null);
4481
4806
  setEditing(null);
4482
4807
  },
4483
- onSave: (draft) => void save(draft)
4808
+ onSave: (draft) => void save(draft),
4809
+ onDelete: editing === null ? void 0 : () => {
4810
+ void remove(editing);
4811
+ setEditing(null);
4812
+ }
4484
4813
  }) : null
4485
4814
  );
4486
4815
  }
4816
+ function datePickerLabel(value) {
4817
+ if (value === "") return "\u4E0D\u8BBE\u622A\u6B62";
4818
+ const date = /* @__PURE__ */ new Date(`${value}T00:00:00`);
4819
+ if (Number.isNaN(date.getTime())) return value;
4820
+ return date.toLocaleDateString("zh-CN", { month: "long", day: "numeric", weekday: "short" });
4821
+ }
4822
+ function shiftDate(days) {
4823
+ const date = /* @__PURE__ */ new Date();
4824
+ date.setDate(date.getDate() + days);
4825
+ return dateKey(date);
4826
+ }
4827
+ function nextFriday() {
4828
+ const date = /* @__PURE__ */ new Date();
4829
+ const delta = (5 - date.getDay() + 7) % 7;
4830
+ date.setDate(date.getDate() + delta);
4831
+ return dateKey(date);
4832
+ }
4833
+ function nextMonday() {
4834
+ const date = /* @__PURE__ */ new Date();
4835
+ const delta = (8 - date.getDay()) % 7 || 7;
4836
+ date.setDate(date.getDate() + delta);
4837
+ return dateKey(date);
4838
+ }
4839
+ function DuePicker({ value, onChange }) {
4840
+ const [open, setOpen] = (0, import_react11.useState)(false);
4841
+ const choose = (next) => {
4842
+ onChange(next);
4843
+ setOpen(false);
4844
+ };
4845
+ const options = [
4846
+ { label: "\u4ECA\u5929", value: shiftDate(0) },
4847
+ { label: "\u660E\u5929", value: shiftDate(1) },
4848
+ { label: "\u672C\u5468\u4E94", value: nextFriday() },
4849
+ { label: "\u4E0B\u5468\u4E00", value: nextMonday() }
4850
+ ];
4851
+ return (0, import_react11.createElement)(
4852
+ "div",
4853
+ { className: "task-due" },
4854
+ (0, import_react11.createElement)(
4855
+ "button",
4856
+ {
4857
+ type: "button",
4858
+ className: value === "" ? "task-due-trigger empty" : "task-due-trigger",
4859
+ onClick: () => setOpen(!open)
4860
+ },
4861
+ (0, import_react11.createElement)(Icon, { name: "calendar", size: 14 }),
4862
+ (0, import_react11.createElement)("span", null, datePickerLabel(value)),
4863
+ (0, import_react11.createElement)(Icon, { name: "chevronRight", size: 12 })
4864
+ ),
4865
+ open ? (0, import_react11.createElement)(
4866
+ "div",
4867
+ { className: "task-due-popover" },
4868
+ (0, import_react11.createElement)(
4869
+ "div",
4870
+ { className: "task-due-quick" },
4871
+ options.map(
4872
+ (option) => (0, import_react11.createElement)(
4873
+ "button",
4874
+ {
4875
+ key: option.label,
4876
+ type: "button",
4877
+ className: value === option.value ? "active" : "",
4878
+ onClick: () => choose(option.value)
4879
+ },
4880
+ option.label
4881
+ )
4882
+ )
4883
+ ),
4884
+ (0, import_react11.createElement)("input", {
4885
+ type: "date",
4886
+ value,
4887
+ onChange: (event) => onChange(event.target.value)
4888
+ }),
4889
+ (0, import_react11.createElement)(
4890
+ "div",
4891
+ { className: "task-due-foot" },
4892
+ (0, import_react11.createElement)("button", { type: "button", className: "subtle small", onClick: () => choose("") }, "\u6E05\u9664\u622A\u6B62"),
4893
+ (0, import_react11.createElement)("button", { type: "button", className: "subtle small", onClick: () => setOpen(false) }, "\u5173\u95ED")
4894
+ )
4895
+ ) : null
4896
+ );
4897
+ }
4898
+ function StatusPicker({
4899
+ value,
4900
+ onChange
4901
+ }) {
4902
+ return (0, import_react11.createElement)(
4903
+ "div",
4904
+ { className: "task-status-picker" },
4905
+ COLUMNS.map(
4906
+ (column) => (0, import_react11.createElement)(
4907
+ "button",
4908
+ {
4909
+ key: column.status,
4910
+ type: "button",
4911
+ className: value === column.status ? "active" : "",
4912
+ onClick: () => onChange(column.status)
4913
+ },
4914
+ (0, import_react11.createElement)("span", { className: `task-dot ${column.status}` }),
4915
+ column.label
4916
+ )
4917
+ )
4918
+ );
4919
+ }
4920
+ function PriorityPicker({
4921
+ value,
4922
+ onChange
4923
+ }) {
4924
+ return (0, import_react11.createElement)(
4925
+ "div",
4926
+ { className: "task-priority-picker" },
4927
+ PRIORITIES.map(
4928
+ (priority) => (0, import_react11.createElement)(
4929
+ "button",
4930
+ {
4931
+ key: priority,
4932
+ type: "button",
4933
+ className: `p${String(priority)}${value === priority ? " active" : ""}`,
4934
+ onClick: () => onChange(priority)
4935
+ },
4936
+ PRIORITY_LABEL[priority] ?? String(priority)
4937
+ )
4938
+ )
4939
+ );
4940
+ }
4487
4941
  function TaskEditor({
4488
4942
  task,
4489
4943
  status,
4490
4944
  projects,
4491
4945
  busy,
4492
4946
  onClose,
4493
- onSave
4947
+ onSave,
4948
+ onDelete
4494
4949
  }) {
4495
4950
  const [draft, setDraft] = (0, import_react11.useState)({
4496
4951
  ...EMPTY,
@@ -4506,7 +4961,16 @@ function TaskEditor({
4506
4961
  projectId: task.projectId ?? ""
4507
4962
  }
4508
4963
  });
4964
+ const [sourceError, setSourceError] = (0, import_react11.useState)("");
4509
4965
  const set = (patch) => setDraft((current) => ({ ...current, ...patch }));
4966
+ const openSource = () => {
4967
+ if (task === null || task.messageKey === "") return;
4968
+ void api.lookupMessage(task.accountId, task.messageKey).then((found) => {
4969
+ requestOpenMail({ accountId: task.accountId, id: found.id, mailbox: found.mailbox });
4970
+ document.querySelector('button[aria-label="MailHarbor"]')?.click();
4971
+ onClose();
4972
+ }).catch((caught) => setSourceError(errorText7(caught)));
4973
+ };
4510
4974
  return (0, import_react11.createElement)(
4511
4975
  Modal,
4512
4976
  {
@@ -4516,7 +4980,16 @@ function TaskEditor({
4516
4980
  footer: (0, import_react11.createElement)(
4517
4981
  "div",
4518
4982
  { className: "task-editor-foot" },
4519
- (0, import_react11.createElement)("span", { className: "small muted" }, "\u63D0\u793A\uFF1A\u4EFB\u52A1\u4F1A\u4FDD\u5B58\u5728\u672C\u5730\uFF0C\u53EF\u5728\u770B\u677F\u4E2D\u62D6\u52A8\u6539\u53D8\u72B6\u6001\u3002"),
4983
+ onDelete === void 0 ? null : (0, import_react11.createElement)(
4984
+ "button",
4985
+ {
4986
+ className: "subtle small danger",
4987
+ onClick: () => {
4988
+ if (window.confirm("\u5220\u9664\u8FD9\u4E2A\u4EFB\u52A1\uFF1F")) onDelete();
4989
+ }
4990
+ },
4991
+ "\u5220\u9664\u4EFB\u52A1"
4992
+ ),
4520
4993
  (0, import_react11.createElement)("span", { className: "spacer" }),
4521
4994
  (0, import_react11.createElement)("button", { className: "ghost", onClick: onClose }, "\u53D6\u6D88"),
4522
4995
  (0, import_react11.createElement)(
@@ -4532,92 +5005,56 @@ function TaskEditor({
4532
5005
  },
4533
5006
  (0, import_react11.createElement)(
4534
5007
  "div",
4535
- { className: "task-editor" },
5008
+ { className: "task-editor-v2" },
4536
5009
  (0, import_react11.createElement)(
4537
5010
  "div",
4538
- { className: "task-editor-main" },
4539
- (0, import_react11.createElement)(
4540
- "div",
4541
- { className: "task-editor-title" },
4542
- (0, import_react11.createElement)("input", {
4543
- value: draft.title,
4544
- autoFocus: true,
4545
- placeholder: "\u8981\u505A\u4EC0\u4E48\uFF1F",
4546
- onChange: (event) => set({ title: event.target.value })
4547
- })
4548
- ),
5011
+ { className: "task-editor-head" },
5012
+ (0, import_react11.createElement)("input", {
5013
+ className: "task-title-input",
5014
+ value: draft.title,
5015
+ autoFocus: true,
5016
+ placeholder: "\u8981\u505A\u4EC0\u4E48\uFF1F",
5017
+ onChange: (event) => set({ title: event.target.value })
5018
+ }),
5019
+ (0, import_react11.createElement)(StatusPicker, {
5020
+ value: draft.status,
5021
+ onChange: (next) => set({ status: next })
5022
+ })
5023
+ ),
5024
+ (0, import_react11.createElement)(
5025
+ "div",
5026
+ { className: "task-editor-columns" },
4549
5027
  (0, import_react11.createElement)(
4550
5028
  "div",
4551
- { className: "task-editor-section" },
4552
- (0, import_react11.createElement)("label", null, "\u5907\u6CE8"),
5029
+ { className: "task-editor-col" },
5030
+ (0, import_react11.createElement)("label", { className: "task-label" }, "\u5907\u6CE8"),
4553
5031
  (0, import_react11.createElement)("textarea", {
4554
- rows: 5,
5032
+ rows: 6,
4555
5033
  value: draft.notes,
4556
5034
  placeholder: "\u80CC\u666F\u3001\u4E0B\u4E00\u6B65\u3001\u94FE\u63A5\u2026",
4557
5035
  onChange: (event) => set({ notes: event.target.value })
4558
- })
4559
- ),
4560
- (0, import_react11.createElement)(
4561
- "div",
4562
- { className: "task-editor-section" },
4563
- (0, import_react11.createElement)("label", null, "\u6765\u6E90"),
4564
- 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)(
4565
- "span",
4566
- { className: "small muted" },
4567
- task?.messageSubject !== void 0 && task.messageSubject !== "" ? `\u6765\u81EA\u90AE\u4EF6\uFF1A${task.messageSubject}` : "\u65E0\u5173\u8054\u90AE\u4EF6"
4568
- )
4569
- )
4570
- ),
4571
- (0, import_react11.createElement)(
4572
- "aside",
4573
- { className: "task-editor-side" },
4574
- (0, import_react11.createElement)(
4575
- "div",
4576
- { className: "task-editor-field" },
4577
- (0, import_react11.createElement)("label", null, "\u72B6\u6001"),
4578
- (0, import_react11.createElement)(
4579
- "select",
4580
- {
4581
- value: draft.status,
4582
- onChange: (event) => set({ status: event.target.value })
4583
- },
4584
- COLUMNS.map((column) => (0, import_react11.createElement)("option", { key: column.status, value: column.status }, column.label))
4585
- )
4586
- ),
4587
- (0, import_react11.createElement)(
4588
- "div",
4589
- { className: "task-editor-field" },
4590
- (0, import_react11.createElement)("label", null, "\u622A\u6B62\u65E5\u671F"),
4591
- (0, import_react11.createElement)("input", {
4592
- type: "date",
4593
- value: draft.due,
4594
- onChange: (event) => set({ due: event.target.value })
4595
- })
4596
- ),
4597
- (0, import_react11.createElement)(
4598
- "div",
4599
- { className: "task-editor-field" },
4600
- (0, import_react11.createElement)("label", null, "\u4F18\u5148\u7EA7"),
4601
- (0, import_react11.createElement)(
5036
+ }),
5037
+ 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)(
4602
5038
  "div",
4603
- { className: "task-priority-picker" },
4604
- [0, 5, 9].map(
4605
- (value) => (0, import_react11.createElement)(
4606
- "button",
4607
- {
4608
- key: value,
4609
- className: draft.priority === value ? "active" : "",
4610
- onClick: () => set({ priority: value })
4611
- },
4612
- PRIORITY_LABEL[value] ?? String(value)
4613
- )
4614
- )
4615
- )
5039
+ { className: "task-source-row" },
5040
+ (0, import_react11.createElement)(
5041
+ "button",
5042
+ { className: "ghost small", onClick: openSource },
5043
+ (0, import_react11.createElement)(Icon, { name: "mail", size: 13 }),
5044
+ "\u6253\u5F00\u6765\u6E90\u90AE\u4EF6"
5045
+ ),
5046
+ (0, import_react11.createElement)("span", { className: "task-hint" }, task.messageSubject === "" ? "" : task.messageSubject)
5047
+ ),
5048
+ sourceError === "" ? null : (0, import_react11.createElement)("p", { className: "task-hint danger" }, sourceError)
4616
5049
  ),
4617
5050
  (0, import_react11.createElement)(
4618
- "div",
4619
- { className: "task-editor-field" },
4620
- (0, import_react11.createElement)("label", null, "\u9879\u76EE"),
5051
+ "aside",
5052
+ { className: "task-editor-col side" },
5053
+ (0, import_react11.createElement)("label", { className: "task-label" }, "\u622A\u6B62\u65E5\u671F"),
5054
+ (0, import_react11.createElement)(DuePicker, { value: draft.due, onChange: (next) => set({ due: next }) }),
5055
+ (0, import_react11.createElement)("label", { className: "task-label" }, "\u4F18\u5148\u7EA7"),
5056
+ (0, import_react11.createElement)(PriorityPicker, { value: draft.priority, onChange: (next) => set({ priority: next }) }),
5057
+ (0, import_react11.createElement)("label", { className: "task-label" }, "\u9879\u76EE"),
4621
5058
  (0, import_react11.createElement)(
4622
5059
  "select",
4623
5060
  {
@@ -4626,15 +5063,11 @@ function TaskEditor({
4626
5063
  },
4627
5064
  (0, import_react11.createElement)("option", { value: "" }, "\u65E0\u9879\u76EE"),
4628
5065
  projects.map((project) => (0, import_react11.createElement)("option", { key: project.id, value: project.id }, project.name))
4629
- )
4630
- ),
4631
- (0, import_react11.createElement)(
4632
- "div",
4633
- { className: "task-editor-field" },
4634
- (0, import_react11.createElement)("label", null, "\u8D1F\u8D23\u4EBA"),
5066
+ ),
5067
+ (0, import_react11.createElement)("label", { className: "task-label" }, "\u8FD9\u4E2A\u4E8B\u8054\u7CFB\u8C01"),
4635
5068
  (0, import_react11.createElement)("input", {
4636
5069
  value: draft.owner,
4637
- placeholder: "\u53EF\u9009",
5070
+ placeholder: "\u59D3\u540D\u6216\u90AE\u7BB1\uFF0C\u53EF\u7559\u7A7A",
4638
5071
  onChange: (event) => set({ owner: event.target.value })
4639
5072
  })
4640
5073
  )
@@ -4644,7 +5077,7 @@ function TaskEditor({
4644
5077
  }
4645
5078
 
4646
5079
  // src/client/index.tsx
4647
- var VERSION = "0.7.1";
5080
+ var VERSION = "0.8.0";
4648
5081
  var inject = ["slots"];
4649
5082
  var PANEL_ID = "mailharbor";
4650
5083
  var TASKS_PANEL_ID = "mailharbor-tasks";