@zaclinley/dsh-mailharbor 0.15.0 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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\n white-space: pre-wrap;\n font-size: 12.5px;\n line-height: 1.65;\n color: var(--m-text);\n}\n\n.mailharbor-ai-card-actions {\n display: flex;\n align-items: center;\n gap: 4px;\n flex-wrap: wrap;\n padding: 6px 8px;\n border-top: 1px solid var(--m-line-soft);\n}\n\n.mailharbor-ai-card-actions button {\n height: 26px;\n padding: 0 8px;\n font-size: 11.5px;\n}\n\n.mailharbor-ai-ask {\n display: flex;\n gap: 6px;\n padding: 10px 12px;\n border-top: 1px solid var(--m-line-soft);\n flex: none;\n}\n\n.mailharbor-ai-ask input {\n flex: 1;\n height: 32px;\n}\n\n.mailharbor-ai-error {\n color: var(--m-danger);\n font-size: 12px;\n padding: 0 2px;\n}\n\n@media (max-width: 1280px) {\n .mailharbor-ai {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n width: min(420px, 94%);\n z-index: 6;\n border-left: 1px solid var(--m-line);\n box-shadow: -12px 0 40px rgba(0, 0, 0, 0.45);\n }\n}\n\n/* ---------- AI summary ---------- */\n\n.mailharbor-divider {\n width: 1px;\n height: 18px;\n margin: 0 4px;\n background: var(--m-line);\n}\n\n.mailharbor-summary {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.mailharbor-summary section h4 {\n margin: 0 0 6px;\n font-size: 11.5px;\n font-weight: 600;\n color: var(--m-text-3);\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n\n.mailharbor-summary section p {\n margin: 0;\n white-space: pre-wrap;\n line-height: 1.75;\n color: var(--m-text);\n}\n\n/* ---------- modal / forms ---------- */\n\n.mailharbor-portal {\n position: fixed;\n inset: 0;\n z-index: 80;\n height: auto;\n background: transparent;\n pointer-events: none;\n}\n\n.mailharbor-portal .mailharbor-modal-mask {\n pointer-events: auto;\n}\n\n.mailharbor-modal-mask {\n position: fixed;\n inset: 0;\n z-index: 60;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 24px;\n background: rgba(0, 0, 0, 0.55);\n backdrop-filter: blur(2px);\n}\n\n.mailharbor-modal {\n display: flex;\n flex-direction: column;\n width: min(720px, 100%);\n max-height: 86vh;\n overflow: hidden;\n border: 1px solid var(--m-line);\n border-radius: 14px;\n background: var(--m-bg-1);\n color: var(--m-text);\n box-shadow: var(--m-shadow);\n}\n\n.mailharbor-modal > header {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 52px;\n padding: 0 14px 0 18px;\n border-bottom: 1px solid var(--m-line-soft);\n font-size: 14px;\n font-weight: 600;\n}\n\n.mailharbor-modal .content {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 18px;\n overflow: auto;\n}\n\n.mailharbor-modal > footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 18px;\n border-top: 1px solid var(--m-line-soft);\n}\n\n.mailharbor-field {\n display: flex;\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n}\n\n.mailharbor-field > input,\n.mailharbor-field > select,\n.mailharbor-field > textarea,\n.mailharbor-card > textarea {\n width: 100%;\n min-width: 0;\n}\n\n.mailharbor-field > label {\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.mailharbor-grid {\n display: grid;\n grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);\n gap: 10px;\n min-width: 0;\n}\n\n.mailharbor-grid.three {\n grid-template-columns: minmax(0, 2fr) minmax(72px, 90px) auto;\n align-items: end;\n min-width: 0;\n}\n\n.mailharbor-toggle {\n display: inline-flex;\n align-items: center;\n gap: 7px;\n color: var(--m-text-2);\n font-size: 12.5px;\n cursor: pointer;\n white-space: nowrap;\n}\n\n.mailharbor-toggle input[type='checkbox'] {\n width: 14px;\n height: 14px;\n accent-color: var(--m-accent);\n}\n\n/* ---------- composer ---------- */\n\n.mailharbor-toolbar {\n display: flex;\n align-items: center;\n gap: 2px;\n flex-wrap: wrap;\n padding: 6px;\n border: 1px solid var(--m-line-soft);\n border-bottom: 0;\n border-radius: 10px 10px 0 0;\n background: var(--m-bg-2);\n}\n\n.mailharbor-toolbar button {\n height: 26px;\n padding: 0 9px;\n border-radius: 6px;\n color: var(--m-text-2);\n font-size: 12px;\n}\n\n.mailharbor-toolbar button:hover {\n background: var(--m-bg-3);\n color: var(--m-text);\n}\n\n.mailharbor-editor {\n min-height: 240px;\n max-height: 44vh;\n overflow: auto;\n padding: 14px 16px;\n border: 1px solid var(--m-line-soft);\n border-radius: 0 0 10px 10px;\n background: #fff;\n color: #171a21;\n outline: none;\n font-size: 13.5px;\n line-height: 1.7;\n}\n\n.mailharbor-editor:empty::before {\n content: attr(data-placeholder);\n color: #9aa0ab;\n}\n\n/* ---------- inline confirm ---------- */\n\n.mailharbor-confirm {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--m-line);\n background: var(--m-bg-2);\n color: var(--m-text-2);\n font-size: 12.5px;\n}\n\n/* ---------- selection / extraction ---------- */\n\n.mailharbor-selectbar {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n margin: 0 12px 8px;\n border: 1px solid var(--m-accent-soft);\n border-radius: 9px;\n background: var(--m-accent-soft);\n}\n\n.mailharbor-selectbar select {\n height: 28px;\n max-width: 200px;\n}\n\n.mailharbor-row.selectable input[type='checkbox'] {\n width: 15px;\n height: 15px;\n flex: none;\n accent-color: var(--m-accent);\n}\n\n.mailharbor-extract-row {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n padding: 9px 10px;\n border: 1px solid var(--m-line-soft);\n border-radius: 9px;\n background: var(--m-bg-1);\n cursor: pointer;\n}\n\n.mailharbor-extract-row input {\n margin-top: 2px;\n accent-color: var(--m-accent);\n}\n\n.mailharbor-extract-row > span {\n display: flex;\n flex-direction: column;\n gap: 3px;\n min-width: 0;\n}\n\n.mailharbor-kv {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr);\n gap: 6px 12px;\n margin: 0;\n font-size: 12.5px;\n}\n\n.mailharbor-kv dt {\n color: var(--m-text-3);\n}\n\n.mailharbor-kv dd {\n margin: 0;\n overflow-wrap: anywhere;\n}\n\n/* ---------- tasks panel ---------- */\n\n.mailharbor .chip {\n height: 26px;\n padding: 0 10px;\n border: 1px solid var(--m-line);\n border-radius: 999px;\n color: var(--m-text-3);\n font-size: 12px;\n}\n\n.mailharbor .chip.active {\n background: var(--m-accent-soft);\n border-color: transparent;\n color: var(--m-text);\n}\n\n.tasks-body {\n flex: 1;\n min-height: 0;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 18px;\n padding: 18px 20px 48px;\n width: 100%;\n max-width: 940px;\n margin: 0 auto;\n}\n\n.tasks-overview {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));\n gap: 12px;\n}\n\n.tasks-progress,\n.tasks-project {\n display: flex;\n flex-direction: column;\n gap: 7px;\n padding: 12px 14px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n min-width: 0;\n}\n\n.tasks-progress-head,\n.tasks-project-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n min-width: 0;\n}\n\n.tasks-project-head .name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12.5px;\n font-weight: 500;\n}\n\n.tasks-bar {\n height: 6px;\n border-radius: 999px;\n background: var(--m-bg-3);\n overflow: hidden;\n}\n\n.tasks-bar span {\n display: block;\n height: 100%;\n border-radius: 999px;\n background: var(--m-accent);\n transition: width 200ms ease;\n}\n\n.tasks-bar.small {\n height: 4px;\n}\n\n.tasks-filters {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n.tasks-list {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.tasks-row {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 9px 12px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n}\n\n.tasks-row input[type='checkbox'] {\n width: 16px;\n height: 16px;\n flex: none;\n accent-color: var(--m-accent);\n}\n\n.tasks-row .tasks-title {\n flex: 1;\n min-width: 0;\n height: auto;\n padding: 0;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n text-align: left;\n border: 0;\n background: transparent;\n}\n\n.tasks-row .tasks-title:hover {\n background: transparent;\n}\n\n.tasks-row .tasks-title > span:first-child {\n font-size: 13px;\n color: var(--m-text);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 100%;\n}\n\n.tasks-row.done .tasks-title > span:first-child {\n color: var(--m-text-3);\n text-decoration: line-through;\n}\n\n.tasks-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.tasks-meta .due.overdue {\n color: var(--m-danger);\n}\n\n.tasks-list-wrap {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n/* ---------- markdown ---------- */\n\n.mailharbor-markdown {\n display: flex;\n flex-direction: column;\n gap: 8px;\n font-size: 12.5px;\n line-height: 1.68;\n overflow-wrap: anywhere;\n}\n\n.mailharbor-markdown > *:first-child {\n margin-top: 0;\n}\n\n.mailharbor-markdown > *:last-child {\n margin-bottom: 0;\n}\n\n.mailharbor-markdown p {\n margin: 0;\n white-space: pre-wrap;\n}\n\n.mailharbor-markdown h1,\n.mailharbor-markdown h2,\n.mailharbor-markdown h3,\n.mailharbor-markdown h4,\n.mailharbor-markdown h5,\n.mailharbor-markdown h6 {\n margin: 4px 0 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--m-text);\n}\n\n.mailharbor-markdown ul,\n.mailharbor-markdown ol {\n margin: 0;\n padding-left: 20px;\n display: flex;\n flex-direction: column;\n gap: 3px;\n}\n\n.mailharbor-markdown li::marker {\n color: var(--m-text-3);\n}\n\n.mailharbor-markdown a {\n color: var(--m-accent);\n text-decoration: none;\n}\n\n.mailharbor-markdown a:hover {\n text-decoration: underline;\n}\n\n.mailharbor-markdown code {\n padding: 1px 4px;\n border-radius: 4px;\n background: var(--m-bg-2);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11.5px;\n}\n\n.mailharbor-markdown pre {\n margin: 0;\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--m-bg);\n border: 1px solid var(--m-line-soft);\n overflow: auto;\n}\n\n.mailharbor-markdown pre code {\n padding: 0;\n background: transparent;\n}\n\n.mailharbor-markdown blockquote {\n margin: 0;\n padding-left: 10px;\n border-left: 2px solid var(--m-line);\n color: var(--m-text-2);\n}\n\n.mailharbor-markdown hr {\n width: 100%;\n margin: 4px 0;\n border: 0;\n border-top: 1px solid var(--m-line-soft);\n}\n\n/* ---------- composer AI ---------- */\n\n.mailharbor-toolbar button.ai {\n color: var(--m-accent);\n}\n\n.mailharbor-compose-foot {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n flex-wrap: wrap;\n}\n\n.mailharbor-versions {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n padding-top: 8px;\n}\n\n.mailharbor-versions .chip {\n height: 22px;\n padding: 0 8px;\n border: 1px solid var(--m-line);\n border-radius: 999px;\n color: var(--m-text-3);\n font-size: 11px;\n}\n\n.mailharbor-versions .chip.active {\n background: var(--m-accent-soft);\n border-color: transparent;\n color: var(--m-text);\n}\n\n/* ---------- settings ---------- */\n\n.mailharbor.mailharbor-settings-page {\n height: auto;\n min-height: 100%;\n overflow: visible;\n}\n\n.mailharbor-settings {\n flex: 0 0 auto;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n padding: 18px 20px 48px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n overflow-x: hidden;\n}\n\n.mailharbor-settings > * {\n min-width: 0;\n}\n\n.mailharbor-settings h2 {\n margin: 0;\n font-size: 18px;\n font-weight: 600;\n letter-spacing: -0.01em;\n}\n\n.mailharbor-settings h3 {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--m-text-3);\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n\n.mailharbor-card {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n min-width: 0;\n overflow: hidden;\n}\n\n.mailharbor-account-row {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.mailharbor-account-row .meta {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.mailharbor-account-row .meta strong {\n font-weight: 600;\n}\n\n.mailharbor-account-row .meta span {\n color: var(--m-text-3);\n font-size: 11.5px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mailharbor .avatar {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n border-radius: 50%;\n background: var(--m-accent-soft);\n color: var(--m-accent);\n font-weight: 600;\n}\n\n.mailharbor-log {\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--m-bg);\n border: 1px solid var(--m-line-soft);\n color: var(--m-text-2);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11px;\n line-height: 1.6;\n max-height: 220px;\n overflow: auto;\n white-space: pre-wrap;\n}\n\n.mailharbor-kv {\n display: grid;\n grid-template-columns: minmax(120px, 170px) 1fr;\n gap: 6px 14px;\n font-size: 12px;\n margin: 0;\n}\n\n.mailharbor-kv dt {\n color: var(--m-text-3);\n}\n\n.mailharbor-kv dd {\n margin: 0;\n color: var(--m-text-2);\n word-break: break-all;\n}\n\n.mailharbor hr {\n border: 0;\n border-top: 1px solid var(--m-line-soft);\n margin: 2px 0;\n}\n\n/* ---------- conversation rows ---------- */\n\n.mailharbor-thread {\n display: flex;\n flex-direction: column;\n}\n\n.mailharbor-row.compact {\n padding-top: 6px;\n padding-bottom: 6px;\n padding-left: 34px;\n background: var(--m-bg);\n}\n\n.mailharbor-row.compact .line-1 {\n opacity: 0.85;\n}\n\n.mailharbor-row.compact .snippet {\n -webkit-line-clamp: 1;\n}\n\n.mailharbor .to-label {\n font-size: 10.5px;\n color: var(--m-text-3);\n flex: none;\n}\n\n.mailharbor .thread-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n border-radius: 999px;\n background: var(--m-bg-3);\n color: var(--m-text-2);\n font-size: 10.5px;\n flex: none;\n}\n\n.mailharbor .thread-count:hover {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.mailharbor-account {\n height: auto;\n padding: 3px 8px 3px 3px;\n border-radius: 8px;\n gap: 8px;\n}\n\n.mailharbor-account:hover {\n background: var(--m-hover);\n}\n\n/* ---------- mailbox sidebar ---------- */\n\n.mailharbor-side {\n display: flex;\n flex-direction: column;\n gap: 2px;\n width: 214px;\n flex: none;\n padding: 10px 8px;\n overflow: auto;\n border-right: 1px solid var(--m-line-soft);\n background: var(--m-bg);\n}\n\n.mailharbor-side-section {\n padding: 12px 8px 4px;\n font-size: 10.5px;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n color: var(--m-text-3);\n}\n\n.mailharbor-side-item {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n height: 32px;\n padding: 0 8px;\n border-radius: 8px;\n color: var(--m-text-2);\n font-size: 12.5px;\n text-align: left;\n flex: none;\n}\n\n.mailharbor-side-item:hover {\n background: var(--m-hover);\n}\n\n.mailharbor-side-item.active {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.mailharbor-side-item .name {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-side-item .sub {\n display: block;\n font-size: 10.5px;\n color: var(--m-text-3);\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.mailharbor-side-item .count {\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.mailharbor-side-item svg {\n flex: none;\n color: var(--m-text-3);\n}\n\n.mailharbor-side-item.active svg {\n color: var(--m-accent);\n}\n\n@media (max-width: 900px) {\n .mailharbor-side {\n display: none;\n }\n}\n\n/* ---------- task board ---------- */\n\n.tasks-board-wrap {\n flex: 1;\n min-height: 0;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 14px;\n padding: 16px 18px 40px;\n}\n\n.tasks-summary {\n display: flex;\n align-items: center;\n gap: 20px;\n padding: 14px 16px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n}\n\n.tasks-summary-main {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 7px;\n}\n\n.tasks-summary-labels {\n display: flex;\n align-items: baseline;\n gap: 10px;\n}\n\n.tasks-stats {\n display: flex;\n gap: 18px;\n}\n\n.tasks-stat {\n display: flex;\n flex-direction: column;\n gap: 1px;\n min-width: 42px;\n}\n\n.tasks-stat strong {\n font-size: 16px;\n font-weight: 600;\n color: var(--m-text);\n}\n\n.tasks-stat span {\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.tasks-stat.danger strong {\n color: var(--m-danger);\n}\n\n.tasks-toolbar {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.tasks-board {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: 14px;\n align-items: start;\n}\n\n.task-column {\n display: flex;\n flex-direction: column;\n gap: 8px;\n min-height: 140px;\n padding: 8px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n}\n\n.task-column-head {\n display: flex;\n align-items: center;\n gap: 7px;\n padding: 2px 4px 6px;\n}\n\n.task-column-head strong {\n font-size: 12.5px;\n font-weight: 600;\n}\n\n.task-column-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n border-radius: 999px;\n background: var(--m-bg-3);\n color: var(--m-text-3);\n font-size: 10.5px;\n}\n\n.task-dot {\n width: 7px;\n height: 7px;\n border-radius: 999px;\n background: var(--m-text-3);\n}\n\n.task-dot.NEEDS-ACTION {\n background: #8a8f98;\n}\n\n.task-dot.IN-PROCESS {\n background: var(--m-accent);\n}\n\n.task-dot.COMPLETED {\n background: var(--m-ok);\n}\n\n.task-dot.CANCELLED {\n background: var(--m-danger);\n opacity: 0.7;\n}\n\n.task-column-body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n min-height: 60px;\n}\n\n.task-column-empty {\n padding: 18px 8px;\n text-align: center;\n color: var(--m-text-3);\n font-size: 11.5px;\n border: 1px dashed var(--m-line-soft);\n border-radius: 9px;\n}\n\n.task-card {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 10px 11px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg);\n cursor: grab;\n transition:\n border-color 120ms ease,\n box-shadow 120ms ease;\n}\n\n.task-card:hover {\n border-color: var(--m-line);\n box-shadow: 0 4px 14px rgba(0, 0, 0, 0.16);\n}\n\n.task-card.dragging {\n opacity: 0.5;\n}\n\n.task-card-top {\n display: flex;\n align-items: flex-start;\n gap: 7px;\n}\n\n.task-card-title {\n flex: 1;\n min-width: 0;\n font-size: 12.5px;\n line-height: 1.45;\n color: var(--m-text);\n overflow-wrap: anywhere;\n}\n\n.task-priority {\n width: 3px;\n height: 14px;\n margin-top: 2px;\n border-radius: 999px;\n background: transparent;\n flex: none;\n}\n\n.task-priority.p5 {\n background: #d9a441;\n}\n\n.task-priority.p9 {\n background: var(--m-danger);\n}\n\n.task-card-delete {\n width: 18px;\n height: 18px;\n flex: none;\n border-radius: 5px;\n color: var(--m-text-3);\n opacity: 0;\n}\n\n.task-card:hover .task-card-delete {\n opacity: 1;\n}\n\n.task-card-notes {\n margin: 0;\n font-size: 11.5px;\n line-height: 1.55;\n color: var(--m-text-3);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.task-card-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n font-size: 10.5px;\n color: var(--m-text-3);\n}\n\n.task-due,\n.task-owner,\n.task-project,\n.task-priority-label {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n padding: 1px 6px;\n border-radius: 5px;\n background: var(--m-bg-2);\n}\n\n.task-due.overdue {\n color: var(--m-danger);\n background: rgba(242, 90, 90, 0.12);\n}\n\n.task-project {\n color: var(--m-accent);\n background: var(--m-accent-soft);\n}\n\n.task-source {\n align-self: flex-start;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n height: 22px;\n padding: 0 6px;\n border-radius: 5px;\n color: var(--m-text-3);\n font-size: 10.5px;\n}\n\n.task-source:hover {\n background: var(--m-hover);\n color: var(--m-text-2);\n}\n\n@media (max-width: 1180px) {\n .tasks-board {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n}\n\n@media (max-width: 720px) {\n .tasks-board {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n/* ---------- AI search ---------- */\n\n.mailharbor-ai-search {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0 12px 8px;\n padding: 7px 10px;\n border-radius: 8px;\n background: var(--m-accent-soft);\n color: var(--m-text-2);\n font-size: 12px;\n}\n\n.mailharbor-ai-search.searching {\n background: var(--m-bg-2);\n color: var(--m-text-3);\n}\n\n/* ---------- task editor ---------- */\n\n.mailharbor-tasks .mailharbor-modal {\n max-width: 760px;\n}\n\n.task-editor {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 230px;\n gap: 18px;\n}\n\n.task-editor-main {\n display: flex;\n flex-direction: column;\n gap: 14px;\n min-width: 0;\n}\n\n.task-editor-title input {\n width: 100%;\n height: 38px;\n font-size: 15px;\n font-weight: 500;\n}\n\n.task-editor-section {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.task-editor-section label,\n.task-editor-field label {\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.task-editor-section textarea {\n width: 100%;\n resize: vertical;\n}\n\n.task-editor-side {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 12px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n align-self: start;\n}\n\n.task-editor-field {\n display: flex;\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n}\n\n.task-editor-field input,\n.task-editor-field select {\n width: 100%;\n}\n\n.task-priority-picker {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 4px;\n padding: 3px;\n border: 1px solid var(--m-line);\n border-radius: 8px;\n background: var(--m-bg);\n}\n\n.task-priority-picker button {\n height: 26px;\n border-radius: 6px;\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.task-priority-picker button.active {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.task-editor-foot {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n}\n\n/* ---------- project manager ---------- */\n\n.project-manager {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.project-manager-row {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 12px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n}\n\n.project-manager-main {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 3px;\n}\n\n.project-manager-main strong {\n font-size: 13px;\n}\n\n.project-manager-main .small {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.project-manager-main input {\n width: 100%;\n height: 28px;\n}\n\n.project-manager-actions {\n display: flex;\n gap: 4px;\n flex: none;\n align-items: center;\n}\n\n/* ---------- task editor v2 ---------- */\n\n.task-editor-v2 {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.task-editor-head {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.task-editor-head .task-title-input {\n width: 100%;\n height: 42px;\n padding: 0 12px;\n border-radius: 10px;\n border: 1px solid var(--m-line);\n background: var(--m-bg);\n color: var(--m-text);\n font-size: 16px;\n font-weight: 500;\n}\n\n.task-editor-head .task-title-input:focus {\n outline: none;\n border-color: var(--m-accent);\n}\n\n.task-status-picker {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: 4px;\n padding: 4px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n}\n\n.task-status-picker button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n height: 30px;\n border-radius: 7px;\n color: var(--m-text-3);\n font-size: 12px;\n}\n\n.task-status-picker button:hover {\n background: var(--m-hover);\n}\n\n.task-status-picker button.active {\n background: var(--m-bg-3);\n color: var(--m-text);\n}\n\n.task-editor-columns {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 250px;\n gap: 18px;\n}\n\n.task-editor-col {\n display: flex;\n flex-direction: column;\n gap: 8px;\n min-width: 0;\n}\n\n.task-editor-col textarea {\n width: 100%;\n resize: vertical;\n min-height: 120px;\n}\n\n.task-editor-col.side {\n padding: 12px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n align-self: start;\n}\n\n.task-label {\n font-size: 11px;\n color: var(--m-text-3);\n margin-top: 2px;\n}\n\n.task-hint {\n margin: 0;\n font-size: 11.5px;\n color: var(--m-text-3);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.task-hint.danger {\n color: var(--m-danger);\n white-space: normal;\n}\n\n.task-source-row {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.task-due {\n position: relative;\n}\n\n.task-due-trigger {\n display: flex;\n align-items: center;\n gap: 7px;\n width: 100%;\n height: 32px;\n padding: 0 10px;\n border: 1px solid var(--m-line);\n border-radius: 8px;\n background: var(--m-bg);\n color: var(--m-text-2);\n font-size: 12.5px;\n}\n\n.task-due-trigger.empty {\n color: var(--m-text-3);\n}\n\n.task-due-trigger span {\n flex: 1;\n text-align: left;\n}\n\n.task-due-popover {\n position: absolute;\n z-index: 20;\n top: calc(100% + 6px);\n left: 0;\n width: 250px;\n padding: 10px;\n border: 1px solid var(--m-line);\n border-radius: 10px;\n background: var(--m-bg-2);\n box-shadow: 0 12px 30px rgba(0, 0, 0, 0.35);\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.task-due-quick {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 5px;\n}\n\n.task-due-quick button {\n height: 28px;\n border-radius: 7px;\n background: var(--m-bg-1);\n border: 1px solid var(--m-line-soft);\n font-size: 11.5px;\n color: var(--m-text-2);\n}\n\n.task-due-quick button.active {\n background: var(--m-accent-soft);\n border-color: transparent;\n color: var(--m-text);\n}\n\n.task-due-popover input[type='date'] {\n width: 100%;\n}\n\n.task-due-foot {\n display: flex;\n justify-content: space-between;\n}\n\n.task-priority-picker {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: 4px;\n padding: 3px;\n border: 1px solid var(--m-line);\n border-radius: 8px;\n background: var(--m-bg);\n}\n\n.task-priority-picker button {\n height: 28px;\n border-radius: 6px;\n font-size: 11.5px;\n color: var(--m-text-3);\n border: 1px solid transparent;\n}\n\n.task-priority-picker button.p3 {\n color: #5aa7f0;\n}\n\n.task-priority-picker button.p5 {\n color: #d9a441;\n}\n\n.task-priority-picker button.p9 {\n color: var(--m-danger);\n}\n\n.task-priority-picker button.active {\n background: var(--m-bg-3);\n border-color: var(--m-line);\n color: var(--m-text);\n}\n\n.task-priority-picker button.p9.active {\n background: rgba(242, 90, 90, 0.16);\n border-color: rgba(242, 90, 90, 0.35);\n color: var(--m-danger);\n}\n\n.task-priority-picker button.p5.active {\n background: rgba(217, 164, 65, 0.16);\n border-color: rgba(217, 164, 65, 0.35);\n color: #d9a441;\n}\n\n.task-priority-picker button.p3.active {\n background: rgba(90, 167, 240, 0.16);\n border-color: rgba(90, 167, 240, 0.35);\n color: #5aa7f0;\n}\n\n.task-priority.p3 {\n background: #5aa7f0;\n}\n\n.task-priority-label.p9 {\n color: var(--m-danger);\n background: rgba(242, 90, 90, 0.12);\n}\n\n.task-priority-label.p5 {\n color: #d9a441;\n background: rgba(217, 164, 65, 0.12);\n}\n\n.task-priority-label.p3 {\n color: #5aa7f0;\n background: rgba(90, 167, 240, 0.12);\n}\n\n@media (max-width: 720px) {\n .task-editor-columns {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n.mailharbor-spinner {\n display: inline-block;\n width: 13px;\n height: 13px;\n border: 2px solid currentColor;\n border-right-color: transparent;\n border-radius: 50%;\n animation: mailharbor-spin 0.7s linear infinite;\n opacity: 0.8;\n vertical-align: -2px;\n flex: none;\n}\n\n@keyframes mailharbor-spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n.extract-body {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.extract-title {\n width: 100%;\n height: 30px;\n font-size: 13px;\n font-weight: 500;\n}\n\n.extract-meta {\n display: grid;\n grid-template-columns: 150px 110px minmax(0, 1fr);\n gap: 6px;\n}\n\n.extract-meta input,\n.extract-meta select {\n height: 28px;\n font-size: 11.5px;\n width: 100%;\n}\n\n.extract-owner {\n width: 100%;\n}\n\n@media (max-width: 720px) {\n .extract-meta {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n/* ---------- conversation reading ---------- */\n\n.mailharbor-thread-view {\n flex: 1;\n min-height: 0;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 14px 18px 32px;\n background: var(--m-bg);\n}\n\n.mailharbor-thread-hint {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 0 4px 2px;\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.mailharbor-thread-msg {\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n overflow: hidden;\n}\n\n.mailharbor-thread-msg.selected {\n border-color: var(--m-accent);\n box-shadow: 0 0 0 1px var(--m-accent-soft);\n}\n\n.mailharbor-thread-head {\n display: flex;\n align-items: center;\n gap: 9px;\n width: 100%;\n height: auto;\n padding: 9px 12px;\n text-align: left;\n border-radius: 0;\n}\n\n.mailharbor-thread-head:hover {\n background: var(--m-hover);\n}\n\n.thread-who {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.thread-who strong {\n font-size: 12.5px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.thread-to {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-thread-preview {\n padding: 0 14px 10px 47px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-thread-body {\n padding: 0 12px 12px;\n}\n\n.mailharbor-thread-frame {\n height: 380px;\n border: 1px solid var(--m-line-soft);\n border-radius: 8px;\n overflow: hidden;\n background: #fff;\n}\n\n.mailharbor-thread-frame iframe {\n display: block;\n width: 100%;\n height: 100%;\n border: 0;\n background: #fff;\n}\n\n.thread-loading {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 4px 12px;\n}\n\n@media (max-width: 900px) {\n .thread-to {\n display: none;\n }\n}\n\n/* ---------- compact reader ---------- */\n\n.mailharbor-reader-head {\n padding: 10px 16px 8px;\n gap: 6px;\n}\n\n.mailharbor-reader-title h2 {\n font-size: 15px;\n}\n\n.mailharbor-reader-meta.compact {\n gap: 10px;\n align-items: center;\n}\n\n.mailharbor-reader-meta.compact .who {\n gap: 6px;\n}\n\n.mailharbor-reader-recipients {\n display: flex;\n flex-wrap: wrap;\n gap: 6px 14px;\n font-size: 11.5px;\n color: var(--m-text-3);\n padding: 0 2px;\n}\n\n.mailharbor-reader-actions {\n gap: 4px;\n flex-wrap: wrap;\n}\n\n.mailharbor-reader-actions button {\n height: 28px;\n padding: 0 8px;\n}\n\n.mailharbor-attachments.compact {\n display: flex;\n gap: 6px;\n padding: 6px 16px;\n overflow-x: auto;\n border-top: 1px solid var(--m-line-soft);\n flex-wrap: nowrap;\n}\n\n.mailharbor-attachments.compact .mailharbor-attachment {\n flex: none;\n padding: 4px 8px;\n border: 1px solid var(--m-line-soft);\n border-radius: 6px;\n max-width: 260px;\n}\n\n.mailharbor-reader-body {\n flex: 1;\n min-height: 0;\n}\n\n.thread-who {\n flex-direction: row;\n align-items: baseline;\n gap: 6px;\n min-width: 0;\n}\n\n.thread-who strong {\n max-width: 45%;\n}\n\n.thread-who .small {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n}\n\n.thread-date {\n flex: none;\n}\n\n.mailharbor button.mailharbor-thread-head {\n justify-content: flex-start;\n padding: 7px 10px;\n gap: 8px;\n}\n\n.mailharbor-thread-preview {\n padding: 0 12px 8px 40px;\n}\n\n.mailharbor-thread-frame {\n height: clamp(220px, 42vh, 420px);\n}\n\n.mailharbor-refreshing {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 0 14px 6px;\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.mailharbor-attachment-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 8px 0 2px;\n}\n\n.mailharbor-attachment-chips .mailharbor-attachment {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n max-width: 280px;\n padding: 4px 8px;\n border: 1px solid var(--m-line-soft);\n border-radius: 6px;\n background: var(--m-bg-1);\n font-size: 11.5px;\n}\n\n.mailharbor-attachment-chips .mailharbor-attachment .name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-thread-recipients {\n display: flex;\n flex-wrap: wrap;\n gap: 4px 14px;\n padding: 0 2px 8px;\n}\n\n.mailharbor-thread-frame {\n height: clamp(260px, 55vh, 640px);\n}\n\n.mailharbor-thread-body {\n padding: 8px 12px 12px;\n}\n\n.mailharbor-ai-summary.clamp,\n.mailharbor-ai-text.clamp {\n max-height: 150px;\n overflow: hidden;\n mask-image: linear-gradient(to bottom, #000 72%, transparent 100%);\n -webkit-mask-image: linear-gradient(to bottom, #000 72%, transparent 100%);\n}\n\n.mailharbor-ai-full {\n display: flex;\n flex-direction: column;\n gap: 14px;\n max-height: 66vh;\n overflow: auto;\n padding-right: 4px;\n font-size: 13px;\n line-height: 1.7;\n color: var(--m-text);\n}\n\n.mailharbor-ai-full h4 {\n margin: 0 0 4px;\n font-size: 11px;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n color: var(--m-text-3);\n}\n\n.mailharbor-ai-full .mailharbor-markdown {\n font-size: 13px;\n line-height: 1.7;\n}\n\n/* ---------- sync popover ---------- */\n\n.mailharbor-sync {\n position: relative;\n}\n\n.mailharbor-sync-pop {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n z-index: 30;\n width: 320px;\n padding: 12px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n border: 1px solid var(--m-line);\n border-radius: 10px;\n background: var(--m-bg-2);\n box-shadow: 0 16px 40px rgba(0, 0, 0, 0.4);\n}\n\n.mailharbor-sync-head {\n display: flex;\n align-items: baseline;\n gap: 8px;\n}\n\n.mailharbor-sync-stats {\n display: flex;\n justify-content: space-between;\n gap: 8px;\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.mailharbor-sync-log {\n max-height: 110px;\n overflow: auto;\n padding: 6px 8px;\n border-radius: 6px;\n background: var(--m-bg);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 10.5px;\n white-space: pre-wrap;\n color: var(--m-text-3);\n}\n\n.mailharbor-sync-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.mailharbor-thread-msg,\n.mailharbor-ai-card {\n flex: none;\n}\n\n.mailharbor-unread-banner {\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 0 10px 8px;\n padding: 6px 10px;\n border-radius: 8px;\n background: var(--m-accent-soft);\n color: var(--m-text-2);\n font-size: 11.5px;\n text-align: left;\n}\n\n.mailharbor-unread-banner:hover {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.mailharbor-starred {\n display: inline-flex;\n align-items: center;\n color: #e0b341;\n flex: none;\n}\n\n.mailharbor-reader-actions select {\n height: 28px;\n max-width: 130px;\n font-size: 11.5px;\n}\n\n.mailharbor-sync-error {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0 12px 6px;\n padding: 6px 10px;\n border-radius: 8px;\n background: rgba(242, 90, 90, 0.12);\n color: var(--m-danger);\n font-size: 11.5px;\n}\n\n.mailharbor-onboarding {\n display: grid;\n gap: 6px;\n margin: 12px 0;\n padding: 10px 12px;\n border: 1px solid var(--m-line);\n border-radius: 10px;\n background: var(--m-bg-2);\n font-size: 12px;\n}\n\n.mailharbor-onboarding strong {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n margin-right: 6px;\n border-radius: 50%;\n background: var(--m-accent-soft);\n color: var(--m-text);\n font-size: 11px;\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: clamp(280px, 28vw, 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.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\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: 1540px) {\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/* ---------- task board ---------- */\n\n.tasks-board-wrap {\n flex: 1;\n min-height: 0;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 14px;\n padding: 16px 18px 40px;\n}\n\n.tasks-summary {\n display: flex;\n align-items: center;\n gap: 20px;\n padding: 14px 16px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n}\n\n.tasks-summary-main {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 7px;\n}\n\n.tasks-summary-labels {\n display: flex;\n align-items: baseline;\n gap: 10px;\n}\n\n.tasks-stats {\n display: flex;\n gap: 18px;\n}\n\n.tasks-stat {\n display: flex;\n flex-direction: column;\n gap: 1px;\n min-width: 42px;\n}\n\n.tasks-stat strong {\n font-size: 16px;\n font-weight: 600;\n color: var(--m-text);\n}\n\n.tasks-stat span {\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.tasks-stat.danger strong {\n color: var(--m-danger);\n}\n\n.tasks-toolbar {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.tasks-board {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: 14px;\n align-items: start;\n}\n\n.task-column {\n display: flex;\n flex-direction: column;\n gap: 8px;\n min-height: 140px;\n padding: 8px;\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n}\n\n.task-column-head {\n display: flex;\n align-items: center;\n gap: 7px;\n padding: 2px 4px 6px;\n}\n\n.task-column-head strong {\n font-size: 12.5px;\n font-weight: 600;\n}\n\n.task-column-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n border-radius: 999px;\n background: var(--m-bg-3);\n color: var(--m-text-3);\n font-size: 10.5px;\n}\n\n.task-dot {\n width: 7px;\n height: 7px;\n border-radius: 999px;\n background: var(--m-text-3);\n}\n\n.task-dot.NEEDS-ACTION {\n background: #8a8f98;\n}\n\n.task-dot.IN-PROCESS {\n background: var(--m-accent);\n}\n\n.task-dot.COMPLETED {\n background: var(--m-ok);\n}\n\n.task-dot.CANCELLED {\n background: var(--m-danger);\n opacity: 0.7;\n}\n\n.task-column-body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n min-height: 60px;\n}\n\n.task-column-empty {\n padding: 18px 8px;\n text-align: center;\n color: var(--m-text-3);\n font-size: 11.5px;\n border: 1px dashed var(--m-line-soft);\n border-radius: 9px;\n}\n\n.task-card {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 10px 11px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg);\n cursor: grab;\n transition:\n border-color 120ms ease,\n box-shadow 120ms ease;\n}\n\n.task-card:hover {\n border-color: var(--m-line);\n box-shadow: 0 4px 14px rgba(0, 0, 0, 0.16);\n}\n\n.task-card.dragging {\n opacity: 0.5;\n}\n\n.task-card-top {\n display: flex;\n align-items: flex-start;\n gap: 7px;\n}\n\n.task-card-title {\n flex: 1;\n min-width: 0;\n font-size: 12.5px;\n line-height: 1.45;\n color: var(--m-text);\n overflow-wrap: anywhere;\n}\n\n.task-priority {\n width: 3px;\n height: 14px;\n margin-top: 2px;\n border-radius: 999px;\n background: transparent;\n flex: none;\n}\n\n.task-priority.p5 {\n background: #d9a441;\n}\n\n.task-priority.p9 {\n background: var(--m-danger);\n}\n\n.task-card-delete {\n width: 18px;\n height: 18px;\n flex: none;\n border-radius: 5px;\n color: var(--m-text-3);\n opacity: 0;\n}\n\n.task-card:hover .task-card-delete {\n opacity: 1;\n}\n\n.task-card-notes {\n margin: 0;\n font-size: 11.5px;\n line-height: 1.55;\n color: var(--m-text-3);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.task-card-meta {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n font-size: 10.5px;\n color: var(--m-text-3);\n}\n\n.task-due,\n.task-owner,\n.task-project,\n.task-priority-label {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n padding: 1px 6px;\n border-radius: 5px;\n background: var(--m-bg-2);\n}\n\n.task-due.overdue {\n color: var(--m-danger);\n background: rgba(242, 90, 90, 0.12);\n}\n\n.task-project {\n color: var(--m-accent);\n background: var(--m-accent-soft);\n}\n\n.task-source {\n align-self: flex-start;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n height: 22px;\n padding: 0 6px;\n border-radius: 5px;\n color: var(--m-text-3);\n font-size: 10.5px;\n}\n\n.task-source:hover {\n background: var(--m-hover);\n color: var(--m-text-2);\n}\n\n@media (max-width: 1180px) {\n .tasks-board {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n}\n\n@media (max-width: 720px) {\n .tasks-board {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n/* ---------- AI search ---------- */\n\n.mailharbor-ai-search {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0 12px 8px;\n padding: 7px 10px;\n border-radius: 8px;\n background: var(--m-accent-soft);\n color: var(--m-text-2);\n font-size: 12px;\n}\n\n.mailharbor-ai-search.searching {\n background: var(--m-bg-2);\n color: var(--m-text-3);\n}\n\n/* ---------- task editor ---------- */\n\n.mailharbor-tasks .mailharbor-modal {\n max-width: 760px;\n}\n\n.task-editor {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 230px;\n gap: 18px;\n}\n\n.task-editor-main {\n display: flex;\n flex-direction: column;\n gap: 14px;\n min-width: 0;\n}\n\n.task-editor-title input {\n width: 100%;\n height: 38px;\n font-size: 15px;\n font-weight: 500;\n}\n\n.task-editor-section {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.task-editor-section label,\n.task-editor-field label {\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.task-editor-section textarea {\n width: 100%;\n resize: vertical;\n}\n\n.task-editor-side {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 12px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n align-self: start;\n}\n\n.task-editor-field {\n display: flex;\n flex-direction: column;\n gap: 5px;\n min-width: 0;\n}\n\n.task-editor-field input,\n.task-editor-field select {\n width: 100%;\n}\n\n.task-priority-picker {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: 4px;\n padding: 3px;\n border: 1px solid var(--m-line);\n border-radius: 8px;\n background: var(--m-bg);\n}\n\n.task-priority-picker button {\n height: 26px;\n border-radius: 6px;\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.task-priority-picker button.active {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.task-editor-foot {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n}\n\n/* ---------- project manager ---------- */\n\n.project-manager {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.project-manager-row {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 10px 12px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n}\n\n.project-manager-main {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 3px;\n}\n\n.project-manager-main strong {\n font-size: 13px;\n}\n\n.project-manager-main .small {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.project-manager-main input {\n width: 100%;\n height: 28px;\n}\n\n.project-manager-actions {\n display: flex;\n gap: 4px;\n flex: none;\n align-items: center;\n}\n\n/* ---------- task editor v2 ---------- */\n\n.task-editor-v2 {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.task-editor-head {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.task-editor-head .task-title-input {\n width: 100%;\n height: 42px;\n padding: 0 12px;\n border-radius: 10px;\n border: 1px solid var(--m-line);\n background: var(--m-bg);\n color: var(--m-text);\n font-size: 16px;\n font-weight: 500;\n}\n\n.task-editor-head .task-title-input:focus {\n outline: none;\n border-color: var(--m-accent);\n}\n\n.task-status-picker {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: 4px;\n padding: 4px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n}\n\n.task-status-picker button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n height: 30px;\n border-radius: 7px;\n color: var(--m-text-3);\n font-size: 12px;\n}\n\n.task-status-picker button:hover {\n background: var(--m-hover);\n}\n\n.task-status-picker button.active {\n background: var(--m-bg-3);\n color: var(--m-text);\n}\n\n.task-editor-columns {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 250px;\n gap: 18px;\n}\n\n.task-editor-col {\n display: flex;\n flex-direction: column;\n gap: 8px;\n min-width: 0;\n}\n\n.task-editor-col textarea {\n width: 100%;\n resize: vertical;\n min-height: 120px;\n}\n\n.task-editor-col.side {\n padding: 12px;\n border: 1px solid var(--m-line-soft);\n border-radius: 10px;\n background: var(--m-bg-1);\n align-self: start;\n}\n\n.task-label {\n font-size: 11px;\n color: var(--m-text-3);\n margin-top: 2px;\n}\n\n.task-hint {\n margin: 0;\n font-size: 11.5px;\n color: var(--m-text-3);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.task-hint.danger {\n color: var(--m-danger);\n white-space: normal;\n}\n\n.task-source-row {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n.task-due {\n position: relative;\n}\n\n.task-due-trigger {\n display: flex;\n align-items: center;\n gap: 7px;\n width: 100%;\n height: 32px;\n padding: 0 10px;\n border: 1px solid var(--m-line);\n border-radius: 8px;\n background: var(--m-bg);\n color: var(--m-text-2);\n font-size: 12.5px;\n}\n\n.task-due-trigger.empty {\n color: var(--m-text-3);\n}\n\n.task-due-trigger span {\n flex: 1;\n text-align: left;\n}\n\n.task-due-popover {\n position: absolute;\n z-index: 20;\n top: calc(100% + 6px);\n left: 0;\n width: 250px;\n padding: 10px;\n border: 1px solid var(--m-line);\n border-radius: 10px;\n background: var(--m-bg-2);\n box-shadow: 0 12px 30px rgba(0, 0, 0, 0.35);\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.task-due-quick {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 5px;\n}\n\n.task-due-quick button {\n height: 28px;\n border-radius: 7px;\n background: var(--m-bg-1);\n border: 1px solid var(--m-line-soft);\n font-size: 11.5px;\n color: var(--m-text-2);\n}\n\n.task-due-quick button.active {\n background: var(--m-accent-soft);\n border-color: transparent;\n color: var(--m-text);\n}\n\n.task-due-popover input[type='date'] {\n width: 100%;\n}\n\n.task-due-foot {\n display: flex;\n justify-content: space-between;\n}\n\n.task-priority-picker {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: 4px;\n padding: 3px;\n border: 1px solid var(--m-line);\n border-radius: 8px;\n background: var(--m-bg);\n}\n\n.task-priority-picker button {\n height: 28px;\n border-radius: 6px;\n font-size: 11.5px;\n color: var(--m-text-3);\n border: 1px solid transparent;\n}\n\n.task-priority-picker button.p3 {\n color: #5aa7f0;\n}\n\n.task-priority-picker button.p5 {\n color: #d9a441;\n}\n\n.task-priority-picker button.p9 {\n color: var(--m-danger);\n}\n\n.task-priority-picker button.active {\n background: var(--m-bg-3);\n border-color: var(--m-line);\n color: var(--m-text);\n}\n\n.task-priority-picker button.p9.active {\n background: rgba(242, 90, 90, 0.16);\n border-color: rgba(242, 90, 90, 0.35);\n color: var(--m-danger);\n}\n\n.task-priority-picker button.p5.active {\n background: rgba(217, 164, 65, 0.16);\n border-color: rgba(217, 164, 65, 0.35);\n color: #d9a441;\n}\n\n.task-priority-picker button.p3.active {\n background: rgba(90, 167, 240, 0.16);\n border-color: rgba(90, 167, 240, 0.35);\n color: #5aa7f0;\n}\n\n.task-priority.p3 {\n background: #5aa7f0;\n}\n\n.task-priority-label.p9 {\n color: var(--m-danger);\n background: rgba(242, 90, 90, 0.12);\n}\n\n.task-priority-label.p5 {\n color: #d9a441;\n background: rgba(217, 164, 65, 0.12);\n}\n\n.task-priority-label.p3 {\n color: #5aa7f0;\n background: rgba(90, 167, 240, 0.12);\n}\n\n@media (max-width: 720px) {\n .task-editor-columns {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n.mailharbor-spinner {\n display: inline-block;\n width: 13px;\n height: 13px;\n border: 2px solid currentColor;\n border-right-color: transparent;\n border-radius: 50%;\n animation: mailharbor-spin 0.7s linear infinite;\n opacity: 0.8;\n vertical-align: -2px;\n flex: none;\n}\n\n@keyframes mailharbor-spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n.extract-body {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.extract-title {\n width: 100%;\n height: 30px;\n font-size: 13px;\n font-weight: 500;\n}\n\n.extract-meta {\n display: grid;\n grid-template-columns: 150px 110px minmax(0, 1fr);\n gap: 6px;\n}\n\n.extract-meta input,\n.extract-meta select {\n height: 28px;\n font-size: 11.5px;\n width: 100%;\n}\n\n.extract-owner {\n width: 100%;\n}\n\n@media (max-width: 720px) {\n .extract-meta {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n/* ---------- conversation reading ---------- */\n\n.mailharbor-thread-view {\n flex: 1;\n min-height: 0;\n overflow: auto;\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 14px 18px 32px;\n background: var(--m-bg);\n}\n\n.mailharbor-thread-hint {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 0 4px 2px;\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.mailharbor-thread-msg {\n border: 1px solid var(--m-line-soft);\n border-radius: 12px;\n background: var(--m-bg-1);\n overflow: hidden;\n}\n\n.mailharbor-thread-msg.selected {\n border-color: var(--m-accent);\n box-shadow: 0 0 0 1px var(--m-accent-soft);\n}\n\n.mailharbor-thread-head {\n display: flex;\n align-items: center;\n gap: 9px;\n width: 100%;\n height: auto;\n padding: 9px 12px;\n text-align: left;\n border-radius: 0;\n}\n\n.mailharbor-thread-head:hover {\n background: var(--m-hover);\n}\n\n.thread-who {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.thread-who strong {\n font-size: 12.5px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.thread-to {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-thread-preview {\n padding: 0 14px 10px 47px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-thread-body {\n padding: 0 12px 12px;\n}\n\n.mailharbor-thread-frame {\n height: 380px;\n border: 1px solid var(--m-line-soft);\n border-radius: 8px;\n overflow: hidden;\n background: #fff;\n}\n\n.mailharbor-thread-frame iframe {\n display: block;\n width: 100%;\n height: 100%;\n border: 0;\n background: #fff;\n}\n\n.thread-loading {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 4px 12px;\n}\n\n@media (max-width: 900px) {\n .thread-to {\n display: none;\n }\n}\n\n/* ---------- compact reader ---------- */\n\n.mailharbor-reader-head {\n padding: 10px 16px 8px;\n gap: 6px;\n}\n\n.mailharbor-reader-title h2 {\n font-size: 15px;\n}\n\n.mailharbor-reader-meta.compact {\n gap: 10px;\n align-items: center;\n}\n\n.mailharbor-reader-meta.compact .who {\n gap: 6px;\n}\n\n.mailharbor-reader-recipients {\n display: flex;\n flex-wrap: wrap;\n gap: 6px 14px;\n font-size: 11.5px;\n color: var(--m-text-3);\n padding: 0 2px;\n}\n\n.mailharbor-reader-actions {\n gap: 4px;\n flex-wrap: wrap;\n}\n\n.mailharbor-reader-actions button {\n height: 28px;\n padding: 0 8px;\n}\n\n.mailharbor-attachments.compact {\n display: flex;\n gap: 6px;\n padding: 6px 16px;\n overflow-x: auto;\n border-top: 1px solid var(--m-line-soft);\n flex-wrap: nowrap;\n}\n\n.mailharbor-attachments.compact .mailharbor-attachment {\n flex: none;\n padding: 4px 8px;\n border: 1px solid var(--m-line-soft);\n border-radius: 6px;\n max-width: 260px;\n}\n\n.mailharbor-reader-body {\n flex: 1;\n min-height: 0;\n}\n\n.thread-who {\n flex-direction: row;\n align-items: baseline;\n gap: 6px;\n min-width: 0;\n}\n\n.thread-who strong {\n max-width: 45%;\n}\n\n.thread-who .small {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n}\n\n.thread-date {\n flex: none;\n}\n\n.mailharbor button.mailharbor-thread-head {\n justify-content: flex-start;\n padding: 7px 10px;\n gap: 8px;\n}\n\n.mailharbor-thread-preview {\n padding: 0 12px 8px 40px;\n}\n\n.mailharbor-thread-frame {\n height: clamp(220px, 42vh, 420px);\n}\n\n.mailharbor-refreshing {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 0 14px 6px;\n font-size: 11px;\n color: var(--m-text-3);\n}\n\n.mailharbor-attachment-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 8px 0 2px;\n}\n\n.mailharbor-attachment-chips .mailharbor-attachment {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n max-width: 280px;\n padding: 4px 8px;\n border: 1px solid var(--m-line-soft);\n border-radius: 6px;\n background: var(--m-bg-1);\n font-size: 11.5px;\n}\n\n.mailharbor-attachment-chips .mailharbor-attachment .name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-thread-recipients {\n display: flex;\n flex-wrap: wrap;\n gap: 4px 14px;\n padding: 0 2px 8px;\n}\n\n.mailharbor-thread-frame {\n height: clamp(260px, 55vh, 640px);\n}\n\n.mailharbor-thread-body {\n padding: 8px 12px 12px;\n}\n\n.mailharbor-ai-summary.clamp,\n.mailharbor-ai-text.clamp {\n max-height: 150px;\n overflow: hidden;\n mask-image: linear-gradient(to bottom, #000 72%, transparent 100%);\n -webkit-mask-image: linear-gradient(to bottom, #000 72%, transparent 100%);\n}\n\n.mailharbor-ai-full {\n display: flex;\n flex-direction: column;\n gap: 14px;\n max-height: 66vh;\n overflow: auto;\n padding-right: 4px;\n font-size: 13px;\n line-height: 1.7;\n color: var(--m-text);\n}\n\n.mailharbor-ai-full h4 {\n margin: 0 0 4px;\n font-size: 11px;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n color: var(--m-text-3);\n}\n\n.mailharbor-ai-full .mailharbor-markdown {\n font-size: 13px;\n line-height: 1.7;\n}\n\n/* ---------- sync popover ---------- */\n\n.mailharbor-sync {\n position: relative;\n}\n\n.mailharbor-sync-pop {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n z-index: 30;\n width: 320px;\n padding: 12px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n border: 1px solid var(--m-line);\n border-radius: 10px;\n background: var(--m-bg-2);\n box-shadow: 0 16px 40px rgba(0, 0, 0, 0.4);\n}\n\n.mailharbor-sync-head {\n display: flex;\n align-items: baseline;\n gap: 8px;\n}\n\n.mailharbor-sync-stats {\n display: flex;\n justify-content: space-between;\n gap: 8px;\n font-size: 11.5px;\n color: var(--m-text-3);\n}\n\n.mailharbor-sync-log {\n max-height: 110px;\n overflow: auto;\n padding: 6px 8px;\n border-radius: 6px;\n background: var(--m-bg);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 10.5px;\n white-space: pre-wrap;\n color: var(--m-text-3);\n}\n\n.mailharbor-sync-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.mailharbor-thread-msg,\n.mailharbor-ai-card {\n flex: none;\n}\n\n.mailharbor-unread-banner {\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 0 10px 8px;\n padding: 6px 10px;\n border-radius: 8px;\n background: var(--m-accent-soft);\n color: var(--m-text-2);\n font-size: 11.5px;\n text-align: left;\n}\n\n.mailharbor-unread-banner:hover {\n background: var(--m-accent-soft);\n color: var(--m-text);\n}\n\n.mailharbor-starred {\n display: inline-flex;\n align-items: center;\n color: #e0b341;\n flex: none;\n}\n\n.mailharbor-reader-actions select {\n height: 28px;\n max-width: 130px;\n font-size: 11.5px;\n}\n\n.mailharbor-sync-error {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0 12px 6px;\n padding: 6px 10px;\n border-radius: 8px;\n background: rgba(242, 90, 90, 0.12);\n color: var(--m-danger);\n font-size: 11.5px;\n}\n\n.mailharbor-onboarding {\n display: grid;\n gap: 6px;\n margin: 12px 0;\n padding: 10px 12px;\n border: 1px solid var(--m-line);\n border-radius: 10px;\n background: var(--m-bg-2);\n font-size: 12px;\n}\n\n.mailharbor-onboarding strong {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n margin-right: 6px;\n border-radius: 50%;\n background: var(--m-accent-soft);\n color: var(--m-text);\n font-size: 11px;\n}\n\n/* ---------- responsive shell ---------- */\n\n.mailharbor-scrim,\n.mailharbor-ai-scrim {\n display: none;\n}\n\n.mailharbor-account {\n flex: 0 1 auto;\n}\n\n.mailharbor-account > div {\n min-width: 0;\n}\n\n.mailharbor-account .small {\n display: block;\n max-width: 150px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.mailharbor-action-label {\n display: inline;\n}\n\n@media (max-width: 1540px) {\n .mailharbor-ai-scrim {\n display: block;\n position: absolute;\n inset: 0;\n z-index: 5;\n border: 0;\n background: rgba(0, 0, 0, 0.32);\n backdrop-filter: blur(1px);\n }\n\n .mailharbor-ai {\n z-index: 6;\n }\n}\n\n@media (max-width: 1220px) {\n .mailharbor-scrim {\n display: block;\n position: absolute;\n inset: 0;\n z-index: 25;\n border: 0;\n background: rgba(0, 0, 0, 0.38);\n }\n\n .mailharbor-side {\n position: absolute;\n inset: 0 auto 0 0;\n z-index: 30;\n display: flex;\n width: min(290px, 86%);\n box-shadow: 20px 0 50px rgba(0, 0, 0, 0.45);\n animation: mailharbor-drawer 160ms ease-out;\n }\n\n .mailharbor-list {\n width: clamp(260px, 36vw, 320px);\n }\n}\n\n@keyframes mailharbor-drawer {\n from {\n transform: translateX(-12px);\n opacity: 0.4;\n }\n to {\n transform: none;\n opacity: 1;\n }\n}\n\n@media (max-width: 900px) {\n .mailharbor-narrow .mailharbor-list {\n width: 100%;\n flex: 1;\n min-width: 0;\n border-right: 0;\n }\n\n .mailharbor-narrow .mailharbor-body[data-mode='reader'] .mailharbor-reader {\n width: 100%;\n flex: 1;\n }\n\n .mailharbor-reader-head {\n padding: 12px 14px 10px;\n gap: 8px;\n }\n\n .mailharbor-reader-title h2 {\n font-size: 16px;\n }\n\n .mailharbor-reader-body {\n padding: 10px 12px 12px;\n }\n\n .mailharbor-ai {\n width: min(420px, 100%);\n }\n}\n\n@media (max-width: 760px) {\n .mailharbor-topbar {\n flex-wrap: wrap;\n height: auto;\n min-height: 52px;\n padding: 8px 10px;\n gap: 6px;\n }\n\n .mailharbor-account {\n max-width: 170px;\n }\n\n .mailharbor-account .small {\n max-width: 105px;\n }\n\n .mailharbor-action-label {\n display: none;\n }\n\n .mailharbor-topbar button.ghost,\n .mailharbor-topbar button.primary {\n padding: 0 9px;\n }\n\n .mailharbor-filters {\n flex-wrap: wrap;\n gap: 6px;\n padding: 8px 10px;\n }\n\n .mailharbor-filters input[type='search'] {\n flex: 1 1 100%;\n order: -1;\n }\n\n .mailharbor-settings-page {\n padding: 16px 12px;\n }\n\n .mailharbor-grid {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .mailharbor-grid.three {\n grid-template-columns: minmax(0, 1fr) minmax(64px, 80px) auto;\n }\n\n .mailharbor-sync-pop {\n position: fixed;\n top: 56px;\n left: 10px;\n right: 10px;\n width: auto;\n }\n}\n\n@media (max-width: 560px) {\n .mailharbor-topbar {\n gap: 4px;\n }\n\n .mailharbor-account {\n max-width: 132px;\n }\n\n .mailharbor-account .small {\n display: none;\n }\n\n .mailharbor-account .badge {\n display: none;\n }\n\n .mailharbor-row {\n padding: 9px 12px;\n }\n\n .mailharbor-row .snippet {\n -webkit-line-clamp: 1;\n }\n\n .mailharbor-reader-actions {\n gap: 4px;\n }\n\n .mailharbor-reader-actions button {\n padding: 0 7px;\n }\n}\n\n/* Reader actions collapse on phones: keep reply/forward, put the rest behind \u66F4\u591A. */\n.mailharbor .mailharbor-more-toggle {\n display: none;\n}\n\n@media (max-width: 760px) {\n .mailharbor-reader-actions .mailharbor-secondary {\n display: none;\n }\n\n .mailharbor-reader-actions.expanded .mailharbor-secondary {\n display: inline-flex;\n }\n\n .mailharbor-reader-actions .mailharbor-more-toggle {\n display: inline-flex;\n }\n\n .mailharbor-reader-actions .mailharbor-divider.mailharbor-secondary {\n display: none;\n }\n}\n\n/* Subtle scrollbars keep long lists readable without stealing width. */\n.mailharbor ::-webkit-scrollbar {\n width: 9px;\n height: 9px;\n}\n\n.mailharbor ::-webkit-scrollbar-thumb {\n background: var(--m-line-strong);\n border: 2px solid transparent;\n border-radius: 999px;\n background-clip: padding-box;\n}\n\n.mailharbor ::-webkit-scrollbar-thumb:hover {\n background: var(--m-text-3);\n background-clip: padding-box;\n}\n\n/* ---------- attachment preview & drop target ---------- */\n\n.mailharbor-preview {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 320px;\n max-height: 68vh;\n overflow: auto;\n border-radius: 10px;\n background: var(--m-bg);\n}\n\n.mailharbor-preview.text {\n align-items: stretch;\n justify-content: flex-start;\n}\n\n.mailharbor-preview img {\n display: block;\n max-width: 100%;\n max-height: 66vh;\n object-fit: contain;\n}\n\n.mailharbor-preview iframe {\n width: 100%;\n height: 66vh;\n border: 0;\n border-radius: 10px;\n background: #fff;\n}\n\n.mailharbor-preview-text {\n width: 100%;\n max-height: 66vh;\n margin: 0;\n padding: 16px;\n overflow: auto;\n white-space: pre-wrap;\n word-break: break-word;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12px;\n color: var(--m-text-2);\n}\n\n.mailharbor-editor.dragging {\n outline: 2px dashed var(--m-accent);\n outline-offset: -2px;\n background: var(--m-accent-soft);\n}\n\n/* Rows off screen skip layout/paint work in large mailboxes. */\n.mailharbor-row {\n content-visibility: auto;\n contain-intrinsic-size: auto 68px;\n}\n";
39
39
 
40
40
  // src/client/icon.tsx
41
41
  var import_react = require("react");
@@ -154,13 +154,6 @@ var api = {
154
154
  method: "POST",
155
155
  body: JSON.stringify(payload)
156
156
  }),
157
- oauthStatus: (accountId) => request(`oauth/status${query({ accountId })}`),
158
- oauthStart: (accountId) => request("oauth/start", { method: "POST", body: JSON.stringify({ accountId }) }),
159
- oauthPoll: (state) => request("oauth/poll", {
160
- method: "POST",
161
- body: JSON.stringify({ state })
162
- }),
163
- oauthRevoke: (accountId) => request("oauth/revoke", { method: "POST", body: JSON.stringify({ accountId }) }),
164
157
  check: (id) => request(`accounts/${encodeURIComponent(id)}/check`, { method: "POST" }),
165
158
  aiStatus: (accountId) => request(`ai/status${query({ accountId: accountId ?? null })}`),
166
159
  aiModels: () => request("ai/models"),
@@ -994,7 +987,7 @@ ${card.output}`
994
987
  ),
995
988
  (0, import_react5.createElement)(
996
989
  "button",
997
- { className: "subtle icon", title: "\u6536\u8D77", onClick: onClose },
990
+ { className: "subtle icon", title: "\u6536\u8D77", "aria-label": "\u5173\u95ED AI \u52A9\u624B", onClick: onClose },
998
991
  (0, import_react5.createElement)(Icon, { name: "chevronRight", size: 14 })
999
992
  )
1000
993
  ),
@@ -1300,8 +1293,6 @@ function AddAccountForm({
1300
1293
  onCancel
1301
1294
  }) {
1302
1295
  const [email, setEmail] = (0, import_react6.useState)("");
1303
- const [authMode, setAuthMode] = (0, import_react6.useState)("password");
1304
- const [oauthProvider, setOauthProvider] = (0, import_react6.useState)("google");
1305
1296
  const [password, setPassword] = (0, import_react6.useState)("");
1306
1297
  const [label, setLabel] = (0, import_react6.useState)("");
1307
1298
  const [remember, setRemember] = (0, import_react6.useState)(true);
@@ -1322,8 +1313,8 @@ function AddAccountForm({
1322
1313
  const domain = domainOf(email);
1323
1314
  const { state } = await api.addAccount({
1324
1315
  email: email.trim(),
1325
- ...authMode === "password" ? { password, remember } : {},
1326
- ...authMode === "oauth2" ? { auth: { type: "oauth2", provider: oauthProvider } } : {},
1316
+ password,
1317
+ remember,
1327
1318
  ...label.trim() === "" ? {} : { label: label.trim() },
1328
1319
  ...advanced ? {
1329
1320
  imap: {
@@ -1350,41 +1341,6 @@ function AddAccountForm({
1350
1341
  "div",
1351
1342
  { className: "mailharbor-card" },
1352
1343
  (0, import_react6.createElement)("h3", null, "\u6DFB\u52A0\u90AE\u7BB1\u8D26\u53F7"),
1353
- (0, import_react6.createElement)(
1354
- "div",
1355
- { className: "mailharbor-grid" },
1356
- (0, import_react6.createElement)(
1357
- Field,
1358
- { label: "\u767B\u5F55\u65B9\u5F0F" },
1359
- (0, import_react6.createElement)(
1360
- "select",
1361
- {
1362
- value: authMode,
1363
- onChange: (event) => setAuthMode(event.target.value === "oauth2" ? "oauth2" : "password")
1364
- },
1365
- (0, import_react6.createElement)("option", { value: "password" }, "\u5BC6\u7801 / \u5E94\u7528\u4E13\u7528\u5BC6\u7801"),
1366
- (0, import_react6.createElement)("option", { value: "oauth2" }, "OAuth2\uFF08Gmail / Outlook\uFF09")
1367
- )
1368
- ),
1369
- authMode === "oauth2" ? (0, import_react6.createElement)(
1370
- Field,
1371
- { label: "OAuth2 \u670D\u52A1\u5546" },
1372
- (0, import_react6.createElement)(
1373
- "select",
1374
- {
1375
- value: oauthProvider,
1376
- onChange: (event) => setOauthProvider(event.target.value === "microsoft" ? "microsoft" : "google")
1377
- },
1378
- (0, import_react6.createElement)("option", { value: "google" }, "Google / Gmail"),
1379
- (0, import_react6.createElement)("option", { value: "microsoft" }, "Microsoft 365 / Outlook")
1380
- )
1381
- ) : null
1382
- ),
1383
- authMode === "oauth2" ? (0, import_react6.createElement)(
1384
- "p",
1385
- { className: "small muted" },
1386
- "\u4FDD\u5B58\u540E\u5230\u8D26\u53F7\u8BBE\u7F6E\u91CC\u70B9\u300COAuth \u6388\u6743\u300D\u3002\u6388\u6743\u524D\u8BF7\u5148\u5728\u8BBE\u7F6E\u4E0B\u65B9\u586B\u597D OAuth \u5E94\u7528 Client ID\u3002"
1387
- ) : null,
1388
1344
  (0, import_react6.createElement)(
1389
1345
  "div",
1390
1346
  { className: "mailharbor-grid" },
@@ -1399,7 +1355,7 @@ function AddAccountForm({
1399
1355
  autoFocus: true
1400
1356
  })
1401
1357
  ),
1402
- authMode === "password" ? (0, import_react6.createElement)(
1358
+ (0, import_react6.createElement)(
1403
1359
  Field,
1404
1360
  { label: "\u5BC6\u7801 / \u5E94\u7528\u4E13\u7528\u5BC6\u7801" },
1405
1361
  (0, import_react6.createElement)("input", {
@@ -1407,7 +1363,7 @@ function AddAccountForm({
1407
1363
  value: password,
1408
1364
  onChange: (event) => setPassword(event.target.value)
1409
1365
  })
1410
- ) : null
1366
+ )
1411
1367
  ),
1412
1368
  (0, import_react6.createElement)(
1413
1369
  Field,
@@ -1418,7 +1374,7 @@ function AddAccountForm({
1418
1374
  onChange: (event) => setLabel(event.target.value)
1419
1375
  })
1420
1376
  ),
1421
- authMode === "password" ? (0, import_react6.createElement)(Toggle, { checked: remember, onChange: setRemember, label: "\u8BB0\u4F4F\u5BC6\u7801\uFF08\u5199\u5165\u7CFB\u7EDF\u94A5\u5319\u4E32\uFF09" }) : null,
1377
+ (0, import_react6.createElement)(Toggle, { checked: remember, onChange: setRemember, label: "\u8BB0\u4F4F\u5BC6\u7801\uFF08\u5199\u5165\u7CFB\u7EDF\u94A5\u5319\u4E32\uFF09" }),
1422
1378
  (0, import_react6.createElement)(
1423
1379
  "button",
1424
1380
  { className: "ghost", onClick: () => setAdvanced(!advanced) },
@@ -1592,6 +1548,7 @@ function Composer({
1592
1548
  const [subject, setSubject] = (0, import_react7.useState)(initial.subject);
1593
1549
  const [showCc, setShowCc] = (0, import_react7.useState)(initial.cc !== "" || initial.bcc !== "");
1594
1550
  const [attachments, setAttachments] = (0, import_react7.useState)(initial.attachments ?? []);
1551
+ const [dragging, setDragging] = (0, import_react7.useState)(false);
1595
1552
  const [busy, setBusy] = (0, import_react7.useState)(false);
1596
1553
  const [error, setError] = (0, import_react7.useState)("");
1597
1554
  const [confirming, setConfirming] = (0, import_react7.useState)(false);
@@ -2009,13 +1966,30 @@ function Composer({
2009
1966
  )
2010
1967
  ),
2011
1968
  (0, import_react7.createElement)("div", {
2012
- className: "mailharbor-editor",
1969
+ className: dragging ? "mailharbor-editor dragging" : "mailharbor-editor",
2013
1970
  ref: editor,
2014
1971
  contentEditable: true,
2015
1972
  suppressContentEditableWarning: true,
2016
- "data-placeholder": "\u5199\u70B9\u4EC0\u4E48\u2026",
1973
+ "data-placeholder": "\u5199\u70B9\u4EC0\u4E48\u2026\uFF08\u53EF\u62D6\u62FD\u9644\u4EF6\u6216\u7C98\u8D34\u622A\u56FE\uFF09",
2017
1974
  spellCheck: true,
2018
- onInput: markDirty
1975
+ onInput: markDirty,
1976
+ onDragOver: (event) => {
1977
+ event.preventDefault();
1978
+ setDragging(true);
1979
+ },
1980
+ onDragLeave: () => setDragging(false),
1981
+ onDrop: (event) => {
1982
+ event.preventDefault();
1983
+ setDragging(false);
1984
+ void addFiles(event.dataTransfer?.files ?? null);
1985
+ },
1986
+ onPaste: (event) => {
1987
+ const files = event.clipboardData?.files;
1988
+ if (files !== void 0 && files !== null && files.length > 0) {
1989
+ event.preventDefault();
1990
+ void addFiles(files);
1991
+ }
1992
+ }
2019
1993
  }),
2020
1994
  (0, import_react7.createElement)(
2021
1995
  "div",
@@ -2089,49 +2063,126 @@ function isSentMailbox(mailbox) {
2089
2063
  function errorText4(error) {
2090
2064
  return error instanceof Error ? error.message : String(error);
2091
2065
  }
2066
+ function previewable(contentType) {
2067
+ const type = contentType.toLowerCase();
2068
+ return type.startsWith("image/") && type !== "image/svg+xml" || type === "application/pdf" || type === "text/plain" || type === "text/csv" || type === "text/markdown" || type === "application/json";
2069
+ }
2070
+ function AttachmentPreviewText({ url }) {
2071
+ const [text, setText] = (0, import_react8.useState)("");
2072
+ const [error, setError] = (0, import_react8.useState)("");
2073
+ (0, import_react8.useEffect)(() => {
2074
+ let cancelled = false;
2075
+ fetch(url).then((response) => response.text()).then((value) => {
2076
+ if (!cancelled) setText(value.slice(0, 2e5));
2077
+ }).catch((caught) => {
2078
+ if (!cancelled) setError(caught instanceof Error ? caught.message : String(caught));
2079
+ });
2080
+ return () => {
2081
+ cancelled = true;
2082
+ };
2083
+ }, [url]);
2084
+ if (error !== "") return (0, import_react8.createElement)("p", { className: "small", style: { color: "var(--m-danger)" } }, error);
2085
+ return (0, import_react8.createElement)("pre", { className: "mailharbor-preview-text" }, text === "" ? "\u52A0\u8F7D\u4E2D\u2026" : text);
2086
+ }
2092
2087
  function AttachmentChips({
2093
2088
  detail,
2094
2089
  source,
2095
2090
  mailbox
2096
2091
  }) {
2097
2092
  const [expanded, setExpanded] = (0, import_react8.useState)(false);
2093
+ const [preview, setPreview] = (0, import_react8.useState)(null);
2098
2094
  if (detail.attachments.length === 0) return null;
2099
2095
  const shown = expanded ? detail.attachments : detail.attachments.slice(0, 3);
2100
2096
  const hidden = detail.attachments.length - shown.length;
2097
+ const urlFor = (file, inline2) => source === "server" ? api.attachmentUrl({
2098
+ accountId: detail.accountId,
2099
+ source: "server",
2100
+ mailbox,
2101
+ uid: detail.uid ?? "",
2102
+ part: file.id,
2103
+ ...inline2 ? { inline: 1 } : {}
2104
+ }) : api.attachmentUrl({
2105
+ accountId: detail.accountId,
2106
+ source: "local",
2107
+ emailId: detail.id,
2108
+ attachmentId: file.id,
2109
+ ...inline2 ? { inline: 1 } : {}
2110
+ });
2111
+ const previewUrl = preview === null ? "" : urlFor(preview, true);
2101
2112
  return (0, import_react8.createElement)(
2102
2113
  "div",
2103
- { className: "mailharbor-attachment-chips" },
2104
- shown.map(
2105
- (file) => (0, import_react8.createElement)(
2106
- "a",
2114
+ null,
2115
+ (0, import_react8.createElement)(
2116
+ "div",
2117
+ { className: "mailharbor-attachment-chips" },
2118
+ shown.map(
2119
+ (file) => previewable(file.contentType) ? (0, import_react8.createElement)(
2120
+ "button",
2121
+ {
2122
+ key: file.id,
2123
+ className: "mailharbor-attachment",
2124
+ title: `\u9884\u89C8 ${file.filename}`,
2125
+ onClick: () => setPreview(file)
2126
+ },
2127
+ (0, import_react8.createElement)(Icon, { name: "paperclip", size: 12 }),
2128
+ (0, import_react8.createElement)("span", { className: "name" }, file.filename),
2129
+ (0, import_react8.createElement)("span", { className: "muted small" }, formatBytes(file.size))
2130
+ ) : (0, import_react8.createElement)(
2131
+ "a",
2132
+ {
2133
+ className: "mailharbor-attachment",
2134
+ key: file.id,
2135
+ href: urlFor(file, false),
2136
+ download: file.filename,
2137
+ title: file.filename
2138
+ },
2139
+ (0, import_react8.createElement)(Icon, { name: "paperclip", size: 12 }),
2140
+ (0, import_react8.createElement)("span", { className: "name" }, file.filename),
2141
+ (0, import_react8.createElement)("span", { className: "muted small" }, formatBytes(file.size))
2142
+ )
2143
+ ),
2144
+ hidden > 0 ? (0, import_react8.createElement)(
2145
+ "button",
2146
+ { className: "subtle small", onClick: () => setExpanded(true) },
2147
+ `+${String(hidden)} \u4E2A\u9644\u4EF6`
2148
+ ) : detail.attachments.length > 3 ? (0, import_react8.createElement)("button", { className: "subtle small", onClick: () => setExpanded(false) }, "\u6536\u8D77\u9644\u4EF6") : null
2149
+ ),
2150
+ preview === null ? null : (0, import_react8.createElement)(
2151
+ Modal,
2152
+ {
2153
+ title: preview.filename,
2154
+ wide: true,
2155
+ onClose: () => setPreview(null),
2156
+ footer: (0, import_react8.createElement)(
2157
+ "div",
2158
+ { style: { display: "flex", gap: "8px", width: "100%", alignItems: "center" } },
2159
+ (0, import_react8.createElement)(
2160
+ "span",
2161
+ { className: "small muted" },
2162
+ `${preview.contentType} \xB7 ${formatBytes(preview.size)}`
2163
+ ),
2164
+ (0, import_react8.createElement)("span", { className: "spacer" }),
2165
+ (0, import_react8.createElement)(
2166
+ "a",
2167
+ {
2168
+ className: "ghost",
2169
+ href: urlFor(preview, false),
2170
+ download: preview.filename,
2171
+ style: { display: "inline-flex", alignItems: "center", gap: "5px" }
2172
+ },
2173
+ "\u4E0B\u8F7D"
2174
+ ),
2175
+ (0, import_react8.createElement)("button", { className: "primary small", onClick: () => setPreview(null) }, "\u5173\u95ED")
2176
+ )
2177
+ },
2178
+ (0, import_react8.createElement)(
2179
+ "div",
2107
2180
  {
2108
- className: "mailharbor-attachment",
2109
- key: file.id,
2110
- href: source === "server" ? api.attachmentUrl({
2111
- accountId: detail.accountId,
2112
- source: "server",
2113
- mailbox,
2114
- uid: detail.uid ?? "",
2115
- part: file.id
2116
- }) : api.attachmentUrl({
2117
- accountId: detail.accountId,
2118
- source: "local",
2119
- emailId: detail.id,
2120
- attachmentId: file.id
2121
- }),
2122
- download: file.filename,
2123
- title: file.filename
2181
+ className: `mailharbor-preview${preview.contentType.toLowerCase().startsWith("image/") ? " image" : preview.contentType.toLowerCase() === "application/pdf" ? " pdf" : " text"}`
2124
2182
  },
2125
- (0, import_react8.createElement)(Icon, { name: "paperclip", size: 12 }),
2126
- (0, import_react8.createElement)("span", { className: "name" }, file.filename),
2127
- (0, import_react8.createElement)("span", { className: "muted small" }, formatBytes(file.size))
2183
+ preview.contentType.toLowerCase().startsWith("image/") ? (0, import_react8.createElement)("img", { src: previewUrl, alt: preview.filename }) : preview.contentType.toLowerCase() === "application/pdf" ? (0, import_react8.createElement)("iframe", { src: previewUrl, title: preview.filename }) : (0, import_react8.createElement)(AttachmentPreviewText, { url: previewUrl })
2128
2184
  )
2129
- ),
2130
- hidden > 0 ? (0, import_react8.createElement)(
2131
- "button",
2132
- { className: "subtle small", onClick: () => setExpanded(true) },
2133
- `+${String(hidden)} \u4E2A\u9644\u4EF6`
2134
- ) : detail.attachments.length > 3 ? (0, import_react8.createElement)("button", { className: "subtle small", onClick: () => setExpanded(false) }, "\u6536\u8D77\u9644\u4EF6") : null
2185
+ )
2135
2186
  );
2136
2187
  }
2137
2188
  function Reader({
@@ -2158,6 +2209,7 @@ function Reader({
2158
2209
  const [details, setDetails] = (0, import_react8.useState)({});
2159
2210
  const [openId, setOpenId] = (0, import_react8.useState)(detail.id);
2160
2211
  const [detailOpen, setDetailOpen] = (0, import_react8.useState)(false);
2212
+ const [moreActions, setMoreActions] = (0, import_react8.useState)(false);
2161
2213
  const selectedCard = (0, import_react8.useRef)(null);
2162
2214
  const [busy, setBusy] = (0, import_react8.useState)(false);
2163
2215
  const [error, setError] = (0, import_react8.useState)("");
@@ -2271,7 +2323,7 @@ function Reader({
2271
2323
  ),
2272
2324
  (0, import_react8.createElement)(
2273
2325
  "div",
2274
- { className: "mailharbor-reader-actions" },
2326
+ { className: moreActions ? "mailharbor-reader-actions expanded" : "mailharbor-reader-actions" },
2275
2327
  (0, import_react8.createElement)(
2276
2328
  "button",
2277
2329
  { className: "ghost", onClick: () => onReply("reply") },
@@ -2290,22 +2342,33 @@ function Reader({
2290
2342
  (0, import_react8.createElement)(Icon, { name: "forward" }),
2291
2343
  "\u8F6C\u53D1"
2292
2344
  ),
2293
- (0, import_react8.createElement)("span", { className: "mailharbor-divider" }),
2345
+ (0, import_react8.createElement)(
2346
+ "button",
2347
+ {
2348
+ className: "ghost mailharbor-more-toggle",
2349
+ "aria-expanded": moreActions,
2350
+ onClick: () => setMoreActions(!moreActions)
2351
+ },
2352
+ moreActions ? "\u6536\u8D77" : "\u66F4\u591A",
2353
+ (0, import_react8.createElement)(Icon, { name: moreActions ? "chevronLeft" : "chevronRight", size: 12 })
2354
+ ),
2355
+ (0, import_react8.createElement)("span", { className: "mailharbor-divider mailharbor-secondary" }),
2294
2356
  onArchive === void 0 ? null : (0, import_react8.createElement)(
2295
2357
  "button",
2296
- { className: "ghost", onClick: onArchive, title: "\u79FB\u5230\u5F52\u6863\u6587\u4EF6\u5939" },
2358
+ { className: "ghost mailharbor-secondary", onClick: onArchive, title: "\u79FB\u5230\u5F52\u6863\u6587\u4EF6\u5939" },
2297
2359
  (0, import_react8.createElement)(Icon, { name: "archive", size: 14 }),
2298
2360
  "\u5F52\u6863"
2299
2361
  ),
2300
2362
  onDelete === void 0 ? null : (0, import_react8.createElement)(
2301
2363
  "button",
2302
- { className: "ghost", onClick: onDelete, title: "\u79FB\u5230\u5783\u573E\u7BB1" },
2364
+ { className: "ghost mailharbor-secondary", onClick: onDelete, title: "\u79FB\u5230\u5783\u573E\u7BB1" },
2303
2365
  (0, import_react8.createElement)(Icon, { name: "trash", size: 14 }),
2304
2366
  "\u5220\u9664"
2305
2367
  ),
2306
2368
  onMove === void 0 || folders.length === 0 ? null : (0, import_react8.createElement)(
2307
2369
  "select",
2308
2370
  {
2371
+ className: "mailharbor-secondary",
2309
2372
  value: "",
2310
2373
  "aria-label": "\u79FB\u52A8\u5230\u6587\u4EF6\u5939",
2311
2374
  title: "\u79FB\u52A8\u5230\u6587\u4EF6\u5939",
@@ -2317,24 +2380,32 @@ function Reader({
2317
2380
  (0, import_react8.createElement)("option", { value: "" }, "\u79FB\u52A8\u5230\u2026"),
2318
2381
  folders.map((folder) => (0, import_react8.createElement)("option", { key: folder.name, value: folder.name }, folder.label))
2319
2382
  ),
2320
- (0, import_react8.createElement)("span", { className: "mailharbor-divider" }),
2383
+ (0, import_react8.createElement)("span", { className: "mailharbor-divider mailharbor-secondary" }),
2321
2384
  (0, import_react8.createElement)(
2322
2385
  "button",
2323
- { className: "ghost", onClick: () => onAiAction("summary") },
2386
+ { className: "ghost mailharbor-secondary", onClick: () => onAiAction("summary") },
2324
2387
  (0, import_react8.createElement)(Icon, { name: "sparkles", size: 14 }),
2325
2388
  "AI \u6458\u8981"
2326
2389
  ),
2327
- (0, import_react8.createElement)("button", { className: "ghost", onClick: () => onAiAction("reply") }, "AI \u56DE\u590D"),
2328
- (0, import_react8.createElement)("button", { className: "ghost", onClick: () => onAiAction("translate") }, "AI \u7FFB\u8BD1"),
2329
2390
  (0, import_react8.createElement)(
2330
2391
  "button",
2331
- { className: "ghost", onClick: onExtractTasks },
2392
+ { className: "ghost mailharbor-secondary", onClick: () => onAiAction("reply") },
2393
+ "AI \u56DE\u590D"
2394
+ ),
2395
+ (0, import_react8.createElement)(
2396
+ "button",
2397
+ { className: "ghost mailharbor-secondary", onClick: () => onAiAction("translate") },
2398
+ "AI \u7FFB\u8BD1"
2399
+ ),
2400
+ (0, import_react8.createElement)(
2401
+ "button",
2402
+ { className: "ghost mailharbor-secondary", onClick: onExtractTasks },
2332
2403
  (0, import_react8.createElement)(Icon, { name: "checklist", size: 14 }),
2333
2404
  "\u63D0\u53D6\u4EFB\u52A1"
2334
2405
  ),
2335
2406
  (0, import_react8.createElement)(
2336
2407
  "button",
2337
- { className: "ghost", onClick: onAddToProject },
2408
+ { className: "ghost mailharbor-secondary", onClick: onAddToProject },
2338
2409
  (0, import_react8.createElement)(Icon, { name: "folder", size: 14 }),
2339
2410
  "\u52A0\u5165\u9879\u76EE"
2340
2411
  ),
@@ -2546,13 +2617,15 @@ function MailPanel() {
2546
2617
  const [selectMode, setSelectMode] = (0, import_react9.useState)(false);
2547
2618
  const [sideOpen, setSideOpen] = (0, import_react9.useState)(() => {
2548
2619
  try {
2549
- return window.localStorage.getItem("mailharbor.side") !== "0";
2620
+ const wide = window.innerWidth > 1220;
2621
+ return wide && window.localStorage.getItem("mailharbor.side") !== "0";
2550
2622
  } catch {
2551
2623
  return true;
2552
2624
  }
2553
2625
  });
2554
2626
  const [expandedGroups, setExpandedGroups] = (0, import_react9.useState)([]);
2555
2627
  const [selectedKeys, setSelectedKeys] = (0, import_react9.useState)([]);
2628
+ const searchRef = (0, import_react9.useRef)(null);
2556
2629
  const [projectOptions, setProjectOptions] = (0, import_react9.useState)([]);
2557
2630
  const [targetProject, setTargetProject] = (0, import_react9.useState)("");
2558
2631
  const [extraction, setExtraction] = (0, import_react9.useState)(null);
@@ -3027,6 +3100,26 @@ ${projectPicker.subject}`,
3027
3100
  cancelled = true;
3028
3101
  };
3029
3102
  }, [accountScope, source, mailbox, search, limit, tick, unreadOnly]);
3103
+ (0, import_react9.useEffect)(() => {
3104
+ const handler = (event) => {
3105
+ const target = event.target;
3106
+ if (target?.closest('input, textarea, select, [contenteditable="true"]') !== null) return;
3107
+ if (event.metaKey || event.ctrlKey || event.altKey) return;
3108
+ if (event.key === "/" && !event.shiftKey) {
3109
+ event.preventDefault();
3110
+ searchRef.current?.focus();
3111
+ return;
3112
+ }
3113
+ if (event.key !== "Escape") return;
3114
+ if (document.querySelector(".mailharbor-modal") !== null) return;
3115
+ if (backupOpen) setBackupOpen(false);
3116
+ else if (railOpen) setRailOpen(false);
3117
+ else if (sideOpen) setSideOpen(false);
3118
+ else if (selected !== null) setSelected(null);
3119
+ };
3120
+ window.addEventListener("keydown", handler);
3121
+ return () => window.removeEventListener("keydown", handler);
3122
+ }, [backupOpen, railOpen, sideOpen, selected]);
3030
3123
  (0, import_react9.useEffect)(() => {
3031
3124
  if (typeof window.matchMedia !== "function") return;
3032
3125
  const media = window.matchMedia("(max-width: 900px)");
@@ -3036,6 +3129,22 @@ ${projectPicker.subject}`,
3036
3129
  media.removeEventListener("change", onChange);
3037
3130
  };
3038
3131
  }, []);
3132
+ (0, import_react9.useEffect)(() => {
3133
+ if (typeof window.matchMedia !== "function") return;
3134
+ const media = window.matchMedia("(max-width: 1220px)");
3135
+ const onChange = () => {
3136
+ if (media.matches) setSideOpen(false);
3137
+ };
3138
+ media.addEventListener("change", onChange);
3139
+ return () => {
3140
+ media.removeEventListener("change", onChange);
3141
+ };
3142
+ }, []);
3143
+ const closeDrawer = () => {
3144
+ if (typeof window.matchMedia === "function" && window.matchMedia("(max-width: 1220px)").matches) {
3145
+ setSideOpen(false);
3146
+ }
3147
+ };
3039
3148
  (0, import_react9.useEffect)(() => {
3040
3149
  if (accountScope === null || isAll) return;
3041
3150
  let cancelled = false;
@@ -3368,13 +3477,13 @@ ${projectPicker.subject}`,
3368
3477
  "div",
3369
3478
  { className: "mailharbor-onboarding" },
3370
3479
  (0, import_react9.createElement)("div", null, (0, import_react9.createElement)("strong", null, "1"), "\u6DFB\u52A0\u90AE\u7BB1\u8D26\u53F7"),
3371
- (0, import_react9.createElement)("div", null, (0, import_react9.createElement)("strong", null, "2"), "\u767B\u5F55\uFF08\u5BC6\u7801 / \u5E94\u7528\u4E13\u7528\u5BC6\u7801 / OAuth2\uFF09"),
3480
+ (0, import_react9.createElement)("div", null, (0, import_react9.createElement)("strong", null, "2"), "\u767B\u5F55\uFF08\u5BC6\u7801 / \u5E94\u7528\u4E13\u7528\u5BC6\u7801\uFF09"),
3372
3481
  (0, import_react9.createElement)("div", null, (0, import_react9.createElement)("strong", null, "3"), "\u81EA\u52A8\u540C\u6B65\u540E\u4F1A\u7ACB\u5373\u51FA\u73B0\u5728\u5217\u8868\u548C AI \u52A9\u624B\u91CC")
3373
3482
  ),
3374
3483
  (0, import_react9.createElement)(
3375
3484
  "p",
3376
3485
  { className: "small muted" },
3377
- "Gmail / Microsoft 365 \u53EF\u76F4\u63A5\u7528 OAuth2\uFF1B\u5176\u4ED6\u90AE\u7BB1\u7528 IMAP \u5E94\u7528\u4E13\u7528\u5BC6\u7801\u5373\u53EF\u3002"
3486
+ "Gmail\u3001Outlook\u3001QQ\u3001163 \u7B49\u8BF7\u4F7F\u7528 IMAP \u5E94\u7528\u4E13\u7528\u5BC6\u7801\uFF1B\u90AE\u7BB1\u670D\u52A1\u5668\u5730\u5740\u53EF\u5728\u9AD8\u7EA7\u8BBE\u7F6E\u91CC\u6539\u3002"
3378
3487
  ),
3379
3488
  error === "" ? null : (0, import_react9.createElement)("div", { className: "small", style: { color: "var(--m-danger)" } }, error),
3380
3489
  (0, import_react9.createElement)(AddAccountForm, {
@@ -3580,7 +3689,7 @@ ${projectPicker.subject}`,
3580
3689
  "button",
3581
3690
  { className: "ghost", onClick: openManager, title: "\u9879\u76EE\u7BA1\u7406" },
3582
3691
  (0, import_react9.createElement)(Icon, { name: "folder" }),
3583
- "\u9879\u76EE"
3692
+ (0, import_react9.createElement)("span", { className: "mailharbor-action-label" }, "\u9879\u76EE")
3584
3693
  ),
3585
3694
  (0, import_react9.createElement)(
3586
3695
  "button",
@@ -3590,13 +3699,13 @@ ${projectPicker.subject}`,
3590
3699
  title: "AI \u5DE5\u4F5C\u53F0"
3591
3700
  },
3592
3701
  (0, import_react9.createElement)(Icon, { name: "sparkles" }),
3593
- "AI"
3702
+ (0, import_react9.createElement)("span", { className: "mailharbor-action-label" }, "AI")
3594
3703
  ),
3595
3704
  (0, import_react9.createElement)(
3596
3705
  "button",
3597
3706
  { className: "primary", onClick: () => startCompose("new") },
3598
3707
  (0, import_react9.createElement)(Icon, { name: "compose" }),
3599
- "\u5199\u90AE\u4EF6"
3708
+ (0, import_react9.createElement)("span", { className: "mailharbor-action-label" }, "\u5199\u90AE\u4EF6")
3600
3709
  )
3601
3710
  ),
3602
3711
  toast === "" ? null : (0, import_react9.createElement)("div", { className: "small", style: { padding: "6px 14px", color: "var(--m-ok)" } }, toast),
@@ -3617,6 +3726,11 @@ ${projectPicker.subject}`,
3617
3726
  ) : (0, import_react9.createElement)(
3618
3727
  "div",
3619
3728
  { className: "mailharbor-body", "data-mode": narrow && selected !== null ? "reader" : "list" },
3729
+ sideOpen ? (0, import_react9.createElement)("button", {
3730
+ className: "mailharbor-scrim",
3731
+ "aria-label": "\u5173\u95ED\u8D26\u53F7\u4E0E\u6587\u4EF6\u5939",
3732
+ onClick: () => setSideOpen(false)
3733
+ }) : null,
3620
3734
  sideOpen ? (0, import_react9.createElement)(
3621
3735
  "aside",
3622
3736
  { className: "mailharbor-side" },
@@ -3630,6 +3744,7 @@ ${projectPicker.subject}`,
3630
3744
  onClick: () => {
3631
3745
  void switchAccount(item.id);
3632
3746
  setMailbox("INBOX");
3747
+ closeDrawer();
3633
3748
  }
3634
3749
  },
3635
3750
  (0, import_react9.createElement)(Avatar, { email: item.email, size: 18 }),
@@ -3656,6 +3771,7 @@ ${projectPicker.subject}`,
3656
3771
  onClick: () => {
3657
3772
  setMailbox(folder.name);
3658
3773
  setSelected(null);
3774
+ closeDrawer();
3659
3775
  },
3660
3776
  onMouseEnter: () => prefetchFolder(folder.name)
3661
3777
  },
@@ -3673,6 +3789,7 @@ ${projectPicker.subject}`,
3673
3789
  { className: "mailharbor-filters" },
3674
3790
  (0, import_react9.createElement)("input", {
3675
3791
  type: "search",
3792
+ ref: searchRef,
3676
3793
  placeholder: showingDrafts ? "\u641C\u7D22\u8349\u7A3F" : aiSearching ? "AI \u6B63\u5728\u7406\u89E3\u4F60\u7684\u641C\u7D22\u2026" : "\u641C\u7D22\u90AE\u4EF6\uFF0C\u6216\u63CF\u8FF0\u4F60\u8981\u627E\u4EC0\u4E48\uFF08AI\uFF09",
3677
3794
  "aria-label": "\u641C\u7D22\u90AE\u4EF6",
3678
3795
  value: query2,
@@ -3904,7 +4021,19 @@ ${projectPicker.subject}`,
3904
4021
  "div",
3905
4022
  { className: "small" },
3906
4023
  aiInfo === null ? source === "local" ? "\u70B9\u53F3\u4E0A\u89D2\u300C\u540C\u6B65\u300D\u628A\u670D\u52A1\u5668\u90AE\u4EF6\u62C9\u4E0B\u6765\u3002" : "\u6362\u4E00\u4E2A\u6587\u4EF6\u5939\u6216\u7A0D\u540E\u5237\u65B0\u3002" : "\u6362\u4E2A\u8BF4\u6CD5\uFF0C\u6216\u76F4\u63A5\u8F93\u5165\u5173\u952E\u8BCD\u540E\u6309\u56DE\u8F66\u3002"
3907
- )
4024
+ ),
4025
+ search !== "" || aiInfo !== null ? (0, import_react9.createElement)(
4026
+ "button",
4027
+ {
4028
+ className: "ghost small",
4029
+ onClick: () => {
4030
+ setQuery("");
4031
+ setSearch("");
4032
+ setAiInfo(null);
4033
+ }
4034
+ },
4035
+ "\u6E05\u9664\u641C\u7D22"
4036
+ ) : null
3908
4037
  ) : selectMode ? items.map((item) => renderMessage(item)) : groups.map((group) => {
3909
4038
  const latest = group.items[0];
3910
4039
  if (latest === void 0) return null;
@@ -3990,6 +4119,11 @@ ${projectPicker.subject}`,
3990
4119
  onMove: (target) => void moveCurrent(target, "\u5DF2\u79FB\u52A8")
3991
4120
  })
3992
4121
  ),
4122
+ railOpen ? (0, import_react9.createElement)("button", {
4123
+ className: "mailharbor-ai-scrim",
4124
+ "aria-label": "\u5173\u95ED AI \u52A9\u624B",
4125
+ onClick: () => setRailOpen(false)
4126
+ }) : null,
3993
4127
  railOpen ? (0, import_react9.createElement)(AiRail, {
3994
4128
  account: accounts.find((item) => item.id === (selected?.accountId ?? accountScope)) ?? currentAccount,
3995
4129
  detail: selected,
@@ -4343,9 +4477,6 @@ function MailSettings() {
4343
4477
  const [checkResults, setCheckResults] = (0, import_react10.useState)({});
4344
4478
  const [adding, setAdding] = (0, import_react10.useState)(false);
4345
4479
  const [tick, setTick] = (0, import_react10.useState)(0);
4346
- const [googleClientId, setGoogleClientId] = (0, import_react10.useState)("");
4347
- const [googleClientSecret, setGoogleClientSecret] = (0, import_react10.useState)("");
4348
- const [microsoftClientId, setMicrosoftClientId] = (0, import_react10.useState)("");
4349
4480
  (0, import_react10.useEffect)(() => {
4350
4481
  let cancelled = false;
4351
4482
  Promise.all([api.state(), api.settings()]).then(([appState, view]) => {
@@ -4361,9 +4492,6 @@ function MailSettings() {
4361
4492
  setAiProvider(view.ai.provider);
4362
4493
  setAiModel(view.ai.model);
4363
4494
  setAiSummaryLength(view.ai.summaryLength);
4364
- setGoogleClientId(view.oauth?.google.clientId ?? "");
4365
- setGoogleClientSecret(view.oauth?.google.clientSecret ?? "");
4366
- setMicrosoftClientId(view.oauth?.microsoft.clientId ?? "");
4367
4495
  }).catch((caught) => {
4368
4496
  if (!cancelled) setError(errorText6(caught));
4369
4497
  });
@@ -4509,72 +4637,11 @@ function MailSettings() {
4509
4637
  onCancel: () => setAdding(false)
4510
4638
  }) : (0, import_react10.createElement)("button", { className: "ghost", onClick: () => setAdding(true) }, "+ \u6DFB\u52A0\u8D26\u53F7")
4511
4639
  ),
4512
- (0, import_react10.createElement)(
4513
- "div",
4514
- { className: "mailharbor-card" },
4515
- (0, import_react10.createElement)("h3", null, "OAuth2 \u5E94\u7528\uFF08Gmail / Microsoft 365\uFF09"),
4516
- (0, import_react10.createElement)(
4517
- "p",
4518
- { className: "small muted" },
4519
- "\u5728 Google Cloud Console \u521B\u5EFA\u300C\u684C\u9762\u5E94\u7528\u300DOAuth \u5BA2\u6237\u7AEF\uFF0C\u6216\u5728 Azure \u6CE8\u518C\u5E94\u7528\u5E76\u5141\u8BB8\u516C\u5171\u5BA2\u6237\u7AEF\u8BBE\u5907\u4EE3\u7801\u6D41\uFF1B\u628A Client ID \u586B\u5230\u8FD9\u91CC\u3002"
4520
- ),
4521
- (0, import_react10.createElement)(
4522
- "div",
4523
- { className: "mailharbor-grid" },
4524
- (0, import_react10.createElement)(
4525
- Field,
4526
- { label: "Google Client ID" },
4527
- (0, import_react10.createElement)("input", {
4528
- value: googleClientId,
4529
- placeholder: "xxxx.apps.googleusercontent.com",
4530
- onChange: (event) => setGoogleClientId(event.target.value)
4531
- })
4532
- ),
4533
- (0, import_react10.createElement)(
4534
- Field,
4535
- { label: "Google Client Secret" },
4536
- (0, import_react10.createElement)("input", {
4537
- type: "password",
4538
- value: googleClientSecret,
4539
- onChange: (event) => setGoogleClientSecret(event.target.value)
4540
- })
4541
- )
4542
- ),
4543
- (0, import_react10.createElement)(
4544
- Field,
4545
- { label: "Microsoft Client ID" },
4546
- (0, import_react10.createElement)("input", {
4547
- value: microsoftClientId,
4548
- onChange: (event) => setMicrosoftClientId(event.target.value)
4549
- })
4550
- ),
4551
- (0, import_react10.createElement)(
4552
- "button",
4553
- {
4554
- className: "ghost",
4555
- onClick: () => void saveGeneral({
4556
- oauth: {
4557
- google: {
4558
- clientId: googleClientId.trim(),
4559
- clientSecret: googleClientSecret.trim(),
4560
- redirectPort: settings?.oauth?.google.redirectPort ?? 8765
4561
- },
4562
- microsoft: { clientId: microsoftClientId.trim() }
4563
- }
4564
- })
4565
- },
4566
- "\u4FDD\u5B58 OAuth \u5E94\u7528"
4567
- )
4568
- ),
4569
4640
  (0, import_react10.createElement)(
4570
4641
  "div",
4571
4642
  { className: "mailharbor-card" },
4572
4643
  (0, import_react10.createElement)("h3", null, "\u5907\u4EFD\u4E0E\u8FC1\u79FB"),
4573
- (0, import_react10.createElement)(
4574
- "p",
4575
- { className: "small muted" },
4576
- "\u5BFC\u51FA\u8D26\u53F7\uFF08\u4E0D\u542B\u5BC6\u7801\u548C OAuth \u4EE4\u724C\uFF09\u3001\u7B7E\u540D\u3001\u9605\u8BFB\u4E0E OAuth \u5E94\u7528\u914D\u7F6E\uFF1B\u5BFC\u5165\u65F6\u6309\u90AE\u7BB1\u53BB\u91CD\u3002"
4577
- ),
4644
+ (0, import_react10.createElement)("p", { className: "small muted" }, "\u5BFC\u51FA\u8D26\u53F7\uFF08\u4E0D\u542B\u5BC6\u7801\uFF09\u3001\u7B7E\u540D\u4E0E\u9605\u8BFB\u8BBE\u7F6E\uFF1B\u5BFC\u5165\u65F6\u6309\u90AE\u7BB1\u53BB\u91CD\u3002"),
4578
4645
  (0, import_react10.createElement)(
4579
4646
  "div",
4580
4647
  { style: { display: "flex", gap: "8px", flexWrap: "wrap" } },
@@ -4596,10 +4663,6 @@ function MailSettings() {
4596
4663
  )
4597
4664
  )
4598
4665
  ),
4599
- state.activeAccountId !== null && settings.accounts.find((item) => item.id === state.activeAccountId)?.auth.type === "oauth2" ? (0, import_react10.createElement)(OAuthCard, {
4600
- account: settings.accounts.find((item) => item.id === state.activeAccountId),
4601
- onChanged: reload
4602
- }) : null,
4603
4666
  (0, import_react10.createElement)(
4604
4667
  "div",
4605
4668
  { className: "mailharbor-card" },
@@ -5121,99 +5184,6 @@ function AccountRow({
5121
5184
  ) : null
5122
5185
  );
5123
5186
  }
5124
- function OAuthCard({ account, onChanged }) {
5125
- const [status, setStatus] = (0, import_react10.useState)(null);
5126
- const [flow, setFlow] = (0, import_react10.useState)(null);
5127
- const [message, setMessage] = (0, import_react10.useState)("");
5128
- const [busy, setBusy] = (0, import_react10.useState)(false);
5129
- (0, import_react10.useEffect)(() => {
5130
- let cancelled = false;
5131
- api.oauthStatus(account.id).then((result) => {
5132
- if (!cancelled) setStatus(result);
5133
- }).catch(() => void 0);
5134
- return () => {
5135
- cancelled = true;
5136
- };
5137
- }, [account.id]);
5138
- (0, import_react10.useEffect)(() => {
5139
- if (flow === null) return;
5140
- const timer = window.setInterval(() => {
5141
- void api.oauthPoll(flow.state).then((result) => {
5142
- if (result.status === "ready") {
5143
- setFlow(null);
5144
- setMessage("\u6388\u6743\u6210\u529F");
5145
- onChanged();
5146
- } else if (result.status === "error") {
5147
- setFlow(null);
5148
- setMessage(result.message ?? "\u6388\u6743\u5931\u8D25");
5149
- }
5150
- }).catch((caught) => {
5151
- setFlow(null);
5152
- setMessage(errorText6(caught));
5153
- });
5154
- }, 2500);
5155
- return () => window.clearInterval(timer);
5156
- }, [flow, onChanged]);
5157
- const start = async () => {
5158
- setBusy(true);
5159
- setMessage("");
5160
- try {
5161
- const result = await api.oauthStart(account.id);
5162
- setFlow(result);
5163
- if (result.flow === "microsoft") setMessage("\u8BF7\u5728\u6D4F\u89C8\u5668\u4E2D\u8F93\u5165\u4E0B\u65B9\u4EE3\u7801\u5B8C\u6210\u767B\u5F55");
5164
- else setMessage("\u5DF2\u5728\u6D4F\u89C8\u5668\u6253\u5F00\u6388\u6743\u9875\uFF0C\u5B8C\u6210\u540E\u4F1A\u81EA\u52A8\u66F4\u65B0");
5165
- } catch (caught) {
5166
- setMessage(errorText6(caught));
5167
- } finally {
5168
- setBusy(false);
5169
- }
5170
- };
5171
- const revoke = async () => {
5172
- setBusy(true);
5173
- try {
5174
- await api.oauthRevoke(account.id);
5175
- setStatus({ ...status ?? { appConfigured: true, expiresAt: null }, authorized: false });
5176
- setMessage("\u5DF2\u64A4\u9500\u6388\u6743");
5177
- onChanged();
5178
- } catch (caught) {
5179
- setMessage(errorText6(caught));
5180
- } finally {
5181
- setBusy(false);
5182
- }
5183
- };
5184
- return (0, import_react10.createElement)(
5185
- "div",
5186
- { className: "mailharbor-card" },
5187
- (0, import_react10.createElement)("h3", null, `OAuth \u6388\u6743 \xB7 ${account.email}`),
5188
- (0, import_react10.createElement)(
5189
- "p",
5190
- { className: "small muted" },
5191
- status?.authorized === true ? `\u5DF2\u6388\u6743${status.expiresAt === null ? "" : `\uFF0C\u8BBF\u95EE\u4EE4\u724C\u6709\u6548\u81F3 ${new Date(status.expiresAt).toLocaleString()}`}` : status?.appConfigured === false ? "\u5C1A\u672A\u914D\u7F6E\u5BF9\u5E94\u670D\u52A1\u5546\u7684 Client ID" : "\u672A\u6388\u6743"
5192
- ),
5193
- flow?.userCode === void 0 ? null : (0, import_react10.createElement)(
5194
- "p",
5195
- null,
5196
- "\u4EE3\u7801\uFF1A",
5197
- (0, import_react10.createElement)("strong", null, flow.userCode),
5198
- flow.verificationUri === void 0 ? null : (0, import_react10.createElement)("span", null, ` \xB7 ${flow.verificationUri}`)
5199
- ),
5200
- message === "" ? null : (0, import_react10.createElement)("p", { className: "small" }, message),
5201
- (0, import_react10.createElement)(
5202
- "div",
5203
- { style: { display: "flex", gap: "8px", flexWrap: "wrap" } },
5204
- (0, import_react10.createElement)(
5205
- "button",
5206
- { className: "primary small", disabled: busy || flow !== null, onClick: () => void start() },
5207
- status?.authorized === true ? "\u91CD\u65B0\u6388\u6743" : "OAuth \u6388\u6743"
5208
- ),
5209
- status?.authorized === true ? (0, import_react10.createElement)(
5210
- "button",
5211
- { className: "ghost small danger", disabled: busy, onClick: () => void revoke() },
5212
- "\u64A4\u9500\u6388\u6743"
5213
- ) : null
5214
- )
5215
- );
5216
- }
5217
5187
 
5218
5188
  // src/client/tasks-panel.tsx
5219
5189
  var import_react11 = require("react");
@@ -5913,7 +5883,7 @@ function TaskEditor({
5913
5883
  }
5914
5884
 
5915
5885
  // src/client/index.tsx
5916
- var VERSION = "0.15.0";
5886
+ var VERSION = "0.16.1";
5917
5887
  var inject = ["slots"];
5918
5888
  var PANEL_ID = "mailharbor";
5919
5889
  var TASKS_PANEL_ID = "mailharbor-tasks";