bothouse-dsh 0.1.57 → 0.1.59

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.
@@ -1,11 +1,11 @@
1
- // dsh-client-source-sha256: d96360e07d625a5c0ea51d1465b0b3814ea77c61bcf8e5abe9142f893ee5badf
2
- // dsh-style-sha256: eb1ce668b0b1783d744af077d35394c83ea96af75a7fb428c315a486340acd35
1
+ // dsh-client-source-sha256: bf3c01b19e0ed8f9d15a02ad7d7e9e9684db4fcbf32f43ba251b220ff57aca56
2
+ // dsh-style-sha256: f6a6de6373a2ead4c3a965e58c158c16626e49a16b91d2d568b35b19fcfdb95a
3
3
  window.__ModuleLoader__.load({
4
4
  id: "bothouse-dsh-channels",
5
5
  factory: (require) => {
6
6
  var module = { exports: {} };
7
7
  var exports = module.exports;
8
- (function(){var s=document.createElement('style');s.setAttribute('data-dsh-plugin',"bothouse-dsh-channels");s.textContent=".dshc_page {\n width: 100%;\n height: 100%;\n min-height: 0;\n padding-top: var(--dsh-frame-top-clearance, 0px);\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-base);\n grid-template-columns: 220px minmax(0, 1fr) 240px;\n font-size: 14px;\n line-height: 1.5;\n display: grid;\n}\n\n.dshc_notice {\n max-width: 480px;\n color: var(--dsw-alias-label-secondary);\n text-align: center;\n grid-column: 1 / -1;\n place-self: center;\n padding: 24px;\n}\n\n.dshc_rooms, .dshc_members {\n background: var(--dsw-alias-bg-layer-2);\n min-height: 0;\n padding: 0 8px 16px;\n overflow-y: auto;\n}\n\n.dshc_membersHead {\n border-bottom: 1px solid var(--dsw-alias-border-l2);\n flex: none;\n height: 44px;\n margin: 0 0 8px;\n}\n\n.dshc_groupTitle {\n color: var(--dsw-alias-label-tertiary);\n letter-spacing: .02em;\n margin: 12px 8px 6px;\n font-size: 12px;\n font-weight: 600;\n}\n\n.dshc_room {\n border-radius: var(--dsw-radius-sm);\n width: 100%;\n color: var(--dsw-alias-label-secondary);\n font: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border: 0;\n align-items: center;\n gap: 6px;\n padding: 6px 8px;\n display: flex;\n}\n\n.dshc_room:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_room:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_workspace {\n padding-left: 22px;\n font-size: .95em;\n}\n\n.dshc_roomLabel {\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.dshc_activeCount {\n color: var(--dsw-alias-label-tertiary);\n flex-shrink: 0;\n margin-left: auto;\n font-size: 11px;\n}\n\n.dshc_activeBusy {\n color: var(--dsw-alias-label-primary);\n}\n\n.dshc_roomActive {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_hash {\n color: var(--dsw-alias-label-tertiary);\n font-size: 16px;\n}\n\n.dshc_chat {\n flex-direction: column;\n min-width: 0;\n min-height: 0;\n display: flex;\n}\n\n.dshc_chatHead {\n -webkit-app-region: drag;\n border-bottom: 1px solid var(--dsw-alias-border-l2);\n align-items: center;\n gap: 6px;\n height: 44px;\n padding: 0 16px;\n font-weight: 600;\n display: flex;\n}\n\n.dshc_log {\n flex: 1;\n min-height: 0;\n padding: 8px 0 12px;\n overflow-y: auto;\n}\n\n.dshc_guide {\n border: 1px dashed var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm);\n color: var(--dsw-alias-label-secondary);\n flex-direction: column;\n align-items: flex-start;\n gap: 10px;\n margin: 16px;\n padding: 14px 16px;\n display: flex;\n}\n\n.dshc_empty {\n color: var(--dsw-alias-label-tertiary);\n padding: 24px 16px;\n}\n\n.dshc_message {\n grid-template-columns: 36px minmax(0, 1fr);\n gap: 12px;\n padding: 6px 16px;\n display: grid;\n}\n\n.dshc_system .dshc_text {\n color: var(--dsw-alias-label-tertiary);\n font-style: italic;\n}\n\n.dshc_avatar {\n corner-shape: round;\n color: #fff;\n border-radius: 50%;\n flex: none;\n place-items: center;\n width: 36px;\n height: 36px;\n font-weight: 700;\n display: grid;\n position: relative;\n}\n\n.dshc_avatarImage {\n object-fit: cover;\n border-radius: 50%;\n width: 100%;\n height: 100%;\n position: absolute;\n inset: 0;\n}\n\n.dshc_avatarSmall {\n width: 28px;\n height: 28px;\n font-size: 12px;\n}\n\n.dshc_avatarAnchor {\n align-self: start;\n position: relative;\n}\n\n.dshc_avatarButton {\n cursor: pointer;\n background: none;\n border: 0;\n border-radius: 50%;\n padding: 0;\n}\n\n.dshc_avatarMenu {\n z-index: 3;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-base);\n min-width: 140px;\n box-shadow: var(--dsw-elevation-panel, 0 8px 24px #0000003d);\n flex-direction: column;\n padding: 6px;\n display: flex;\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n}\n\n.dshc_avatarMenuTitle {\n padding: 4px 8px;\n font-weight: 700;\n}\n\n.dshc_avatarMenuItem {\n border-radius: var(--dsw-radius-sm);\n color: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border: 0;\n padding: 6px 8px;\n}\n\n.dshc_avatarMenuItem:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_messageBody {\n min-width: 0;\n}\n\n.dshc_messageHead {\n align-items: baseline;\n gap: 6px;\n display: flex;\n}\n\n.dshc_author {\n font-weight: 600;\n}\n\n.dshc_time {\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n}\n\n.dshc_tag {\n border-radius: var(--dsw-radius-xs);\n color: var(--dsw-alias-label-primary-inverted);\n background: var(--dsw-alias-state-business-primary);\n white-space: nowrap;\n padding: 0 4px;\n font-size: 10px;\n font-weight: 600;\n}\n\n.dshc_edited {\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n}\n\n.dshc_ownActions {\n margin-left: auto;\n margin-right: var(--channels-reply-clearance);\n opacity: 0;\n gap: 8px;\n display: inline-flex;\n}\n\n.dshc_message:hover .dshc_ownActions, .dshc_ownActions:focus-within {\n opacity: 1;\n}\n\n@media (hover: none) {\n .dshc_ownActions {\n display: none;\n }\n\n .dshc_message[data-tools-open] .dshc_ownActions {\n opacity: 1;\n display: inline-flex;\n }\n}\n\n.dshc_editBox {\n flex-direction: column;\n gap: 6px;\n margin-top: 4px;\n display: flex;\n}\n\n.dshc_editInput {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-base);\n min-height: 60px;\n color: inherit;\n font: inherit;\n resize: vertical;\n padding: 8px;\n}\n\n.dshc_editBar {\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.dshc_editBar .dshc_time {\n margin-right: auto;\n}\n\n.dshc_text {\n white-space: normal;\n overflow-wrap: anywhere;\n}\n\n.dshc_card {\n border-left: 4px solid var(--dsw-alias-state-business-primary);\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-layer-2);\n margin-top: 4px;\n padding: 6px 10px;\n}\n\n.dshc_card[data-state=\"failed\"] {\n border-left-color: var(--dsw-alias-state-error-primary);\n}\n\n.dshc_card[data-state=\"retrying\"] {\n border-left-color: var(--dsw-alias-state-warning-primary, #faa61a);\n}\n\n.dshc_cardButtons {\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n margin-top: 6px;\n display: flex;\n}\n\n.dshc_cardTitle {\n font-size: 13px;\n font-weight: 600;\n}\n\n.dshc_cardHead {\n justify-content: space-between;\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.dshc_cardViews {\n gap: 4px;\n display: flex;\n}\n\n.dshc_cardViewButton {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm);\n color: inherit;\n cursor: pointer;\n background: none;\n padding: 0 6px;\n font-size: 12px;\n}\n\n.dshc_cardViewButton[aria-pressed=\"true\"] {\n background: var(--dsw-alias-bg-base);\n font-weight: 600;\n}\n\n.dshc_permActions {\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n margin-top: 6px;\n display: flex;\n}\n\n.dshc_permScope {\n color: var(--dsw-alias-text-secondary);\n flex-basis: 100%;\n font-size: 12px;\n}\n\n.dshc_permStatus {\n margin-top: 6px;\n font-size: 13px;\n font-weight: 600;\n}\n\n.dshc_message {\n --channels-reply-clearance: 36px;\n position: relative;\n}\n\n.dshc_quote {\n border-left: 2px solid var(--dsw-alias-label-tertiary);\n min-width: 0;\n color: var(--dsw-alias-label-tertiary);\n white-space: nowrap;\n text-overflow: ellipsis;\n gap: 6px;\n margin-bottom: 2px;\n padding-left: 8px;\n font-size: 12px;\n display: flex;\n overflow: hidden;\n}\n\n.dshc_quoteDeleted {\n font-style: italic;\n}\n\n.dshc_quoteAuthor {\n flex: none;\n font-weight: 600;\n}\n\n.dshc_replyButton {\n border-radius: var(--dsw-radius-xs);\n color: var(--dsw-alias-label-tertiary);\n background: var(--dsw-alias-bg-layer-2);\n cursor: pointer;\n border: 0;\n padding: 0 6px;\n}\n\n.dshc_msgTools {\n z-index: 1;\n border: 1px solid var(--dsw-alias-separator, #7f7f7f40);\n border-radius: var(--dsw-radius-sm, 6px);\n background: var(--dsw-alias-bg-elevated, var(--dsw-alias-bg-primary, #fff));\n opacity: 0;\n pointer-events: none;\n align-items: center;\n gap: 2px;\n padding: 2px;\n display: inline-flex;\n position: absolute;\n top: 2px;\n right: 16px;\n box-shadow: 0 2px 6px #00000014;\n}\n\n.dshc_msgTool {\n border-radius: var(--dsw-radius-sm, 6px);\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n cursor: pointer;\n background: none;\n border: 0;\n padding: 2px 8px;\n font-size: 12px;\n}\n\n.dshc_msgTool:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n.dshc_msgTool:disabled {\n cursor: default;\n opacity: .6;\n}\n\n.dshc_msgToolNote {\n color: var(--dsw-alias-label-tertiary);\n white-space: nowrap;\n padding: 0 6px;\n font-size: 12px;\n}\n\n.dshc_message:hover .dshc_msgTools, .dshc_message:focus-within .dshc_msgTools, .dshc_msgTools:has(.dshc_msgToolNote) {\n opacity: 1;\n pointer-events: auto;\n}\n\n@media (hover: none) {\n .dshc_message {\n -webkit-touch-callout: none;\n }\n\n .dshc_msgTools {\n display: none;\n }\n\n .dshc_message[data-tools-open] {\n background: var(--dsw-alias-interactive-bg-hover);\n }\n\n .dshc_message[data-tools-open] .dshc_msgTools {\n z-index: 3;\n opacity: 1;\n pointer-events: auto;\n display: inline-flex;\n top: -14px;\n right: 12px;\n }\n\n .dshc_message[data-tools-open] .dshc_msgTool {\n width: 40px;\n height: 36px;\n }\n}\n\n.dshc_replyBar {\n border-radius: var(--dsw-radius-sm);\n color: var(--dsw-alias-label-tertiary);\n background: var(--dsw-alias-bg-layer-2);\n align-items: center;\n gap: 8px;\n margin-bottom: 6px;\n padding: 4px 8px;\n font-size: 12px;\n display: flex;\n}\n\n.dshc_replyBarText {\n white-space: nowrap;\n text-overflow: ellipsis;\n flex: 1;\n min-width: 0;\n overflow: hidden;\n}\n\n.dshc_replyCancel {\n color: inherit;\n cursor: pointer;\n background: none;\n border: 0;\n flex: none;\n}\n\n.dshc_working {\n min-height: 20px;\n color: var(--dsw-alias-label-tertiary);\n align-items: center;\n gap: 6px;\n padding: 0 16px;\n font-size: 12px;\n display: flex;\n}\n\n.dshc_composer {\n padding: 0 16px 16px;\n position: relative;\n}\n\n.dshc_composerBox {\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-xl);\n background: var(--dsw-alias-bg-layer-1, var(--dsw-alias-bg-layer-2));\n box-shadow: var(--dsw-shadow-lv1-blur);\n flex-direction: column;\n display: flex;\n overflow: hidden;\n}\n\n.dshc_composerBox:focus-within {\n border-color: var(--dsw-alias-label-tertiary);\n}\n\n.dshc_composerToolbar {\n flex: none;\n align-items: center;\n gap: 4px;\n padding: 4px 10px 10px;\n display: flex;\n}\n\n.dshc_composerBox > .dshc_replyBar, .dshc_composerBox > .dshc_attachments {\n margin: 10px 14px 0;\n}\n\n.dshc_mentionButton {\n border-radius: var(--dsw-radius-full, 50%);\n width: 32px;\n height: 32px;\n color: var(--dsw-alias-label-secondary);\n font: inherit;\n cursor: pointer;\n background: none;\n border: 0;\n flex: none;\n justify-content: center;\n align-items: center;\n padding: 0;\n font-size: 18px;\n display: inline-flex;\n}\n\n.dshc_mentionButton:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_sendButton {\n border-radius: var(--dsw-radius-full, 50%);\n width: 32px;\n height: 32px;\n color: var(--dsw-alias-label-primary-inverted);\n background: var(--dsw-alias-label-primary);\n font: inherit;\n cursor: pointer;\n border: 0;\n flex: none;\n justify-content: center;\n align-items: center;\n margin-left: auto;\n padding: 0;\n display: inline-flex;\n}\n\n.dshc_sendButton:disabled {\n opacity: .45;\n cursor: default;\n}\n\n.dshc_sendButton:focus-visible, .dshc_mentionButton:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_mentionPopup {\n z-index: 2;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-base);\n max-height: 320px;\n box-shadow: var(--dsw-elevation-panel, 0 8px 24px #0000003d);\n flex-direction: column;\n padding: 6px;\n display: flex;\n position: absolute;\n bottom: calc(100% - 8px);\n left: 16px;\n right: 16px;\n}\n\n.dshc_mentionPopup > [role=\"listbox\"] {\n min-height: 0;\n overflow-y: auto;\n}\n\n.dshc_mentionTitle {\n color: var(--dsw-alias-label-tertiary);\n padding: 4px 8px 6px;\n font-size: 12px;\n font-weight: 600;\n}\n\n.dshc_mentionItem {\n border-radius: var(--dsw-radius-sm);\n cursor: pointer;\n align-items: center;\n gap: 10px;\n padding: 6px 8px;\n display: flex;\n}\n\n.dshc_mentionActive {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_mentionName {\n font-weight: 600;\n}\n\n.dshc_mentionMeta {\n color: var(--dsw-alias-label-tertiary);\n margin-left: auto;\n font-size: 12px;\n}\n\n.dshc_mentionHint {\n border-top: 1px solid var(--dsw-alias-border-l2);\n color: var(--dsw-alias-label-tertiary);\n padding: 6px 8px 2px;\n font-size: 11px;\n}\n\n.dshc_mentionBadge {\n background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #5865f2) 15%, transparent);\n color: var(--dsw-alias-state-business-primary, #5865f2);\n font-weight: 500;\n line-height: inherit;\n vertical-align: baseline;\n -webkit-box-decoration-break: clone;\n box-decoration-break: clone;\n cursor: pointer;\n border-radius: 3px;\n padding: 0 4px;\n transition: background-color .16s cubic-bezier(.2, 0, 0, 1), color .16s cubic-bezier(.2, 0, 0, 1);\n display: inline-block;\n}\n\n.dshc_mentionBadge:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #5865f2) 28%, transparent);\n}\n\n.dshc_sendError {\n color: var(--dsw-alias-state-error-primary);\n margin-bottom: 6px;\n font-size: 12px;\n}\n\n.dshc_input {\n box-sizing: border-box;\n width: 100%;\n min-height: 52px;\n max-height: 40vh;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n resize: none;\n field-sizing: content;\n background: none;\n border: 0;\n border-radius: 0;\n flex: 1;\n min-width: 0;\n padding: 14px 16px 8px;\n line-height: 1.5;\n}\n\n.dshc_input::placeholder {\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n}\n\n@media (width <= 600px) {\n .dshc_composer {\n padding: 0 8px 8px;\n }\n\n .dshc_composerToolbar {\n padding: 4px 8px 8px;\n }\n\n .dshc_input {\n padding: 12px 14px 8px;\n }\n}\n\n.dshc_input:focus-visible {\n outline: none;\n}\n\n.dshc_member {\n border-radius: var(--dsw-radius-sm);\n min-width: 0;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border: 0;\n flex: 1;\n align-items: center;\n gap: 10px;\n padding: 5px 8px;\n display: flex;\n}\n\n.dshc_member:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_member:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_offline {\n opacity: .5;\n}\n\n.dshc_memberAvatar {\n position: relative;\n}\n\n.dshc_presence {\n border: 2px solid var(--dsw-alias-bg-layer-2);\n corner-shape: round;\n background: #23a55a;\n border-radius: 50%;\n width: 10px;\n height: 10px;\n position: absolute;\n bottom: -2px;\n right: -2px;\n}\n\n.dshc_offline .dshc_presence {\n background: var(--dsw-alias-label-tertiary);\n}\n\n.dshc_memberText {\n flex-direction: column;\n min-width: 0;\n display: flex;\n}\n\n.dshc_memberName {\n align-items: center;\n gap: 6px;\n display: flex;\n}\n\n.dshc_memberStatus {\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n}\n\n@media (width <= 900px) {\n .dshc_page {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .dshc_rooms, .dshc_members {\n display: none;\n }\n}\n\n.dshc_groupHead {\n justify-content: space-between;\n align-items: center;\n padding-right: 4px;\n display: flex;\n}\n\n.dshc_iconButton {\n border-radius: var(--dsw-radius-sm);\n width: 22px;\n height: 22px;\n color: var(--dsw-alias-label-tertiary);\n font: inherit;\n cursor: pointer;\n background: none;\n border: 0;\n font-size: 16px;\n line-height: 1;\n}\n\n.dshc_iconButton:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_roomInput, .dshc_fieldInput {\n box-sizing: border-box;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm);\n width: 100%;\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-base);\n font: inherit;\n padding: 6px 8px;\n}\n\n.dshc_roomInput {\n margin: 2px 0 6px;\n}\n\n.dshc_roomInput:focus-visible, .dshc_fieldInput:focus-visible, .dshc_iconButton:focus-visible, .dshc_linkButton:focus-visible, .dshc_addMemberButton:focus-visible, .dshc_primaryButton:focus-visible, .dshc_secondaryButton:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_addMemberButton {\n box-sizing: border-box;\n border: 1px dashed var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm);\n width: 100%;\n color: var(--dsw-alias-label-secondary);\n font: inherit;\n cursor: pointer;\n background: none;\n margin: 4px 0;\n padding: 7px 8px;\n}\n\n.dshc_addMemberButton:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_settingsDivider {\n border: 0;\n border-top: 1px solid var(--dsw-alias-border-l1);\n width: 100%;\n margin: 8px 0 4px;\n}\n\n.dshc_memberListDivider {\n border: 0;\n border-top: 1px solid var(--dsw-alias-border-l1);\n width: calc(100% - 16px);\n margin: 12px 8px 2px;\n}\n\n.dshc_settingsButton {\n text-align: left;\n border-style: solid;\n border-color: #0000;\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.dshc_settingsButton svg {\n flex: none;\n}\n\n.dshc_memberRow {\n border-radius: var(--dsw-radius-sm);\n align-items: center;\n display: flex;\n position: relative;\n}\n\n.dshc_memberRow:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_memberRow .dshc_member:hover {\n background: none;\n}\n\n.dshc_memberModel {\n color: var(--dsw-alias-label-tertiary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 11px;\n overflow: hidden;\n}\n\n.dshc_memberActions {\n color: var(--dsw-alias-label-tertiary);\n opacity: 0;\n flex: none;\n gap: 4px;\n padding-right: 6px;\n font-size: 12px;\n display: flex;\n}\n\n.dshc_memberRow:hover .dshc_memberActions, .dshc_memberRow:focus-within .dshc_memberActions {\n opacity: 1;\n}\n\n.dshc_linkButton {\n border-radius: var(--dsw-radius-xs);\n color: var(--dsw-alias-label-secondary);\n font: inherit;\n cursor: pointer;\n background: none;\n border: 0;\n padding: 2px 4px;\n font-size: 12px;\n}\n\n.dshc_linkButton:hover {\n color: var(--dsw-alias-label-primary);\n text-decoration: underline;\n}\n\n.dshc_dialogBackdrop {\n z-index: 10;\n background: #00000073;\n place-items: center;\n padding: 16px;\n display: grid;\n position: fixed;\n inset: 0;\n}\n\n.dshc_dialog {\n box-sizing: border-box;\n border-radius: var(--dsw-radius-lg);\n width: min(460px, 100%);\n max-height: calc(100vh - 32px);\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-base);\n box-shadow: var(--dsw-elevation-panel, 0 12px 32px #0000004d);\n flex-direction: column;\n gap: 12px;\n padding: 20px;\n display: flex;\n overflow-y: auto;\n}\n\n.dshc_settingsDialog {\n box-sizing: border-box;\n height: min(70vh, 100dvh - 32px);\n max-height: calc(100dvh - 32px);\n overflow: hidden;\n}\n\n.dshc_settingsBody {\n overscroll-behavior: contain;\n flex: auto;\n min-height: 0;\n padding: 2px;\n overflow-y: auto;\n}\n\n.dshc_settingsDialog > :not(.dshc_settingsBody) {\n flex-shrink: 0;\n}\n\n.dshc_settingsFields {\n flex-direction: column;\n gap: 12px;\n display: flex;\n}\n\n.dshc_settingsFeedback {\n overflow-wrap: anywhere;\n max-height: 20%;\n overflow-y: auto;\n}\n\n.dshc_settingsDialog .dshc_dialogActions {\n justify-content: space-between;\n}\n\n@media (width <= 599px) {\n .dshc_settingsDialog {\n height: calc(100dvh - 32px);\n padding: 16px;\n }\n}\n\n.dshc_avatarCropStage {\n background: #000000a6;\n padding: 20px;\n}\n\n.dshc_avatarCropFrame {\n aspect-ratio: 1;\n touch-action: none;\n cursor: grab;\n outline: 2px solid #fff;\n width: min(256px, 100%);\n margin: auto;\n position: relative;\n overflow: hidden;\n}\n\n.dshc_avatarCropFrame:active {\n cursor: grabbing;\n}\n\n.dshc_avatarCropFrame img {\n pointer-events: none;\n user-select: none;\n max-width: none;\n position: absolute;\n}\n\n.dshc_dialogTitle {\n margin: 0;\n font-size: 16px;\n}\n\n.dshc_field {\n color: var(--dsw-alias-label-secondary);\n flex-direction: column;\n gap: 4px;\n font-size: 12px;\n display: flex;\n}\n\n.dshc_field textarea {\n resize: vertical;\n}\n\n.dshc_choiceRow {\n flex-wrap: wrap;\n gap: 12px;\n display: flex;\n}\n\n.dshc_choiceColumn {\n flex-direction: column;\n gap: 12px;\n display: flex;\n}\n\n.dshc_choiceColumn .dshc_choice {\n grid-template-columns: max-content minmax(0, 1fr);\n align-items: start;\n display: grid;\n}\n\n.dshc_choice {\n color: var(--dsw-alias-label-primary, inherit);\n cursor: pointer;\n align-items: center;\n gap: 4px;\n font-size: 13px;\n display: inline-flex;\n}\n\n.dshc_dialogActions {\n justify-content: flex-end;\n gap: 8px;\n display: flex;\n}\n\n.dshc_primaryButton, .dshc_secondaryButton {\n border-radius: var(--dsw-radius-sm);\n font: inherit;\n cursor: pointer;\n padding: 7px 14px;\n}\n\n.dshc_primaryButton {\n color: #fff;\n background: var(--dsw-alias-state-business-primary);\n border: 0;\n}\n\n.dshc_primaryButton:disabled {\n cursor: not-allowed;\n opacity: .5;\n}\n\n.dshc_secondaryButton {\n border: 1px solid var(--dsw-alias-border-l2);\n color: var(--dsw-alias-label-primary);\n background: none;\n}\n\n.dshc_memberFailed .dshc_memberStatus {\n color: var(--dsw-alias-state-error-primary, #ed4245);\n}\n\n.dshc_memberFailed .dshc_presence {\n background: #ed4245;\n}\n\n.dshc_mobileButton, .dshc_drawerBackdrop {\n display: none;\n}\n\n.dshc_panelToggle {\n border-radius: var(--dsw-radius-sm);\n width: 28px;\n height: 28px;\n color: var(--dsw-alias-label-tertiary);\n font: inherit;\n cursor: pointer;\n background: none;\n border: 0;\n justify-content: center;\n align-items: center;\n font-size: 16px;\n line-height: 1;\n display: inline-flex;\n}\n\n.dshc_panelToggle:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_panelToggle:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_panelToggleEnd {\n margin-left: auto;\n}\n\n.dshc_capabilityMenu {\n z-index: 4;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-base);\n max-height: 260px;\n box-shadow: var(--dsw-elevation-panel, 0 8px 24px #0000003d);\n gap: 2px;\n padding: 5px;\n display: grid;\n position: absolute;\n bottom: calc(100% + 4px);\n left: 0;\n right: 0;\n overflow-y: auto;\n}\n\n.dshc_capabilityItem:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_capabilityHelp {\n color: var(--dsw-alias-label-secondary);\n white-space: normal;\n margin: 6px;\n font-size: 12px;\n}\n\n.dshc_capabilityItem:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_capabilityItem {\n text-align: left;\n cursor: pointer;\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n background: none;\n border: 0;\n padding: 5px 8px;\n font-size: 12px;\n font-weight: 400;\n}\n\n@media (width >= 901px) {\n .dshc_page.dshc_roomsHidden {\n grid-template-columns: minmax(0, 1fr) 240px;\n }\n\n .dshc_page.dshc_membersHidden {\n grid-template-columns: 220px minmax(0, 1fr);\n }\n\n .dshc_page.dshc_roomsHidden.dshc_membersHidden {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .dshc_roomsHidden > .dshc_rooms, .dshc_membersHidden > .dshc_members {\n display: none;\n }\n}\n\n@media (width <= 900px) {\n .dshc_page {\n position: relative;\n overflow: hidden;\n }\n\n .dshc_mobileButton {\n min-width: 40px;\n min-height: 40px;\n color: inherit;\n font: inherit;\n cursor: pointer;\n background: none;\n border: 0;\n border-radius: 6px;\n justify-content: center;\n align-items: center;\n display: inline-flex;\n }\n\n .dshc_mobileButton:last-child {\n margin-left: auto;\n }\n\n .dshc_panelToggle {\n display: none;\n }\n\n .dshc_drawerBackdrop {\n z-index: 4;\n background: #00000073;\n border: 0;\n display: block;\n position: absolute;\n inset: 0;\n }\n\n .dshc_rooms.dshc_drawerOpen, .dshc_members.dshc_drawerOpen {\n z-index: 5;\n box-sizing: border-box;\n width: min(280px, 85%);\n display: block;\n position: absolute;\n top: 0;\n bottom: 0;\n box-shadow: 0 0 24px #0000004d;\n }\n\n .dshc_rooms.dshc_drawerOpen {\n left: 0;\n }\n\n .dshc_members.dshc_drawerOpen {\n right: 0;\n }\n\n .dshc_memberActions {\n opacity: 1;\n }\n\n .dshc_messageHead {\n flex-wrap: wrap;\n }\n}\n\n.dshc_avatarPicker {\n flex-wrap: wrap;\n gap: 8px;\n display: flex;\n}\n\n.dshc_avatarOption {\n cursor: pointer;\n background: none;\n border: 2px solid #0000;\n border-radius: 50%;\n padding: 2px;\n display: grid;\n}\n\n.dshc_avatarOption[aria-checked=\"true\"] {\n border-color: var(--dsw-alias-accent, #5865f2);\n}\n\n.dshc_taskBoardTrigger {\n box-sizing: border-box;\n border-radius: var(--dsw-radius-sm);\n width: 100%;\n height: 34px;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border: 0;\n flex: none;\n align-items: center;\n gap: 8px;\n margin: 4px 0;\n padding: 7px 8px;\n font-size: 12px;\n display: flex;\n}\n\n.dshc_taskBoardTrigger:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_taskBoardTrigger:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_taskBoardSummary {\n color: var(--dsw-alias-label-secondary);\n text-align: right;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n overflow: hidden;\n}\n\n.dshc_taskBoardDialog {\n width: min(920px, 100%);\n height: min(70vh, 100dvh - 32px);\n overflow: hidden;\n}\n\n.dshc_taskBoardBody {\n overscroll-behavior: contain;\n flex: auto;\n min-height: 0;\n overflow-y: auto;\n}\n\n.dshc_taskBoardDialog > :not(.dshc_taskBoardBody) {\n flex-shrink: 0;\n}\n\n.dshc_boardTabs {\n border-bottom: 1px solid var(--dsw-alias-border-l2);\n gap: 4px;\n padding-bottom: 8px;\n display: flex;\n overflow-x: auto;\n}\n\n.dshc_boardTabs button {\n border-radius: var(--dsw-radius-sm);\n color: var(--dsw-alias-label-secondary);\n font: inherit;\n cursor: pointer;\n background: none;\n border: 0;\n flex: none;\n padding: 7px 10px;\n font-size: 13px;\n}\n\n.dshc_boardTabs button:hover, .dshc_boardTabs button[aria-selected=\"true\"] {\n color: var(--dsw-alias-state-business-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_boardTabs button:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n outline-offset: -2px;\n}\n\n.dshc_boardTabCount {\n font-variant-numeric: tabular-nums;\n margin-left: 4px;\n}\n\n.dshc_boardCardGrid {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 12px;\n margin: 6px 0 16px;\n padding: 2px;\n list-style: none;\n display: grid;\n}\n\n.dshc_boardTaskCard {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-base);\n border-radius: 12px;\n flex-direction: column;\n gap: 10px;\n min-width: 0;\n padding: 14px;\n transition: transform .14s, box-shadow .14s;\n display: flex;\n}\n\n.dshc_boardTaskCard[data-working=\"true\"] {\n border-color: var(--dsw-alias-state-business-primary);\n}\n\n.dshc_boardTaskCard[data-status=\"done\"] {\n filter: saturate(.25);\n color: var(--dsw-alias-label-secondary);\n}\n\n.dshc_boardTaskCard:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 12px #00000014;\n}\n\n.dshc_boardTaskHeader {\n align-items: flex-start;\n gap: 8px;\n display: flex;\n}\n\n.dshc_boardTaskTitle {\n overflow-wrap: anywhere;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n flex: 1;\n font-size: 14px;\n font-weight: 600;\n line-height: 1.5;\n display: -webkit-box;\n overflow: hidden;\n}\n\n.dshc_boardTaskHeader .dshc_taskStatus {\n border-radius: 999px;\n padding: 3px 7px;\n font-size: 11px;\n}\n\n.dshc_boardTaskCard .dshc_taskLinks {\n justify-content: flex-end;\n margin-top: auto;\n}\n\n.dshc_boardTabEmpty {\n min-height: 240px;\n color: var(--dsw-alias-label-secondary);\n text-align: center;\n justify-content: center;\n align-items: center;\n padding: 40px 16px;\n display: flex;\n}\n\n@media (width <= 640px) {\n .dshc_boardCardGrid {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dshc_boardTaskCard {\n transition: none;\n }\n\n .dshc_boardTaskCard:hover {\n transform: none;\n }\n}\n\n.dshc_taskBoardScope {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n\n.dshc_taskSection + .dshc_taskSection {\n margin-top: 8px;\n}\n\n.dshc_taskSectionTitle {\n color: var(--dsw-alias-label-secondary);\n margin: 0 0 4px;\n padding: 0 8px;\n font-size: 12px;\n font-weight: 600;\n}\n\n.dshc_taskOwnerGroup + .dshc_taskOwnerGroup {\n margin-top: 4px;\n}\n\n.dshc_taskOwnerName {\n color: var(--dsw-alias-label-tertiary);\n padding: 0 8px;\n font-size: 12px;\n}\n\n.dshc_taskList {\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.dshc_taskRow {\n border-radius: var(--dsw-radius-sm);\n padding: 6px 8px;\n}\n\n.dshc_taskRow:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_taskLine {\n align-items: center;\n gap: 6px;\n min-width: 0;\n display: flex;\n}\n\n.dshc_taskTitle {\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 13px;\n overflow: hidden;\n}\n\n.dshc_taskMeta {\n color: var(--dsw-alias-label-tertiary);\n flex-wrap: wrap;\n gap: 0 8px;\n font-size: 12px;\n display: flex;\n}\n\n.dshc_taskLinks {\n gap: 8px;\n display: flex;\n}\n\n.dshc_taskEmpty {\n color: var(--dsw-alias-label-tertiary);\n margin: 0 8px;\n font-size: 12px;\n}\n\n.dshc_taskDone summary {\n cursor: pointer;\n}\n\n.dshc_taskStatus {\n border-radius: var(--dsw-radius-xs);\n color: var(--dsw-alias-label-primary-inverted);\n background: var(--dsw-alias-state-business-primary);\n flex: none;\n padding: 0 4px;\n font-size: 10px;\n font-style: normal;\n font-weight: 600;\n}\n\n.dshc_taskStatus[data-status=\"asked\"], .dshc_taskStatus[data-status=\"escalated\"], .dshc_taskStatus[data-status=\"declined\"], .dshc_taskStatus[data-status=\"rework\"] {\n background: var(--dsw-alias-state-warning-primary, var(--dsw-alias-state-error-primary));\n}\n\n.dshc_taskStatus[data-status=\"done\"] {\n background: var(--dsw-alias-label-tertiary);\n}\n\n.dshc_taskCard {\n margin-top: 4px;\n font-style: normal;\n}\n\n.dshc_taskMembers {\n margin: 4px 0 0;\n padding: 0;\n list-style: none;\n}\n\n.dshc_taskMember {\n align-items: center;\n gap: 8px;\n font-size: 13px;\n display: flex;\n}\n\n.dshc_taskMemberName {\n font-weight: 600;\n}\n\n.dshc_taskSub {\n color: var(--dsw-alias-label-secondary);\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.dshc_focused {\n background: var(--dsw-alias-interactive-bg-hover);\n outline: 2px solid var(--dsw-alias-state-business-primary);\n}\n\n.dshc_attachments {\n flex-wrap: wrap;\n gap: 6px;\n margin: 4px 0;\n display: flex;\n}\n\n.dshc_attachmentImage {\n border-radius: 4px;\n max-width: min(320px, 100%);\n max-height: 240px;\n display: block;\n}\n\n.dshc_imageAttachment {\n align-content: start;\n max-width: 100%;\n display: grid;\n}\n\n.dshc_imagePreviewTrigger {\n cursor: zoom-in;\n background: none;\n border: 0;\n border-radius: 4px;\n grid-area: 1 / 1;\n padding: 0;\n}\n\n.dshc_imagePreviewTrigger:focus-visible {\n outline: 2px solid var(--dsw-alias-state-business-primary);\n outline-offset: 2px;\n}\n\n.dshc_imagePreviewDialog {\n box-sizing: border-box;\n width: fit-content;\n max-width: 90vw;\n max-height: 90dvh;\n overflow: auto;\n}\n\n.dshc_imagePreviewHeader {\n flex-shrink: 0;\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n display: flex;\n}\n\n.dshc_imagePreviewHeader span {\n overflow-wrap: anywhere;\n min-width: 0;\n}\n\n.dshc_imagePreviewHeader button {\n flex-shrink: 0;\n}\n\n.dshc_imagePreviewImage {\n object-fit: contain;\n align-self: center;\n max-width: 100%;\n min-height: 0;\n max-height: 65dvh;\n display: block;\n}\n\n.dshc_imagePreviewActions {\n flex-wrap: wrap;\n flex-shrink: 0;\n gap: 8px;\n display: flex;\n}\n\n.dshc_imagePreviewActions a {\n text-decoration: none;\n}\n\n.dshc_imagePreviewActions button:disabled {\n cursor: wait;\n opacity: .5;\n}\n\n.dshc_attachmentActions {\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-base);\n opacity: 0;\n pointer-events: none;\n flex-wrap: wrap;\n grid-area: 1 / 1;\n place-self: start end;\n gap: 4px;\n margin: 4px;\n padding: 4px;\n display: flex;\n}\n\n.dshc_attachmentActions a {\n text-decoration: none;\n}\n\n.dshc_attachmentActions button:disabled {\n cursor: wait;\n opacity: .5;\n}\n\n.dshc_imageAttachment:hover .dshc_attachmentActions, .dshc_imageAttachment:focus-within .dshc_attachmentActions, .dshc_imageAttachment[data-copy-state=\"error\"] .dshc_attachmentActions, .dshc_imageAttachment[data-copy-state=\"copying\"] .dshc_attachmentActions, .dshc_imageAttachment[data-copy-state=\"copied\"] .dshc_attachmentActions {\n opacity: 1;\n pointer-events: auto;\n}\n\n@media (hover: none), (pointer: coarse), (width <= 768px) {\n .dshc_attachmentActions {\n opacity: 1;\n pointer-events: auto;\n }\n}\n\n.dshc_attachmentThumb {\n object-fit: cover;\n vertical-align: middle;\n border-radius: 3px;\n width: 32px;\n height: 32px;\n}\n\n.dshc_attachmentFile {\n background: var(--background-secondary, #7f7f7f26);\n color: inherit;\n border-radius: 4px;\n align-items: center;\n gap: 4px;\n padding: 4px 8px;\n text-decoration: none;\n display: inline-flex;\n}\n\n.dshc_attachmentSize {\n opacity: .6;\n font-size: .85em;\n}\n\n.dshc_attachmentAudio {\n flex-direction: column;\n gap: 2px;\n width: min(320px, 100%);\n display: flex;\n}\n\n.dshc_attachmentAudio audio {\n width: 100%;\n}\n\n.dshc_attachmentAudio a {\n color: inherit;\n text-decoration: none;\n}\n\n.dshc_attachmentFile {\n overflow-wrap: anywhere;\n max-width: 100%;\n}\n\n.dshc_chatHead button, .dshc_chatHead input, .dshc_chatHead select, .dshc_chatHead a, .dshc_chatHead [role=\"menu\"] {\n -webkit-app-region: no-drag;\n}\n\n.dshc_text pre, .dshc_text table {\n max-width: 100%;\n overflow-x: auto;\n}\n\n@media (width >= 901px) {\n .dshc_page {\n grid-template-columns: 232px minmax(0, 1fr) 272px;\n }\n\n .dshc_page.dshc_roomsHidden {\n grid-template-columns: minmax(0, 1fr) 272px;\n }\n\n .dshc_page.dshc_membersHidden {\n grid-template-columns: 232px minmax(0, 1fr);\n }\n\n .dshc_page.dshc_roomsHidden.dshc_membersHidden {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n.dshc_rooms {\n padding-top: 4px;\n}\n\n.dshc_room {\n border-radius: var(--dsw-radius-md);\n min-height: 34px;\n padding: 6px 10px;\n transition: background-color .15s, color .15s;\n}\n\n.dshc_workspace {\n min-height: 30px;\n padding-left: 28px;\n font-size: 13px;\n position: relative;\n}\n\n.dshc_workspace:before {\n content: \"\";\n border-left: 1px solid var(--dsw-alias-border-l2);\n border-bottom: 1px solid var(--dsw-alias-border-l2);\n border-bottom-left-radius: 4px;\n width: 7px;\n position: absolute;\n top: 0;\n bottom: 50%;\n left: 15px;\n}\n\n.dshc_workspace .dshc_hash {\n display: none;\n}\n\n.dshc_roomActive {\n color: var(--dsw-alias-label-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-business-primary) 14%, transparent);\n box-shadow: inset 2px 0 0 var(--dsw-alias-state-business-primary);\n font-weight: 600;\n}\n\n.dshc_activeCount {\n font-variant-numeric: tabular-nums;\n border-radius: 999px;\n margin-left: 0;\n padding: 0 6px;\n font-size: 11px;\n line-height: 18px;\n}\n\n.dshc_activeBusy {\n color: var(--dsw-alias-state-business-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-business-primary) 14%, transparent);\n}\n\n.dshc_roomLabel {\n flex: auto;\n min-width: 0;\n}\n\n.dshc_avatarStack {\n flex: none;\n align-items: center;\n padding-left: 4px;\n display: inline-flex;\n}\n\n.dshc_stackDot {\n border: 2px solid var(--dsw-alias-bg-layer-2);\n background-position: center;\n background-size: cover;\n border-radius: 50%;\n width: 18px;\n height: 18px;\n margin-left: -6px;\n}\n\n.dshc_room .dshc_stackDot {\n width: 16px;\n height: 16px;\n}\n\n.dshc_roomActive .dshc_stackDot {\n border-color: color-mix(in srgb, var(--dsw-alias-state-business-primary) 14%, var(--dsw-alias-bg-layer-2));\n}\n\n.dshc_chatHead {\n gap: 8px;\n height: 52px;\n}\n\n.dshc_roomName {\n letter-spacing: -.01em;\n white-space: nowrap;\n font-size: 15px;\n}\n\n.dshc_headMeta {\n color: var(--dsw-alias-label-tertiary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n font-weight: 400;\n overflow: hidden;\n}\n\n.dshc_headActivity {\n color: var(--dsw-alias-label-secondary);\n flex: none;\n align-items: center;\n gap: 6px;\n margin-left: auto;\n font-size: 12px;\n font-weight: 500;\n display: inline-flex;\n}\n\n.dshc_headActivity .dshc_stackDot {\n border-color: var(--dsw-alias-bg-base);\n width: 22px;\n height: 22px;\n}\n\n.dshc_headActivity + .dshc_panelToggleEnd {\n margin-left: 4px;\n}\n\n.dshc_chatHead > .dshc_roomName {\n text-overflow: ellipsis;\n min-width: 0;\n overflow: hidden;\n}\n\n.dshc_chatHead > .dshc_taskBoardTrigger {\n width: auto;\n margin: 0 0 0 auto;\n}\n\n.dshc_chatHead .dshc_taskBoardSummary {\n display: none;\n}\n\n.dshc_headLead {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n border-radius: 999px;\n flex: 0 auto;\n align-items: center;\n gap: 6px;\n min-width: 0;\n padding: 4px 8px;\n font-size: 12px;\n display: inline-flex;\n}\n\n.dshc_headLeadText {\n flex-direction: column;\n min-width: 0;\n display: flex;\n}\n\n.dshc_headLeadName {\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.dshc_headLeadStatus {\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n font-size: 11px;\n font-weight: 400;\n}\n\n.dshc_headLead + .dshc_panelToggleEnd {\n margin-left: 0;\n}\n\n.dshc_membersHead {\n align-items: center;\n height: 52px;\n padding: 0 4px;\n display: flex;\n}\n\n.dshc_membersHeadTitle {\n color: var(--dsw-alias-label-tertiary);\n letter-spacing: .08em;\n font-size: 11px;\n font-weight: 650;\n}\n\n.dshc_log {\n padding: 12px 0 16px;\n}\n\n.dshc_message {\n grid-template-columns: 36px minmax(0, 1fr);\n gap: 12px;\n padding: 8px 20px 2px;\n transition: background-color .15s;\n}\n\n.dshc_message.dshc_grouped {\n padding-top: 1px;\n}\n\n.dshc_message:hover {\n background: color-mix(in srgb, var(--dsw-alias-interactive-bg-hover) 70%, transparent);\n}\n\n.dshc_messageHead {\n gap: 8px;\n margin-bottom: 2px;\n}\n\n.dshc_messageHeadGrouped {\n margin-bottom: 0;\n}\n\n.dshc_messageHeadGrouped:not(:has(*)) {\n display: none;\n}\n\n.dshc_author {\n font-size: 13px;\n}\n\n.dshc_time, .dshc_edited {\n font-variant-numeric: tabular-nums;\n font-size: 11px;\n}\n\n.dshc_gutterTime {\n color: var(--dsw-alias-label-tertiary);\n font-variant-numeric: tabular-nums;\n text-align: right;\n opacity: 0;\n align-self: start;\n padding-top: 3px;\n font-size: 10px;\n transition: opacity .15s;\n}\n\n.dshc_message:hover .dshc_gutterTime {\n opacity: 1;\n}\n\n.dshc_text {\n line-height: 1.6;\n}\n\n.dshc_own {\n grid-template-columns: minmax(0, 1fr) 36px;\n}\n\n.dshc_own > :first-child {\n grid-area: 1 / 2;\n}\n\n.dshc_own > .dshc_messageBody {\n flex-direction: column;\n grid-area: 1 / 1;\n align-items: flex-end;\n display: flex;\n}\n\n.dshc_own .dshc_messageHead {\n flex-direction: row-reverse;\n}\n\n.dshc_own .dshc_ownActions {\n margin-left: 0;\n margin-right: auto;\n}\n\n.dshc_own > .dshc_messageBody > .dshc_text {\n max-width: min(560px, 100%);\n color: var(--dsw-alias-label-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-business-primary) 16%, var(--dsw-alias-bg-layer-2));\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--dsw-alias-state-business-primary) 28%, transparent);\n border-radius: 16px 6px 16px 16px;\n padding: 8px 14px;\n}\n\n.dshc_own > .dshc_messageBody > .dshc_quote {\n align-self: flex-end;\n}\n\n.dshc_own .dshc_msgTools {\n left: 16px;\n right: auto;\n}\n\n.dshc_own.dshc_grouped > .dshc_messageBody > .dshc_text {\n border-radius: 16px 6px 6px 16px;\n}\n\n.dshc_systemRecord {\n flex-direction: column;\n align-items: center;\n padding-bottom: 4px;\n display: flex;\n}\n\n.dshc_systemRecord > .dshc_systemLine {\n align-self: stretch;\n}\n\n.dshc_taskRecord {\n box-sizing: border-box;\n width: min(480px, 100% - 40px);\n margin-top: 0;\n}\n\n.dshc_systemLine {\n color: var(--dsw-alias-label-tertiary);\n align-items: center;\n gap: 12px;\n padding: 10px 32px;\n font-size: 12px;\n display: flex;\n}\n\n.dshc_systemLine:before, .dshc_systemLine:after {\n content: \"\";\n background: var(--dsw-alias-border-l2);\n flex: 24px;\n min-width: 24px;\n height: 1px;\n}\n\n.dshc_systemText {\n text-align: center;\n max-width: min(640px, 80%);\n}\n\n.dshc_systemText p {\n margin: 0;\n}\n\n.dshc_errorBar {\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 35%, transparent);\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 9%, transparent);\n border-radius: 12px;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px 10px;\n margin: 6px 20px 6px 68px;\n padding: 8px 12px;\n font-size: 13px;\n display: flex;\n}\n\n.dshc_errorBar .dshc_cardButtons {\n margin: 0 0 0 auto;\n}\n\n.dshc_errorBar .dshc_secondaryButton {\n padding: 3px 10px;\n font-size: 12px;\n}\n\n.dshc_errorBar[data-state=\"retried\"] {\n opacity: .65;\n}\n\n.dshc_errorIcon {\n color: #fff;\n background: var(--dsw-alias-state-error-primary);\n border-radius: 50%;\n flex: none;\n place-items: center;\n width: 18px;\n height: 18px;\n font-size: 12px;\n font-weight: 700;\n display: grid;\n}\n\n.dshc_errorText {\n min-width: 0;\n color: var(--dsw-alias-label-primary);\n flex: 200px;\n}\n\n.dshc_errorText p {\n margin: 0;\n}\n\n.dshc_runStrip {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1, var(--dsw-alias-bg-layer-2));\n border-radius: 12px;\n flex-direction: column;\n max-width: 100%;\n margin-top: 4px;\n padding: 5px 10px;\n font-size: 12px;\n display: inline-flex;\n}\n\n.dshc_runStrip[data-state=\"running\"] {\n border-color: color-mix(in srgb, var(--dsw-alias-state-business-primary) 45%, var(--dsw-alias-border-l2));\n}\n\n.dshc_runStrip[data-state=\"failed\"] {\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, var(--dsw-alias-border-l2));\n}\n\n.dshc_runHead {\n min-width: 0;\n color: var(--dsw-alias-label-secondary);\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.dshc_runTitle {\n color: var(--dsw-alias-label-primary);\n flex: none;\n font-weight: 600;\n}\n\n.dshc_runSummary {\n font-variant-numeric: tabular-nums;\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.dshc_runHead .dshc_cardViews {\n margin-left: 8px;\n}\n\n.dshc_runHead .dshc_cardViewButton {\n color: var(--dsw-alias-label-tertiary);\n border-radius: 999px;\n font-size: 11px;\n}\n\n.dshc_runHead .dshc_cardViewButton[aria-pressed=\"true\"] {\n color: var(--dsw-alias-label-primary);\n}\n\n.dshc_runIcon {\n border-radius: 50%;\n flex: none;\n width: 12px;\n height: 12px;\n position: relative;\n}\n\n.dshc_runStrip[data-state=\"running\"] .dshc_runIcon {\n border: 2px solid color-mix(in srgb, var(--dsw-alias-state-business-primary) 25%, transparent);\n border-top-color: var(--dsw-alias-state-business-primary);\n animation: .8s linear infinite dshc_channels-spin;\n}\n\n.dshc_runStrip[data-state=\"completed\"] .dshc_runIcon {\n background: #23a55a;\n}\n\n.dshc_runStrip[data-state=\"completed\"] .dshc_runIcon:after {\n content: \"\";\n border: 1.5px solid #fff;\n border-width: 0 1.5px 1.5px 0;\n width: 3px;\n height: 6px;\n position: absolute;\n top: 2px;\n left: 4px;\n transform: rotate(45deg);\n}\n\n.dshc_runStrip[data-state=\"failed\"] .dshc_runIcon {\n background: var(--dsw-alias-state-error-primary);\n}\n\n.dshc_runSteps {\n color: var(--dsw-alias-label-secondary);\n margin-top: 4px;\n font-size: 12px;\n line-height: 1.55;\n}\n\n.dshc_runSteps p {\n margin: 0;\n}\n\n.dshc_runStrip .dshc_cardButtons {\n margin-top: 6px;\n}\n\n@keyframes dshc_channels-spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dshc_runStrip[data-state=\"running\"] .dshc_runIcon {\n animation-duration: 2.4s;\n }\n}\n\n.dshc_card {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n border-left-width: 1px;\n border-radius: 14px;\n margin-top: 6px;\n padding: 10px 12px;\n}\n\n.dshc_card[data-state=\"failed\"] {\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 40%, var(--dsw-alias-border-l2));\n}\n\n.dshc_taskAnchor {\n max-width: 560px;\n box-shadow: inset 3px 0 0 var(--channels-accent-warm, #d08a2e);\n}\n\n.dshc_permInline {\n color: var(--dsw-alias-label-secondary);\n flex-wrap: wrap;\n align-items: baseline;\n gap: 4px 8px;\n display: flex;\n}\n\n.dshc_permInline .dshc_text {\n flex: 0 auto;\n min-width: 0;\n}\n\n.dshc_permInline .dshc_text p {\n margin: 0;\n}\n\n.dshc_permLock {\n color: var(--dsw-alias-state-warning-primary, #e9a23b);\n flex: none;\n font-size: 9px;\n}\n\n.dshc_permWaiting {\n color: var(--dsw-alias-state-warning-primary, #e9a23b);\n flex: none;\n font-size: 11px;\n font-weight: 600;\n}\n\n.dshc_permTray {\n flex-direction: column;\n gap: 6px;\n max-height: 40%;\n margin: 0 16px 8px;\n display: flex;\n overflow-y: auto;\n}\n\n.dshc_permTrayItem {\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warning-primary, #e9a23b) 55%, var(--dsw-alias-border-l2));\n background: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #e9a23b) 7%, var(--dsw-alias-bg-layer-2));\n border-radius: 14px;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px 12px;\n padding: 10px 12px;\n display: flex;\n box-shadow: 0 6px 20px -12px #00000059;\n}\n\n.dshc_permTrayText {\n flex: 240px;\n min-width: 0;\n font-size: 13px;\n}\n\n.dshc_permTrayText .dshc_text p {\n margin: 0;\n}\n\n.dshc_permTrayWho {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n font-weight: 600;\n}\n\n.dshc_permTrayItem .dshc_permActions {\n flex-wrap: nowrap;\n margin: 0;\n}\n\n.dshc_permTrayItem .dshc_permScope {\n display: none;\n}\n\n.dshc_members {\n flex-direction: column;\n padding: 0 10px 16px;\n}\n\n@media (width >= 901px) {\n .dshc_members {\n display: flex;\n }\n\n .dshc_membersHidden > .dshc_members {\n display: none;\n }\n}\n\n.dshc_members.dshc_drawerOpen {\n display: flex;\n}\n\n.dshc_activityNow {\n flex-direction: column;\n gap: 2px;\n margin-bottom: 6px;\n display: flex;\n}\n\n.dshc_activityItem {\n border: 1px solid var(--dsw-alias-border-l2);\n width: 100%;\n color: inherit;\n background: var(--dsw-alias-bg-base);\n font: inherit;\n text-align: left;\n cursor: pointer;\n border-radius: 12px;\n align-items: center;\n gap: 10px;\n padding: 8px 10px;\n display: flex;\n}\n\n.dshc_activityItem + .dshc_activityItem {\n margin-top: 4px;\n}\n\n.dshc_activityItem:hover {\n border-color: color-mix(in srgb, var(--dsw-alias-state-business-primary) 40%, var(--dsw-alias-border-l2));\n}\n\n.dshc_activityItem:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_activityText {\n flex-direction: column;\n flex: 1;\n min-width: 0;\n display: flex;\n}\n\n.dshc_activityName {\n font-size: 13px;\n font-weight: 600;\n}\n\n.dshc_activityWhat {\n color: var(--dsw-alias-label-tertiary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n overflow: hidden;\n}\n\n.dshc_activityPulse {\n background: var(--dsw-alias-state-business-primary);\n border-radius: 50%;\n flex: none;\n width: 8px;\n height: 8px;\n animation: 1.6s ease-in-out infinite dshc_channels-pulse;\n}\n\n@keyframes dshc_channels-pulse {\n 50% {\n box-shadow: 0 0 0 3px #23a55a40;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dshc_activityPulse {\n animation: none;\n }\n}\n\n.dshc_member {\n padding: 6px 8px;\n}\n\n.dshc_memberText {\n flex: 1;\n}\n\n.dshc_memberStatus {\n flex: none;\n margin-left: auto;\n font-size: 11px;\n}\n\n.dshc_memberStatus[data-status=\"busy\"] {\n color: var(--dsw-alias-state-business-primary);\n font-weight: 600;\n}\n\n.dshc_memberStatus[data-status=\"error\"] {\n color: var(--dsw-alias-state-error-primary);\n font-weight: 600;\n}\n\n.dshc_memberActions {\n background: var(--dsw-alias-bg-layer-2);\n padding-left: 8px;\n position: absolute;\n top: 50%;\n right: 8px;\n transform: translateY(-50%);\n}\n\n.dshc_addMemberButton {\n border-radius: 10px;\n}\n\n@media (width <= 900px) {\n .dshc_headMeta, .dshc_headActivityText {\n display: none;\n }\n\n .dshc_chatHead {\n padding: 0 8px;\n }\n\n .dshc_mobileButton {\n white-space: nowrap;\n }\n\n .dshc_headActivity ~ .dshc_mobileButton:last-child {\n margin-left: 4px;\n }\n\n .dshc_message {\n padding-left: 12px;\n padding-right: 12px;\n }\n\n .dshc_errorBar {\n margin-left: 12px;\n margin-right: 12px;\n }\n\n .dshc_permTray {\n margin: 0 8px 8px;\n }\n\n .dshc_permTrayItem .dshc_permActions {\n flex-wrap: wrap;\n }\n\n .dshc_systemLine {\n padding: 8px 12px;\n }\n\n .dshc_systemText {\n max-width: 90%;\n }\n\n .dshc_memberActions {\n background: none;\n padding-left: 0;\n position: static;\n transform: none;\n }\n}\n\n@keyframes dshc_channelsEnter {\n from {\n opacity: 0;\n transform: translateY(6px);\n }\n\n to {\n opacity: 1;\n transform: none;\n }\n}\n\n@keyframes dshc_channelsEnterOwn {\n from {\n opacity: 0;\n transform: translateY(12px) scale(.985);\n }\n\n to {\n opacity: 1;\n transform: none;\n }\n}\n\n@keyframes dshc_channelsGlow {\n from {\n opacity: 1;\n }\n\n to {\n opacity: 0;\n }\n}\n\n@keyframes dshc_channelsPop {\n from {\n opacity: 0;\n transform: translateY(4px) scale(.98);\n }\n\n to {\n opacity: 1;\n transform: none;\n }\n}\n\n@keyframes dshc_channelsDot {\n 0%, 60%, 100% {\n opacity: .35;\n transform: none;\n }\n\n 30% {\n opacity: 1;\n transform: translateY(-2px);\n }\n}\n\n@keyframes dshc_channelsDrain {\n from {\n transform: scaleX(1);\n }\n\n to {\n transform: scaleX(0);\n }\n}\n\n.dshc_enter {\n animation: .18s cubic-bezier(.2, 0, 0, 1) both dshc_channelsEnter;\n}\n\n.dshc_enterOwn {\n animation: .22s cubic-bezier(.22, 1, .36, 1) both dshc_channelsEnterOwn;\n}\n\n.dshc_enterGlow:before {\n content: \"\";\n pointer-events: none;\n background: linear-gradient(90deg, color-mix(in srgb, var(--dsw-alias-state-business-primary) 10%, transparent), transparent 70%);\n animation: .7s cubic-bezier(.4, 0, .2, 1) both dshc_channelsGlow;\n animation-delay: inherit;\n position: absolute;\n inset: 0;\n}\n\n.dshc_message {\n transition: background-color .16s cubic-bezier(.2, 0, 0, 1);\n}\n\n.dshc_room {\n transition: background-color .16s cubic-bezier(.2, 0, 0, 1), color .16s cubic-bezier(.2, 0, 0, 1);\n}\n\n.dshc_card {\n transition: border-color .32s cubic-bezier(.2, 0, 0, 1), background-color .32s cubic-bezier(.2, 0, 0, 1);\n}\n\n.dshc_sendButton, .dshc_primaryButton, .dshc_secondaryButton, .dshc_mentionButton, .dshc_cardViewButton {\n transition: background-color .16s cubic-bezier(.2, 0, 0, 1), opacity .16s cubic-bezier(.2, 0, 0, 1), transform .12s cubic-bezier(.2, 0, 0, 1);\n}\n\n.dshc_sendButton:not(:disabled):active, .dshc_primaryButton:not(:disabled):active, .dshc_secondaryButton:not(:disabled):active, .dshc_mentionButton:not(:disabled):active, .dshc_cardViewButton:active {\n transform: translateY(1px);\n}\n\n.dshc_mentionPopup {\n transform-origin: bottom;\n animation: .16s cubic-bezier(.22, 1, .36, 1) both dshc_channelsPop;\n}\n\n.dshc_typingDots {\n vertical-align: middle;\n gap: 3px;\n margin-right: 6px;\n display: inline-flex;\n}\n\n.dshc_typingDots i {\n background: currentColor;\n border-radius: 50%;\n width: 4px;\n height: 4px;\n animation: 1.2s ease-in-out infinite dshc_channelsDot;\n}\n\n.dshc_typingDots i:nth-child(2) {\n animation-delay: .15s;\n}\n\n.dshc_typingDots i:nth-child(3) {\n animation-delay: .3s;\n}\n\n.dshc_logWrap {\n flex-direction: column;\n flex: 1;\n min-height: 0;\n display: flex;\n position: relative;\n}\n\n.dshc_olderLoading {\n color: var(--dsw-alias-label-tertiary);\n text-align: center;\n padding: 8px 16px;\n font-size: 12px;\n}\n\n.dshc_unreadDivider {\n color: var(--dsw-alias-state-error-primary);\n align-items: center;\n gap: 8px;\n margin: 8px 16px;\n font-size: 12px;\n font-weight: 600;\n display: flex;\n}\n\n.dshc_unreadDivider:before, .dshc_unreadDivider:after {\n content: \"\";\n opacity: .35;\n background: currentColor;\n flex: 1;\n height: 1px;\n}\n\n.dshc_withdrawnRow {\n text-align: right;\n color: var(--dsw-alias-label-tertiary);\n padding: 6px 16px;\n font-size: 13px;\n font-style: italic;\n animation: .18s cubic-bezier(.2, 0, 0, 1) both dshc_channelsEnter;\n}\n\n.dshc_jumpLatest {\n z-index: 3;\n border: 1px solid var(--dsw-alias-border-l2);\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-base);\n box-shadow: var(--dsw-elevation-panel, 0 8px 24px #00000029);\n font: inherit;\n cursor: pointer;\n border-radius: 999px;\n align-items: center;\n gap: 6px;\n padding: 6px 14px;\n font-size: 12px;\n animation: .22s cubic-bezier(.22, 1, .36, 1) both dshc_channelsPop;\n display: inline-flex;\n position: absolute;\n bottom: 12px;\n left: 50%;\n transform: translateX(-50%);\n}\n\n.dshc_jumpLatest:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_jumpLatest:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_jumpCount {\n color: var(--dsw-alias-state-business-primary);\n font-weight: 600;\n}\n\n.dshc_undoToast {\n z-index: 4;\n border-radius: var(--dsw-radius-md);\n width: max-content;\n max-width: calc(100% - 32px);\n color: var(--dsw-alias-label-primary-inverted);\n background: var(--dsw-alias-label-primary);\n box-shadow: var(--dsw-elevation-panel, 0 8px 24px #0000003d);\n align-items: center;\n gap: 12px;\n margin: 0 auto;\n padding: 8px 8px 8px 14px;\n font-size: 13px;\n animation: .22s cubic-bezier(.22, 1, .36, 1) both dshc_channelsPop;\n display: flex;\n position: absolute;\n bottom: 12px;\n left: 0;\n right: 0;\n overflow: hidden;\n}\n\n.dshc_undoButton {\n border-radius: var(--dsw-radius-sm);\n color: inherit;\n background: color-mix(in srgb, currentColor 16%, transparent);\n font: inherit;\n cursor: pointer;\n border: 0;\n padding: 2px 10px;\n font-weight: 600;\n}\n\n.dshc_undoButton:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_undoBar {\n background: var(--dsw-alias-state-business-primary);\n transform-origin: 0;\n height: 2px;\n animation: linear forwards dshc_channelsDrain;\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n}\n\n.dshc_undoToast ~ .dshc_jumpLatest {\n display: none;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dshc_enter, .dshc_enterOwn, .dshc_enterGlow:before, .dshc_mentionPopup, .dshc_jumpLatest, .dshc_undoToast, .dshc_withdrawnRow {\n animation: none;\n }\n\n .dshc_typingDots i {\n opacity: .6;\n animation: none;\n }\n\n .dshc_undoBar {\n animation: none;\n }\n\n .dshc_message, .dshc_room, .dshc_card, .dshc_sendButton, .dshc_primaryButton, .dshc_secondaryButton, .dshc_mentionButton, .dshc_mentionBadge, .dshc_cardViewButton {\n transition: none;\n }\n}\n\n.dshc_leadCard {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n border-radius: 14px;\n align-items: center;\n gap: 10px;\n margin: 8px 8px 4px;\n display: flex;\n}\n\n.dshc_leadCardButton {\n border-radius: inherit;\n min-width: 0;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border: 0;\n flex: auto;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n display: flex;\n}\n\n.dshc_leadCardButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_leadCardButton:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-alias-border-focus, currentColor);\n outline-offset: -2px;\n}\n\n.dshc_leadCardButton:disabled {\n cursor: default;\n background: none;\n}\n\n.dshc_leadCardText {\n flex-direction: column;\n min-width: 0;\n display: flex;\n}\n\n.dshc_leadCardName {\n color: var(--dsw-alias-label-primary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n font-weight: 650;\n overflow: hidden;\n}\n\n.dshc_leadCardStatus {\n color: var(--dsw-alias-label-secondary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n overflow: hidden;\n}\n\n.dshc_message:not(.dshc_own) > .dshc_messageBody > .dshc_text {\n background: var(--dsw-alias-bg-layer-2);\n border-radius: 6px 16px 16px;\n width: fit-content;\n max-width: min(640px, 100%);\n padding: 8px 14px;\n}\n\n.dshc_message.dshc_grouped:not(.dshc_own) > .dshc_messageBody > .dshc_text {\n border-radius: 6px 16px 16px 6px;\n}\n\n.dshc_own > .dshc_messageBody > .dshc_text {\n color: var(--dsw-alias-bg-base);\n background: var(--dsw-alias-label-primary);\n box-shadow: none;\n}\n\n.dshc_own > .dshc_messageBody > .dshc_text * {\n color: inherit;\n}\n\n.dshc_own > .dshc_messageBody > .dshc_text a {\n color: inherit;\n text-decoration: underline;\n}\n\n.dshc_own > .dshc_messageBody > .dshc_text code {\n color: inherit;\n background: color-mix(in srgb, var(--dsw-alias-bg-base) 18%, transparent);\n}\n\n.dshc_own > .dshc_messageBody > .dshc_text .dshc_mentionBadge {\n color: var(--dsw-alias-bg-base);\n background: color-mix(in srgb, var(--dsw-alias-bg-base) 24%, transparent);\n}\n\n.dshc_own > .dshc_messageBody > .dshc_text .dshc_mentionBadge:hover {\n background: color-mix(in srgb, var(--dsw-alias-bg-base) 36%, transparent);\n}\n\n.dshc_boardDrawerBackdrop {\n background: #00000040;\n place-items: stretch end;\n padding: 0;\n}\n\n.dshc_boardDrawerBackdrop > .dshc_taskBoardDialog {\n box-sizing: border-box;\n border-radius: 0;\n width: min(440px, 100%);\n height: 100dvh;\n max-height: none;\n animation: .2s ease-out dshc_boardDrawerIn;\n}\n\n@keyframes dshc_boardDrawerIn {\n from {\n opacity: 0;\n transform: translateX(24px);\n }\n\n to {\n opacity: 1;\n transform: none;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dshc_boardDrawerBackdrop > .dshc_taskBoardDialog {\n animation: none;\n }\n}\n\n.dshc_schemeToggle {\n border-radius: var(--dsw-radius-sm);\n width: 28px;\n height: 28px;\n color: var(--dsw-alias-label-tertiary);\n font: inherit;\n cursor: pointer;\n background: none;\n border: 0;\n flex: none;\n justify-content: center;\n align-items: center;\n margin-left: 4px;\n font-size: 16px;\n line-height: 1;\n display: inline-flex;\n}\n\n.dshc_schemeToggle:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_schemeToggle:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_schemeToggle + .dshc_panelToggleEnd {\n margin-left: 4px;\n}\n\n.dshc_progressCard {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-base);\n box-shadow: 0 6px 18px #0000000a, 0 -12px 0 0 var(--dsw-alias-bg-base);\n border-radius: 14px;\n flex: none;\n margin: 8px 16px 4px;\n padding: 8px 14px;\n font-size: 12px;\n position: relative;\n}\n\n.dshc_progressHead {\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.dshc_progressTitle {\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n}\n\n.dshc_progressSummary {\n white-space: nowrap;\n text-overflow: ellipsis;\n min-width: 0;\n color: var(--dsw-alias-label-tertiary);\n flex: 1;\n overflow: hidden;\n}\n\n.dshc_progressToggle {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm);\n min-width: 22px;\n height: 24px;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n cursor: pointer;\n background: none;\n flex: none;\n justify-content: center;\n align-items: center;\n gap: 4px;\n margin-left: auto;\n padding: 0 10px;\n font-size: 12px;\n font-weight: 500;\n line-height: 1;\n display: inline-flex;\n}\n\n.dshc_progressChevron {\n font-size: 12px;\n}\n\n.dshc_progressToggle:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_progressToggle:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_progressCard[data-folded=\"true\"] {\n padding: 6px 12px;\n}\n\n.dshc_progressRows {\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: 0 14px;\n margin: 4px 0 0;\n display: grid;\n}\n\n.dshc_progressRow {\n min-width: 0;\n}\n\n.dshc_progressRow dt {\n color: var(--dsw-alias-label-tertiary);\n font-size: 10px;\n}\n\n.dshc_progressRow dd {\n white-space: nowrap;\n text-overflow: ellipsis;\n min-width: 0;\n color: var(--dsw-alias-label-primary);\n margin: 0;\n overflow: hidden;\n}\n\n.dshc_progressRow[data-empty=\"true\"] dd {\n color: var(--dsw-alias-label-tertiary);\n}\n\n.dshc_progressRow[data-row=\"open\"][data-empty=\"false\"] dd, .dshc_progressRow[data-row=\"open\"] .dshc_progressLink {\n color: var(--dsw-alias-state-warning-primary, #b7791f);\n}\n\n.dshc_progressLink {\n max-width: 100%;\n color: inherit;\n font: inherit;\n text-align: left;\n white-space: nowrap;\n text-overflow: ellipsis;\n cursor: pointer;\n background: none;\n border: 0;\n padding: 0;\n overflow: hidden;\n}\n\n.dshc_progressLink:hover {\n text-decoration: underline;\n}\n\n@media (width <= 760px) {\n .dshc_progressCard {\n margin: 6px 10px 2px;\n }\n\n .dshc_progressRows {\n grid-template-columns: 52px minmax(0, 1fr);\n }\n\n .dshc_progressRow {\n display: contents;\n }\n}\n\n.dshc_stepChips {\n flex-wrap: wrap;\n gap: 6px;\n margin-top: 6px;\n display: flex;\n}\n\n.dshc_stepChip {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-base);\n max-width: 220px;\n color: var(--dsw-alias-label-secondary);\n font: inherit;\n cursor: pointer;\n border-radius: 999px;\n align-items: center;\n gap: 5px;\n padding: 2px 9px 2px 7px;\n font-size: 11px;\n display: inline-flex;\n}\n\n.dshc_stepChip b {\n color: var(--dsw-alias-label-primary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 600;\n overflow: hidden;\n}\n\n.dshc_stepChip:disabled {\n cursor: default;\n}\n\n.dshc_stepChip[aria-expanded=\"true\"] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_stepChip[data-state=\"failed\"] {\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, var(--dsw-alias-border-l2));\n}\n\n.dshc_stepChip[data-state=\"failed\"] b {\n color: var(--dsw-alias-state-error-primary);\n}\n\n.dshc_stepChip[data-state=\"running\"] {\n border-color: color-mix(in srgb, var(--dsw-alias-state-business-primary) 55%, var(--dsw-alias-border-l2));\n}\n\n.dshc_stepMark {\n background: var(--dsw-alias-label-tertiary);\n border-radius: 50%;\n flex: none;\n width: 7px;\n height: 7px;\n}\n\n.dshc_stepChip[data-state=\"ok\"] .dshc_stepMark {\n background: #23a55a;\n}\n\n.dshc_stepChip[data-state=\"failed\"] .dshc_stepMark {\n background: var(--dsw-alias-state-error-primary);\n}\n\n.dshc_stepChip[data-state=\"running\"] .dshc_stepMark {\n background: var(--dsw-alias-state-business-primary);\n animation: 1s ease-in-out infinite dshc_channels-blink;\n}\n\n@keyframes dshc_channels-blink {\n 50% {\n opacity: .3;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dshc_stepChip[data-state=\"running\"] .dshc_stepMark {\n animation: none;\n }\n}\n\n.dshc_stepOut {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-base));\n color: var(--dsw-alias-label-secondary);\n border-radius: 8px;\n flex-basis: 100%;\n gap: 4px;\n padding: 8px 10px;\n font-size: 11px;\n line-height: 1.5;\n display: grid;\n}\n\n.dshc_stepOut[data-state=\"failed\"] {\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, var(--dsw-alias-border-l2));\n}\n\n.dshc_stepOut div {\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n.dshc_stepOut span {\n color: var(--dsw-alias-label-tertiary);\n flex: none;\n}\n\n.dshc_stepOut code {\n overflow-wrap: anywhere;\n min-width: 0;\n font-family: ui-monospace, Menlo, monospace;\n}\n\n.dshc_stepOut[data-state=\"failed\"] > div[data-state=\"failed\"] > div:last-child > code {\n color: var(--dsw-alias-state-error-primary);\n}\n\n.dshc_decideTray {\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warning-primary, #e9a23b) 55%, var(--dsw-alias-border-l2));\n background: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #e9a23b) 7%, var(--dsw-alias-bg-layer-2));\n border-radius: 14px;\n flex-direction: column;\n max-height: 45%;\n margin: 0 16px 8px;\n display: flex;\n overflow-y: auto;\n}\n\n.dshc_decideTrayHead {\n width: 100%;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border: 0;\n flex: none;\n align-items: baseline;\n gap: 8px;\n padding: 7px 12px;\n font-size: 12px;\n display: flex;\n}\n\n.dshc_decideTrayHead strong {\n color: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #e9a23b) 70%, var(--dsw-alias-label-primary));\n}\n\n.dshc_decideTrayHead small {\n color: var(--dsw-alias-label-secondary);\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.dshc_decideTrayHead:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n outline-offset: -2px;\n}\n\n.dshc_decideTrayToggle {\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n margin-left: auto;\n}\n\n.dshc_decideTray .dshc_permTray {\n max-height: none;\n margin: 0;\n padding: 0 8px 8px;\n}\n\n.dshc_askList {\n flex-direction: column;\n display: flex;\n}\n\n.dshc_askItem {\n border-top: 1px solid color-mix(in srgb, var(--dsw-alias-state-warning-primary, #e9a23b) 30%, transparent);\n background: var(--dsw-alias-bg-layer-2);\n flex-wrap: wrap;\n align-items: center;\n gap: 6px 10px;\n padding: 8px 12px;\n display: flex;\n}\n\n.dshc_askKind {\n color: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #e9a23b) 75%, var(--dsw-alias-label-primary));\n background: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #e9a23b) 15%, transparent);\n border-radius: 5px;\n flex: none;\n padding: 0 6px;\n font-size: 11px;\n}\n\n.dshc_askText {\n flex-direction: column;\n flex: 200px;\n min-width: 0;\n font-size: 13px;\n display: flex;\n}\n\n.dshc_askQuestion {\n overflow-wrap: anywhere;\n}\n\n.dshc_askFrom {\n color: var(--dsw-alias-label-secondary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 11px;\n overflow: hidden;\n}\n\n.dshc_askForm {\n flex: 0 260px;\n align-items: center;\n gap: 6px;\n min-width: 160px;\n display: flex;\n}\n\n.dshc_askInput {\n border: 1px solid var(--dsw-alias-border-l2);\n min-width: 0;\n color: inherit;\n background: var(--dsw-alias-bg-base);\n font: inherit;\n border-radius: 8px;\n flex: 1;\n padding: 4px 8px;\n font-size: 12px;\n}\n\n.dshc_askInput:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_askSend {\n width: 26px;\n height: 26px;\n color: var(--dsw-alias-bg-base);\n background: var(--dsw-alias-label-primary);\n cursor: pointer;\n border: 0;\n border-radius: 50%;\n flex: none;\n justify-content: center;\n align-items: center;\n padding: 0;\n display: inline-flex;\n}\n\n.dshc_askSend:disabled {\n opacity: .3;\n cursor: default;\n}\n\n.dshc_askSend:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n outline-offset: 2px;\n}\n\n.dshc_askDone {\n color: var(--dsw-alias-label-secondary);\n align-items: center;\n gap: 8px;\n font-size: 12px;\n display: inline-flex;\n}\n\n.dshc_askNotice {\n color: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #e9a23b) 75%, var(--dsw-alias-label-primary));\n flex-basis: 100%;\n font-size: 12px;\n}\n\n@media (width <= 900px) {\n .dshc_decideTray {\n margin: 0 8px 8px;\n }\n\n .dshc_askForm {\n flex-basis: 100%;\n }\n}\n\n.dshc_headTeam {\n flex: none;\n align-items: center;\n margin-left: auto;\n display: inline-flex;\n}\n\n.dshc_mate, .dshc_mateMore {\n border: 2px solid var(--dsw-alias-bg-base);\n background: var(--dsw-alias-bg-base);\n cursor: pointer;\n border-radius: 50%;\n justify-content: center;\n align-items: center;\n margin-left: -6px;\n padding: 0;\n display: inline-flex;\n position: relative;\n}\n\n.dshc_mate:first-child {\n margin-left: 0;\n}\n\n.dshc_mate .dshc_avatar {\n margin: 0;\n}\n\n.dshc_mateMore {\n background: var(--dsw-alias-interactive-bg-hover);\n width: 28px;\n height: 28px;\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n font-weight: 600;\n}\n\n.dshc_mateDot {\n box-sizing: border-box;\n border: 2px solid var(--dsw-alias-bg-base);\n background: var(--dsw-alias-label-tertiary);\n border-radius: 50%;\n width: 9px;\n height: 9px;\n position: absolute;\n bottom: -2px;\n right: -2px;\n}\n\n.dshc_mate[data-state=\"busy\"] .dshc_mateDot {\n background: #23a55a;\n animation: 1.6s ease-in-out infinite dshc_channels-pulse;\n}\n\n.dshc_mate[data-state=\"idle\"] .dshc_mateDot {\n background: var(--dsw-alias-bg-base);\n box-shadow: inset 0 0 0 1.5px var(--dsw-alias-label-tertiary);\n}\n\n.dshc_mate[data-state=\"error\"] .dshc_mateDot {\n background: var(--dsw-alias-state-error-primary);\n}\n\n.dshc_mate[data-state=\"offline\"] {\n opacity: .55;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dshc_mate[data-state=\"busy\"] .dshc_mateDot {\n animation: none;\n }\n}\n\n@media (width <= 760px) {\n .dshc_headTeam {\n display: none;\n }\n}\n\n.dshc_chatHead > .dshc_headTeam + .dshc_taskBoardTrigger {\n margin-left: 12px;\n}\n\n.dshc_sideDock {\n display: none;\n}\n\n@media (width >= 1101px) {\n .dshc_page.dshc_panelOpen {\n grid-template-columns: 220px minmax(0, 1fr) min(420px, 36%) 240px;\n }\n\n .dshc_page.dshc_panelOpen.dshc_roomsHidden {\n grid-template-columns: minmax(0, 1fr) min(420px, 36%) 240px;\n }\n\n .dshc_page.dshc_panelOpen.dshc_membersHidden {\n grid-template-columns: 220px minmax(0, 1fr) min(420px, 36%);\n }\n\n .dshc_page.dshc_panelOpen.dshc_roomsHidden.dshc_membersHidden {\n grid-template-columns: minmax(0, 1fr) min(420px, 36%);\n }\n\n .dshc_page.dshc_panelOpen > .dshc_sideDock {\n border-left: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-base);\n min-width: 0;\n min-height: 0;\n display: flex;\n }\n}\n\n.dshc_sidePanel {\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n max-height: none;\n box-shadow: none;\n border: 0;\n border-radius: 0;\n margin: 0;\n animation: .2s ease-out dshc_boardDrawerIn;\n position: relative;\n}\n\n.dshc_sidePanel:focus {\n outline: none;\n}\n\n.dshc_sidePanelClose {\n width: 28px;\n height: 28px;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n background: none;\n border: 0;\n border-radius: 6px;\n font-size: 18px;\n line-height: 1;\n position: absolute;\n top: 10px;\n right: 10px;\n}\n\n.dshc_sidePanelClose:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dshc_sidePanel {\n animation: none;\n }\n}\n\n.dshc_sidePanel .dshc_boardCardGrid {\n grid-template-columns: minmax(0, 1fr);\n}\n\n.dshc_slashPopup {\n z-index: 6;\n width: min(360px, 100% - 32px);\n animation: none;\n right: auto;\n}\n\n.dshc_slashGroup {\n color: var(--dsw-alias-label-tertiary);\n padding: 6px 8px 2px;\n font-size: 11px;\n}\n\n.dshc_slashItem {\n border-radius: var(--dsw-radius-sm);\n cursor: pointer;\n align-items: baseline;\n gap: 8px;\n padding: 5px 8px;\n display: flex;\n}\n\n.dshc_slashActive {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_slashName {\n flex: none;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-weight: 600;\n}\n\n.dshc_slashMeta {\n min-width: 0;\n color: var(--dsw-alias-label-tertiary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n overflow: hidden;\n}\n\n.dshc_sendButton.dshc_stopButton {\n background: var(--dsw-alias-label-primary);\n}\n\n.dshc_stopNote + .dshc_sendButton {\n margin-left: 8px;\n}\n\n.dshc_sendButton.dshc_stopButton[data-phase=\"stopping\"] {\n opacity: .6;\n cursor: progress;\n}\n\n.dshc_stopNote {\n color: var(--dsw-alias-label-tertiary);\n white-space: nowrap;\n margin-left: auto;\n font-size: 12px;\n}\n\n.dshc_cmdLine {\n color: var(--dsw-alias-label-tertiary);\n flex-wrap: wrap;\n align-items: baseline;\n gap: 6px;\n padding: 1px 16px 1px 72px;\n font-size: 12px;\n display: flex;\n}\n\n.dshc_cmdLine code {\n color: var(--dsw-alias-label-secondary);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n}\n\n.dshc_cmdResult {\n min-width: 0;\n max-width: 60ch;\n color: inherit;\n font: inherit;\n text-align: left;\n text-overflow: ellipsis;\n white-space: nowrap;\n cursor: pointer;\n background: none;\n border: 0;\n padding: 0;\n overflow: hidden;\n}\n\n.dshc_cmdResult[aria-expanded=\"true\"] {\n white-space: pre-line;\n max-width: none;\n}\n\n.dshc_cmdLine[data-failed=\"true\"] .dshc_cmdResult {\n color: var(--dsw-alias-danger, #d94848);\n}\n\n@media (width <= 720px) {\n .dshc_cmdLine {\n padding-left: 16px;\n }\n}\n\n.dshc_msgTool {\n justify-content: center;\n align-items: center;\n width: 26px;\n height: 24px;\n padding: 0;\n display: inline-flex;\n position: relative;\n}\n\n.dshc_msgTool[data-tip]:after {\n content: attr(data-tip);\n z-index: 3;\n background: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-label-primary-inverted);\n white-space: nowrap;\n opacity: 0;\n pointer-events: none;\n border-radius: 4px;\n padding: 2px 6px;\n font-size: 11px;\n position: absolute;\n top: calc(100% + 4px);\n left: 50%;\n transform: translateX(-50%);\n}\n\n.dshc_msgTool[data-tip]:hover:after, .dshc_msgTool[data-tip]:focus-visible:after {\n opacity: 1;\n transition: opacity 0s 80ms;\n}\n\n.dshc_permSessionButton {\n color: var(--dsw-alias-label-secondary);\n font: inherit;\n text-underline-offset: 2px;\n cursor: pointer;\n background: none;\n border: 0;\n padding: 4px 6px;\n font-size: 12px;\n text-decoration: underline;\n}\n\n.dshc_permSessionButton:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n.dshc_permSessionButton:disabled {\n opacity: .5;\n cursor: default;\n}\n\n.dshc_queuedButton {\n border: 1px solid var(--dsw-alias-border-default, #0000001f);\n color: var(--dsw-alias-label-secondary);\n font: inherit;\n cursor: pointer;\n background: none;\n border-radius: 9px;\n padding: 0 6px;\n font-size: 11px;\n line-height: 16px;\n}\n\n.dshc_queuedButton:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n.dshc_queuedTag {\n color: #a76a06;\n background: #eaa02824;\n border-radius: 4px;\n padding: 0 5px;\n font-size: 11px;\n line-height: 16px;\n}\n\n[data-queued] .dshc_ownActions {\n opacity: 1;\n}\n\n.dshc_memory {\n margin-top: 4px;\n}\n\n.dshc_memoryBadge {\n background: var(--dsw-alias-fill-secondary, #0000000d);\n color: var(--dsw-alias-label-tertiary);\n font: inherit;\n cursor: pointer;\n border: 0;\n border-radius: 9px;\n align-items: center;\n gap: 4px;\n padding: 0 6px;\n font-size: 11px;\n line-height: 18px;\n display: inline-flex;\n}\n\n.dshc_memoryBadge:hover, .dshc_memoryBadge[aria-expanded=\"true\"] {\n color: var(--dsw-alias-label-secondary);\n}\n\n.dshc_memoryList {\n border-left: 2px solid var(--dsw-alias-border-default, #0000001f);\n flex-direction: column;\n gap: 4px;\n max-width: 560px;\n margin: 4px 0 0;\n padding: 6px 10px;\n font-size: 12px;\n list-style: none;\n display: flex;\n}\n\n.dshc_memoryItem {\n flex-direction: column;\n display: flex;\n}\n\n.dshc_memoryTitle {\n color: var(--dsw-alias-label-secondary);\n line-height: 1.5;\n}\n\n.dshc_memoryPage {\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n font-family: var(--dsw-font-mono, ui-monospace, monospace);\n}\n\n.dshc_delivery {\n flex-direction: column;\n gap: 6px;\n max-width: 720px;\n margin-top: 8px;\n display: flex;\n}\n\n.dshc_deliveryFrame {\n border: 1px solid var(--background-modifier-accent, #7f7f7f4d);\n background: #fff;\n border-radius: 6px;\n height: 360px;\n display: flex;\n overflow: hidden;\n}\n\n.dshc_deliveryActions {\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n display: flex;\n}\n\n.dshc_deliveryActions a {\n text-decoration: none;\n}\n\n.dshc_deliveryDone {\n color: var(--text-muted, #888);\n font-size: 12px;\n}\n\n.dshc_deliveryFullDialog {\n box-sizing: border-box;\n flex-direction: column;\n gap: 8px;\n width: 94vw;\n max-width: none;\n height: 92dvh;\n display: flex;\n}\n\n.dshc_deliveryFullFrame {\n background: #fff;\n border-radius: 6px;\n flex: 1;\n min-height: 0;\n display: flex;\n overflow: hidden;\n}\n\n.dshc_dmTitle {\n color: var(--text-muted, #888);\n margin: 14px 8px 4px;\n font-size: 12px;\n font-weight: 600;\n}\n\n.dshc_dmAvatar {\n margin-right: 6px;\n display: inline-flex;\n}\n\n.dshc_dmRow {\n align-items: center;\n display: flex;\n position: relative;\n}\n\n.dshc_dmRow .dshc_room {\n padding-right: 26px;\n}\n\n.dshc_dmClose {\n border-radius: var(--dsw-radius-sm, 4px);\n width: 20px;\n height: 20px;\n color: var(--dsw-alias-label-tertiary, #888);\n font: inherit;\n cursor: pointer;\n opacity: 0;\n background: none;\n border: 0;\n padding: 0;\n font-size: 15px;\n line-height: 20px;\n position: absolute;\n right: 4px;\n}\n\n.dshc_dmRow:hover .dshc_dmClose, .dshc_dmClose:focus-visible {\n opacity: 1;\n}\n\n.dshc_dmClose:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n@media (hover: none) {\n .dshc_dmClose {\n opacity: 1;\n }\n}\n\n.dshc_dmHead {\n margin-top: 14px;\n}\n\n.dshc_dmPicker {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-2);\n flex-direction: column;\n margin: 0 4px 4px;\n padding: 4px;\n display: flex;\n}\n\n.dshc_dmPickNone {\n color: var(--dsw-alias-label-tertiary);\n padding: 6px 8px;\n font-size: 12px;\n}\n\n.dshc_dmNewRow {\n color: var(--dsw-alias-label-tertiary);\n font-size: 13px;\n}\n\nbutton.dshc_headMeta {\n border-radius: var(--dsw-radius-sm);\n min-width: 0;\n font: inherit;\n cursor: pointer;\n background: none;\n border: 0;\n flex: 0 auto;\n padding: 2px 6px;\n font-size: 12px;\n}\n\nbutton.dshc_headMeta:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_headSpacer {\n flex: auto;\n}\n\n.dshc_roomUnread {\n color: var(--dsw-alias-label-primary);\n font-weight: 650;\n}\n\n.dshc_unreadBadge {\n color: #fff;\n background: var(--dsw-alias-state-danger-primary, #e5484d);\n text-align: center;\n font-variant-numeric: tabular-nums;\n border-radius: 999px;\n flex: none;\n min-width: 18px;\n padding: 0 5px;\n font-size: 11px;\n font-weight: 600;\n line-height: 18px;\n}\n\n.dshc_slashDisabled {\n opacity: .45;\n cursor: not-allowed;\n}\n\n.dshc_leadCardHint {\n color: var(--dsw-alias-label-tertiary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 11px;\n overflow: hidden;\n}\n\n.dshc_roomWorking {\n max-width: 96px;\n color: var(--dsw-alias-state-business-primary);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: none;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n font-weight: 500;\n display: inline-flex;\n overflow: hidden;\n}\n\n.dshc_roomWorkingDot {\n background: currentColor;\n border-radius: 50%;\n flex: none;\n width: 6px;\n height: 6px;\n animation: 1.4s ease-in-out infinite dshc_roomWorkingPulse;\n}\n\n@keyframes dshc_roomWorkingPulse {\n 50% {\n opacity: .35;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dshc_roomWorkingDot {\n animation: none;\n }\n}\n\n.dshc_drawerTools {\n display: none;\n}\n\n@media (width <= 600px) {\n .dshc_drawerTools {\n flex-wrap: wrap;\n gap: 6px;\n margin: 0 8px 8px;\n display: flex;\n }\n\n .dshc_chatHead > .dshc_taskBoardTrigger, .dshc_chatHead > .dshc_schemeToggle, .dshc_chatHead > .dshc_headMeta, .dshc_chatHead > .dshc_headTeam {\n display: none;\n }\n\n .dshc_chatHead > .dshc_roomName {\n flex: auto;\n }\n}\n\n.dshc_panelOpen .dshc_chatHead > .dshc_headTeam, .dshc_panelOpen .dshc_chatHead > .dshc_headMeta {\n display: none;\n}\n\n.dshc_panelOpen .dshc_chatHead > .dshc_roomName {\n flex: 0 auto;\n}\n[data-dc-scheme=\"light\"] {\n --dsw-static-amber-100: #fef5e7;\n --dsw-static-amber-400: #f7ad31;\n --dsw-static-amber-500: #f59e0b;\n --dsw-static-amber-600: #dd8629;\n --dsw-static-amber-900: #27241f;\n --dsw-static-blue-100: #dbeafe;\n --dsw-static-blue-300: #93c5fd;\n --dsw-static-blue-400: #60a5fa;\n --dsw-static-blue-450: #4d93f8;\n --dsw-static-blue-500: #3b82f6;\n --dsw-static-blue-50: #eff6ff;\n --dsw-static-blue-50p: #eaf3ff;\n --dsw-static-blue-600: #2563eb;\n --dsw-static-blue-75: #e5f0ff;\n --dsw-static-blue-800: #1e40af;\n --dsw-static-blue-900: #0e3074;\n --dsw-static-blue-950: #172554;\n --dsw-static-deepseek-100: #e4edfd;\n --dsw-static-deepseek-200: #d3e2ff;\n --dsw-static-deepseek-300: #b7c8fe;\n --dsw-static-deepseek-400: #7aaaff;\n --dsw-static-deepseek-450: #5686fe;\n --dsw-static-deepseek-500: #4176e6;\n --dsw-static-deepseek-50: #edf3fe;\n --dsw-static-deepseek-600: #4868b2;\n --dsw-static-deepseek-700-delete: #2f4c8f;\n --dsw-static-deepseek-800: #34415b;\n --dsw-static-deepseek-900: #283142;\n --dsw-static-green-100: #e6faed;\n --dsw-static-green-400: #4ed17e;\n --dsw-static-green-500: #22c55e;\n --dsw-static-green-500-a08: #22c55e14;\n --dsw-static-green-500-a12: #22c55e1f;\n --dsw-static-green-900: #233c2c;\n --dsw-static-neutral-00: #fff;\n --dsw-static-neutral-1000: #000;\n --dsw-static-neutral-100: #f5f5f5;\n --dsw-static-neutral-150: #ededed;\n --dsw-static-neutral-200: #e5e5e5;\n --dsw-static-neutral-250: #dcdcdc;\n --dsw-static-neutral-300: #d4d4d4;\n --dsw-static-neutral-400: #a2a4a6;\n --dsw-static-neutral-500: #7f8287;\n --dsw-static-neutral-50: #fafafa;\n --dsw-static-neutral-550: #65676b;\n --dsw-static-neutral-600: #545557;\n --dsw-static-neutral-700: #3c3c3d;\n --dsw-static-neutral-800: #292929;\n --dsw-static-neutral-850: #212123;\n --dsw-static-neutral-900: #0f0f0f;\n --dsw-static-neutral-bluish-00: #fff;\n --dsw-static-neutral-bluish-1000: #0f1115;\n --dsw-static-neutral-bluish-100: #ebeef2;\n --dsw-static-neutral-bluish-150: #e9ecf2;\n --dsw-static-neutral-bluish-200: #e1e5ee;\n --dsw-static-neutral-bluish-300: #cfd3d6;\n --dsw-static-neutral-bluish-400: #adb2b8;\n --dsw-static-neutral-bluish-500: #979da6;\n --dsw-static-neutral-bluish-50: #f9fafb;\n --dsw-static-neutral-bluish-600: #81858c;\n --dsw-static-neutral-bluish-60: #f5f6f7;\n --dsw-static-neutral-bluish-700: #61666b;\n --dsw-static-neutral-bluish-750: #43454a;\n --dsw-static-neutral-bluish-75: #f1f3f5;\n --dsw-static-neutral-bluish-800: #353638;\n --dsw-static-neutral-bluish-850: #2c2c2e;\n --dsw-static-neutral-bluish-875: #232324;\n --dsw-static-neutral-bluish-900: #1b1b1c;\n --dsw-static-neutral-bluish-950: #151517;\n --dsw-static-red-100: #fee2e2;\n --dsw-static-red-400: #f25a5a;\n --dsw-static-red-400-a12: #f25a5a1f;\n --dsw-static-red-500: #ef4444;\n --dsw-static-red-50: #fef2f2;\n --dsw-static-red-600: #ec1313;\n --dsw-static-red-600-a08: #ec131314;\n --dsw-static-red-900: #570c0c;\n}\n\n[data-dc-scheme=\"dark\"] {\n --dsw-static-amber-100: #fef5e7;\n --dsw-static-amber-400: #f7ad31;\n --dsw-static-amber-500: #f59e0b;\n --dsw-static-amber-600: #dd8629;\n --dsw-static-amber-900: #27241f;\n --dsw-static-blue-100: #dbeafe;\n --dsw-static-blue-300: #93c5fd;\n --dsw-static-blue-400: #60a5fa;\n --dsw-static-blue-450: #4d93f8;\n --dsw-static-blue-500: #3b82f6;\n --dsw-static-blue-50: #eff6ff;\n --dsw-static-blue-50p: #eaf3ff;\n --dsw-static-blue-600: #2563eb;\n --dsw-static-blue-75: #e5f0ff;\n --dsw-static-blue-800: #1e40af;\n --dsw-static-blue-900: #0e3074;\n --dsw-static-blue-950: #172554;\n --dsw-static-deepseek-100: #e4edfd;\n --dsw-static-deepseek-200: #d3e2ff;\n --dsw-static-deepseek-300: #b7c8fe;\n --dsw-static-deepseek-400: #7aaaff;\n --dsw-static-deepseek-450: #5686fe;\n --dsw-static-deepseek-500: #4176e6;\n --dsw-static-deepseek-50: #edf3fe;\n --dsw-static-deepseek-600: #4868b2;\n --dsw-static-deepseek-700-delete: #2f4c8f;\n --dsw-static-deepseek-800: #34415b;\n --dsw-static-deepseek-900: #283142;\n --dsw-static-green-100: #e6faed;\n --dsw-static-green-400: #4ed17e;\n --dsw-static-green-500: #22c55e;\n --dsw-static-green-500-a08: #22c55e14;\n --dsw-static-green-500-a12: #22c55e1f;\n --dsw-static-green-900: #233c2c;\n --dsw-static-neutral-00: #fff;\n --dsw-static-neutral-1000: #000;\n --dsw-static-neutral-100: #f5f5f5;\n --dsw-static-neutral-150: #ededed;\n --dsw-static-neutral-200: #e5e5e5;\n --dsw-static-neutral-250: #dcdcdc;\n --dsw-static-neutral-300: #d4d4d4;\n --dsw-static-neutral-400: #a2a4a6;\n --dsw-static-neutral-500: #7f8287;\n --dsw-static-neutral-50: #fafafa;\n --dsw-static-neutral-550: #65676b;\n --dsw-static-neutral-600: #545557;\n --dsw-static-neutral-700: #3c3c3d;\n --dsw-static-neutral-800: #292929;\n --dsw-static-neutral-850: #212123;\n --dsw-static-neutral-900: #0f0f0f;\n --dsw-static-neutral-bluish-00: #fff;\n --dsw-static-neutral-bluish-1000: #0f1115;\n --dsw-static-neutral-bluish-100: #ebeef2;\n --dsw-static-neutral-bluish-150: #e9ecf2;\n --dsw-static-neutral-bluish-200: #e1e5ee;\n --dsw-static-neutral-bluish-300: #cfd3d6;\n --dsw-static-neutral-bluish-400: #adb2b8;\n --dsw-static-neutral-bluish-500: #979da6;\n --dsw-static-neutral-bluish-50: #f9fafb;\n --dsw-static-neutral-bluish-600: #81858c;\n --dsw-static-neutral-bluish-60: #f9fafb;\n --dsw-static-neutral-bluish-700: #61666b;\n --dsw-static-neutral-bluish-750: #43454a;\n --dsw-static-neutral-bluish-75: #f1f3f5;\n --dsw-static-neutral-bluish-800: #353638;\n --dsw-static-neutral-bluish-850: #2c2c2e;\n --dsw-static-neutral-bluish-875: #232324;\n --dsw-static-neutral-bluish-900: #1b1b1c;\n --dsw-static-neutral-bluish-950: #151517;\n --dsw-static-red-100: #fee2e2;\n --dsw-static-red-400: #f25a5a;\n --dsw-static-red-400-a12: #f25a5a1f;\n --dsw-static-red-500: #ef4444;\n --dsw-static-red-50: #fef2f2;\n --dsw-static-red-600: #ec1313;\n --dsw-static-red-600-a08: #ec131314;\n --dsw-static-red-900: #570c0c;\n}\n\n[data-dc-scheme=\"light\"] {\n --dsw-alias-bg-base: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-bg-document-preview: var(--dsw-static-neutral-bluish-100);\n --dsw-alias-bg-document-selection: color-mix(in srgb, var(--dsw-static-blue-500) 40%, transparent);\n --dsw-alias-label-document-preview: var(--dsw-static-neutral-bluish-700);\n --dsw-alias-bg-layer-1: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-bg-layer-2: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-bg-layer-3: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-bg-mask-1: #0000003d;\n --dsw-alias-bg-mask-2: #0000001f;\n --dsw-alias-bg-mask-3: #0000007a;\n --dsw-alias-bg-mask-photo: #000000e0;\n --dsw-alias-bg-mask-drop: #ffffffb3;\n --dsw-alias-bg-module-platform: var(--dsw-static-neutral-bluish-60);\n --dsw-alias-bg-multi-select: var(--dsw-static-neutral-bluish-60);\n --dsw-alias-bg-overlay: var(--dsw-static-neutral-bluish-150);\n --dsw-alias-bg-skeleton: #0000000a;\n --dsw-alias-border-inverted2: #0000;\n --dsw-alias-border-inverted: #0000;\n --dsw-alias-border-l1: #0000000a;\n --dsw-alias-border-l2-darkmode-thin: #0000001a;\n --dsw-alias-border-l2: #0000001a;\n --dsw-alias-border-l3: #0000001f;\n --dsw-alias-border-l4: #00000029;\n --dsw-alias-brand-primary-invert: var(--dsw-static-neutral-bluish-1000);\n --dsw-alias-brand-primary-new-colorprimary-new-color: #4176e6;\n --dsw-alias-brand-primary: var(--dsw-static-neutral-bluish-1000);\n --dsw-alias-brand-text: var(--dsw-static-neutral-bluish-1000);\n --dsw-alias-button-contrast-fill: var(--dsw-static-neutral-bluish-700);\n --dsw-alias-button-elevated-fill: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-button-floating-fill: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-button-floating-hover: var(--dsw-static-neutral-bluish-75);\n --dsw-alias-button-ghost-active-border: var(--dsw-static-neutral-bluish-500);\n --dsw-alias-button-ghost-active-fill: var(--dsw-static-neutral-bluish-100);\n --dsw-alias-button-ghost-active-hover: var(--dsw-static-neutral-bluish-150);\n --dsw-alias-button-info-fill: var(--dsw-static-deepseek-500);\n --dsw-alias-button-info-hover: var(--dsw-static-deepseek-400);\n --dsw-alias-button-primary-dimmed: var(--dsw-static-neutral-bluish-100);\n --dsw-alias-button-primary-fill: var(--dsw-alias-brand-primary);\n --dsw-alias-button-primary-hover: var(--dsw-static-neutral-bluish-750);\n --dsw-alias-button-tool-bar-fill-invisible: #1f1f1f5c;\n --dsw-alias-button-tool-bar-fill: #54555780;\n --dsw-alias-button-tool-bar-hover: #54555799;\n --dsw-alias-interactive-bg-active: #2631481a;\n --dsw-alias-interactive-bg-hover-accent: #26314824;\n --dsw-alias-interactive-bg-hover-danger: #ec13130d;\n --dsw-alias-interactive-bg-hover-solid: var(--dsw-static-neutral-bluish-75);\n --dsw-alias-interactive-bg-hover: #2631480f;\n --dsw-alias-label-caption: var(--dsw-static-neutral-bluish-400);\n --dsw-alias-label-deep-diving: color-mix(in srgb, var(--dsw-static-deepseek-500) 70%, var(--dsw-static-blue-950));\n --dsw-alias-label-deep-diving-shimmer: color-mix(in srgb, var(--dsw-static-deepseek-500) 30%, var(--dsw-static-blue-950));\n --dsw-alias-label-dimmed: var(--dsw-static-neutral-bluish-200);\n --dsw-alias-label-primary-bluish: var(--dsw-static-blue-900);\n --dsw-alias-label-primary-dimmed: var(--dsw-static-neutral-bluish-950);\n --dsw-alias-label-primary-foreground: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-label-primary-inverted: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-label-primary: var(--dsw-static-neutral-bluish-1000);\n --dsw-alias-label-secondary: var(--dsw-static-neutral-bluish-700);\n --dsw-alias-label-shimmer: color-mix(in srgb, var(--dsw-static-neutral-1000) 30%, transparent);\n --dsw-alias-label-tertiary: var(--dsw-static-neutral-bluish-600);\n --dsw-alias-menu-icon: var(--dsw-static-neutral-bluish-800);\n --dsw-alias-link: var(--dsw-static-deepseek-500);\n --dsw-alias-markdown-citation: var(--dsw-static-neutral-bluish-100);\n --dsw-alias-markdown-code-block-banner: var(--dsw-static-neutral-bluish-50);\n --dsw-alias-markdown-code-block: var(--dsw-static-neutral-bluish-50);\n --dsw-alias-markdown-code-segment-selected: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-markdown-code-segment-unselected: var(--dsw-static-neutral-bluish-75);\n --dsw-alias-markdown-inline-code: var(--dsw-static-neutral-50);\n --dsw-alias-markdown-placeholder: var(--dsw-static-neutral-bluish-60);\n --dsw-alias-markdown-tag: var(--dsw-static-neutral-bluish-75);\n --dsw-alias-scrollbar-bg-l1: var(--dsw-static-neutral-200);\n --dsw-alias-scrollbar-bg-l2: var(--dsw-static-neutral-200);\n --dsw-alias-scrollbar-hover-l1: var(--dsw-static-neutral-300);\n --dsw-alias-scrollbar-hover-l2: var(--dsw-static-neutral-300);\n --dsw-alias-state-business-primary: var(--dsw-static-deepseek-500);\n --dsw-alias-state-business-tertiary: var(--dsw-static-deepseek-100);\n --dsw-alias-code-diff-added: var(--dsw-static-green-500-a08);\n --dsw-alias-code-diff-deleted: var(--dsw-static-red-600-a08);\n --dsw-alias-file-diff-added-bg: #e6f4e7;\n --dsw-alias-file-diff-added-gutter: #edf7ed;\n --dsw-alias-file-diff-added-marker: #01a241;\n --dsw-alias-file-diff-deleted-bg: #fce6e2;\n --dsw-alias-file-diff-deleted-gutter: #fdece9;\n --dsw-alias-file-diff-deleted-marker: #ba2723;\n --dsw-alias-state-error-primary: var(--dsw-static-red-600);\n --dsw-alias-state-error-secondary: var(--dsw-static-red-400);\n --dsw-alias-state-idle-primary: var(--dsw-static-neutral-300);\n --dsw-alias-state-success-primary: var(--dsw-static-green-500);\n --dsw-alias-state-success-secondary: var(--dsw-static-green-400);\n --dsw-alias-state-success-tertiary: var(--dsw-static-green-100);\n --dsw-alias-state-warn-label: var(--dsw-static-amber-600);\n --dsw-alias-state-warn-primary: var(--dsw-static-amber-500);\n --dsw-alias-state-warn-secondary: var(--dsw-static-amber-400);\n --dsw-alias-state-warn-tertiary: var(--dsw-static-amber-100);\n --dsw-alias-switch-thumb: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-toast-bg: var(--dsw-static-neutral-bluish-800);\n --dsw-alias-toast-label: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-tooltip-bg: var(--dsw-static-neutral-bluish-850);\n --dsw-alias-tooltip-key-bg: color-mix(in srgb, var(--dsw-alias-tooltip-bg), white 18%);\n --dsw-alias-turn-trigger-bg: var(--dsw-alias-markdown-code-block);\n --dsw-alias-turn-trigger-bg-hover: var(--dsw-alias-interactive-bg-hover);\n --dsw-specific-bubble-highlight: var(--dsw-static-deepseek-200);\n --dsw-specific-bubble: var(--dsw-static-deepseek-50);\n --dsw-specific-input-major: var(--dsw-static-neutral-bluish-00);\n --dsw-specific-login-input: var(--dsw-static-neutral-bluish-50);\n --dsw-menu-surface-fill: #f8f9fa94;\n --dsw-alias-menu-group-header-fill: #f8f9faf0;\n --dsw-specific-menu: var(--dsw-menu-surface-fill);\n --dsw-specific-selector: var(--dsw-static-neutral-bluish-60);\n --dsw-specific-sidebar-fill: var(--dsw-static-neutral-bluish-50);\n --dsw-specific-sidebar-nav-item-active-accent: var(--dsw-static-deepseek-100);\n --dsw-specific-sidebar-nav-item-active: var(--dsw-static-neutral-bluish-100);\n --dsw-specific-sidebar-nav-item-hover: var(--dsw-static-neutral-bluish-75);\n --dsw-specific-tip: var(--dsw-static-neutral-bluish-60);\n}\n\n[data-dc-scheme=\"dark\"] {\n --dsw-alias-bg-base: var(--dsw-static-neutral-bluish-950);\n --dsw-alias-bg-document-preview: var(--dsw-static-neutral-bluish-950);\n --dsw-alias-bg-document-selection: color-mix(in srgb, var(--dsw-static-blue-500) 40%, transparent);\n --dsw-alias-label-document-preview: var(--dsw-static-neutral-bluish-300);\n --dsw-alias-bg-layer-1: var(--dsw-static-neutral-bluish-875);\n --dsw-alias-bg-layer-2: var(--dsw-static-neutral-bluish-850);\n --dsw-alias-bg-layer-3: var(--dsw-static-neutral-bluish-800);\n --dsw-alias-bg-mask-1: #00000080;\n --dsw-alias-bg-mask-2: #0003;\n --dsw-alias-bg-mask-3: #0000007a;\n --dsw-alias-bg-mask-photo: #000000e0;\n --dsw-alias-bg-mask-drop: #272730b3;\n --dsw-alias-bg-module-platform: var(--dsw-static-neutral-bluish-800);\n --dsw-alias-bg-multi-select: var(--dsw-static-neutral-850);\n --dsw-alias-bg-overlay: var(--dsw-static-neutral-bluish-700);\n --dsw-alias-bg-skeleton: #ffffff14;\n --dsw-alias-border-inverted2: #ffffff14;\n --dsw-alias-border-inverted: #ffffff0f;\n --dsw-alias-border-l1: #ffffff0f;\n --dsw-alias-border-l2-darkmode-thin: #ffffff0f;\n --dsw-alias-border-l2: #ffffff1f;\n --dsw-alias-border-l3: #ffffff29;\n --dsw-alias-border-l4: #fff3;\n --dsw-alias-brand-primary-invert: var(--dsw-static-neutral-bluish-50);\n --dsw-alias-brand-primary-new-colorprimary-new-color: var(--dsw-static-deepseek-450);\n --dsw-alias-brand-primary: var(--dsw-static-neutral-bluish-50);\n --dsw-alias-brand-text: var(--dsw-static-neutral-bluish-50);\n --dsw-alias-button-contrast-fill: var(--dsw-static-neutral-bluish-50);\n --dsw-alias-button-elevated-fill: var(--dsw-static-neutral-bluish-750);\n --dsw-alias-button-floating-fill: var(--dsw-static-neutral-bluish-850);\n --dsw-alias-button-floating-hover: var(--dsw-static-neutral-bluish-800);\n --dsw-alias-button-ghost-active-border: var(--dsw-static-neutral-bluish-600);\n --dsw-alias-button-ghost-active-fill: var(--dsw-static-neutral-bluish-750);\n --dsw-alias-button-ghost-active-hover: var(--dsw-static-neutral-bluish-700);\n --dsw-alias-button-info-fill: var(--dsw-static-deepseek-400);\n --dsw-alias-button-info-hover: var(--dsw-static-deepseek-500);\n --dsw-alias-button-primary-dimmed: var(--dsw-static-neutral-bluish-750);\n --dsw-alias-button-primary-fill: var(--dsw-alias-brand-primary);\n --dsw-alias-button-primary-hover: var(--dsw-static-neutral-bluish-100);\n --dsw-alias-button-tool-bar-fill-invisible: #1f1f1f5c;\n --dsw-alias-button-tool-bar-fill: #54555780;\n --dsw-alias-button-tool-bar-hover: #54555799;\n --dsw-alias-interactive-bg-active: #ffffff24;\n --dsw-alias-interactive-bg-hover-accent: #ffffff3d;\n --dsw-alias-interactive-bg-hover-danger: #f25a5a26;\n --dsw-alias-interactive-bg-hover-solid: var(--dsw-static-neutral-bluish-800);\n --dsw-alias-interactive-bg-hover: #ffffff14;\n --dsw-alias-label-caption: var(--dsw-static-neutral-bluish-600);\n --dsw-alias-label-deep-diving: color-mix(in srgb, var(--dsw-static-deepseek-450) 55%, var(--dsw-static-neutral-bluish-400));\n --dsw-alias-label-deep-diving-shimmer: color-mix(in srgb, var(--dsw-static-blue-300) 65%, var(--dsw-static-deepseek-400));\n --dsw-alias-label-dimmed: var(--dsw-static-neutral-bluish-750);\n --dsw-alias-label-primary-bluish: var(--dsw-static-neutral-bluish-50);\n --dsw-alias-label-primary-dimmed: var(--dsw-static-neutral-bluish-100);\n --dsw-alias-label-primary-foreground: var(--dsw-static-neutral-bluish-1000);\n --dsw-alias-label-primary-inverted: var(--dsw-static-neutral-bluish-800);\n --dsw-alias-label-primary: var(--dsw-static-neutral-bluish-50);\n --dsw-alias-label-secondary: var(--dsw-static-neutral-bluish-300);\n --dsw-alias-label-shimmer: color-mix(in srgb, var(--dsw-static-neutral-00) 45%, transparent);\n --dsw-alias-label-tertiary: var(--dsw-static-neutral-bluish-400);\n --dsw-alias-menu-icon: var(--dsw-alias-label-primary-dimmed);\n --dsw-alias-link: var(--dsw-static-deepseek-400);\n --dsw-alias-markdown-citation: var(--dsw-static-neutral-bluish-800);\n --dsw-alias-markdown-code-block-banner: var(--dsw-static-neutral-bluish-850);\n --dsw-alias-markdown-code-block: var(--dsw-static-neutral-bluish-900);\n --dsw-alias-markdown-code-segment-selected: var(--dsw-static-neutral-bluish-800);\n --dsw-alias-markdown-code-segment-unselected: var(--dsw-static-neutral-bluish-900);\n --dsw-alias-markdown-inline-code: var(--dsw-static-neutral-800);\n --dsw-alias-markdown-placeholder: var(--dsw-static-neutral-bluish-850);\n --dsw-alias-markdown-tag: var(--dsw-static-neutral-bluish-850);\n --dsw-alias-scrollbar-bg-l1: var(--dsw-static-neutral-700);\n --dsw-alias-scrollbar-bg-l2: var(--dsw-static-neutral-600);\n --dsw-alias-scrollbar-hover-l1: var(--dsw-static-neutral-600);\n --dsw-alias-scrollbar-hover-l2: var(--dsw-static-neutral-550);\n --dsw-alias-state-business-primary: var(--dsw-static-deepseek-400);\n --dsw-alias-state-business-tertiary: var(--dsw-static-deepseek-800);\n --dsw-alias-code-diff-added: var(--dsw-static-green-500-a12);\n --dsw-alias-code-diff-deleted: var(--dsw-static-red-400-a12);\n --dsw-alias-file-diff-added-bg: #1f3124;\n --dsw-alias-file-diff-added-gutter: #132016;\n --dsw-alias-file-diff-added-marker: #41c977;\n --dsw-alias-file-diff-deleted-bg: #3c1f1b;\n --dsw-alias-file-diff-deleted-gutter: #28130e;\n --dsw-alias-file-diff-deleted-marker: #fa423e;\n --dsw-alias-state-error-primary: var(--dsw-static-red-400);\n --dsw-alias-state-error-secondary: var(--dsw-static-red-400);\n --dsw-alias-state-idle-primary: var(--dsw-static-neutral-600);\n --dsw-alias-state-success-primary: var(--dsw-static-green-500);\n --dsw-alias-state-success-secondary: var(--dsw-static-green-400);\n --dsw-alias-state-success-tertiary: var(--dsw-static-green-900);\n --dsw-alias-state-warn-label: var(--dsw-static-amber-600);\n --dsw-alias-state-warn-primary: var(--dsw-static-amber-500);\n --dsw-alias-state-warn-secondary: var(--dsw-static-amber-400);\n --dsw-alias-state-warn-tertiary: var(--dsw-static-amber-900);\n --dsw-alias-switch-thumb: var(--dsw-static-neutral-bluish-400);\n --dsw-alias-toast-bg: var(--dsw-static-neutral-bluish-750);\n --dsw-alias-toast-label: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-turn-trigger-bg: var(--dsw-alias-interactive-bg-hover);\n --dsw-alias-turn-trigger-bg-hover: var(--dsw-alias-interactive-bg-active);\n --dsw-alias-tooltip-bg: var(--dsw-static-neutral-bluish-750);\n --dsw-alias-tooltip-key-bg: color-mix(in srgb, var(--dsw-alias-tooltip-bg), white 18%);\n --dsw-specific-bubble-highlight: var(--dsw-static-neutral-bluish-750);\n --dsw-specific-bubble: var(--dsw-static-neutral-bluish-850);\n --dsw-specific-input-major: var(--dsw-static-neutral-bluish-850);\n --dsw-specific-login-input: var(--dsw-static-neutral-bluish-900);\n --dsw-menu-surface-fill: #43454a73;\n --dsw-alias-menu-group-header-fill: #303136f0;\n --dsw-specific-menu: var(--dsw-menu-surface-fill);\n --dsw-specific-selector: var(--dsw-static-neutral-bluish-800);\n --dsw-specific-sidebar-fill: var(--dsw-static-neutral-bluish-900);\n --dsw-specific-sidebar-nav-item-active-accent: var(--dsw-static-neutral-bluish-800);\n --dsw-specific-sidebar-nav-item-active: var(--dsw-static-neutral-bluish-750);\n --dsw-specific-sidebar-nav-item-hover: var(--dsw-static-neutral-bluish-850);\n --dsw-specific-tip: var(--dsw-static-neutral-bluish-800);\n}\n\nhtml[data-platform=\"darwin\"] [data-dc-scheme=\"light\"] {\n --dsw-specific-menu: #f8f9faf0;\n}\n\nhtml[data-platform=\"darwin\"] [data-dc-scheme=\"dark\"] {\n --dsw-specific-menu: #303136f0;\n}\n\n[data-dc-scheme=\"light\"] {\n color-scheme: light;\n}\n\n[data-dc-scheme=\"dark\"] {\n color-scheme: dark;\n}\n.dshc_embed {\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n min-height: 0;\n padding-top: var(--dsh-frame-top-clearance, 0px);\n background: var(--dsw-alias-bg-base);\n display: flex;\n}\n\n.dshc_frame {\n background: var(--dsw-alias-bg-base);\n border: 0;\n flex: 1;\n width: 100%;\n height: 100%;\n}\n";document.head.appendChild(s)})();
8
+ (function(){var s=document.createElement('style');s.setAttribute('data-dsh-plugin',"bothouse-dsh-channels");s.textContent=".dshc_page {\n width: 100%;\n height: 100%;\n min-height: 0;\n padding-top: var(--dsh-frame-top-clearance, 0px);\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-base);\n grid-template-columns: 220px minmax(0, 1fr) 240px;\n font-size: 14px;\n line-height: 1.5;\n display: grid;\n}\n\n.dshc_notice {\n max-width: 480px;\n color: var(--dsw-alias-label-secondary);\n text-align: center;\n grid-column: 1 / -1;\n place-self: center;\n padding: 24px;\n}\n\n.dshc_rooms, .dshc_members {\n background: var(--dsw-alias-bg-layer-2);\n min-height: 0;\n padding: 0 8px 16px;\n overflow-y: auto;\n}\n\n.dshc_membersHead {\n border-bottom: 1px solid var(--dsw-alias-border-l2);\n flex: none;\n height: 44px;\n margin: 0 0 8px;\n}\n\n.dshc_groupTitle {\n color: var(--dsw-alias-label-tertiary);\n letter-spacing: .02em;\n margin: 12px 8px 6px;\n font-size: 12px;\n font-weight: 600;\n}\n\n.dshc_room {\n border-radius: var(--dsw-radius-sm);\n width: 100%;\n color: var(--dsw-alias-label-secondary);\n font: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border: 0;\n align-items: center;\n gap: 6px;\n padding: 6px 8px;\n display: flex;\n}\n\n.dshc_room:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_room:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_workspace {\n padding-left: 22px;\n font-size: .95em;\n}\n\n.dshc_roomLabel {\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.dshc_activeCount {\n color: var(--dsw-alias-label-tertiary);\n flex-shrink: 0;\n margin-left: auto;\n font-size: 11px;\n}\n\n.dshc_activeBusy {\n color: var(--dsw-alias-label-primary);\n}\n\n.dshc_roomActive {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_hash {\n color: var(--dsw-alias-label-tertiary);\n font-size: 16px;\n}\n\n.dshc_chat {\n flex-direction: column;\n min-width: 0;\n min-height: 0;\n display: flex;\n}\n\n.dshc_chatHead {\n -webkit-app-region: drag;\n border-bottom: 1px solid var(--dsw-alias-border-l2);\n align-items: center;\n gap: 6px;\n height: 44px;\n padding: 0 16px;\n font-weight: 600;\n display: flex;\n}\n\n.dshc_log {\n flex: 1;\n min-height: 0;\n padding: 8px 0 12px;\n overflow-y: auto;\n}\n\n.dshc_guide {\n border: 1px dashed var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm);\n color: var(--dsw-alias-label-secondary);\n flex-direction: column;\n align-items: flex-start;\n gap: 10px;\n margin: 16px;\n padding: 14px 16px;\n display: flex;\n}\n\n.dshc_empty {\n color: var(--dsw-alias-label-tertiary);\n padding: 24px 16px;\n}\n\n.dshc_message {\n grid-template-columns: 36px minmax(0, 1fr);\n gap: 12px;\n padding: 6px 16px;\n display: grid;\n}\n\n.dshc_system .dshc_text {\n color: var(--dsw-alias-label-tertiary);\n font-style: italic;\n}\n\n.dshc_avatar {\n corner-shape: round;\n color: #fff;\n border-radius: 50%;\n flex: none;\n place-items: center;\n width: 36px;\n height: 36px;\n font-weight: 700;\n display: grid;\n position: relative;\n}\n\n.dshc_avatarImage {\n object-fit: cover;\n border-radius: 50%;\n width: 100%;\n height: 100%;\n position: absolute;\n inset: 0;\n}\n\n.dshc_avatarSmall {\n width: 28px;\n height: 28px;\n font-size: 12px;\n}\n\n.dshc_avatarAnchor {\n align-self: start;\n position: relative;\n}\n\n.dshc_avatarButton {\n cursor: pointer;\n background: none;\n border: 0;\n border-radius: 50%;\n padding: 0;\n}\n\n.dshc_avatarMenu {\n z-index: 3;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-base);\n min-width: 140px;\n box-shadow: var(--dsw-elevation-panel, 0 8px 24px #0000003d);\n flex-direction: column;\n padding: 6px;\n display: flex;\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n}\n\n.dshc_avatarMenuTitle {\n padding: 4px 8px;\n font-weight: 700;\n}\n\n.dshc_avatarMenuItem {\n border-radius: var(--dsw-radius-sm);\n color: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border: 0;\n padding: 6px 8px;\n}\n\n.dshc_avatarMenuItem:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_messageBody {\n min-width: 0;\n}\n\n.dshc_messageHead {\n align-items: baseline;\n gap: 6px;\n display: flex;\n}\n\n.dshc_author {\n font-weight: 600;\n}\n\n.dshc_time {\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n}\n\n.dshc_tag {\n border-radius: var(--dsw-radius-xs);\n color: var(--dsw-alias-label-primary-inverted);\n background: var(--dsw-alias-state-business-primary);\n white-space: nowrap;\n padding: 0 4px;\n font-size: 10px;\n font-weight: 600;\n}\n\n.dshc_edited {\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n}\n\n.dshc_ownActions {\n margin-left: auto;\n margin-right: var(--channels-reply-clearance);\n opacity: 0;\n gap: 8px;\n display: inline-flex;\n}\n\n.dshc_message:hover .dshc_ownActions, .dshc_ownActions:focus-within {\n opacity: 1;\n}\n\n@media (hover: none) {\n .dshc_ownActions {\n display: none;\n }\n\n .dshc_message[data-tools-open] .dshc_ownActions {\n opacity: 1;\n display: inline-flex;\n }\n}\n\n.dshc_editBox {\n flex-direction: column;\n gap: 6px;\n margin-top: 4px;\n display: flex;\n}\n\n.dshc_editInput {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-base);\n min-height: 60px;\n color: inherit;\n font: inherit;\n resize: vertical;\n padding: 8px;\n}\n\n.dshc_editBar {\n justify-content: flex-end;\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.dshc_editBar .dshc_time {\n margin-right: auto;\n}\n\n.dshc_text {\n white-space: normal;\n overflow-wrap: anywhere;\n}\n\n.dshc_card {\n border-left: 4px solid var(--dsw-alias-state-business-primary);\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-layer-2);\n margin-top: 4px;\n padding: 6px 10px;\n}\n\n.dshc_card[data-state=\"failed\"] {\n border-left-color: var(--dsw-alias-state-error-primary);\n}\n\n.dshc_card[data-state=\"retrying\"] {\n border-left-color: var(--dsw-alias-state-warning-primary, #faa61a);\n}\n\n.dshc_cardButtons {\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n margin-top: 6px;\n display: flex;\n}\n\n.dshc_cardTitle {\n font-size: 13px;\n font-weight: 600;\n}\n\n.dshc_cardHead {\n justify-content: space-between;\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.dshc_cardViews {\n gap: 4px;\n display: flex;\n}\n\n.dshc_cardViewButton {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm);\n color: inherit;\n cursor: pointer;\n background: none;\n padding: 0 6px;\n font-size: 12px;\n}\n\n.dshc_cardViewButton[aria-pressed=\"true\"] {\n background: var(--dsw-alias-bg-base);\n font-weight: 600;\n}\n\n.dshc_permActions {\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n margin-top: 6px;\n display: flex;\n}\n\n.dshc_permScope {\n color: var(--dsw-alias-text-secondary);\n flex-basis: 100%;\n font-size: 12px;\n}\n\n.dshc_permStatus {\n margin-top: 6px;\n font-size: 13px;\n font-weight: 600;\n}\n\n.dshc_message {\n --channels-reply-clearance: 36px;\n position: relative;\n}\n\n.dshc_quote {\n border-left: 2px solid var(--dsw-alias-label-tertiary);\n min-width: 0;\n color: var(--dsw-alias-label-tertiary);\n white-space: nowrap;\n text-overflow: ellipsis;\n gap: 6px;\n margin-bottom: 2px;\n padding-left: 8px;\n font-size: 12px;\n display: flex;\n overflow: hidden;\n}\n\n.dshc_quoteDeleted {\n font-style: italic;\n}\n\n.dshc_quoteAuthor {\n flex: none;\n font-weight: 600;\n}\n\n.dshc_replyButton {\n border-radius: var(--dsw-radius-xs);\n color: var(--dsw-alias-label-tertiary);\n background: var(--dsw-alias-bg-layer-2);\n cursor: pointer;\n border: 0;\n padding: 0 6px;\n}\n\n.dshc_msgTools {\n z-index: 1;\n border: 1px solid var(--dsw-alias-separator, #7f7f7f40);\n border-radius: var(--dsw-radius-sm, 6px);\n background: var(--dsw-alias-bg-elevated, var(--dsw-alias-bg-primary, #fff));\n opacity: 0;\n pointer-events: none;\n align-items: center;\n gap: 2px;\n padding: 2px;\n display: inline-flex;\n position: absolute;\n top: 2px;\n right: 16px;\n box-shadow: 0 2px 6px #00000014;\n}\n\n.dshc_msgTool {\n border-radius: var(--dsw-radius-sm, 6px);\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n cursor: pointer;\n background: none;\n border: 0;\n padding: 2px 8px;\n font-size: 12px;\n}\n\n.dshc_msgTool:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n.dshc_msgTool:disabled {\n cursor: default;\n opacity: .6;\n}\n\n.dshc_msgToolNote {\n color: var(--dsw-alias-label-tertiary);\n white-space: nowrap;\n padding: 0 6px;\n font-size: 12px;\n}\n\n.dshc_message:hover .dshc_msgTools, .dshc_message:focus-within .dshc_msgTools, .dshc_msgTools:has(.dshc_msgToolNote) {\n opacity: 1;\n pointer-events: auto;\n}\n\n@media (hover: none) {\n .dshc_message {\n -webkit-touch-callout: none;\n }\n\n .dshc_msgTools {\n display: none;\n }\n\n .dshc_message[data-tools-open] {\n background: var(--dsw-alias-interactive-bg-hover);\n }\n\n .dshc_message[data-tools-open] .dshc_msgTools {\n z-index: 3;\n opacity: 1;\n pointer-events: auto;\n display: inline-flex;\n top: -14px;\n right: 12px;\n }\n\n .dshc_message[data-tools-open] .dshc_msgTool {\n width: 40px;\n height: 36px;\n }\n}\n\n.dshc_replyBar {\n border-radius: var(--dsw-radius-sm);\n color: var(--dsw-alias-label-tertiary);\n background: var(--dsw-alias-bg-layer-2);\n align-items: center;\n gap: 8px;\n margin-bottom: 6px;\n padding: 4px 8px;\n font-size: 12px;\n display: flex;\n}\n\n.dshc_replyBarText {\n white-space: nowrap;\n text-overflow: ellipsis;\n flex: 1;\n min-width: 0;\n overflow: hidden;\n}\n\n.dshc_replyCancel {\n color: inherit;\n cursor: pointer;\n background: none;\n border: 0;\n flex: none;\n}\n\n.dshc_working {\n min-height: 20px;\n color: var(--dsw-alias-label-tertiary);\n align-items: center;\n gap: 6px;\n padding: 0 16px;\n font-size: 12px;\n display: flex;\n}\n\n.dshc_composer {\n padding: 0 16px 16px;\n position: relative;\n}\n\n.dshc_composerBox {\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: var(--dsw-radius-xl);\n background: var(--dsw-alias-bg-layer-1, var(--dsw-alias-bg-layer-2));\n box-shadow: var(--dsw-shadow-lv1-blur);\n flex-direction: column;\n display: flex;\n overflow: hidden;\n}\n\n.dshc_composerBox:focus-within {\n border-color: var(--dsw-alias-label-tertiary);\n}\n\n.dshc_composerToolbar {\n flex: none;\n align-items: center;\n gap: 4px;\n padding: 4px 10px 10px;\n display: flex;\n}\n\n.dshc_composerBox > .dshc_replyBar, .dshc_composerBox > .dshc_attachments {\n margin: 10px 14px 0;\n}\n\n.dshc_mentionButton {\n border-radius: var(--dsw-radius-full, 50%);\n width: 32px;\n height: 32px;\n color: var(--dsw-alias-label-secondary);\n font: inherit;\n cursor: pointer;\n background: none;\n border: 0;\n flex: none;\n justify-content: center;\n align-items: center;\n padding: 0;\n font-size: 18px;\n display: inline-flex;\n}\n\n.dshc_mentionButton:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_sendButton {\n border-radius: var(--dsw-radius-full, 50%);\n width: 32px;\n height: 32px;\n color: var(--dsw-alias-label-primary-inverted);\n background: var(--dsw-alias-label-primary);\n font: inherit;\n cursor: pointer;\n border: 0;\n flex: none;\n justify-content: center;\n align-items: center;\n margin-left: auto;\n padding: 0;\n display: inline-flex;\n}\n\n.dshc_sendButton:disabled {\n opacity: .45;\n cursor: default;\n}\n\n.dshc_sendButton:focus-visible, .dshc_mentionButton:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_mentionPopup {\n z-index: 2;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-base);\n max-height: 320px;\n box-shadow: var(--dsw-elevation-panel, 0 8px 24px #0000003d);\n flex-direction: column;\n padding: 6px;\n display: flex;\n position: absolute;\n bottom: calc(100% - 8px);\n left: 16px;\n right: 16px;\n}\n\n.dshc_mentionPopup > [role=\"listbox\"] {\n min-height: 0;\n overflow-y: auto;\n}\n\n.dshc_mentionTitle {\n color: var(--dsw-alias-label-tertiary);\n padding: 4px 8px 6px;\n font-size: 12px;\n font-weight: 600;\n}\n\n.dshc_mentionItem {\n border-radius: var(--dsw-radius-sm);\n cursor: pointer;\n align-items: center;\n gap: 10px;\n padding: 6px 8px;\n display: flex;\n}\n\n.dshc_mentionActive {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_mentionName {\n font-weight: 600;\n}\n\n.dshc_mentionMeta {\n color: var(--dsw-alias-label-tertiary);\n margin-left: auto;\n font-size: 12px;\n}\n\n.dshc_mentionHint {\n border-top: 1px solid var(--dsw-alias-border-l2);\n color: var(--dsw-alias-label-tertiary);\n padding: 6px 8px 2px;\n font-size: 11px;\n}\n\n.dshc_mentionBadge {\n background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #5865f2) 15%, transparent);\n color: var(--dsw-alias-state-business-primary, #5865f2);\n font-weight: 500;\n line-height: inherit;\n vertical-align: baseline;\n -webkit-box-decoration-break: clone;\n box-decoration-break: clone;\n cursor: pointer;\n border-radius: 3px;\n padding: 0 4px;\n transition: background-color .16s cubic-bezier(.2, 0, 0, 1), color .16s cubic-bezier(.2, 0, 0, 1);\n display: inline-block;\n}\n\n.dshc_mentionBadge:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-business-primary, #5865f2) 28%, transparent);\n}\n\n.dshc_sendError {\n color: var(--dsw-alias-state-error-primary);\n margin-bottom: 6px;\n font-size: 12px;\n}\n\n.dshc_inputSurface {\n min-width: 0;\n display: flex;\n position: relative;\n}\n\n.dshc_input, .dshc_inputHighlights {\n box-sizing: border-box;\n width: 100%;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n white-space: pre-wrap;\n overflow-wrap: break-word;\n background: none;\n border: 0;\n border-radius: 0;\n min-width: 0;\n padding: 14px 16px 8px;\n line-height: 1.5;\n}\n\n.dshc_input {\n resize: none;\n field-sizing: content;\n color: #0000;\n min-width: 0;\n min-height: 52px;\n max-height: 40vh;\n caret-color: var(--dsw-alias-label-primary);\n flex: 1;\n}\n\n.dshc_inputHighlights {\n pointer-events: none;\n height: 100%;\n position: absolute;\n inset: 0;\n overflow: hidden;\n}\n\n.dshc_inputHighlights .dshc_inputMention {\n font-weight: inherit;\n cursor: inherit;\n padding: 0;\n display: inline;\n}\n\n.dshc_inputComposing .dshc_input {\n color: var(--dsw-alias-label-primary);\n}\n\n.dshc_inputComposing .dshc_inputHighlights {\n visibility: hidden;\n}\n\n@media (forced-colors: active) {\n .dshc_input {\n color: canvastext;\n caret-color: canvastext;\n }\n\n .dshc_inputHighlights {\n display: none;\n }\n}\n\n.dshc_input::placeholder {\n color: var(--dsw-alias-label-tertiary);\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n}\n\n@media (width <= 600px) {\n .dshc_composer {\n padding: 0 8px 8px;\n }\n\n .dshc_composerToolbar {\n padding: 4px 8px 8px;\n }\n\n .dshc_input, .dshc_inputHighlights {\n padding: 12px 14px 8px;\n }\n}\n\n.dshc_input:focus-visible {\n outline: none;\n}\n\n.dshc_member {\n border-radius: var(--dsw-radius-sm);\n min-width: 0;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border: 0;\n flex: 1;\n align-items: center;\n gap: 10px;\n padding: 5px 8px;\n display: flex;\n}\n\n.dshc_member:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_member:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_offline {\n opacity: .5;\n}\n\n.dshc_memberAvatar {\n position: relative;\n}\n\n.dshc_presence {\n border: 2px solid var(--dsw-alias-bg-layer-2);\n corner-shape: round;\n background: #23a55a;\n border-radius: 50%;\n width: 10px;\n height: 10px;\n position: absolute;\n bottom: -2px;\n right: -2px;\n}\n\n.dshc_offline .dshc_presence {\n background: var(--dsw-alias-label-tertiary);\n}\n\n.dshc_memberText {\n flex-direction: column;\n min-width: 0;\n display: flex;\n}\n\n.dshc_memberName {\n align-items: center;\n gap: 6px;\n display: flex;\n}\n\n.dshc_memberStatus {\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n}\n\n@media (width <= 900px) {\n .dshc_page {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .dshc_rooms, .dshc_members {\n display: none;\n }\n}\n\n.dshc_groupHead {\n justify-content: space-between;\n align-items: center;\n padding-right: 4px;\n display: flex;\n}\n\n.dshc_iconButton {\n border-radius: var(--dsw-radius-sm);\n width: 22px;\n height: 22px;\n color: var(--dsw-alias-label-tertiary);\n font: inherit;\n cursor: pointer;\n background: none;\n border: 0;\n font-size: 16px;\n line-height: 1;\n}\n\n.dshc_iconButton:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_roomInput, .dshc_fieldInput {\n box-sizing: border-box;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm);\n width: 100%;\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-base);\n font: inherit;\n padding: 6px 8px;\n}\n\n.dshc_roomInput {\n margin: 2px 0 6px;\n}\n\n.dshc_roomInput:focus-visible, .dshc_fieldInput:focus-visible, .dshc_iconButton:focus-visible, .dshc_linkButton:focus-visible, .dshc_addMemberButton:focus-visible, .dshc_primaryButton:focus-visible, .dshc_secondaryButton:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_addMemberButton {\n box-sizing: border-box;\n border: 1px dashed var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm);\n width: 100%;\n color: var(--dsw-alias-label-secondary);\n font: inherit;\n cursor: pointer;\n background: none;\n margin: 4px 0;\n padding: 7px 8px;\n}\n\n.dshc_addMemberButton:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_settingsDivider {\n border: 0;\n border-top: 1px solid var(--dsw-alias-border-l1);\n width: 100%;\n margin: 8px 0 4px;\n}\n\n.dshc_memberListDivider {\n border: 0;\n border-top: 1px solid var(--dsw-alias-border-l1);\n width: calc(100% - 16px);\n margin: 12px 8px 2px;\n}\n\n.dshc_settingsButton {\n text-align: left;\n border-style: solid;\n border-color: #0000;\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.dshc_settingsButton svg {\n flex: none;\n}\n\n.dshc_memberRow {\n border-radius: var(--dsw-radius-sm);\n align-items: center;\n display: flex;\n position: relative;\n}\n\n.dshc_memberRow:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_memberRow .dshc_member:hover {\n background: none;\n}\n\n.dshc_memberModel {\n color: var(--dsw-alias-label-tertiary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 11px;\n overflow: hidden;\n}\n\n.dshc_memberActions {\n color: var(--dsw-alias-label-tertiary);\n opacity: 0;\n flex: none;\n gap: 4px;\n padding-right: 6px;\n font-size: 12px;\n display: flex;\n}\n\n.dshc_memberRow:hover .dshc_memberActions, .dshc_memberRow:focus-within .dshc_memberActions {\n opacity: 1;\n}\n\n.dshc_linkButton {\n border-radius: var(--dsw-radius-xs);\n color: var(--dsw-alias-label-secondary);\n font: inherit;\n cursor: pointer;\n background: none;\n border: 0;\n padding: 2px 4px;\n font-size: 12px;\n}\n\n.dshc_linkButton:hover {\n color: var(--dsw-alias-label-primary);\n text-decoration: underline;\n}\n\n.dshc_dialogBackdrop {\n z-index: 10;\n background: #00000073;\n place-items: center;\n padding: 16px;\n display: grid;\n position: fixed;\n inset: 0;\n}\n\n.dshc_dialog {\n box-sizing: border-box;\n border-radius: var(--dsw-radius-lg);\n width: min(460px, 100%);\n max-height: calc(100vh - 32px);\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-base);\n box-shadow: var(--dsw-elevation-panel, 0 12px 32px #0000004d);\n flex-direction: column;\n gap: 12px;\n padding: 20px;\n display: flex;\n overflow-y: auto;\n}\n\n.dshc_settingsDialog {\n box-sizing: border-box;\n height: min(70vh, 100dvh - 32px);\n max-height: calc(100dvh - 32px);\n overflow: hidden;\n}\n\n.dshc_settingsBody {\n overscroll-behavior: contain;\n flex: auto;\n min-height: 0;\n padding: 2px;\n overflow-y: auto;\n}\n\n.dshc_settingsDialog > :not(.dshc_settingsBody) {\n flex-shrink: 0;\n}\n\n.dshc_settingsFields {\n flex-direction: column;\n gap: 12px;\n display: flex;\n}\n\n.dshc_settingsFeedback {\n overflow-wrap: anywhere;\n max-height: 20%;\n overflow-y: auto;\n}\n\n.dshc_settingsDialog .dshc_dialogActions {\n justify-content: space-between;\n}\n\n@media (width <= 599px) {\n .dshc_settingsDialog {\n height: calc(100dvh - 32px);\n padding: 16px;\n }\n}\n\n.dshc_avatarCropStage {\n background: #000000a6;\n padding: 20px;\n}\n\n.dshc_avatarCropFrame {\n aspect-ratio: 1;\n touch-action: none;\n cursor: grab;\n outline: 2px solid #fff;\n width: min(256px, 100%);\n margin: auto;\n position: relative;\n overflow: hidden;\n}\n\n.dshc_avatarCropFrame:active {\n cursor: grabbing;\n}\n\n.dshc_avatarCropFrame img {\n pointer-events: none;\n user-select: none;\n max-width: none;\n position: absolute;\n}\n\n.dshc_dialogTitle {\n margin: 0;\n font-size: 16px;\n}\n\n.dshc_field {\n color: var(--dsw-alias-label-secondary);\n flex-direction: column;\n gap: 4px;\n font-size: 12px;\n display: flex;\n}\n\n.dshc_field textarea {\n resize: vertical;\n}\n\n.dshc_choiceRow {\n flex-wrap: wrap;\n gap: 12px;\n display: flex;\n}\n\n.dshc_choiceColumn {\n flex-direction: column;\n gap: 12px;\n display: flex;\n}\n\n.dshc_choiceColumn .dshc_choice {\n grid-template-columns: max-content minmax(0, 1fr);\n align-items: start;\n display: grid;\n}\n\n.dshc_choice {\n color: var(--dsw-alias-label-primary, inherit);\n cursor: pointer;\n align-items: center;\n gap: 4px;\n font-size: 13px;\n display: inline-flex;\n}\n\n.dshc_dialogActions {\n justify-content: flex-end;\n gap: 8px;\n display: flex;\n}\n\n.dshc_primaryButton, .dshc_secondaryButton {\n border-radius: var(--dsw-radius-sm);\n font: inherit;\n cursor: pointer;\n padding: 7px 14px;\n}\n\n.dshc_primaryButton {\n color: #fff;\n background: var(--dsw-alias-state-business-primary);\n border: 0;\n}\n\n.dshc_primaryButton:disabled {\n cursor: not-allowed;\n opacity: .5;\n}\n\n.dshc_secondaryButton {\n border: 1px solid var(--dsw-alias-border-l2);\n color: var(--dsw-alias-label-primary);\n background: none;\n}\n\n.dshc_memberFailed .dshc_memberStatus {\n color: var(--dsw-alias-state-error-primary, #ed4245);\n}\n\n.dshc_memberFailed .dshc_presence {\n background: #ed4245;\n}\n\n.dshc_mobileButton, .dshc_drawerBackdrop {\n display: none;\n}\n\n.dshc_panelToggle {\n border-radius: var(--dsw-radius-sm);\n width: 28px;\n height: 28px;\n color: var(--dsw-alias-label-tertiary);\n font: inherit;\n cursor: pointer;\n background: none;\n border: 0;\n justify-content: center;\n align-items: center;\n font-size: 16px;\n line-height: 1;\n display: inline-flex;\n}\n\n.dshc_panelToggle:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_panelToggle:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_panelToggleEnd {\n margin-left: auto;\n}\n\n.dshc_capabilityMenu {\n z-index: 4;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-base);\n max-height: 260px;\n box-shadow: var(--dsw-elevation-panel, 0 8px 24px #0000003d);\n gap: 2px;\n padding: 5px;\n display: grid;\n position: absolute;\n bottom: calc(100% + 4px);\n left: 0;\n right: 0;\n overflow-y: auto;\n}\n\n.dshc_capabilityItem:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_capabilityHelp {\n color: var(--dsw-alias-label-secondary);\n white-space: normal;\n margin: 6px;\n font-size: 12px;\n}\n\n.dshc_capabilityItem:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_capabilityItem {\n text-align: left;\n cursor: pointer;\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n background: none;\n border: 0;\n padding: 5px 8px;\n font-size: 12px;\n font-weight: 400;\n}\n\n@media (width >= 901px) {\n .dshc_page.dshc_roomsHidden {\n grid-template-columns: minmax(0, 1fr) 240px;\n }\n\n .dshc_page.dshc_membersHidden {\n grid-template-columns: 220px minmax(0, 1fr);\n }\n\n .dshc_page.dshc_roomsHidden.dshc_membersHidden {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .dshc_roomsHidden > .dshc_rooms, .dshc_membersHidden > .dshc_members {\n display: none;\n }\n}\n\n@media (width <= 900px) {\n .dshc_page {\n position: relative;\n overflow: hidden;\n }\n\n .dshc_mobileButton {\n min-width: 40px;\n min-height: 40px;\n color: inherit;\n font: inherit;\n cursor: pointer;\n background: none;\n border: 0;\n border-radius: 6px;\n justify-content: center;\n align-items: center;\n display: inline-flex;\n }\n\n .dshc_mobileButton:last-child {\n margin-left: auto;\n }\n\n .dshc_panelToggle {\n display: none;\n }\n\n .dshc_drawerBackdrop {\n z-index: 4;\n background: #00000073;\n border: 0;\n display: block;\n position: absolute;\n inset: 0;\n }\n\n .dshc_rooms.dshc_drawerOpen, .dshc_members.dshc_drawerOpen {\n z-index: 5;\n box-sizing: border-box;\n width: min(280px, 85%);\n display: block;\n position: absolute;\n top: 0;\n bottom: 0;\n box-shadow: 0 0 24px #0000004d;\n }\n\n .dshc_rooms.dshc_drawerOpen {\n left: 0;\n }\n\n .dshc_members.dshc_drawerOpen {\n right: 0;\n }\n\n .dshc_memberActions {\n opacity: 1;\n }\n\n .dshc_messageHead {\n flex-wrap: wrap;\n }\n}\n\n.dshc_avatarPicker {\n flex-wrap: wrap;\n gap: 8px;\n display: flex;\n}\n\n.dshc_avatarOption {\n cursor: pointer;\n background: none;\n border: 2px solid #0000;\n border-radius: 50%;\n padding: 2px;\n display: grid;\n}\n\n.dshc_avatarOption[aria-checked=\"true\"] {\n border-color: var(--dsw-alias-accent, #5865f2);\n}\n\n.dshc_taskBoardTrigger {\n box-sizing: border-box;\n border-radius: var(--dsw-radius-sm);\n width: 100%;\n height: 34px;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border: 0;\n flex: none;\n align-items: center;\n gap: 8px;\n margin: 4px 0;\n padding: 7px 8px;\n font-size: 12px;\n display: flex;\n}\n\n.dshc_taskBoardTrigger:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_taskBoardTrigger:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_taskBoardSummary {\n color: var(--dsw-alias-label-secondary);\n text-align: right;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n overflow: hidden;\n}\n\n.dshc_taskBoardDialog {\n width: min(920px, 100%);\n height: min(70vh, 100dvh - 32px);\n overflow: hidden;\n}\n\n.dshc_taskBoardBody {\n overscroll-behavior: contain;\n flex: auto;\n min-height: 0;\n overflow-y: auto;\n}\n\n.dshc_taskBoardDialog > :not(.dshc_taskBoardBody) {\n flex-shrink: 0;\n}\n\n.dshc_boardTabs {\n border-bottom: 1px solid var(--dsw-alias-border-l2);\n gap: 4px;\n padding-bottom: 8px;\n display: flex;\n overflow-x: auto;\n}\n\n.dshc_boardTabs button {\n border-radius: var(--dsw-radius-sm);\n color: var(--dsw-alias-label-secondary);\n font: inherit;\n cursor: pointer;\n background: none;\n border: 0;\n flex: none;\n padding: 7px 10px;\n font-size: 13px;\n}\n\n.dshc_boardTabs button:hover, .dshc_boardTabs button[aria-selected=\"true\"] {\n color: var(--dsw-alias-state-business-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_boardTabs button:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n outline-offset: -2px;\n}\n\n.dshc_boardTabCount {\n font-variant-numeric: tabular-nums;\n margin-left: 4px;\n}\n\n.dshc_boardCardGrid {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 12px;\n margin: 6px 0 16px;\n padding: 2px;\n list-style: none;\n display: grid;\n}\n\n.dshc_boardTaskCard {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-base);\n border-radius: 12px;\n flex-direction: column;\n gap: 10px;\n min-width: 0;\n padding: 14px;\n transition: transform .14s, box-shadow .14s;\n display: flex;\n}\n\n.dshc_boardTaskCard[data-working=\"true\"] {\n border-color: var(--dsw-alias-state-business-primary);\n}\n\n.dshc_boardTaskCard[data-status=\"done\"] {\n filter: saturate(.25);\n color: var(--dsw-alias-label-secondary);\n}\n\n.dshc_boardTaskCard:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 12px #00000014;\n}\n\n.dshc_boardTaskHeader {\n align-items: flex-start;\n gap: 8px;\n display: flex;\n}\n\n.dshc_boardTaskTitle {\n overflow-wrap: anywhere;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n flex: 1;\n font-size: 14px;\n font-weight: 600;\n line-height: 1.5;\n display: -webkit-box;\n overflow: hidden;\n}\n\n.dshc_boardTaskHeader .dshc_taskStatus {\n border-radius: 999px;\n padding: 3px 7px;\n font-size: 11px;\n}\n\n.dshc_boardTaskCard .dshc_taskLinks {\n justify-content: flex-end;\n margin-top: auto;\n}\n\n.dshc_boardTabEmpty {\n min-height: 240px;\n color: var(--dsw-alias-label-secondary);\n text-align: center;\n justify-content: center;\n align-items: center;\n padding: 40px 16px;\n display: flex;\n}\n\n@media (width <= 640px) {\n .dshc_boardCardGrid {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dshc_boardTaskCard {\n transition: none;\n }\n\n .dshc_boardTaskCard:hover {\n transform: none;\n }\n}\n\n.dshc_taskBoardScope {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n\n.dshc_taskSection + .dshc_taskSection {\n margin-top: 8px;\n}\n\n.dshc_taskSectionTitle {\n color: var(--dsw-alias-label-secondary);\n margin: 0 0 4px;\n padding: 0 8px;\n font-size: 12px;\n font-weight: 600;\n}\n\n.dshc_taskOwnerGroup + .dshc_taskOwnerGroup {\n margin-top: 4px;\n}\n\n.dshc_taskOwnerName {\n color: var(--dsw-alias-label-tertiary);\n padding: 0 8px;\n font-size: 12px;\n}\n\n.dshc_taskList {\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.dshc_taskRow {\n border-radius: var(--dsw-radius-sm);\n padding: 6px 8px;\n}\n\n.dshc_taskRow:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_taskLine {\n align-items: center;\n gap: 6px;\n min-width: 0;\n display: flex;\n}\n\n.dshc_taskTitle {\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 13px;\n overflow: hidden;\n}\n\n.dshc_taskMeta {\n color: var(--dsw-alias-label-tertiary);\n flex-wrap: wrap;\n gap: 0 8px;\n font-size: 12px;\n display: flex;\n}\n\n.dshc_taskLinks {\n gap: 8px;\n display: flex;\n}\n\n.dshc_taskEmpty {\n color: var(--dsw-alias-label-tertiary);\n margin: 0 8px;\n font-size: 12px;\n}\n\n.dshc_taskDone summary {\n cursor: pointer;\n}\n\n.dshc_taskStatus {\n border-radius: var(--dsw-radius-xs);\n color: var(--dsw-alias-label-primary-inverted);\n background: var(--dsw-alias-state-business-primary);\n flex: none;\n padding: 0 4px;\n font-size: 10px;\n font-style: normal;\n font-weight: 600;\n}\n\n.dshc_taskStatus[data-status=\"asked\"], .dshc_taskStatus[data-status=\"escalated\"], .dshc_taskStatus[data-status=\"declined\"], .dshc_taskStatus[data-status=\"rework\"] {\n background: var(--dsw-alias-state-warning-primary, var(--dsw-alias-state-error-primary));\n}\n\n.dshc_taskStatus[data-status=\"done\"] {\n background: var(--dsw-alias-label-tertiary);\n}\n\n.dshc_taskCard {\n margin-top: 4px;\n font-style: normal;\n}\n\n.dshc_taskMembers {\n margin: 4px 0 0;\n padding: 0;\n list-style: none;\n}\n\n.dshc_taskMember {\n align-items: center;\n gap: 8px;\n font-size: 13px;\n display: flex;\n}\n\n.dshc_taskMemberName {\n font-weight: 600;\n}\n\n.dshc_taskSub {\n color: var(--dsw-alias-label-secondary);\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.dshc_focused {\n background: var(--dsw-alias-interactive-bg-hover);\n outline: 2px solid var(--dsw-alias-state-business-primary);\n}\n\n.dshc_attachments {\n flex-wrap: wrap;\n gap: 6px;\n margin: 4px 0;\n display: flex;\n}\n\n.dshc_attachmentImage {\n border-radius: 4px;\n max-width: min(320px, 100%);\n max-height: 240px;\n display: block;\n}\n\n.dshc_imageAttachment {\n align-content: start;\n max-width: 100%;\n display: grid;\n}\n\n.dshc_imagePreviewTrigger {\n cursor: zoom-in;\n background: none;\n border: 0;\n border-radius: 4px;\n grid-area: 1 / 1;\n padding: 0;\n}\n\n.dshc_imagePreviewTrigger:focus-visible {\n outline: 2px solid var(--dsw-alias-state-business-primary);\n outline-offset: 2px;\n}\n\n.dshc_imagePreviewDialog {\n box-sizing: border-box;\n width: fit-content;\n max-width: 90vw;\n max-height: 90dvh;\n overflow: auto;\n}\n\n.dshc_imagePreviewHeader {\n flex-shrink: 0;\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n display: flex;\n}\n\n.dshc_imagePreviewHeader span {\n overflow-wrap: anywhere;\n min-width: 0;\n}\n\n.dshc_imagePreviewHeader button {\n flex-shrink: 0;\n}\n\n.dshc_imagePreviewImage {\n object-fit: contain;\n align-self: center;\n max-width: 100%;\n min-height: 0;\n max-height: 65dvh;\n display: block;\n}\n\n.dshc_imagePreviewActions {\n flex-wrap: wrap;\n flex-shrink: 0;\n gap: 8px;\n display: flex;\n}\n\n.dshc_imagePreviewActions a {\n text-decoration: none;\n}\n\n.dshc_imagePreviewActions button:disabled {\n cursor: wait;\n opacity: .5;\n}\n\n.dshc_attachmentActions {\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-bg-base);\n opacity: 0;\n pointer-events: none;\n flex-wrap: wrap;\n grid-area: 1 / 1;\n place-self: start end;\n gap: 4px;\n margin: 4px;\n padding: 4px;\n display: flex;\n}\n\n.dshc_attachmentActions a {\n text-decoration: none;\n}\n\n.dshc_attachmentActions button:disabled {\n cursor: wait;\n opacity: .5;\n}\n\n.dshc_imageAttachment:hover .dshc_attachmentActions, .dshc_imageAttachment:focus-within .dshc_attachmentActions, .dshc_imageAttachment[data-copy-state=\"error\"] .dshc_attachmentActions, .dshc_imageAttachment[data-copy-state=\"copying\"] .dshc_attachmentActions, .dshc_imageAttachment[data-copy-state=\"copied\"] .dshc_attachmentActions {\n opacity: 1;\n pointer-events: auto;\n}\n\n@media (hover: none), (pointer: coarse), (width <= 768px) {\n .dshc_attachmentActions {\n opacity: 1;\n pointer-events: auto;\n }\n}\n\n.dshc_attachmentThumb {\n object-fit: cover;\n vertical-align: middle;\n border-radius: 3px;\n width: 32px;\n height: 32px;\n}\n\n.dshc_attachmentFile {\n background: var(--background-secondary, #7f7f7f26);\n color: inherit;\n border-radius: 4px;\n align-items: center;\n gap: 4px;\n padding: 4px 8px;\n text-decoration: none;\n display: inline-flex;\n}\n\n.dshc_attachmentSize {\n opacity: .6;\n font-size: .85em;\n}\n\n.dshc_attachmentAudio {\n flex-direction: column;\n gap: 2px;\n width: min(320px, 100%);\n display: flex;\n}\n\n.dshc_attachmentAudio audio {\n width: 100%;\n}\n\n.dshc_attachmentAudio a {\n color: inherit;\n text-decoration: none;\n}\n\n.dshc_attachmentFile {\n overflow-wrap: anywhere;\n max-width: 100%;\n}\n\n.dshc_uploadBar {\n background: var(--dsw-alias-border-l2);\n border-radius: 2px;\n flex: 80px;\n min-width: 60px;\n height: 4px;\n overflow: hidden;\n}\n\n.dshc_uploadFill {\n background: var(--dsw-alias-state-business-primary);\n height: 100%;\n transition: width .12s linear;\n display: block;\n}\n\n.dshc_uploadState {\n opacity: .7;\n white-space: nowrap;\n font-size: .85em;\n}\n\n.dshc_attachmentFile[data-state=\"failed\"] {\n color: var(--dsw-alias-state-error-primary);\n}\n\n.dshc_attachmentFile[data-state=\"failed\"] .dshc_uploadState {\n opacity: 1;\n}\n\n.dshc_chatHead button, .dshc_chatHead input, .dshc_chatHead select, .dshc_chatHead a, .dshc_chatHead [role=\"menu\"] {\n -webkit-app-region: no-drag;\n}\n\n.dshc_text pre, .dshc_text table {\n max-width: 100%;\n overflow-x: auto;\n}\n\n@media (width >= 901px) {\n .dshc_page {\n grid-template-columns: 232px minmax(0, 1fr) 272px;\n }\n\n .dshc_page.dshc_roomsHidden {\n grid-template-columns: minmax(0, 1fr) 272px;\n }\n\n .dshc_page.dshc_membersHidden {\n grid-template-columns: 232px minmax(0, 1fr);\n }\n\n .dshc_page.dshc_roomsHidden.dshc_membersHidden {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n.dshc_rooms {\n padding-top: 4px;\n}\n\n.dshc_room {\n border-radius: var(--dsw-radius-md);\n min-height: 34px;\n padding: 6px 10px;\n transition: background-color .15s, color .15s;\n}\n\n.dshc_workspace {\n min-height: 30px;\n padding-left: 28px;\n font-size: 13px;\n position: relative;\n}\n\n.dshc_workspace:before {\n content: \"\";\n border-left: 1px solid var(--dsw-alias-border-l2);\n border-bottom: 1px solid var(--dsw-alias-border-l2);\n border-bottom-left-radius: 4px;\n width: 7px;\n position: absolute;\n top: 0;\n bottom: 50%;\n left: 15px;\n}\n\n.dshc_workspace .dshc_hash {\n display: none;\n}\n\n.dshc_roomActive {\n color: var(--dsw-alias-label-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-business-primary) 14%, transparent);\n box-shadow: inset 2px 0 0 var(--dsw-alias-state-business-primary);\n font-weight: 600;\n}\n\n.dshc_activeCount {\n font-variant-numeric: tabular-nums;\n border-radius: 999px;\n margin-left: 0;\n padding: 0 6px;\n font-size: 11px;\n line-height: 18px;\n}\n\n.dshc_activeBusy {\n color: var(--dsw-alias-state-business-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-business-primary) 14%, transparent);\n}\n\n.dshc_roomLabel {\n flex: auto;\n min-width: 0;\n}\n\n.dshc_avatarStack {\n flex: none;\n align-items: center;\n padding-left: 4px;\n display: inline-flex;\n}\n\n.dshc_stackDot {\n border: 2px solid var(--dsw-alias-bg-layer-2);\n background-position: center;\n background-size: cover;\n border-radius: 50%;\n width: 18px;\n height: 18px;\n margin-left: -6px;\n}\n\n.dshc_room .dshc_stackDot {\n width: 16px;\n height: 16px;\n}\n\n.dshc_roomActive .dshc_stackDot {\n border-color: color-mix(in srgb, var(--dsw-alias-state-business-primary) 14%, var(--dsw-alias-bg-layer-2));\n}\n\n.dshc_chatHead {\n gap: 8px;\n height: 52px;\n}\n\n.dshc_roomName {\n letter-spacing: -.01em;\n white-space: nowrap;\n font-size: 15px;\n}\n\n.dshc_headMeta {\n color: var(--dsw-alias-label-tertiary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n font-weight: 400;\n overflow: hidden;\n}\n\n.dshc_headActivity {\n color: var(--dsw-alias-label-secondary);\n flex: none;\n align-items: center;\n gap: 6px;\n margin-left: auto;\n font-size: 12px;\n font-weight: 500;\n display: inline-flex;\n}\n\n.dshc_headActivity .dshc_stackDot {\n border-color: var(--dsw-alias-bg-base);\n width: 22px;\n height: 22px;\n}\n\n.dshc_headActivity + .dshc_panelToggleEnd {\n margin-left: 4px;\n}\n\n.dshc_chatHead > .dshc_roomName {\n text-overflow: ellipsis;\n min-width: 0;\n overflow: hidden;\n}\n\n.dshc_chatHead > .dshc_taskBoardTrigger {\n width: auto;\n margin: 0 0 0 auto;\n}\n\n.dshc_chatHead .dshc_taskBoardSummary {\n display: none;\n}\n\n.dshc_headLead {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n border-radius: 999px;\n flex: 0 auto;\n align-items: center;\n gap: 6px;\n min-width: 0;\n padding: 4px 8px;\n font-size: 12px;\n display: inline-flex;\n}\n\n.dshc_headLeadText {\n flex-direction: column;\n min-width: 0;\n display: flex;\n}\n\n.dshc_headLeadName {\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.dshc_headLeadStatus {\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n font-size: 11px;\n font-weight: 400;\n}\n\n.dshc_headLead + .dshc_panelToggleEnd {\n margin-left: 0;\n}\n\n.dshc_membersHead {\n align-items: center;\n height: 52px;\n padding: 0 4px;\n display: flex;\n}\n\n.dshc_membersHeadTitle {\n color: var(--dsw-alias-label-tertiary);\n letter-spacing: .08em;\n font-size: 11px;\n font-weight: 650;\n}\n\n.dshc_log {\n padding: 12px 0 16px;\n}\n\n.dshc_message {\n grid-template-columns: 36px minmax(0, 1fr);\n gap: 12px;\n padding: 8px 20px 2px;\n transition: background-color .15s;\n}\n\n.dshc_message.dshc_grouped {\n padding-top: 1px;\n}\n\n.dshc_message:hover {\n background: color-mix(in srgb, var(--dsw-alias-interactive-bg-hover) 70%, transparent);\n}\n\n.dshc_messageHead {\n gap: 8px;\n margin-bottom: 2px;\n}\n\n.dshc_messageHeadGrouped {\n margin-bottom: 0;\n}\n\n.dshc_messageHeadGrouped:not(:has(*)) {\n display: none;\n}\n\n.dshc_author {\n font-size: 13px;\n}\n\n.dshc_time, .dshc_edited {\n font-variant-numeric: tabular-nums;\n font-size: 11px;\n}\n\n.dshc_gutterTime {\n color: var(--dsw-alias-label-tertiary);\n font-variant-numeric: tabular-nums;\n text-align: right;\n opacity: 0;\n align-self: start;\n padding-top: 3px;\n font-size: 10px;\n transition: opacity .15s;\n}\n\n.dshc_message:hover .dshc_gutterTime {\n opacity: 1;\n}\n\n.dshc_text {\n line-height: 1.6;\n}\n\n.dshc_own {\n grid-template-columns: minmax(0, 1fr) 36px;\n}\n\n.dshc_own > :first-child {\n grid-area: 1 / 2;\n}\n\n.dshc_own > .dshc_messageBody {\n flex-direction: column;\n grid-area: 1 / 1;\n align-items: flex-end;\n display: flex;\n}\n\n.dshc_own .dshc_messageHead {\n flex-direction: row-reverse;\n}\n\n.dshc_own .dshc_ownActions {\n margin-left: 0;\n margin-right: auto;\n}\n\n.dshc_own > .dshc_messageBody > .dshc_text {\n max-width: min(560px, 100%);\n color: var(--dsw-alias-label-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-business-primary) 16%, var(--dsw-alias-bg-layer-2));\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--dsw-alias-state-business-primary) 28%, transparent);\n border-radius: 16px 6px 16px 16px;\n padding: 8px 14px;\n}\n\n.dshc_own > .dshc_messageBody > .dshc_quote {\n align-self: flex-end;\n}\n\n.dshc_own .dshc_msgTools {\n left: 16px;\n right: auto;\n}\n\n.dshc_own.dshc_grouped > .dshc_messageBody > .dshc_text {\n border-radius: 16px 6px 6px 16px;\n}\n\n.dshc_systemRecord {\n flex-direction: column;\n align-items: center;\n padding-bottom: 4px;\n display: flex;\n}\n\n.dshc_systemRecord > .dshc_systemLine {\n align-self: stretch;\n}\n\n.dshc_taskRecord {\n box-sizing: border-box;\n width: min(480px, 100% - 40px);\n margin-top: 0;\n}\n\n.dshc_systemLine {\n color: var(--dsw-alias-label-tertiary);\n align-items: center;\n gap: 12px;\n padding: 10px 32px;\n font-size: 12px;\n display: flex;\n}\n\n.dshc_systemLine:before, .dshc_systemLine:after {\n content: \"\";\n background: var(--dsw-alias-border-l2);\n flex: 24px;\n min-width: 24px;\n height: 1px;\n}\n\n.dshc_systemText {\n text-align: center;\n max-width: min(640px, 80%);\n}\n\n.dshc_systemText p {\n margin: 0;\n}\n\n.dshc_errorBar {\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 35%, transparent);\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 9%, transparent);\n border-radius: 12px;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px 10px;\n margin: 6px 20px 6px 68px;\n padding: 8px 12px;\n font-size: 13px;\n display: flex;\n}\n\n.dshc_errorBar .dshc_cardButtons {\n margin: 0 0 0 auto;\n}\n\n.dshc_errorBar .dshc_secondaryButton {\n padding: 3px 10px;\n font-size: 12px;\n}\n\n.dshc_errorBar[data-state=\"retried\"] {\n opacity: .65;\n}\n\n.dshc_errorIcon {\n color: #fff;\n background: var(--dsw-alias-state-error-primary);\n border-radius: 50%;\n flex: none;\n place-items: center;\n width: 18px;\n height: 18px;\n font-size: 12px;\n font-weight: 700;\n display: grid;\n}\n\n.dshc_errorText {\n min-width: 0;\n color: var(--dsw-alias-label-primary);\n flex: 200px;\n}\n\n.dshc_errorText p {\n margin: 0;\n}\n\n.dshc_runStrip {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-1, var(--dsw-alias-bg-layer-2));\n border-radius: 12px;\n flex-direction: column;\n max-width: 100%;\n margin-top: 4px;\n padding: 5px 10px;\n font-size: 12px;\n display: inline-flex;\n}\n\n.dshc_runStrip[data-state=\"running\"] {\n border-color: color-mix(in srgb, var(--dsw-alias-state-business-primary) 45%, var(--dsw-alias-border-l2));\n}\n\n.dshc_runStrip[data-state=\"failed\"] {\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, var(--dsw-alias-border-l2));\n}\n\n.dshc_runHead {\n min-width: 0;\n color: var(--dsw-alias-label-secondary);\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.dshc_runTitle {\n color: var(--dsw-alias-label-primary);\n flex: none;\n font-weight: 600;\n}\n\n.dshc_runSummary {\n font-variant-numeric: tabular-nums;\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.dshc_runHead .dshc_cardViews {\n margin-left: 8px;\n}\n\n.dshc_runHead .dshc_cardViewButton {\n color: var(--dsw-alias-label-tertiary);\n border-radius: 999px;\n font-size: 11px;\n}\n\n.dshc_runHead .dshc_cardViewButton[aria-pressed=\"true\"] {\n color: var(--dsw-alias-label-primary);\n}\n\n.dshc_runIcon {\n border-radius: 50%;\n flex: none;\n width: 12px;\n height: 12px;\n position: relative;\n}\n\n.dshc_runStrip[data-state=\"running\"] .dshc_runIcon {\n border: 2px solid color-mix(in srgb, var(--dsw-alias-state-business-primary) 25%, transparent);\n border-top-color: var(--dsw-alias-state-business-primary);\n animation: .8s linear infinite dshc_channels-spin;\n}\n\n.dshc_runStrip[data-state=\"completed\"] .dshc_runIcon {\n background: #23a55a;\n}\n\n.dshc_runStrip[data-state=\"completed\"] .dshc_runIcon:after {\n content: \"\";\n border: 1.5px solid #fff;\n border-width: 0 1.5px 1.5px 0;\n width: 3px;\n height: 6px;\n position: absolute;\n top: 2px;\n left: 4px;\n transform: rotate(45deg);\n}\n\n.dshc_runStrip[data-state=\"failed\"] .dshc_runIcon {\n background: var(--dsw-alias-state-error-primary);\n}\n\n.dshc_runSteps {\n color: var(--dsw-alias-label-secondary);\n margin-top: 4px;\n font-size: 12px;\n line-height: 1.55;\n}\n\n.dshc_runSteps p {\n margin: 0;\n}\n\n.dshc_runStrip .dshc_cardButtons {\n margin-top: 6px;\n}\n\n@keyframes dshc_channels-spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dshc_runStrip[data-state=\"running\"] .dshc_runIcon {\n animation-duration: 2.4s;\n }\n}\n\n.dshc_card {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n border-left-width: 1px;\n border-radius: 14px;\n margin-top: 6px;\n padding: 10px 12px;\n}\n\n.dshc_card[data-state=\"failed\"] {\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 40%, var(--dsw-alias-border-l2));\n}\n\n.dshc_taskAnchor {\n max-width: 560px;\n box-shadow: inset 3px 0 0 var(--channels-accent-warm, #d08a2e);\n}\n\n.dshc_permInline {\n color: var(--dsw-alias-label-secondary);\n flex-wrap: wrap;\n align-items: baseline;\n gap: 4px 8px;\n display: flex;\n}\n\n.dshc_permInline .dshc_text {\n flex: 0 auto;\n min-width: 0;\n}\n\n.dshc_permInline .dshc_text p {\n margin: 0;\n}\n\n.dshc_permLock {\n color: var(--dsw-alias-state-warning-primary, #e9a23b);\n flex: none;\n font-size: 9px;\n}\n\n.dshc_permWaiting {\n color: var(--dsw-alias-state-warning-primary, #e9a23b);\n flex: none;\n font-size: 11px;\n font-weight: 600;\n}\n\n.dshc_permTray {\n flex-direction: column;\n gap: 6px;\n max-height: 40%;\n margin: 0 16px 8px;\n display: flex;\n overflow-y: auto;\n}\n\n.dshc_permTrayItem {\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warning-primary, #e9a23b) 55%, var(--dsw-alias-border-l2));\n background: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #e9a23b) 7%, var(--dsw-alias-bg-layer-2));\n border-radius: 14px;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px 12px;\n padding: 10px 12px;\n display: flex;\n box-shadow: 0 6px 20px -12px #00000059;\n}\n\n.dshc_permTrayText {\n flex: 240px;\n min-width: 0;\n font-size: 13px;\n}\n\n.dshc_permTrayText .dshc_text p {\n margin: 0;\n}\n\n.dshc_permTrayWho {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n font-weight: 600;\n}\n\n.dshc_permTrayItem .dshc_permActions {\n flex-wrap: nowrap;\n margin: 0;\n}\n\n.dshc_permTrayItem .dshc_permScope {\n display: none;\n}\n\n.dshc_members {\n flex-direction: column;\n padding: 0 10px 16px;\n}\n\n@media (width >= 901px) {\n .dshc_members {\n display: flex;\n }\n\n .dshc_membersHidden > .dshc_members {\n display: none;\n }\n}\n\n.dshc_members.dshc_drawerOpen {\n display: flex;\n}\n\n.dshc_activityNow {\n flex-direction: column;\n gap: 2px;\n margin-bottom: 6px;\n display: flex;\n}\n\n.dshc_activityItem {\n border: 1px solid var(--dsw-alias-border-l2);\n width: 100%;\n color: inherit;\n background: var(--dsw-alias-bg-base);\n font: inherit;\n text-align: left;\n cursor: pointer;\n border-radius: 12px;\n align-items: center;\n gap: 10px;\n padding: 8px 10px;\n display: flex;\n}\n\n.dshc_activityItem + .dshc_activityItem {\n margin-top: 4px;\n}\n\n.dshc_activityItem:hover {\n border-color: color-mix(in srgb, var(--dsw-alias-state-business-primary) 40%, var(--dsw-alias-border-l2));\n}\n\n.dshc_activityItem:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_activityText {\n flex-direction: column;\n flex: 1;\n min-width: 0;\n display: flex;\n}\n\n.dshc_activityName {\n font-size: 13px;\n font-weight: 600;\n}\n\n.dshc_activityWhat {\n color: var(--dsw-alias-label-tertiary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n overflow: hidden;\n}\n\n.dshc_activityPulse {\n background: var(--dsw-alias-state-business-primary);\n border-radius: 50%;\n flex: none;\n width: 8px;\n height: 8px;\n animation: 1.6s ease-in-out infinite dshc_channels-pulse;\n}\n\n@keyframes dshc_channels-pulse {\n 50% {\n box-shadow: 0 0 0 3px #23a55a40;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dshc_activityPulse {\n animation: none;\n }\n}\n\n.dshc_member {\n padding: 6px 8px;\n}\n\n.dshc_memberText {\n flex: 1;\n}\n\n.dshc_memberStatus {\n flex: none;\n margin-left: auto;\n font-size: 11px;\n}\n\n.dshc_memberStatus[data-status=\"busy\"] {\n color: var(--dsw-alias-state-business-primary);\n font-weight: 600;\n}\n\n.dshc_memberStatus[data-status=\"error\"] {\n color: var(--dsw-alias-state-error-primary);\n font-weight: 600;\n}\n\n.dshc_memberActions {\n background: var(--dsw-alias-bg-layer-2);\n padding-left: 8px;\n position: absolute;\n top: 50%;\n right: 8px;\n transform: translateY(-50%);\n}\n\n.dshc_addMemberButton {\n border-radius: 10px;\n}\n\n@media (width <= 900px) {\n .dshc_headMeta, .dshc_headActivityText {\n display: none;\n }\n\n .dshc_chatHead {\n padding: 0 8px;\n }\n\n .dshc_mobileButton {\n white-space: nowrap;\n }\n\n .dshc_headActivity ~ .dshc_mobileButton:last-child {\n margin-left: 4px;\n }\n\n .dshc_message {\n padding-left: 12px;\n padding-right: 12px;\n }\n\n .dshc_errorBar {\n margin-left: 12px;\n margin-right: 12px;\n }\n\n .dshc_permTray {\n margin: 0 8px 8px;\n }\n\n .dshc_permTrayItem .dshc_permActions {\n flex-wrap: wrap;\n }\n\n .dshc_systemLine {\n padding: 8px 12px;\n }\n\n .dshc_systemText {\n max-width: 90%;\n }\n\n .dshc_memberActions {\n background: none;\n padding-left: 0;\n position: static;\n transform: none;\n }\n}\n\n@keyframes dshc_channelsEnter {\n from {\n opacity: 0;\n transform: translateY(6px);\n }\n\n to {\n opacity: 1;\n transform: none;\n }\n}\n\n@keyframes dshc_channelsEnterOwn {\n from {\n opacity: 0;\n transform: translateY(12px) scale(.985);\n }\n\n to {\n opacity: 1;\n transform: none;\n }\n}\n\n@keyframes dshc_channelsGlow {\n from {\n opacity: 1;\n }\n\n to {\n opacity: 0;\n }\n}\n\n@keyframes dshc_channelsPop {\n from {\n opacity: 0;\n transform: translateY(4px) scale(.98);\n }\n\n to {\n opacity: 1;\n transform: none;\n }\n}\n\n@keyframes dshc_channelsDot {\n 0%, 60%, 100% {\n opacity: .35;\n transform: none;\n }\n\n 30% {\n opacity: 1;\n transform: translateY(-2px);\n }\n}\n\n@keyframes dshc_channelsDrain {\n from {\n transform: scaleX(1);\n }\n\n to {\n transform: scaleX(0);\n }\n}\n\n.dshc_enter {\n animation: .18s cubic-bezier(.2, 0, 0, 1) both dshc_channelsEnter;\n}\n\n.dshc_enterOwn {\n animation: .22s cubic-bezier(.22, 1, .36, 1) both dshc_channelsEnterOwn;\n}\n\n.dshc_enterGlow:before {\n content: \"\";\n pointer-events: none;\n background: linear-gradient(90deg, color-mix(in srgb, var(--dsw-alias-state-business-primary) 10%, transparent), transparent 70%);\n animation: .7s cubic-bezier(.4, 0, .2, 1) both dshc_channelsGlow;\n animation-delay: inherit;\n position: absolute;\n inset: 0;\n}\n\n.dshc_message {\n transition: background-color .16s cubic-bezier(.2, 0, 0, 1);\n}\n\n.dshc_room {\n transition: background-color .16s cubic-bezier(.2, 0, 0, 1), color .16s cubic-bezier(.2, 0, 0, 1);\n}\n\n.dshc_card {\n transition: border-color .32s cubic-bezier(.2, 0, 0, 1), background-color .32s cubic-bezier(.2, 0, 0, 1);\n}\n\n.dshc_sendButton, .dshc_primaryButton, .dshc_secondaryButton, .dshc_mentionButton, .dshc_cardViewButton {\n transition: background-color .16s cubic-bezier(.2, 0, 0, 1), opacity .16s cubic-bezier(.2, 0, 0, 1), transform .12s cubic-bezier(.2, 0, 0, 1);\n}\n\n.dshc_sendButton:not(:disabled):active, .dshc_primaryButton:not(:disabled):active, .dshc_secondaryButton:not(:disabled):active, .dshc_mentionButton:not(:disabled):active, .dshc_cardViewButton:active {\n transform: translateY(1px);\n}\n\n.dshc_mentionPopup {\n transform-origin: bottom;\n animation: .16s cubic-bezier(.22, 1, .36, 1) both dshc_channelsPop;\n}\n\n.dshc_typingDots {\n vertical-align: middle;\n gap: 3px;\n margin-right: 6px;\n display: inline-flex;\n}\n\n.dshc_typingDots i {\n background: currentColor;\n border-radius: 50%;\n width: 4px;\n height: 4px;\n animation: 1.2s ease-in-out infinite dshc_channelsDot;\n}\n\n.dshc_typingDots i:nth-child(2) {\n animation-delay: .15s;\n}\n\n.dshc_typingDots i:nth-child(3) {\n animation-delay: .3s;\n}\n\n.dshc_logWrap {\n flex-direction: column;\n flex: 1;\n min-height: 0;\n display: flex;\n position: relative;\n}\n\n.dshc_olderLoading {\n color: var(--dsw-alias-label-tertiary);\n text-align: center;\n padding: 8px 16px;\n font-size: 12px;\n}\n\n.dshc_unreadDivider {\n color: var(--dsw-alias-state-error-primary);\n align-items: center;\n gap: 8px;\n margin: 8px 16px;\n font-size: 12px;\n font-weight: 600;\n display: flex;\n}\n\n.dshc_unreadDivider:before, .dshc_unreadDivider:after {\n content: \"\";\n opacity: .35;\n background: currentColor;\n flex: 1;\n height: 1px;\n}\n\n.dshc_withdrawnRow {\n text-align: right;\n color: var(--dsw-alias-label-tertiary);\n padding: 6px 16px;\n font-size: 13px;\n font-style: italic;\n animation: .18s cubic-bezier(.2, 0, 0, 1) both dshc_channelsEnter;\n}\n\n.dshc_jumpLatest {\n z-index: 3;\n border: 1px solid var(--dsw-alias-border-l2);\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-base);\n box-shadow: var(--dsw-elevation-panel, 0 8px 24px #00000029);\n font: inherit;\n cursor: pointer;\n border-radius: 999px;\n align-items: center;\n gap: 6px;\n padding: 6px 14px;\n font-size: 12px;\n animation: .22s cubic-bezier(.22, 1, .36, 1) both dshc_channelsPop;\n display: inline-flex;\n position: absolute;\n bottom: 12px;\n left: 50%;\n transform: translateX(-50%);\n}\n\n.dshc_jumpLatest:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_jumpLatest:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_jumpCount {\n color: var(--dsw-alias-state-business-primary);\n font-weight: 600;\n}\n\n.dshc_undoToast {\n z-index: 4;\n border-radius: var(--dsw-radius-md);\n width: max-content;\n max-width: calc(100% - 32px);\n color: var(--dsw-alias-label-primary-inverted);\n background: var(--dsw-alias-label-primary);\n box-shadow: var(--dsw-elevation-panel, 0 8px 24px #0000003d);\n align-items: center;\n gap: 12px;\n margin: 0 auto;\n padding: 8px 8px 8px 14px;\n font-size: 13px;\n animation: .22s cubic-bezier(.22, 1, .36, 1) both dshc_channelsPop;\n display: flex;\n position: absolute;\n bottom: 12px;\n left: 0;\n right: 0;\n overflow: hidden;\n}\n\n.dshc_undoButton {\n border-radius: var(--dsw-radius-sm);\n color: inherit;\n background: color-mix(in srgb, currentColor 16%, transparent);\n font: inherit;\n cursor: pointer;\n border: 0;\n padding: 2px 10px;\n font-weight: 600;\n}\n\n.dshc_undoButton:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_undoBar {\n background: var(--dsw-alias-state-business-primary);\n transform-origin: 0;\n height: 2px;\n animation: linear forwards dshc_channelsDrain;\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n}\n\n.dshc_undoToast ~ .dshc_jumpLatest {\n display: none;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dshc_enter, .dshc_enterOwn, .dshc_enterGlow:before, .dshc_mentionPopup, .dshc_jumpLatest, .dshc_undoToast, .dshc_withdrawnRow {\n animation: none;\n }\n\n .dshc_typingDots i {\n opacity: .6;\n animation: none;\n }\n\n .dshc_undoBar {\n animation: none;\n }\n\n .dshc_message, .dshc_room, .dshc_card, .dshc_sendButton, .dshc_primaryButton, .dshc_secondaryButton, .dshc_mentionButton, .dshc_mentionBadge, .dshc_cardViewButton {\n transition: none;\n }\n}\n\n.dshc_leadCard {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n border-radius: 14px;\n align-items: center;\n gap: 10px;\n margin: 8px 8px 4px;\n display: flex;\n}\n\n.dshc_leadCardButton {\n border-radius: inherit;\n min-width: 0;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border: 0;\n flex: auto;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n display: flex;\n}\n\n.dshc_leadCardButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_leadCardButton:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-alias-border-focus, currentColor);\n outline-offset: -2px;\n}\n\n.dshc_leadCardButton:disabled {\n cursor: default;\n background: none;\n}\n\n.dshc_leadCardText {\n flex-direction: column;\n min-width: 0;\n display: flex;\n}\n\n.dshc_leadCardName {\n color: var(--dsw-alias-label-primary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n font-weight: 650;\n overflow: hidden;\n}\n\n.dshc_leadCardStatus {\n color: var(--dsw-alias-label-secondary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n overflow: hidden;\n}\n\n.dshc_message:not(.dshc_own) > .dshc_messageBody > .dshc_text {\n background: var(--dsw-alias-bg-layer-2);\n border-radius: 6px 16px 16px;\n width: fit-content;\n max-width: min(640px, 100%);\n padding: 8px 14px;\n}\n\n.dshc_message.dshc_grouped:not(.dshc_own) > .dshc_messageBody > .dshc_text {\n border-radius: 6px 16px 16px 6px;\n}\n\n.dshc_own > .dshc_messageBody > .dshc_text {\n color: var(--dsw-alias-bg-base);\n background: var(--dsw-alias-label-primary);\n box-shadow: none;\n}\n\n.dshc_own > .dshc_messageBody > .dshc_text * {\n color: inherit;\n}\n\n.dshc_own > .dshc_messageBody > .dshc_text a {\n color: inherit;\n text-decoration: underline;\n}\n\n.dshc_own > .dshc_messageBody > .dshc_text code {\n color: inherit;\n background: color-mix(in srgb, var(--dsw-alias-bg-base) 18%, transparent);\n}\n\n.dshc_own > .dshc_messageBody > .dshc_text .dshc_mentionBadge {\n color: var(--dsw-alias-bg-base);\n background: color-mix(in srgb, var(--dsw-alias-bg-base) 24%, transparent);\n}\n\n.dshc_own > .dshc_messageBody > .dshc_text .dshc_mentionBadge:hover {\n background: color-mix(in srgb, var(--dsw-alias-bg-base) 36%, transparent);\n}\n\n.dshc_boardDrawerBackdrop {\n background: #00000040;\n place-items: stretch end;\n padding: 0;\n}\n\n.dshc_boardDrawerBackdrop > .dshc_taskBoardDialog {\n box-sizing: border-box;\n border-radius: 0;\n width: min(440px, 100%);\n height: 100dvh;\n max-height: none;\n animation: .2s ease-out dshc_boardDrawerIn;\n}\n\n@keyframes dshc_boardDrawerIn {\n from {\n opacity: 0;\n transform: translateX(24px);\n }\n\n to {\n opacity: 1;\n transform: none;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dshc_boardDrawerBackdrop > .dshc_taskBoardDialog {\n animation: none;\n }\n}\n\n.dshc_schemeToggle {\n border-radius: var(--dsw-radius-sm);\n width: 28px;\n height: 28px;\n color: var(--dsw-alias-label-tertiary);\n font: inherit;\n cursor: pointer;\n background: none;\n border: 0;\n flex: none;\n justify-content: center;\n align-items: center;\n margin-left: 4px;\n font-size: 16px;\n line-height: 1;\n display: inline-flex;\n}\n\n.dshc_schemeToggle:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_schemeToggle:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_schemeToggle + .dshc_panelToggleEnd {\n margin-left: 4px;\n}\n\n.dshc_progressCard {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-base);\n box-shadow: 0 6px 18px #0000000a, 0 -12px 0 0 var(--dsw-alias-bg-base);\n border-radius: 14px;\n flex: none;\n margin: 8px 16px 4px;\n padding: 8px 14px;\n font-size: 12px;\n position: relative;\n}\n\n.dshc_progressHead {\n align-items: center;\n gap: 8px;\n display: flex;\n}\n\n.dshc_progressTitle {\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n}\n\n.dshc_progressSummary {\n white-space: nowrap;\n text-overflow: ellipsis;\n min-width: 0;\n color: var(--dsw-alias-label-tertiary);\n flex: 1;\n overflow: hidden;\n}\n\n.dshc_progressToggle {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-sm);\n min-width: 22px;\n height: 24px;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n cursor: pointer;\n background: none;\n flex: none;\n justify-content: center;\n align-items: center;\n gap: 4px;\n margin-left: auto;\n padding: 0 10px;\n font-size: 12px;\n font-weight: 500;\n line-height: 1;\n display: inline-flex;\n}\n\n.dshc_progressChevron {\n font-size: 12px;\n}\n\n.dshc_progressToggle:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_progressToggle:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_progressCard[data-folded=\"true\"] {\n padding: 6px 12px;\n}\n\n.dshc_progressRows {\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: 0 14px;\n margin: 4px 0 0;\n display: grid;\n}\n\n.dshc_progressRow {\n min-width: 0;\n}\n\n.dshc_progressRow dt {\n color: var(--dsw-alias-label-tertiary);\n font-size: 10px;\n}\n\n.dshc_progressRow dd {\n white-space: nowrap;\n text-overflow: ellipsis;\n min-width: 0;\n color: var(--dsw-alias-label-primary);\n margin: 0;\n overflow: hidden;\n}\n\n.dshc_progressRow[data-empty=\"true\"] dd {\n color: var(--dsw-alias-label-tertiary);\n}\n\n.dshc_progressRow[data-row=\"open\"][data-empty=\"false\"] dd, .dshc_progressRow[data-row=\"open\"] .dshc_progressLink {\n color: var(--dsw-alias-state-warning-primary, #b7791f);\n}\n\n.dshc_progressLink {\n max-width: 100%;\n color: inherit;\n font: inherit;\n text-align: left;\n white-space: nowrap;\n text-overflow: ellipsis;\n cursor: pointer;\n background: none;\n border: 0;\n padding: 0;\n overflow: hidden;\n}\n\n.dshc_progressLink:hover {\n text-decoration: underline;\n}\n\n@media (width <= 760px) {\n .dshc_progressCard {\n margin: 6px 10px 2px;\n }\n\n .dshc_progressRows {\n grid-template-columns: 52px minmax(0, 1fr);\n }\n\n .dshc_progressRow {\n display: contents;\n }\n}\n\n.dshc_stepChips {\n flex-wrap: wrap;\n gap: 6px;\n margin-top: 6px;\n display: flex;\n}\n\n.dshc_stepChip {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-base);\n max-width: 220px;\n color: var(--dsw-alias-label-secondary);\n font: inherit;\n cursor: pointer;\n border-radius: 999px;\n align-items: center;\n gap: 5px;\n padding: 2px 9px 2px 7px;\n font-size: 11px;\n display: inline-flex;\n}\n\n.dshc_stepChip b {\n color: var(--dsw-alias-label-primary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 600;\n overflow: hidden;\n}\n\n.dshc_stepChip:disabled {\n cursor: default;\n}\n\n.dshc_stepChip[aria-expanded=\"true\"] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_stepChip[data-state=\"failed\"] {\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, var(--dsw-alias-border-l2));\n}\n\n.dshc_stepChip[data-state=\"failed\"] b {\n color: var(--dsw-alias-state-error-primary);\n}\n\n.dshc_stepChip[data-state=\"running\"] {\n border-color: color-mix(in srgb, var(--dsw-alias-state-business-primary) 55%, var(--dsw-alias-border-l2));\n}\n\n.dshc_stepMark {\n background: var(--dsw-alias-label-tertiary);\n border-radius: 50%;\n flex: none;\n width: 7px;\n height: 7px;\n}\n\n.dshc_stepChip[data-state=\"ok\"] .dshc_stepMark {\n background: #23a55a;\n}\n\n.dshc_stepChip[data-state=\"failed\"] .dshc_stepMark {\n background: var(--dsw-alias-state-error-primary);\n}\n\n.dshc_stepChip[data-state=\"running\"] .dshc_stepMark {\n background: var(--dsw-alias-state-business-primary);\n animation: 1s ease-in-out infinite dshc_channels-blink;\n}\n\n@keyframes dshc_channels-blink {\n 50% {\n opacity: .3;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dshc_stepChip[data-state=\"running\"] .dshc_stepMark {\n animation: none;\n }\n}\n\n.dshc_stepOut {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-base));\n color: var(--dsw-alias-label-secondary);\n border-radius: 8px;\n flex-basis: 100%;\n gap: 4px;\n padding: 8px 10px;\n font-size: 11px;\n line-height: 1.5;\n display: grid;\n}\n\n.dshc_stepOut[data-state=\"failed\"] {\n border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, var(--dsw-alias-border-l2));\n}\n\n.dshc_stepOut div {\n gap: 8px;\n min-width: 0;\n display: flex;\n}\n\n.dshc_stepOut span {\n color: var(--dsw-alias-label-tertiary);\n flex: none;\n}\n\n.dshc_stepOut code {\n overflow-wrap: anywhere;\n min-width: 0;\n font-family: ui-monospace, Menlo, monospace;\n}\n\n.dshc_stepOut[data-state=\"failed\"] > div[data-state=\"failed\"] > div:last-child > code {\n color: var(--dsw-alias-state-error-primary);\n}\n\n.dshc_decideTray {\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warning-primary, #e9a23b) 55%, var(--dsw-alias-border-l2));\n background: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #e9a23b) 7%, var(--dsw-alias-bg-layer-2));\n border-radius: 14px;\n flex-direction: column;\n max-height: 45%;\n margin: 0 16px 8px;\n display: flex;\n overflow-y: auto;\n}\n\n.dshc_decideTrayHead {\n width: 100%;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n background: none;\n border: 0;\n flex: none;\n align-items: baseline;\n gap: 8px;\n padding: 7px 12px;\n font-size: 12px;\n display: flex;\n}\n\n.dshc_decideTrayHead strong {\n color: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #e9a23b) 70%, var(--dsw-alias-label-primary));\n}\n\n.dshc_decideTrayHead small {\n color: var(--dsw-alias-label-secondary);\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.dshc_decideTrayHead:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n outline-offset: -2px;\n}\n\n.dshc_decideTrayToggle {\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n margin-left: auto;\n}\n\n.dshc_decideTray .dshc_permTray {\n max-height: none;\n margin: 0;\n padding: 0 8px 8px;\n}\n\n.dshc_askList {\n flex-direction: column;\n display: flex;\n}\n\n.dshc_askItem {\n border-top: 1px solid color-mix(in srgb, var(--dsw-alias-state-warning-primary, #e9a23b) 30%, transparent);\n background: var(--dsw-alias-bg-layer-2);\n flex-wrap: wrap;\n align-items: center;\n gap: 6px 10px;\n padding: 8px 12px;\n display: flex;\n}\n\n.dshc_askKind {\n color: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #e9a23b) 75%, var(--dsw-alias-label-primary));\n background: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #e9a23b) 15%, transparent);\n border-radius: 5px;\n flex: none;\n padding: 0 6px;\n font-size: 11px;\n}\n\n.dshc_askText {\n flex-direction: column;\n flex: 200px;\n min-width: 0;\n font-size: 13px;\n display: flex;\n}\n\n.dshc_askQuestion {\n overflow-wrap: anywhere;\n}\n\n.dshc_askFrom {\n color: var(--dsw-alias-label-secondary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 11px;\n overflow: hidden;\n}\n\n.dshc_askForm {\n flex: 0 260px;\n align-items: center;\n gap: 6px;\n min-width: 160px;\n display: flex;\n}\n\n.dshc_askInput {\n border: 1px solid var(--dsw-alias-border-l2);\n min-width: 0;\n color: inherit;\n background: var(--dsw-alias-bg-base);\n font: inherit;\n border-radius: 8px;\n flex: 1;\n padding: 4px 8px;\n font-size: 12px;\n}\n\n.dshc_askInput:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n}\n\n.dshc_askSend {\n width: 26px;\n height: 26px;\n color: var(--dsw-alias-bg-base);\n background: var(--dsw-alias-label-primary);\n cursor: pointer;\n border: 0;\n border-radius: 50%;\n flex: none;\n justify-content: center;\n align-items: center;\n padding: 0;\n display: inline-flex;\n}\n\n.dshc_askSend:disabled {\n opacity: .3;\n cursor: default;\n}\n\n.dshc_askSend:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color);\n outline-offset: 2px;\n}\n\n.dshc_askDone {\n color: var(--dsw-alias-label-secondary);\n align-items: center;\n gap: 8px;\n font-size: 12px;\n display: inline-flex;\n}\n\n.dshc_askNotice {\n color: color-mix(in srgb, var(--dsw-alias-state-warning-primary, #e9a23b) 75%, var(--dsw-alias-label-primary));\n flex-basis: 100%;\n font-size: 12px;\n}\n\n@media (width <= 900px) {\n .dshc_decideTray {\n margin: 0 8px 8px;\n }\n\n .dshc_askForm {\n flex-basis: 100%;\n }\n}\n\n.dshc_headTeam {\n flex: none;\n align-items: center;\n margin-left: auto;\n display: inline-flex;\n}\n\n.dshc_mate, .dshc_mateMore {\n border: 2px solid var(--dsw-alias-bg-base);\n background: var(--dsw-alias-bg-base);\n cursor: pointer;\n border-radius: 50%;\n justify-content: center;\n align-items: center;\n margin-left: -6px;\n padding: 0;\n display: inline-flex;\n position: relative;\n}\n\n.dshc_mate:first-child {\n margin-left: 0;\n}\n\n.dshc_mate .dshc_avatar {\n margin: 0;\n}\n\n.dshc_mateMore {\n background: var(--dsw-alias-interactive-bg-hover);\n width: 28px;\n height: 28px;\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n font-weight: 600;\n}\n\n.dshc_mateDot {\n box-sizing: border-box;\n border: 2px solid var(--dsw-alias-bg-base);\n background: var(--dsw-alias-label-tertiary);\n border-radius: 50%;\n width: 9px;\n height: 9px;\n position: absolute;\n bottom: -2px;\n right: -2px;\n}\n\n.dshc_mate[data-state=\"busy\"] .dshc_mateDot {\n background: #23a55a;\n animation: 1.6s ease-in-out infinite dshc_channels-pulse;\n}\n\n.dshc_mate[data-state=\"idle\"] .dshc_mateDot {\n background: var(--dsw-alias-bg-base);\n box-shadow: inset 0 0 0 1.5px var(--dsw-alias-label-tertiary);\n}\n\n.dshc_mate[data-state=\"error\"] .dshc_mateDot {\n background: var(--dsw-alias-state-error-primary);\n}\n\n.dshc_mate[data-state=\"offline\"] {\n opacity: .55;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dshc_mate[data-state=\"busy\"] .dshc_mateDot {\n animation: none;\n }\n}\n\n@media (width <= 760px) {\n .dshc_headTeam {\n display: none;\n }\n}\n\n.dshc_chatHead > .dshc_headTeam + .dshc_taskBoardTrigger {\n margin-left: 12px;\n}\n\n.dshc_sideDock {\n display: none;\n}\n\n@media (width >= 1101px) {\n .dshc_page.dshc_panelOpen {\n grid-template-columns: 220px minmax(0, 1fr) min(420px, 36%) 240px;\n }\n\n .dshc_page.dshc_panelOpen.dshc_roomsHidden {\n grid-template-columns: minmax(0, 1fr) min(420px, 36%) 240px;\n }\n\n .dshc_page.dshc_panelOpen.dshc_membersHidden {\n grid-template-columns: 220px minmax(0, 1fr) min(420px, 36%);\n }\n\n .dshc_page.dshc_panelOpen.dshc_roomsHidden.dshc_membersHidden {\n grid-template-columns: minmax(0, 1fr) min(420px, 36%);\n }\n\n .dshc_page.dshc_panelOpen > .dshc_sideDock {\n border-left: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-base);\n min-width: 0;\n min-height: 0;\n display: flex;\n }\n}\n\n.dshc_sidePanel {\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n max-height: none;\n box-shadow: none;\n border: 0;\n border-radius: 0;\n margin: 0;\n animation: .2s ease-out dshc_boardDrawerIn;\n position: relative;\n}\n\n.dshc_sidePanel:focus {\n outline: none;\n}\n\n.dshc_sidePanelClose {\n width: 28px;\n height: 28px;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n background: none;\n border: 0;\n border-radius: 6px;\n font-size: 18px;\n line-height: 1;\n position: absolute;\n top: 10px;\n right: 10px;\n}\n\n.dshc_sidePanelClose:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dshc_sidePanel {\n animation: none;\n }\n}\n\n.dshc_sidePanel .dshc_boardCardGrid {\n grid-template-columns: minmax(0, 1fr);\n}\n\n.dshc_slashPopup {\n z-index: 6;\n width: min(360px, 100% - 32px);\n animation: none;\n right: auto;\n}\n\n.dshc_slashGroup {\n color: var(--dsw-alias-label-tertiary);\n padding: 6px 8px 2px;\n font-size: 11px;\n}\n\n.dshc_slashItem {\n border-radius: var(--dsw-radius-sm);\n cursor: pointer;\n align-items: baseline;\n gap: 8px;\n padding: 5px 8px;\n display: flex;\n}\n\n.dshc_slashActive {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_slashName {\n flex: none;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-weight: 600;\n}\n\n.dshc_slashMeta {\n min-width: 0;\n color: var(--dsw-alias-label-tertiary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 12px;\n overflow: hidden;\n}\n\n.dshc_sendButton.dshc_stopButton {\n background: var(--dsw-alias-label-primary);\n}\n\n.dshc_stopNote + .dshc_sendButton {\n margin-left: 8px;\n}\n\n.dshc_sendButton.dshc_stopButton[data-phase=\"stopping\"] {\n opacity: .6;\n cursor: progress;\n}\n\n.dshc_stopNote {\n color: var(--dsw-alias-label-tertiary);\n white-space: nowrap;\n margin-left: auto;\n font-size: 12px;\n}\n\n.dshc_cmdLine {\n color: var(--dsw-alias-label-tertiary);\n flex-wrap: wrap;\n align-items: baseline;\n gap: 6px;\n padding: 1px 16px 1px 72px;\n font-size: 12px;\n display: flex;\n}\n\n.dshc_cmdLine code {\n color: var(--dsw-alias-label-secondary);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n}\n\n.dshc_cmdResult {\n min-width: 0;\n max-width: 60ch;\n color: inherit;\n font: inherit;\n text-align: left;\n text-overflow: ellipsis;\n white-space: nowrap;\n cursor: pointer;\n background: none;\n border: 0;\n padding: 0;\n overflow: hidden;\n}\n\n.dshc_cmdResult[aria-expanded=\"true\"] {\n white-space: pre-line;\n max-width: none;\n}\n\n.dshc_cmdLine[data-failed=\"true\"] .dshc_cmdResult {\n color: var(--dsw-alias-danger, #d94848);\n}\n\n@media (width <= 720px) {\n .dshc_cmdLine {\n padding-left: 16px;\n }\n}\n\n.dshc_msgTool {\n justify-content: center;\n align-items: center;\n width: 26px;\n height: 24px;\n padding: 0;\n display: inline-flex;\n position: relative;\n}\n\n.dshc_msgTool[data-tip]:after {\n content: attr(data-tip);\n z-index: 3;\n background: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-label-primary-inverted);\n white-space: nowrap;\n opacity: 0;\n pointer-events: none;\n border-radius: 4px;\n padding: 2px 6px;\n font-size: 11px;\n position: absolute;\n top: calc(100% + 4px);\n left: 50%;\n transform: translateX(-50%);\n}\n\n.dshc_msgTool[data-tip]:hover:after, .dshc_msgTool[data-tip]:focus-visible:after {\n opacity: 1;\n transition: opacity 0s 80ms;\n}\n\n.dshc_permSessionButton {\n color: var(--dsw-alias-label-secondary);\n font: inherit;\n text-underline-offset: 2px;\n cursor: pointer;\n background: none;\n border: 0;\n padding: 4px 6px;\n font-size: 12px;\n text-decoration: underline;\n}\n\n.dshc_permSessionButton:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n.dshc_permSessionButton:disabled {\n opacity: .5;\n cursor: default;\n}\n\n.dshc_queuedButton {\n border: 1px solid var(--dsw-alias-border-default, #0000001f);\n color: var(--dsw-alias-label-secondary);\n font: inherit;\n cursor: pointer;\n background: none;\n border-radius: 9px;\n padding: 0 6px;\n font-size: 11px;\n line-height: 16px;\n}\n\n.dshc_queuedButton:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n.dshc_queuedTag {\n color: #a76a06;\n background: #eaa02824;\n border-radius: 4px;\n padding: 0 5px;\n font-size: 11px;\n line-height: 16px;\n}\n\n[data-queued] .dshc_ownActions {\n opacity: 1;\n}\n\n.dshc_memory {\n margin-top: 4px;\n}\n\n.dshc_memoryBadge {\n background: var(--dsw-alias-fill-secondary, #0000000d);\n color: var(--dsw-alias-label-tertiary);\n font: inherit;\n cursor: pointer;\n border: 0;\n border-radius: 9px;\n align-items: center;\n gap: 4px;\n padding: 0 6px;\n font-size: 11px;\n line-height: 18px;\n display: inline-flex;\n}\n\n.dshc_memoryBadge:hover, .dshc_memoryBadge[aria-expanded=\"true\"] {\n color: var(--dsw-alias-label-secondary);\n}\n\n.dshc_memoryList {\n border-left: 2px solid var(--dsw-alias-border-default, #0000001f);\n flex-direction: column;\n gap: 4px;\n max-width: 560px;\n margin: 4px 0 0;\n padding: 6px 10px;\n font-size: 12px;\n list-style: none;\n display: flex;\n}\n\n.dshc_memoryItem {\n flex-direction: column;\n display: flex;\n}\n\n.dshc_memoryTitle {\n color: var(--dsw-alias-label-secondary);\n line-height: 1.5;\n}\n\n.dshc_memoryPage {\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n font-family: var(--dsw-font-mono, ui-monospace, monospace);\n}\n\n.dshc_delivery {\n flex-direction: column;\n gap: 6px;\n max-width: 720px;\n margin-top: 8px;\n display: flex;\n}\n\n.dshc_deliveryFrame {\n border: 1px solid var(--background-modifier-accent, #7f7f7f4d);\n background: #fff;\n border-radius: 6px;\n height: 360px;\n display: flex;\n overflow: hidden;\n}\n\n.dshc_deliveryActions {\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n display: flex;\n}\n\n.dshc_deliveryActions a {\n text-decoration: none;\n}\n\n.dshc_deliveryDone {\n color: var(--text-muted, #888);\n font-size: 12px;\n}\n\n.dshc_deliveryFullDialog {\n box-sizing: border-box;\n flex-direction: column;\n gap: 8px;\n width: 94vw;\n max-width: none;\n height: 92dvh;\n display: flex;\n}\n\n.dshc_deliveryFullFrame {\n background: #fff;\n border-radius: 6px;\n flex: 1;\n min-height: 0;\n display: flex;\n overflow: hidden;\n}\n\n.dshc_dmTitle {\n color: var(--text-muted, #888);\n margin: 14px 8px 4px;\n font-size: 12px;\n font-weight: 600;\n}\n\n.dshc_dmAvatar {\n margin-right: 6px;\n display: inline-flex;\n}\n\n.dshc_dmRow {\n align-items: center;\n display: flex;\n position: relative;\n}\n\n.dshc_dmRow .dshc_room {\n padding-right: 26px;\n}\n\n.dshc_dmClose {\n border-radius: var(--dsw-radius-sm, 4px);\n width: 20px;\n height: 20px;\n color: var(--dsw-alias-label-tertiary, #888);\n font: inherit;\n cursor: pointer;\n opacity: 0;\n background: none;\n border: 0;\n padding: 0;\n font-size: 15px;\n line-height: 20px;\n position: absolute;\n right: 4px;\n}\n\n.dshc_dmRow:hover .dshc_dmClose, .dshc_dmClose:focus-visible {\n opacity: 1;\n}\n\n.dshc_dmClose:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n@media (hover: none) {\n .dshc_dmClose {\n opacity: 1;\n }\n}\n\n.dshc_dmHead {\n margin-top: 14px;\n}\n\n.dshc_dmPicker {\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-layer-2);\n flex-direction: column;\n margin: 0 4px 4px;\n padding: 4px;\n display: flex;\n}\n\n.dshc_dmPickNone {\n color: var(--dsw-alias-label-tertiary);\n padding: 6px 8px;\n font-size: 12px;\n}\n\n.dshc_dmNewRow {\n color: var(--dsw-alias-label-tertiary);\n font-size: 13px;\n}\n\nbutton.dshc_headMeta {\n border-radius: var(--dsw-radius-sm);\n min-width: 0;\n font: inherit;\n cursor: pointer;\n background: none;\n border: 0;\n flex: 0 auto;\n padding: 2px 6px;\n font-size: 12px;\n}\n\nbutton.dshc_headMeta:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.dshc_headSpacer {\n flex: auto;\n}\n\n.dshc_roomUnread {\n color: var(--dsw-alias-label-primary);\n font-weight: 650;\n}\n\n.dshc_unreadBadge {\n color: #fff;\n background: var(--dsw-alias-state-danger-primary, #e5484d);\n text-align: center;\n font-variant-numeric: tabular-nums;\n border-radius: 999px;\n flex: none;\n min-width: 18px;\n padding: 0 5px;\n font-size: 11px;\n font-weight: 600;\n line-height: 18px;\n}\n\n.dshc_slashDisabled {\n opacity: .45;\n cursor: not-allowed;\n}\n\n.dshc_leadCardHint {\n color: var(--dsw-alias-label-tertiary);\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 11px;\n overflow: hidden;\n}\n\n.dshc_roomWorking {\n max-width: 96px;\n color: var(--dsw-alias-state-business-primary);\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: none;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n font-weight: 500;\n display: inline-flex;\n overflow: hidden;\n}\n\n.dshc_roomWorkingDot {\n background: currentColor;\n border-radius: 50%;\n flex: none;\n width: 6px;\n height: 6px;\n animation: 1.4s ease-in-out infinite dshc_roomWorkingPulse;\n}\n\n@keyframes dshc_roomWorkingPulse {\n 50% {\n opacity: .35;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dshc_roomWorkingDot {\n animation: none;\n }\n}\n\n.dshc_drawerTools {\n display: none;\n}\n\n@media (width <= 600px) {\n .dshc_drawerTools {\n flex-wrap: wrap;\n gap: 6px;\n margin: 0 8px 8px;\n display: flex;\n }\n\n .dshc_chatHead > .dshc_taskBoardTrigger, .dshc_chatHead > .dshc_schemeToggle, .dshc_chatHead > .dshc_headMeta, .dshc_chatHead > .dshc_headTeam {\n display: none;\n }\n\n .dshc_chatHead > .dshc_roomName {\n flex: auto;\n }\n}\n\n.dshc_panelOpen .dshc_chatHead > .dshc_headTeam, .dshc_panelOpen .dshc_chatHead > .dshc_headMeta {\n display: none;\n}\n\n.dshc_panelOpen .dshc_chatHead > .dshc_roomName {\n flex: 0 auto;\n}\n[data-dc-scheme=\"light\"] {\n --dsw-static-amber-100: #fef5e7;\n --dsw-static-amber-400: #f7ad31;\n --dsw-static-amber-500: #f59e0b;\n --dsw-static-amber-600: #dd8629;\n --dsw-static-amber-900: #27241f;\n --dsw-static-blue-100: #dbeafe;\n --dsw-static-blue-300: #93c5fd;\n --dsw-static-blue-400: #60a5fa;\n --dsw-static-blue-450: #4d93f8;\n --dsw-static-blue-500: #3b82f6;\n --dsw-static-blue-50: #eff6ff;\n --dsw-static-blue-50p: #eaf3ff;\n --dsw-static-blue-600: #2563eb;\n --dsw-static-blue-75: #e5f0ff;\n --dsw-static-blue-800: #1e40af;\n --dsw-static-blue-900: #0e3074;\n --dsw-static-blue-950: #172554;\n --dsw-static-deepseek-100: #e4edfd;\n --dsw-static-deepseek-200: #d3e2ff;\n --dsw-static-deepseek-300: #b7c8fe;\n --dsw-static-deepseek-400: #7aaaff;\n --dsw-static-deepseek-450: #5686fe;\n --dsw-static-deepseek-500: #4176e6;\n --dsw-static-deepseek-50: #edf3fe;\n --dsw-static-deepseek-600: #4868b2;\n --dsw-static-deepseek-700-delete: #2f4c8f;\n --dsw-static-deepseek-800: #34415b;\n --dsw-static-deepseek-900: #283142;\n --dsw-static-green-100: #e6faed;\n --dsw-static-green-400: #4ed17e;\n --dsw-static-green-500: #22c55e;\n --dsw-static-green-500-a08: #22c55e14;\n --dsw-static-green-500-a12: #22c55e1f;\n --dsw-static-green-900: #233c2c;\n --dsw-static-neutral-00: #fff;\n --dsw-static-neutral-1000: #000;\n --dsw-static-neutral-100: #f5f5f5;\n --dsw-static-neutral-150: #ededed;\n --dsw-static-neutral-200: #e5e5e5;\n --dsw-static-neutral-250: #dcdcdc;\n --dsw-static-neutral-300: #d4d4d4;\n --dsw-static-neutral-400: #a2a4a6;\n --dsw-static-neutral-500: #7f8287;\n --dsw-static-neutral-50: #fafafa;\n --dsw-static-neutral-550: #65676b;\n --dsw-static-neutral-600: #545557;\n --dsw-static-neutral-700: #3c3c3d;\n --dsw-static-neutral-800: #292929;\n --dsw-static-neutral-850: #212123;\n --dsw-static-neutral-900: #0f0f0f;\n --dsw-static-neutral-bluish-00: #fff;\n --dsw-static-neutral-bluish-1000: #0f1115;\n --dsw-static-neutral-bluish-100: #ebeef2;\n --dsw-static-neutral-bluish-150: #e9ecf2;\n --dsw-static-neutral-bluish-200: #e1e5ee;\n --dsw-static-neutral-bluish-300: #cfd3d6;\n --dsw-static-neutral-bluish-400: #adb2b8;\n --dsw-static-neutral-bluish-500: #979da6;\n --dsw-static-neutral-bluish-50: #f9fafb;\n --dsw-static-neutral-bluish-600: #81858c;\n --dsw-static-neutral-bluish-60: #f5f6f7;\n --dsw-static-neutral-bluish-700: #61666b;\n --dsw-static-neutral-bluish-750: #43454a;\n --dsw-static-neutral-bluish-75: #f1f3f5;\n --dsw-static-neutral-bluish-800: #353638;\n --dsw-static-neutral-bluish-850: #2c2c2e;\n --dsw-static-neutral-bluish-875: #232324;\n --dsw-static-neutral-bluish-900: #1b1b1c;\n --dsw-static-neutral-bluish-950: #151517;\n --dsw-static-red-100: #fee2e2;\n --dsw-static-red-400: #f25a5a;\n --dsw-static-red-400-a12: #f25a5a1f;\n --dsw-static-red-500: #ef4444;\n --dsw-static-red-50: #fef2f2;\n --dsw-static-red-600: #ec1313;\n --dsw-static-red-600-a08: #ec131314;\n --dsw-static-red-900: #570c0c;\n}\n\n[data-dc-scheme=\"dark\"] {\n --dsw-static-amber-100: #fef5e7;\n --dsw-static-amber-400: #f7ad31;\n --dsw-static-amber-500: #f59e0b;\n --dsw-static-amber-600: #dd8629;\n --dsw-static-amber-900: #27241f;\n --dsw-static-blue-100: #dbeafe;\n --dsw-static-blue-300: #93c5fd;\n --dsw-static-blue-400: #60a5fa;\n --dsw-static-blue-450: #4d93f8;\n --dsw-static-blue-500: #3b82f6;\n --dsw-static-blue-50: #eff6ff;\n --dsw-static-blue-50p: #eaf3ff;\n --dsw-static-blue-600: #2563eb;\n --dsw-static-blue-75: #e5f0ff;\n --dsw-static-blue-800: #1e40af;\n --dsw-static-blue-900: #0e3074;\n --dsw-static-blue-950: #172554;\n --dsw-static-deepseek-100: #e4edfd;\n --dsw-static-deepseek-200: #d3e2ff;\n --dsw-static-deepseek-300: #b7c8fe;\n --dsw-static-deepseek-400: #7aaaff;\n --dsw-static-deepseek-450: #5686fe;\n --dsw-static-deepseek-500: #4176e6;\n --dsw-static-deepseek-50: #edf3fe;\n --dsw-static-deepseek-600: #4868b2;\n --dsw-static-deepseek-700-delete: #2f4c8f;\n --dsw-static-deepseek-800: #34415b;\n --dsw-static-deepseek-900: #283142;\n --dsw-static-green-100: #e6faed;\n --dsw-static-green-400: #4ed17e;\n --dsw-static-green-500: #22c55e;\n --dsw-static-green-500-a08: #22c55e14;\n --dsw-static-green-500-a12: #22c55e1f;\n --dsw-static-green-900: #233c2c;\n --dsw-static-neutral-00: #fff;\n --dsw-static-neutral-1000: #000;\n --dsw-static-neutral-100: #f5f5f5;\n --dsw-static-neutral-150: #ededed;\n --dsw-static-neutral-200: #e5e5e5;\n --dsw-static-neutral-250: #dcdcdc;\n --dsw-static-neutral-300: #d4d4d4;\n --dsw-static-neutral-400: #a2a4a6;\n --dsw-static-neutral-500: #7f8287;\n --dsw-static-neutral-50: #fafafa;\n --dsw-static-neutral-550: #65676b;\n --dsw-static-neutral-600: #545557;\n --dsw-static-neutral-700: #3c3c3d;\n --dsw-static-neutral-800: #292929;\n --dsw-static-neutral-850: #212123;\n --dsw-static-neutral-900: #0f0f0f;\n --dsw-static-neutral-bluish-00: #fff;\n --dsw-static-neutral-bluish-1000: #0f1115;\n --dsw-static-neutral-bluish-100: #ebeef2;\n --dsw-static-neutral-bluish-150: #e9ecf2;\n --dsw-static-neutral-bluish-200: #e1e5ee;\n --dsw-static-neutral-bluish-300: #cfd3d6;\n --dsw-static-neutral-bluish-400: #adb2b8;\n --dsw-static-neutral-bluish-500: #979da6;\n --dsw-static-neutral-bluish-50: #f9fafb;\n --dsw-static-neutral-bluish-600: #81858c;\n --dsw-static-neutral-bluish-60: #f9fafb;\n --dsw-static-neutral-bluish-700: #61666b;\n --dsw-static-neutral-bluish-750: #43454a;\n --dsw-static-neutral-bluish-75: #f1f3f5;\n --dsw-static-neutral-bluish-800: #353638;\n --dsw-static-neutral-bluish-850: #2c2c2e;\n --dsw-static-neutral-bluish-875: #232324;\n --dsw-static-neutral-bluish-900: #1b1b1c;\n --dsw-static-neutral-bluish-950: #151517;\n --dsw-static-red-100: #fee2e2;\n --dsw-static-red-400: #f25a5a;\n --dsw-static-red-400-a12: #f25a5a1f;\n --dsw-static-red-500: #ef4444;\n --dsw-static-red-50: #fef2f2;\n --dsw-static-red-600: #ec1313;\n --dsw-static-red-600-a08: #ec131314;\n --dsw-static-red-900: #570c0c;\n}\n\n[data-dc-scheme=\"light\"] {\n --dsw-alias-bg-base: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-bg-document-preview: var(--dsw-static-neutral-bluish-100);\n --dsw-alias-bg-document-selection: color-mix(in srgb, var(--dsw-static-blue-500) 40%, transparent);\n --dsw-alias-label-document-preview: var(--dsw-static-neutral-bluish-700);\n --dsw-alias-bg-layer-1: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-bg-layer-2: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-bg-layer-3: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-bg-mask-1: #0000003d;\n --dsw-alias-bg-mask-2: #0000001f;\n --dsw-alias-bg-mask-3: #0000007a;\n --dsw-alias-bg-mask-photo: #000000e0;\n --dsw-alias-bg-mask-drop: #ffffffb3;\n --dsw-alias-bg-module-platform: var(--dsw-static-neutral-bluish-60);\n --dsw-alias-bg-multi-select: var(--dsw-static-neutral-bluish-60);\n --dsw-alias-bg-overlay: var(--dsw-static-neutral-bluish-150);\n --dsw-alias-bg-skeleton: #0000000a;\n --dsw-alias-border-inverted2: #0000;\n --dsw-alias-border-inverted: #0000;\n --dsw-alias-border-l1: #0000000a;\n --dsw-alias-border-l2-darkmode-thin: #0000001a;\n --dsw-alias-border-l2: #0000001a;\n --dsw-alias-border-l3: #0000001f;\n --dsw-alias-border-l4: #00000029;\n --dsw-alias-brand-primary-invert: var(--dsw-static-neutral-bluish-1000);\n --dsw-alias-brand-primary-new-colorprimary-new-color: #4176e6;\n --dsw-alias-brand-primary: var(--dsw-static-neutral-bluish-1000);\n --dsw-alias-brand-text: var(--dsw-static-neutral-bluish-1000);\n --dsw-alias-button-contrast-fill: var(--dsw-static-neutral-bluish-700);\n --dsw-alias-button-elevated-fill: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-button-floating-fill: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-button-floating-hover: var(--dsw-static-neutral-bluish-75);\n --dsw-alias-button-ghost-active-border: var(--dsw-static-neutral-bluish-500);\n --dsw-alias-button-ghost-active-fill: var(--dsw-static-neutral-bluish-100);\n --dsw-alias-button-ghost-active-hover: var(--dsw-static-neutral-bluish-150);\n --dsw-alias-button-info-fill: var(--dsw-static-deepseek-500);\n --dsw-alias-button-info-hover: var(--dsw-static-deepseek-400);\n --dsw-alias-button-primary-dimmed: var(--dsw-static-neutral-bluish-100);\n --dsw-alias-button-primary-fill: var(--dsw-alias-brand-primary);\n --dsw-alias-button-primary-hover: var(--dsw-static-neutral-bluish-750);\n --dsw-alias-button-tool-bar-fill-invisible: #1f1f1f5c;\n --dsw-alias-button-tool-bar-fill: #54555780;\n --dsw-alias-button-tool-bar-hover: #54555799;\n --dsw-alias-interactive-bg-active: #2631481a;\n --dsw-alias-interactive-bg-hover-accent: #26314824;\n --dsw-alias-interactive-bg-hover-danger: #ec13130d;\n --dsw-alias-interactive-bg-hover-solid: var(--dsw-static-neutral-bluish-75);\n --dsw-alias-interactive-bg-hover: #2631480f;\n --dsw-alias-label-caption: var(--dsw-static-neutral-bluish-400);\n --dsw-alias-label-deep-diving: color-mix(in srgb, var(--dsw-static-deepseek-500) 70%, var(--dsw-static-blue-950));\n --dsw-alias-label-deep-diving-shimmer: color-mix(in srgb, var(--dsw-static-deepseek-500) 30%, var(--dsw-static-blue-950));\n --dsw-alias-label-dimmed: var(--dsw-static-neutral-bluish-200);\n --dsw-alias-label-primary-bluish: var(--dsw-static-blue-900);\n --dsw-alias-label-primary-dimmed: var(--dsw-static-neutral-bluish-950);\n --dsw-alias-label-primary-foreground: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-label-primary-inverted: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-label-primary: var(--dsw-static-neutral-bluish-1000);\n --dsw-alias-label-secondary: var(--dsw-static-neutral-bluish-700);\n --dsw-alias-label-shimmer: color-mix(in srgb, var(--dsw-static-neutral-1000) 30%, transparent);\n --dsw-alias-label-tertiary: var(--dsw-static-neutral-bluish-600);\n --dsw-alias-menu-icon: var(--dsw-static-neutral-bluish-800);\n --dsw-alias-link: var(--dsw-static-deepseek-500);\n --dsw-alias-markdown-citation: var(--dsw-static-neutral-bluish-100);\n --dsw-alias-markdown-code-block-banner: var(--dsw-static-neutral-bluish-50);\n --dsw-alias-markdown-code-block: var(--dsw-static-neutral-bluish-50);\n --dsw-alias-markdown-code-segment-selected: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-markdown-code-segment-unselected: var(--dsw-static-neutral-bluish-75);\n --dsw-alias-markdown-inline-code: var(--dsw-static-neutral-50);\n --dsw-alias-markdown-placeholder: var(--dsw-static-neutral-bluish-60);\n --dsw-alias-markdown-tag: var(--dsw-static-neutral-bluish-75);\n --dsw-alias-scrollbar-bg-l1: var(--dsw-static-neutral-200);\n --dsw-alias-scrollbar-bg-l2: var(--dsw-static-neutral-200);\n --dsw-alias-scrollbar-hover-l1: var(--dsw-static-neutral-300);\n --dsw-alias-scrollbar-hover-l2: var(--dsw-static-neutral-300);\n --dsw-alias-state-business-primary: var(--dsw-static-deepseek-500);\n --dsw-alias-state-business-tertiary: var(--dsw-static-deepseek-100);\n --dsw-alias-code-diff-added: var(--dsw-static-green-500-a08);\n --dsw-alias-code-diff-deleted: var(--dsw-static-red-600-a08);\n --dsw-alias-file-diff-added-bg: #e6f4e7;\n --dsw-alias-file-diff-added-gutter: #edf7ed;\n --dsw-alias-file-diff-added-marker: #01a241;\n --dsw-alias-file-diff-deleted-bg: #fce6e2;\n --dsw-alias-file-diff-deleted-gutter: #fdece9;\n --dsw-alias-file-diff-deleted-marker: #ba2723;\n --dsw-alias-state-error-primary: var(--dsw-static-red-600);\n --dsw-alias-state-error-secondary: var(--dsw-static-red-400);\n --dsw-alias-state-idle-primary: var(--dsw-static-neutral-300);\n --dsw-alias-state-success-primary: var(--dsw-static-green-500);\n --dsw-alias-state-success-secondary: var(--dsw-static-green-400);\n --dsw-alias-state-success-tertiary: var(--dsw-static-green-100);\n --dsw-alias-state-warn-label: var(--dsw-static-amber-600);\n --dsw-alias-state-warn-primary: var(--dsw-static-amber-500);\n --dsw-alias-state-warn-secondary: var(--dsw-static-amber-400);\n --dsw-alias-state-warn-tertiary: var(--dsw-static-amber-100);\n --dsw-alias-switch-thumb: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-toast-bg: var(--dsw-static-neutral-bluish-800);\n --dsw-alias-toast-label: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-tooltip-bg: var(--dsw-static-neutral-bluish-850);\n --dsw-alias-tooltip-key-bg: color-mix(in srgb, var(--dsw-alias-tooltip-bg), white 18%);\n --dsw-alias-turn-trigger-bg: var(--dsw-alias-markdown-code-block);\n --dsw-alias-turn-trigger-bg-hover: var(--dsw-alias-interactive-bg-hover);\n --dsw-specific-bubble-highlight: var(--dsw-static-deepseek-200);\n --dsw-specific-bubble: var(--dsw-static-deepseek-50);\n --dsw-specific-input-major: var(--dsw-static-neutral-bluish-00);\n --dsw-specific-login-input: var(--dsw-static-neutral-bluish-50);\n --dsw-menu-surface-fill: #f8f9fa94;\n --dsw-alias-menu-group-header-fill: #f8f9faf0;\n --dsw-specific-menu: var(--dsw-menu-surface-fill);\n --dsw-specific-selector: var(--dsw-static-neutral-bluish-60);\n --dsw-specific-sidebar-fill: var(--dsw-static-neutral-bluish-50);\n --dsw-specific-sidebar-nav-item-active-accent: var(--dsw-static-deepseek-100);\n --dsw-specific-sidebar-nav-item-active: var(--dsw-static-neutral-bluish-100);\n --dsw-specific-sidebar-nav-item-hover: var(--dsw-static-neutral-bluish-75);\n --dsw-specific-tip: var(--dsw-static-neutral-bluish-60);\n}\n\n[data-dc-scheme=\"dark\"] {\n --dsw-alias-bg-base: var(--dsw-static-neutral-bluish-950);\n --dsw-alias-bg-document-preview: var(--dsw-static-neutral-bluish-950);\n --dsw-alias-bg-document-selection: color-mix(in srgb, var(--dsw-static-blue-500) 40%, transparent);\n --dsw-alias-label-document-preview: var(--dsw-static-neutral-bluish-300);\n --dsw-alias-bg-layer-1: var(--dsw-static-neutral-bluish-875);\n --dsw-alias-bg-layer-2: var(--dsw-static-neutral-bluish-850);\n --dsw-alias-bg-layer-3: var(--dsw-static-neutral-bluish-800);\n --dsw-alias-bg-mask-1: #00000080;\n --dsw-alias-bg-mask-2: #0003;\n --dsw-alias-bg-mask-3: #0000007a;\n --dsw-alias-bg-mask-photo: #000000e0;\n --dsw-alias-bg-mask-drop: #272730b3;\n --dsw-alias-bg-module-platform: var(--dsw-static-neutral-bluish-800);\n --dsw-alias-bg-multi-select: var(--dsw-static-neutral-850);\n --dsw-alias-bg-overlay: var(--dsw-static-neutral-bluish-700);\n --dsw-alias-bg-skeleton: #ffffff14;\n --dsw-alias-border-inverted2: #ffffff14;\n --dsw-alias-border-inverted: #ffffff0f;\n --dsw-alias-border-l1: #ffffff0f;\n --dsw-alias-border-l2-darkmode-thin: #ffffff0f;\n --dsw-alias-border-l2: #ffffff1f;\n --dsw-alias-border-l3: #ffffff29;\n --dsw-alias-border-l4: #fff3;\n --dsw-alias-brand-primary-invert: var(--dsw-static-neutral-bluish-50);\n --dsw-alias-brand-primary-new-colorprimary-new-color: var(--dsw-static-deepseek-450);\n --dsw-alias-brand-primary: var(--dsw-static-neutral-bluish-50);\n --dsw-alias-brand-text: var(--dsw-static-neutral-bluish-50);\n --dsw-alias-button-contrast-fill: var(--dsw-static-neutral-bluish-50);\n --dsw-alias-button-elevated-fill: var(--dsw-static-neutral-bluish-750);\n --dsw-alias-button-floating-fill: var(--dsw-static-neutral-bluish-850);\n --dsw-alias-button-floating-hover: var(--dsw-static-neutral-bluish-800);\n --dsw-alias-button-ghost-active-border: var(--dsw-static-neutral-bluish-600);\n --dsw-alias-button-ghost-active-fill: var(--dsw-static-neutral-bluish-750);\n --dsw-alias-button-ghost-active-hover: var(--dsw-static-neutral-bluish-700);\n --dsw-alias-button-info-fill: var(--dsw-static-deepseek-400);\n --dsw-alias-button-info-hover: var(--dsw-static-deepseek-500);\n --dsw-alias-button-primary-dimmed: var(--dsw-static-neutral-bluish-750);\n --dsw-alias-button-primary-fill: var(--dsw-alias-brand-primary);\n --dsw-alias-button-primary-hover: var(--dsw-static-neutral-bluish-100);\n --dsw-alias-button-tool-bar-fill-invisible: #1f1f1f5c;\n --dsw-alias-button-tool-bar-fill: #54555780;\n --dsw-alias-button-tool-bar-hover: #54555799;\n --dsw-alias-interactive-bg-active: #ffffff24;\n --dsw-alias-interactive-bg-hover-accent: #ffffff3d;\n --dsw-alias-interactive-bg-hover-danger: #f25a5a26;\n --dsw-alias-interactive-bg-hover-solid: var(--dsw-static-neutral-bluish-800);\n --dsw-alias-interactive-bg-hover: #ffffff14;\n --dsw-alias-label-caption: var(--dsw-static-neutral-bluish-600);\n --dsw-alias-label-deep-diving: color-mix(in srgb, var(--dsw-static-deepseek-450) 55%, var(--dsw-static-neutral-bluish-400));\n --dsw-alias-label-deep-diving-shimmer: color-mix(in srgb, var(--dsw-static-blue-300) 65%, var(--dsw-static-deepseek-400));\n --dsw-alias-label-dimmed: var(--dsw-static-neutral-bluish-750);\n --dsw-alias-label-primary-bluish: var(--dsw-static-neutral-bluish-50);\n --dsw-alias-label-primary-dimmed: var(--dsw-static-neutral-bluish-100);\n --dsw-alias-label-primary-foreground: var(--dsw-static-neutral-bluish-1000);\n --dsw-alias-label-primary-inverted: var(--dsw-static-neutral-bluish-800);\n --dsw-alias-label-primary: var(--dsw-static-neutral-bluish-50);\n --dsw-alias-label-secondary: var(--dsw-static-neutral-bluish-300);\n --dsw-alias-label-shimmer: color-mix(in srgb, var(--dsw-static-neutral-00) 45%, transparent);\n --dsw-alias-label-tertiary: var(--dsw-static-neutral-bluish-400);\n --dsw-alias-menu-icon: var(--dsw-alias-label-primary-dimmed);\n --dsw-alias-link: var(--dsw-static-deepseek-400);\n --dsw-alias-markdown-citation: var(--dsw-static-neutral-bluish-800);\n --dsw-alias-markdown-code-block-banner: var(--dsw-static-neutral-bluish-850);\n --dsw-alias-markdown-code-block: var(--dsw-static-neutral-bluish-900);\n --dsw-alias-markdown-code-segment-selected: var(--dsw-static-neutral-bluish-800);\n --dsw-alias-markdown-code-segment-unselected: var(--dsw-static-neutral-bluish-900);\n --dsw-alias-markdown-inline-code: var(--dsw-static-neutral-800);\n --dsw-alias-markdown-placeholder: var(--dsw-static-neutral-bluish-850);\n --dsw-alias-markdown-tag: var(--dsw-static-neutral-bluish-850);\n --dsw-alias-scrollbar-bg-l1: var(--dsw-static-neutral-700);\n --dsw-alias-scrollbar-bg-l2: var(--dsw-static-neutral-600);\n --dsw-alias-scrollbar-hover-l1: var(--dsw-static-neutral-600);\n --dsw-alias-scrollbar-hover-l2: var(--dsw-static-neutral-550);\n --dsw-alias-state-business-primary: var(--dsw-static-deepseek-400);\n --dsw-alias-state-business-tertiary: var(--dsw-static-deepseek-800);\n --dsw-alias-code-diff-added: var(--dsw-static-green-500-a12);\n --dsw-alias-code-diff-deleted: var(--dsw-static-red-400-a12);\n --dsw-alias-file-diff-added-bg: #1f3124;\n --dsw-alias-file-diff-added-gutter: #132016;\n --dsw-alias-file-diff-added-marker: #41c977;\n --dsw-alias-file-diff-deleted-bg: #3c1f1b;\n --dsw-alias-file-diff-deleted-gutter: #28130e;\n --dsw-alias-file-diff-deleted-marker: #fa423e;\n --dsw-alias-state-error-primary: var(--dsw-static-red-400);\n --dsw-alias-state-error-secondary: var(--dsw-static-red-400);\n --dsw-alias-state-idle-primary: var(--dsw-static-neutral-600);\n --dsw-alias-state-success-primary: var(--dsw-static-green-500);\n --dsw-alias-state-success-secondary: var(--dsw-static-green-400);\n --dsw-alias-state-success-tertiary: var(--dsw-static-green-900);\n --dsw-alias-state-warn-label: var(--dsw-static-amber-600);\n --dsw-alias-state-warn-primary: var(--dsw-static-amber-500);\n --dsw-alias-state-warn-secondary: var(--dsw-static-amber-400);\n --dsw-alias-state-warn-tertiary: var(--dsw-static-amber-900);\n --dsw-alias-switch-thumb: var(--dsw-static-neutral-bluish-400);\n --dsw-alias-toast-bg: var(--dsw-static-neutral-bluish-750);\n --dsw-alias-toast-label: var(--dsw-static-neutral-bluish-00);\n --dsw-alias-turn-trigger-bg: var(--dsw-alias-interactive-bg-hover);\n --dsw-alias-turn-trigger-bg-hover: var(--dsw-alias-interactive-bg-active);\n --dsw-alias-tooltip-bg: var(--dsw-static-neutral-bluish-750);\n --dsw-alias-tooltip-key-bg: color-mix(in srgb, var(--dsw-alias-tooltip-bg), white 18%);\n --dsw-specific-bubble-highlight: var(--dsw-static-neutral-bluish-750);\n --dsw-specific-bubble: var(--dsw-static-neutral-bluish-850);\n --dsw-specific-input-major: var(--dsw-static-neutral-bluish-850);\n --dsw-specific-login-input: var(--dsw-static-neutral-bluish-900);\n --dsw-menu-surface-fill: #43454a73;\n --dsw-alias-menu-group-header-fill: #303136f0;\n --dsw-specific-menu: var(--dsw-menu-surface-fill);\n --dsw-specific-selector: var(--dsw-static-neutral-bluish-800);\n --dsw-specific-sidebar-fill: var(--dsw-static-neutral-bluish-900);\n --dsw-specific-sidebar-nav-item-active-accent: var(--dsw-static-neutral-bluish-800);\n --dsw-specific-sidebar-nav-item-active: var(--dsw-static-neutral-bluish-750);\n --dsw-specific-sidebar-nav-item-hover: var(--dsw-static-neutral-bluish-850);\n --dsw-specific-tip: var(--dsw-static-neutral-bluish-800);\n}\n\nhtml[data-platform=\"darwin\"] [data-dc-scheme=\"light\"] {\n --dsw-specific-menu: #f8f9faf0;\n}\n\nhtml[data-platform=\"darwin\"] [data-dc-scheme=\"dark\"] {\n --dsw-specific-menu: #303136f0;\n}\n\n[data-dc-scheme=\"light\"] {\n color-scheme: light;\n}\n\n[data-dc-scheme=\"dark\"] {\n color-scheme: dark;\n}\n.dshc_embed {\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n min-height: 0;\n padding-top: var(--dsh-frame-top-clearance, 0px);\n background: var(--dsw-alias-bg-base);\n display: flex;\n}\n\n.dshc_frame {\n background: var(--dsw-alias-bg-base);\n border: 0;\n flex: 1;\n width: 100%;\n height: 100%;\n}\n\n.dshc_remote {\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n min-height: 0;\n padding-top: var(--dsh-frame-top-clearance, 0px);\n background: var(--dsw-alias-bg-base);\n flex-direction: column;\n display: flex;\n}\n\n.dshc_remoteBar {\n border-bottom: 1px solid var(--dsw-alias-border-subtle, #7f7f7f40);\n color: var(--dsw-alias-label-secondary);\n align-items: center;\n gap: 12px;\n padding: 6px 12px;\n font-size: 13px;\n display: flex;\n}\n\n.dshc_remoteName {\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n min-width: 0;\n overflow: hidden;\n}\n\n.dshc_remoteBack {\n border: 1px solid var(--dsw-alias-border-subtle, #7f7f7f59);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n cursor: pointer;\n background: none;\n border-radius: 6px;\n flex: none;\n padding: 2px 10px;\n}\n\n.dshc_remoteBody {\n flex: 1;\n min-height: 0;\n}\n";document.head.appendChild(s)})();
9
9
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
10
10
  // \0rolldown/runtime.js
11
11
  var __create = Object.create;
@@ -63,8 +63,9 @@ function randomUUID() {
63
63
  // src/client/channel-source.ts
64
64
  /** Relative URL of a stored attachment (same base as the other collab requests). */
65
65
  const attachmentUrl = (id) => `collab/api/attachments/${encodeURIComponent(id)}`;
66
- /** Read a browser File into the POST form. */
67
66
  const MAX_MESSAGE_BODY = 8388608;
67
+ /** #197: fallback when the service does not report its cap (`max_upload_bytes`); matches collab's DEFAULT_MAX_UPLOAD_BYTES. */
68
+ const DEFAULT_MAX_UPLOAD_BYTES = 1073741824;
68
69
  /** Whether a message with these attachments would exceed the server's body cap (checked before sending). */
69
70
  const messageTooLarge = (text, attachments) => new TextEncoder().encode(JSON.stringify({
70
71
  text,
@@ -72,16 +73,14 @@ const messageTooLarge = (text, attachments) => new TextEncoder().encode(JSON.str
72
73
  reply_to: Number.MAX_SAFE_INTEGER,
73
74
  attachments
74
75
  })).length > MAX_MESSAGE_BODY;
75
- const readAttachment = async (file) => {
76
- const bytes = new Uint8Array(await file.arrayBuffer());
77
- let binary = "";
78
- for (let i = 0; i < bytes.length; i += 32768) binary += String.fromCharCode(...bytes.subarray(i, i + 32768));
79
- return {
80
- name: file.name || "pasted",
81
- mime: file.type || "application/octet-stream",
82
- data: btoa(binary)
83
- };
76
+ /** Bytes as a limit reads in the UI: 1 GB, 500 MB, 12.5 MB. */
77
+ const formatBytes = (bytes) => {
78
+ if (bytes >= 1024 ** 3) return `${Number((bytes / 1024 ** 3).toFixed(2))} GB`;
79
+ if (bytes >= 1024 ** 2) return `${Number((bytes / 1024 ** 2).toFixed(1))} MB`;
80
+ return `${Math.max(1, Math.round(bytes / 1024))} KB`;
84
81
  };
82
+ /** The upload route's path for one file: a header cannot carry 中文, so name and type ride the query. */
83
+ const uploadUrl = (file) => `collab/api/attachments?name=${encodeURIComponent(file.name || "pasted")}&mime=${encodeURIComponent(file.type || "application/octet-stream")}`;
85
84
  /** #1023: the private chats, one per agent member, in id order. */
86
85
  const dmRooms = (rooms) => rooms.filter((r) => r.dm_member != null);
87
86
  /**
@@ -121,7 +120,8 @@ const INITIAL = {
121
120
  tasks: [],
122
121
  taskChat: void 0,
123
122
  hasMoreOlder: false,
124
- outbox: []
123
+ outbox: [],
124
+ maxUploadBytes: DEFAULT_MAX_UPLOAD_BYTES
125
125
  };
126
126
  /** Position of message `id` in rows ascending by id, or -1. */
127
127
  function indexOfId(rows, id) {
@@ -160,15 +160,77 @@ const rememberedRoom = () => {
160
160
  };
161
161
  /** Messages requested per catch-up read after a reconnect. */
162
162
  const CATCH_UP_LIMIT = 200;
163
+ /** #197: one file the composer holds beyond the service's cap, named so the message can say which. */
164
+ var UploadTooLarge = class extends Error {
165
+ fileName;
166
+ size;
167
+ limit;
168
+ constructor(fileName, size, limit) {
169
+ super(`${fileName}:${formatBytes(size)} > ${formatBytes(limit)}`);
170
+ this.fileName = fileName;
171
+ this.size = size;
172
+ this.limit = limit;
173
+ this.name = "UploadTooLarge";
174
+ }
175
+ };
176
+ /**
177
+ * #216: where the instance that lost the lock publishes its holder. It is an exact route the
178
+ * refused plugin registers before throwing, so it answers while every other `/collab/api/*`
179
+ * path is a bare 404.
180
+ */
181
+ const LOCK_HOLDER_PATH = "collab/api/lock";
163
182
  /** Status-coded service failure so the panel can tell "not enabled" from "not signed in". */
164
183
  var ServiceError = class extends Error {
165
184
  status;
166
- constructor(status, message) {
185
+ code;
186
+ /**
187
+ * @param status - HTTP status the service answered with.
188
+ * @param message - the service's own sentence, kept for logs and the fallback line.
189
+ * @param code - the machine code the service sends beside it (`conflict`, `invalid`, …), if any.
190
+ */
191
+ constructor(status, message, code) {
167
192
  super(message);
168
193
  this.status = status;
194
+ this.code = code;
169
195
  this.name = "ServiceError";
170
196
  }
171
197
  };
198
+ /** 工作区<n> is how a workspace is addressed, so the store refuses that shape for a chat channel (collab/store.mjs WORKSPACE_PREFIX). */
199
+ const WORKSPACE_NAME = /^工作区\d+$/;
200
+ /** The cap the service puts on a member name; source: collab/roster.mjs `MAX_NAME = 32`. */
201
+ const MEMBER_NAME_MAX = 32;
202
+ /** The one member name the service accepts with a space; source: collab/roster.mjs `validate` (`/^Claude Code(?:-\d+)?$/`). */
203
+ const MEMBER_NAME_SPACED = /^Claude Code(?:-\d+)?$/;
204
+ /**
205
+ * The member-name shape the service refuses, copied from collab/roster.mjs `validate` so a name it
206
+ * accepted (say `Claude Code`) is never blamed for an unrelated `invalid` such as a missing model.
207
+ * @param name - the name after the service's own trim.
208
+ * @returns whether the service would word this as a bad name.
209
+ */
210
+ function memberNameRefused(name) {
211
+ return name.length > MEMBER_NAME_MAX || /[@<>\r\n\t]/.test(name) || /\s/.test(name) && !MEMBER_NAME_SPACED.test(name);
212
+ }
213
+ /**
214
+ * #268: the collab service answers a refusal with `code` plus an English sentence, and the panel
215
+ * used to show that sentence as-is. Word the failures a person can act on from the `code` alone —
216
+ * never by matching the English text — and keep the service sentence only inside the last resort.
217
+ * @param error - whatever the action rejected with.
218
+ * @param t - the panel's dictionary, so an English UI stays English.
219
+ * @param place - the field being edited when the action failed.
220
+ * @param typed - the name the person typed, for the copy that names it.
221
+ * @returns one line to show under the form.
222
+ */
223
+ function errorText(error, t, place = "other", typed = "") {
224
+ const message = error instanceof Error ? error.message : String(error);
225
+ if (!(error instanceof ServiceError)) return message;
226
+ const code = error.code;
227
+ const name = place === "room" ? typed.trim().replace(/^#/, "") : typed.trim();
228
+ if (code === "conflict" && place === "room") return WORKSPACE_NAME.test(name) ? t("channelNameReserved", { name }) : t("channelNameTaken", { name });
229
+ if (code === "invalid" && place === "room") return t("channelNameInvalid");
230
+ if (code === "conflict" && place === "member") return t("memberNameTaken", { name });
231
+ if (code === "invalid" && place === "member" && memberNameRefused(name)) return t("memberNameInvalid");
232
+ return t("actionFailed", { message });
233
+ }
172
234
  function json(method, body) {
173
235
  return {
174
236
  method,
@@ -186,6 +248,37 @@ function browserTransport() {
186
248
  credentials: "same-origin",
187
249
  ...init
188
250
  }),
251
+ upload: (url, body, onProgress, signal) => new Promise((resolve, reject) => {
252
+ const xhr = new XMLHttpRequest();
253
+ xhr.open("POST", url);
254
+ xhr.withCredentials = true;
255
+ xhr.setRequestHeader("content-type", body.type || "application/octet-stream");
256
+ xhr.upload.addEventListener("progress", (event) => {
257
+ if (event.lengthComputable) onProgress(event.loaded, event.total);
258
+ });
259
+ xhr.addEventListener("load", () => {
260
+ let parsed;
261
+ try {
262
+ parsed = JSON.parse(xhr.responseText);
263
+ } catch {
264
+ parsed = void 0;
265
+ }
266
+ resolve({
267
+ status: xhr.status,
268
+ body: parsed
269
+ });
270
+ });
271
+ xhr.addEventListener("error", () => {
272
+ reject(/* @__PURE__ */ new Error("Upload failed: the connection dropped"));
273
+ });
274
+ xhr.addEventListener("abort", () => {
275
+ reject(/* @__PURE__ */ new Error("Upload cancelled"));
276
+ });
277
+ signal?.addEventListener("abort", () => {
278
+ xhr.abort();
279
+ }, { once: true });
280
+ xhr.send(body);
281
+ }),
189
282
  openEvents: (url) => new EventSource(url, { withCredentials: true }),
190
283
  url: (path) => new URL(path, document.baseURI).toString(),
191
284
  delay: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
@@ -208,6 +301,8 @@ function createChannelSource(transport) {
208
301
  /** Identifies the scheduled retry, so a stop() or a newer retry cancels it. */
209
302
  let reconnectToken;
210
303
  /** Unconfirmed messages for every room; the snapshot exposes the selected room's. */
304
+ /** #197: how big one attachment may be, as the service reported it (state) or the collab default. */
305
+ let uploadLimit = DEFAULT_MAX_UPLOAD_BYTES;
211
306
  let outbox = [];
212
307
  /**
213
308
  * Page-back request in flight per room, tagged with the ticket and the epoch
@@ -250,17 +345,54 @@ function createChannelSource(transport) {
250
345
  const response = await transport.fetch(transport.url(path), init);
251
346
  if (!response.ok) {
252
347
  const body = await response.json().catch(() => ({}));
253
- throw new ServiceError(response.status, body.error ?? response.statusText);
348
+ throw new ServiceError(response.status, body.error ?? response.statusText, body.code);
254
349
  }
255
350
  return await response.json();
256
351
  };
257
- const fail = (error) => {
258
- if (error instanceof ServiceError && error.status === 404) set({
259
- phase: "unavailable",
260
- error: void 0
261
- });
262
- else if (error instanceof ServiceError && error.status === 401) set({
352
+ /**
353
+ * #216: a 404 from the channel service means one of two things — no service is configured,
354
+ * or another DSH on this machine already holds the channel data and its plugin refused to
355
+ * start. Only the refusing instance knows which, and it publishes `busy` at
356
+ * `collab/api/lock` before it gives up; a host without that route answers 404 there too, so
357
+ * the plain "not configured" reading stands.
358
+ */
359
+ const readLockHolder = async () => {
360
+ try {
361
+ const body = await request(LOCK_HOLDER_PATH);
362
+ if (body.busy !== true) return body.free === true ? { free: true } : void 0;
363
+ return {
364
+ holder: body.owner ?? void 0,
365
+ dataDir: body.dataDir,
366
+ lock: body.lock,
367
+ free: false
368
+ };
369
+ } catch (error) {
370
+ return;
371
+ }
372
+ };
373
+ const fail = async (error, current = () => true) => {
374
+ if (error instanceof ServiceError && error.status === 404) {
375
+ const lock = await readLockHolder();
376
+ if (!current()) return;
377
+ if (lock !== void 0) set({
378
+ phase: "locked",
379
+ lockHolder: lock.holder,
380
+ lockDataDir: lock.dataDir,
381
+ lockPath: lock.lock,
382
+ lockFree: lock.free,
383
+ error: void 0
384
+ });
385
+ else set({
386
+ phase: "unavailable",
387
+ lockHolder: void 0,
388
+ lockDataDir: void 0,
389
+ lockPath: void 0,
390
+ lockFree: void 0,
391
+ error: void 0
392
+ });
393
+ } else if (error instanceof ServiceError && error.status === 401) set({
263
394
  phase: "unauthorized",
395
+ lockHolder: void 0,
264
396
  error: void 0
265
397
  });
266
398
  else set({
@@ -429,6 +561,7 @@ function createChannelSource(transport) {
429
561
  try {
430
562
  const state = await request("collab/api/state", { signal: read.controller.signal });
431
563
  if (!current()) return;
564
+ if (Number.isSafeInteger(state.max_upload_bytes) && (state.max_upload_bytes ?? 0) > 0) uploadLimit = state.max_upload_bytes;
432
565
  const remembered = previous.roomId === void 0 ? rememberedRoom() : void 0;
433
566
  const roomId = state.rooms.some((r) => r.id === previous.roomId) ? previous.roomId : state.rooms.some((r) => r.id === remembered) ? remembered : state.rooms[0]?.id;
434
567
  const rows = [];
@@ -483,6 +616,10 @@ function createChannelSource(transport) {
483
616
  let next = {
484
617
  phase: "ready",
485
618
  error: void 0,
619
+ lockHolder: void 0,
620
+ lockDataDir: void 0,
621
+ lockPath: void 0,
622
+ lockFree: void 0,
486
623
  rooms: state.rooms,
487
624
  roomId,
488
625
  members: state.members,
@@ -493,6 +630,7 @@ function createChannelSource(transport) {
493
630
  hasMoreNewer,
494
631
  leadId: state.lead_id ?? null,
495
632
  effectiveLeadId: state.effective_lead_id ?? state.lead_id ?? null,
633
+ maxUploadBytes: uploadLimit,
496
634
  tasks: keepBoard ? previous.tasks : [],
497
635
  taskChat: keepBoard ? previous.taskChat : void 0,
498
636
  outbox: outbox.filter((entry) => entry.roomId === roomId)
@@ -509,8 +647,8 @@ function createChannelSource(transport) {
509
647
  if (roomId !== void 0) loadBoard(owner, roomId);
510
648
  } catch (error) {
511
649
  if (!current()) return;
512
- pending = void 0;
513
- fail(error);
650
+ await fail(error, current);
651
+ if (pending === read) pending = void 0;
514
652
  }
515
653
  };
516
654
  const selectRoom = async (roomId) => {
@@ -573,6 +711,7 @@ function createChannelSource(transport) {
573
711
  pending?.controller.abort();
574
712
  pending = void 0;
575
713
  retry(owner);
714
+ refresh(true);
576
715
  };
577
716
  events.onmessage = (event) => {
578
717
  if (lifetime !== owner || stream !== events) return;
@@ -588,7 +727,7 @@ function createChannelSource(transport) {
588
727
  reconnectToken = token;
589
728
  const wait = backoffMs(attempt);
590
729
  attempt += 1;
591
- set({
730
+ if (snapshot.phase !== "locked" && snapshot.phase !== "unavailable" && snapshot.phase !== "unauthorized") set({
592
731
  phase: "reconnecting",
593
732
  error: void 0
594
733
  });
@@ -685,9 +824,33 @@ function createChannelSource(transport) {
685
824
  throw error;
686
825
  }
687
826
  };
827
+ /**
828
+ * #197: stream one file to the service and return the metadata the message names.
829
+ * The bytes never pass through the message JSON, so the size cap is the service's
830
+ * `maxUploadBytes` instead of MAX_MESSAGE_BODY.
831
+ */
832
+ const upload = async (file, onProgress, signal) => {
833
+ if (file.size > uploadLimit) throw new UploadTooLarge(file.name, file.size, uploadLimit);
834
+ if (transport.upload === void 0) throw new Error("This browser cannot stream uploads");
835
+ const { status, body } = await transport.upload(transport.url(uploadUrl(file)), file, onProgress ?? (() => {}), signal);
836
+ const value = body;
837
+ if (status === 413) {
838
+ uploadLimit = Number(value?.max_upload_bytes ?? uploadLimit);
839
+ throw new UploadTooLarge(file.name, file.size, uploadLimit);
840
+ }
841
+ const stored = value?.attachment;
842
+ if (status >= 400 || stored?.id === void 0) throw new ServiceError(status, value?.error ?? "Upload failed");
843
+ return {
844
+ id: stored.id,
845
+ name: stored.name ?? file.name,
846
+ mime: stored.mime ?? file.type,
847
+ size: stored.size ?? file.size
848
+ };
849
+ };
688
850
  return {
689
851
  source,
690
852
  actions: {
853
+ uploadAttachment: upload,
691
854
  async reviewTask(id, verdict, note) {
692
855
  const { task } = await request(`collab/api/tasks/${id}/review`, json("POST", {
693
856
  verdict,
@@ -706,8 +869,8 @@ function createChannelSource(transport) {
706
869
  set({ tasks: [...(snapshot.tasks ?? []).filter((row) => row.id !== task.id), task] });
707
870
  },
708
871
  selectRoom,
709
- async send(text, replyTo, attachments) {
710
- const roomId = snapshot.roomId;
872
+ async send(text, replyTo, attachments, targetRoomId) {
873
+ const roomId = targetRoomId ?? snapshot.roomId;
711
874
  if (roomId === void 0) throw new Error("No channel is open");
712
875
  await post(roomId, randomUUID(), text, replyTo, attachments);
713
876
  },
@@ -16648,6 +16811,44 @@ function softBreaksToHard(text) {
16648
16811
  for (let k = breaks.length - 1; k >= 0; k--) out = out.slice(0, breaks[k]) + " " + out.slice(breaks[k]);
16649
16812
  return out;
16650
16813
  }
16814
+ // src/client/collab-url.ts
16815
+ /**
16816
+ * #236: which DSH a channels panel talks to. The local panel uses the collab paths as they are
16817
+ * (`collab/api/…`, relative to document.baseURI); a panel opened from 其他电脑 on a paired
16818
+ * computer sends the same paths through this DSH's forwarder `collab/remote/<link>/…`
16819
+ * (dsh/collab/pairing.mjs remoteProxyRoute), so mentions, avatars, replies, attachments and the
16820
+ * task board all read and write the other computer and never this one.
16821
+ */
16822
+ /** Local panel: paths stay as they are. */
16823
+ const localCollabUrl = (path) => path;
16824
+ /** A paired link id, as dsh/collab/pairing.mjs PairClient issues them (randomUUID). */
16825
+ const LINK_ID = /^[0-9a-f-]{36}$/;
16826
+ /**
16827
+ * Paths of a paired computer, through this DSH's remote forwarder.
16828
+ * @param linkId - link id from `GET collab/api/remote/links`.
16829
+ * @returns the path mapper; non-collab paths (http links) are left alone.
16830
+ */
16831
+ function remoteCollabUrl(linkId) {
16832
+ if (!LINK_ID.test(linkId)) throw new Error(`bad remote link id: ${linkId}`);
16833
+ const mount = `collab/remote/${linkId}/`;
16834
+ return (path) => path.startsWith("collab/") ? mount + path.slice(7) : path;
16835
+ }
16836
+ /**
16837
+ * Same transport with its paths sent to a paired computer.
16838
+ * @param base - transport bound to this page (browserTransport).
16839
+ * @param map - path mapper from remoteCollabUrl.
16840
+ * @returns the remote transport.
16841
+ */
16842
+ function mappedTransport(base, map) {
16843
+ return {
16844
+ ...base,
16845
+ url: (path) => base.url(map(path))
16846
+ };
16847
+ }
16848
+ /** The mapper of the panel a component renders in; the local panel when none is provided. */
16849
+ const CollabUrlContext = (0, react.createContext)(localCollabUrl);
16850
+ /** Read the mapper of the surrounding channels panel. */
16851
+ const useCollabUrl = () => (0, react.useContext)(CollabUrlContext);
16651
16852
  // src/client/ChannelsPage.module.css
16652
16853
  var ChannelsPage_module_default = {
16653
16854
  "activeBusy": "dshc_activeBusy",
@@ -16789,6 +16990,10 @@ var ChannelsPage_module_default = {
16789
16990
  "imagePreviewImage": "dshc_imagePreviewImage",
16790
16991
  "imagePreviewTrigger": "dshc_imagePreviewTrigger",
16791
16992
  "input": "dshc_input",
16993
+ "inputComposing": "dshc_inputComposing",
16994
+ "inputHighlights": "dshc_inputHighlights",
16995
+ "inputMention": "dshc_inputMention",
16996
+ "inputSurface": "dshc_inputSurface",
16792
16997
  "jumpCount": "dshc_jumpCount",
16793
16998
  "jumpLatest": "dshc_jumpLatest",
16794
16999
  "leadCard": "dshc_leadCard",
@@ -16962,6 +17167,9 @@ var ChannelsPage_module_default = {
16962
17167
  "undoToast": "dshc_undoToast",
16963
17168
  "unreadBadge": "dshc_unreadBadge",
16964
17169
  "unreadDivider": "dshc_unreadDivider",
17170
+ "uploadBar": "dshc_uploadBar",
17171
+ "uploadFill": "dshc_uploadFill",
17172
+ "uploadState": "dshc_uploadState",
16965
17173
  "withdrawnRow": "dshc_withdrawnRow",
16966
17174
  "working": "dshc_working",
16967
17175
  "workspace": "dshc_workspace"
@@ -17027,8 +17235,10 @@ function useScheme() {
17027
17235
  // src/client/Attachments.tsx
17028
17236
  const isImage = (mime) => /^image\/(png|jpeg|gif|webp)$/.test(mime);
17029
17237
  const isAudio = (mime) => mime.startsWith("audio/");
17030
- const size = (bytes) => bytes < 1024 ? `${bytes} B` : bytes < 1048576 ? `${(bytes / 1024).toFixed(1)} KB` : `${(bytes / 1024 / 1024).toFixed(1)} MB`;
17238
+ const size = formatBytes;
17031
17239
  function ImageAttachment({ attachment: a, t }) {
17240
+ const url = useCollabUrl();
17241
+ const attachmentUrl$1 = (id) => url(attachmentUrl(id));
17032
17242
  const [opened, setOpened] = (0, react.useState)(false);
17033
17243
  const trigger = (0, react.useRef)(null);
17034
17244
  const dialog = (0, react.useRef)(null);
@@ -17060,7 +17270,7 @@ function ImageAttachment({ attachment: a, t }) {
17060
17270
  setCopyState("error");
17061
17271
  return;
17062
17272
  }
17063
- const response = await fetch(attachmentUrl(a.id));
17273
+ const response = await fetch(attachmentUrl$1(a.id));
17064
17274
  if (!response.ok) throw new Error("Image download failed");
17065
17275
  const blob = await response.blob();
17066
17276
  await navigator.clipboard.write([new ClipboardItem({ [blob.type]: blob })]);
@@ -17072,7 +17282,7 @@ function ImageAttachment({ attachment: a, t }) {
17072
17282
  const copyLabel = t(copyState === "copied" ? "attachmentCopied" : copyState === "copying" ? "attachmentCopying" : "attachmentCopy");
17073
17283
  const actions = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
17074
17284
  className: copyState === "error" ? ChannelsPage_module_default.primaryButton : ChannelsPage_module_default.secondaryButton,
17075
- href: attachmentUrl(a.id),
17285
+ href: attachmentUrl$1(a.id),
17076
17286
  download: a.name,
17077
17287
  target: "_blank",
17078
17288
  rel: "noreferrer",
@@ -17108,7 +17318,7 @@ function ImageAttachment({ attachment: a, t }) {
17108
17318
  onClick: () => setOpened(true),
17109
17319
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
17110
17320
  className: ChannelsPage_module_default.attachmentImage,
17111
- src: attachmentUrl(a.id),
17321
+ src: attachmentUrl$1(a.id),
17112
17322
  alt: a.name,
17113
17323
  loading: "lazy"
17114
17324
  })
@@ -17164,7 +17374,7 @@ function ImageAttachment({ attachment: a, t }) {
17164
17374
  }),
17165
17375
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
17166
17376
  className: ChannelsPage_module_default.imagePreviewImage,
17167
- src: attachmentUrl(a.id),
17377
+ src: attachmentUrl$1(a.id),
17168
17378
  alt: a.name
17169
17379
  }),
17170
17380
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -17180,6 +17390,8 @@ function ImageAttachment({ attachment: a, t }) {
17180
17390
  }
17181
17391
  /** Thumbnails for images, a download card for other files. */
17182
17392
  function AttachmentList({ attachments, t }) {
17393
+ const url = useCollabUrl();
17394
+ const attachmentUrl$2 = (id) => url(attachmentUrl(id));
17183
17395
  if (attachments === void 0 || attachments.length === 0) return null;
17184
17396
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
17185
17397
  className: ChannelsPage_module_default.attachments,
@@ -17191,11 +17403,11 @@ function AttachmentList({ attachments, t }) {
17191
17403
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("audio", {
17192
17404
  controls: true,
17193
17405
  preload: "metadata",
17194
- src: attachmentUrl(a.id),
17406
+ src: attachmentUrl$2(a.id),
17195
17407
  title: a.name
17196
17408
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
17197
17409
  className: ChannelsPage_module_default.attachmentSize,
17198
- href: attachmentUrl(a.id),
17410
+ href: attachmentUrl$2(a.id),
17199
17411
  download: a.name,
17200
17412
  children: [
17201
17413
  a.name,
@@ -17205,7 +17417,7 @@ function AttachmentList({ attachments, t }) {
17205
17417
  })]
17206
17418
  }, a.id) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
17207
17419
  className: ChannelsPage_module_default.attachmentFile,
17208
- href: attachmentUrl(a.id),
17420
+ href: attachmentUrl$2(a.id),
17209
17421
  download: a.name,
17210
17422
  children: [
17211
17423
  "📎 ",
@@ -17225,13 +17437,11 @@ const eventFiles = (list) => list === null ? [] : Array.from(list.files);
17225
17437
  * Composer helpers: an attach button with its hidden file input, the pending
17226
17438
  * list with remove buttons, and paste/drop handlers for the textarea.
17227
17439
  */
17228
- function useComposerAttachments(add, onError) {
17440
+ function useComposerAttachments(add) {
17229
17441
  const inputRef = (0, react.useRef)(null);
17230
17442
  const take = (files) => {
17231
17443
  if (files.length === 0) return;
17232
- Promise.all(files.map(readAttachment)).then(add).catch((error) => {
17233
- onError(error instanceof Error ? error.message : String(error));
17234
- });
17444
+ add(files);
17235
17445
  };
17236
17446
  return {
17237
17447
  onPaste(event) {
@@ -17281,37 +17491,67 @@ function useComposerAttachments(add, onError) {
17281
17491
  }
17282
17492
  };
17283
17493
  }
17284
- /** Files waiting to be sent with the next message. */
17285
- function PendingAttachments({ files, onRemove, removeLabel }) {
17494
+ /** Files waiting to be sent with the next message, each with its upload progress. */
17495
+ function PendingAttachments({ files, onRemove, removeLabel, labels }) {
17286
17496
  if (files.length === 0) return null;
17287
17497
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
17288
17498
  className: ChannelsPage_module_default.attachments,
17289
- children: files.map((f, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
17290
- className: ChannelsPage_module_default.attachmentFile,
17291
- children: [
17292
- isImage(f.mime) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
17293
- className: ChannelsPage_module_default.attachmentThumb,
17294
- src: `data:${f.mime};base64,${f.data}`,
17295
- alt: f.name
17296
- }) : "📎",
17297
- " ",
17298
- f.name,
17299
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
17300
- type: "button",
17301
- className: ChannelsPage_module_default.replyCancel,
17302
- title: removeLabel,
17303
- "aria-label": removeLabel,
17304
- onClick: () => onRemove(i),
17305
- children: "×"
17306
- })
17307
- ]
17308
- }, `${i}-${f.name}`))
17499
+ children: files.map((f) => {
17500
+ const percent = Math.round(f.progress * 100);
17501
+ const state = f.error !== void 0 ? f.error : f.attachment !== void 0 ? "" : percent > 0 ? labels.uploading : labels.queued;
17502
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
17503
+ className: ChannelsPage_module_default.attachmentFile,
17504
+ "data-state": f.error !== void 0 ? "failed" : f.attachment !== void 0 ? "done" : "uploading",
17505
+ children: [
17506
+ f.preview !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
17507
+ className: ChannelsPage_module_default.attachmentThumb,
17508
+ src: f.preview,
17509
+ alt: f.name
17510
+ }) : "📎",
17511
+ " ",
17512
+ f.name,
17513
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
17514
+ className: ChannelsPage_module_default.attachmentSize,
17515
+ children: size(f.size)
17516
+ }),
17517
+ f.attachment === void 0 && f.error === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
17518
+ className: ChannelsPage_module_default.uploadBar,
17519
+ role: "progressbar",
17520
+ "aria-valuenow": percent,
17521
+ "aria-valuemin": 0,
17522
+ "aria-valuemax": 100,
17523
+ "aria-label": `${f.name} ${percent}%`,
17524
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
17525
+ className: ChannelsPage_module_default.uploadFill,
17526
+ style: { width: `${percent}%` }
17527
+ })
17528
+ }),
17529
+ state !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
17530
+ className: ChannelsPage_module_default.uploadState,
17531
+ children: state
17532
+ }),
17533
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
17534
+ type: "button",
17535
+ className: ChannelsPage_module_default.replyCancel,
17536
+ title: removeLabel,
17537
+ "aria-label": removeLabel,
17538
+ onClick: () => onRemove(f.key),
17539
+ children: "×"
17540
+ })
17541
+ ]
17542
+ }, f.key);
17543
+ })
17309
17544
  });
17310
17545
  }
17311
17546
  // src/client/PanelPages.module.css
17312
17547
  var PanelPages_module_default = {
17313
17548
  "embed": "dshc_embed",
17314
- "frame": "dshc_frame"
17549
+ "frame": "dshc_frame",
17550
+ "remote": "dshc_remote",
17551
+ "remoteBack": "dshc_remoteBack",
17552
+ "remoteBar": "dshc_remoteBar",
17553
+ "remoteBody": "dshc_remoteBody",
17554
+ "remoteName": "dshc_remoteName"
17315
17555
  };
17316
17556
  // src/client/EmbedPage.tsx
17317
17557
  /**
@@ -17344,10 +17584,10 @@ function firstWebLink(text) {
17344
17584
  return /https?:\/\/[^\s<>()\]"'`]+/i.exec(text)?.[0].replace(/[.,;:!?。,;:!?]+$/, "");
17345
17585
  }
17346
17586
  /** The web page this message delivers: an .html upload first, else the first link. */
17347
- function deliverableOf(message) {
17587
+ function deliverableOf(message, url = (path) => path) {
17348
17588
  const page = message.attachments?.find(isHtmlAttachment);
17349
17589
  if (page !== void 0) return {
17350
- src: `${attachmentUrl(page.id)}?view=page`,
17590
+ src: `${url(attachmentUrl(page.id))}?view=page`,
17351
17591
  title: page.name,
17352
17592
  sameOrigin: true
17353
17593
  };
@@ -18495,7 +18735,8 @@ const GROUP_TITLE = {
18495
18735
  model: "slashGroupModel",
18496
18736
  view: "slashGroupView"
18497
18737
  };
18498
- function SlashMenu({ commands, selected, target, dmName, disabled = () => false, grouped, t, onPick, onHover }) {
18738
+ function SlashMenu({ commands, selected, target, leadName, dmName, disabled = () => false, grouped, t, onPick, onHover }) {
18739
+ const noCmd = dmName ?? leadName;
18499
18740
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
18500
18741
  className: `${ChannelsPage_module_default.mentionPopup} ${ChannelsPage_module_default.slashPopup}`,
18501
18742
  role: "region",
@@ -18503,7 +18744,7 @@ function SlashMenu({ commands, selected, target, dmName, disabled = () => false,
18503
18744
  children: [
18504
18745
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
18505
18746
  className: ChannelsPage_module_default.mentionTitle,
18506
- children: target !== void 0 ? t("slashTitleLead", { name: target }) : dmName !== void 0 ? t("slashTitleDmNoCmd", { name: dmName }) : t("slashTitleNoLead")
18747
+ children: target !== void 0 ? t("slashTitleLead", { name: target }) : noCmd !== void 0 ? t("slashTitleDmNoCmd", { name: noCmd }) : t("slashTitleNoLead")
18507
18748
  }),
18508
18749
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
18509
18750
  role: "listbox",
@@ -18810,10 +19051,248 @@ function insertMention(text, caret, member) {
18810
19051
  * Highlights valid channel members/roles as pill badges (Discord-style),
18811
19052
  * cleanly separated from regular text, without false positives in code or emails.
18812
19053
  */
19054
+ const FENCE = "```";
18813
19055
  function escapeRegex(s) {
18814
19056
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
18815
19057
  }
18816
19058
  /**
19059
+ * True when the text holds a blank line: two line endings with only spaces or tabs between.
19060
+ * A `code span` cannot cross one — the blank line ends the paragraph, so the renderer closes the
19061
+ * span before it (#245: `@肥鱼` + blank line + `@G哥` inside one pair of backticks is plain text
19062
+ * on the page, and must be plain text on the backend too).
19063
+ */
19064
+ function hasBlankLine(text) {
19065
+ return /\n[ \t]*\n/.test(text.replace(/\r\n?/g, "\n"));
19066
+ }
19067
+ const HTML_BLOCK_TAGS = "address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul";
19068
+ const HTML_BLOCK_TAG = new RegExp(`^ {0,3}</?(?:${HTML_BLOCK_TAGS})(?:[ \\t]|/?>|$)`, "i");
19069
+ const HTML_ANY_TAG = /^ {0,3}<\/?[A-Za-z][A-Za-z0-9-]*(?:[ \t]+[^<>]*)?[ \t]*\/?>[ \t]*$/;
19070
+ const LIST_MARKER = /^ {0,3}(?:[-*+]|\d{1,9}[.)])(?=[ \t]|$)/;
19071
+ const FENCE_LINE = /^ {0,3}(?:`{3,}|~{3,})/;
19072
+ /** Columns the leading indent of `text` covers, starting from column `base`. */
19073
+ function indentWidth(text, base = 0) {
19074
+ let col = base;
19075
+ for (const ch of text) if (ch === " ") col += 1;
19076
+ else if (ch === " ") col += 4 - col % 4;
19077
+ else break;
19078
+ return col - base;
19079
+ }
19080
+ /**
19081
+ * The blockquote prefix at `line[i]` (three spaces at most, then `>` and one optional blank), read
19082
+ * from column `col`; `{ next, col }` after it, or undefined when the line has none there.
19083
+ */
19084
+ function quotePrefixAt(line, from, col) {
19085
+ let i = from;
19086
+ let at = col;
19087
+ let spaces = 0;
19088
+ while (spaces < 4 && line[i] === " ") {
19089
+ i++;
19090
+ at++;
19091
+ spaces++;
19092
+ }
19093
+ if (spaces > 3 || line[i] !== ">") return void 0;
19094
+ i++;
19095
+ at++;
19096
+ if (line[i] === " " || line[i] === " ") {
19097
+ at += line[i] === " " ? 4 - at % 4 : 1;
19098
+ i++;
19099
+ }
19100
+ return {
19101
+ next: i,
19102
+ col: at
19103
+ };
19104
+ }
19105
+ /** Strips every blockquote marker of a line, so its content can be measured from column 0. */
19106
+ function stripQuotes(line) {
19107
+ let i = 0;
19108
+ let col = 0;
19109
+ let depth = 0;
19110
+ for (;;) {
19111
+ const prefix = quotePrefixAt(line, i, col);
19112
+ if (!prefix) return {
19113
+ rest: line.slice(i),
19114
+ depth,
19115
+ col
19116
+ };
19117
+ i = prefix.next;
19118
+ col = prefix.col;
19119
+ depth++;
19120
+ }
19121
+ }
19122
+ /**
19123
+ * Column where a list item's content begins, or undefined when the line is not a list item. An
19124
+ * empty marker (`1.` alone on its line) cannot open a list inside a paragraph, so it counts as
19125
+ * neither.
19126
+ */
19127
+ function itemContentIndent(line) {
19128
+ const { rest, col } = stripQuotes(line);
19129
+ const lead = indentWidth(rest, col);
19130
+ if (lead >= 4) return void 0;
19131
+ const body = rest.slice(/^[ \t]*/.exec(rest)[0].length);
19132
+ const marker = LIST_MARKER.exec(body);
19133
+ if (!marker) return void 0;
19134
+ if (body.slice(marker[0].length).trim() === "") return void 0;
19135
+ const gap = /^[ \t]*/.exec(body.slice(marker[0].length))[0];
19136
+ const padding = gap === "" ? 1 : Math.min(indentWidth(gap, col + lead + marker[0].length), 4);
19137
+ return lead + marker[0].length + padding;
19138
+ }
19139
+ /**
19140
+ * True when a line whose content starts with `content` opens one of the block-level structures
19141
+ * this rule knows, ending the paragraph before it: ATX headings, setext underlines, thematic
19142
+ * breaks, backtick fences, list items, HTML blocks and a further quote marker. Tilde fences and
19143
+ * math blocks also end a paragraph in CommonMark, but the backend reads neither, so treating them
19144
+ * as spans keeps a different bug out of this change (#259 stays on the six families the report
19145
+ * names; the deviation list above splitMentions() records both). A footnote definition is handled
19146
+ * by footnoteRanges(), not here: it ends a body, not the paragraph a code span sits in (#271).
19147
+ * `container` is set for a line that lazily continues an outer container: there a bare list
19148
+ * marker or a lone HTML tag already opens a block the paragraph cannot hold.
19149
+ */
19150
+ function startsBlock(content, setext = true, container = false) {
19151
+ if (indentWidth(content) >= 4) return false;
19152
+ if (container && /^ {0,3}(?:[-*+]|\d{1,9}[.)])(?:[ \t]|$)/.test(content)) return true;
19153
+ if (container && HTML_ANY_TAG.test(content)) return true;
19154
+ return /^ {0,3}#{1,6}(?:[ \t]|$)/.test(content) || setext && /^ {0,3}(?:=+|-+)[ \t]*$/.test(content) || /^ {0,3}(?:[*\-_][ \t]*){3,}$/.test(content) || /^ {0,3}`{3,}[^`]*$/.test(content) || /^ {0,3}>/.test(content) || /^ {0,3}[-*+][ \t]+\S/.test(content) || /^ {0,3}1[.)][ \t]+\S/.test(content) || /^ {0,3}<(?:script|pre|style|textarea)(?:[ \t>]|$)/i.test(content) || /^ {0,3}<!--/.test(content) || /^ {0,3}<\?/.test(content) || /^ {0,3}<![A-Za-z]/.test(content) || /^ {0,3}<!\[CDATA\[/.test(content) || HTML_BLOCK_TAG.test(content);
19155
+ }
19156
+ /**
19157
+ * [start, end) offsets of every physical line; CRLF, CR and LF all end one. Read once per
19158
+ * codeSpanRanges() call and handed to lineIndex(), not rescanned per backtick run (#271: doing
19159
+ * that cost O(runs × lines) — 128 KiB of one-backtick lines took 54 s inside hub.post's
19160
+ * transaction).
19161
+ */
19162
+ function splitLines(text) {
19163
+ const lines = [];
19164
+ for (let start = 0; start <= text.length;) {
19165
+ let end = start;
19166
+ while (end < text.length && text[end] !== "\n" && text[end] !== "\r") end++;
19167
+ lines.push([start, end]);
19168
+ if (end >= text.length) break;
19169
+ start = text[end] === "\r" && text[end + 1] === "\n" ? end + 2 : end + 1;
19170
+ }
19171
+ return lines;
19172
+ }
19173
+ /**
19174
+ * The line holding `offset`: the last line that starts at or before it. `splitLines` covers the
19175
+ * whole text contiguously, so that is the line `offset` sits on, or the one that ends there.
19176
+ */
19177
+ function lineAt(lines, offset) {
19178
+ let lo = 0;
19179
+ let hi = lines.length - 1;
19180
+ while (lo < hi) {
19181
+ const mid = lo + hi + 1 >> 1;
19182
+ if (lines[mid][0] <= offset) lo = mid;
19183
+ else hi = mid - 1;
19184
+ }
19185
+ return lo;
19186
+ }
19187
+ function lineFacts(text, lines, i) {
19188
+ const line = text.slice(lines[i][0], lines[i][1]);
19189
+ const { rest, depth, col } = stripQuotes(line);
19190
+ return {
19191
+ blank: line.trim() === "",
19192
+ fence: FENCE_LINE.test(line),
19193
+ itemIndent: itemContentIndent(line),
19194
+ rest,
19195
+ depth,
19196
+ col,
19197
+ atDepth: startsBlock(rest, false, true)
19198
+ };
19199
+ }
19200
+ function lineIndex(text) {
19201
+ const lines = splitLines(text);
19202
+ const facts = lines.map((_, i) => lineFacts(text, lines, i));
19203
+ const contained = new Array(lines.length);
19204
+ for (let i = 0; i < lines.length; i++) {
19205
+ const f = facts[i];
19206
+ if (f.blank || f.fence) {
19207
+ contained[i] = {
19208
+ baseIndent: 0,
19209
+ depth: 0
19210
+ };
19211
+ continue;
19212
+ }
19213
+ const run = i > 0 && !facts[i - 1].blank && !facts[i - 1].fence ? contained[i - 1] : void 0;
19214
+ contained[i] = {
19215
+ baseIndent: f.itemIndent !== void 0 ? f.itemIndent : run ? run.baseIndent : 0,
19216
+ depth: Math.max(f.depth, run ? run.depth : 0)
19217
+ };
19218
+ }
19219
+ return {
19220
+ lines,
19221
+ facts,
19222
+ contained
19223
+ };
19224
+ }
19225
+ /**
19226
+ * True when the text between an opening and a closing backtick run holds something that ends the
19227
+ * paragraph, so the run cannot close the span (#259): a blank line, or a line that opens a
19228
+ * block-level structure. The renderer decides this inside the containers the span sits in, so the
19229
+ * list item's content indent and the blockquote depth of the opening line are carried along, and
19230
+ * a line that lazily continues an outer container is judged by what it would start there.
19231
+ *
19232
+ * `index` is the lineIndex(text) of the whole text, shared by every pair (#271): rebuilt per pair
19233
+ * it cost O(runs × lines), 128 KiB of one-backtick lines taking 54 s.
19234
+ */
19235
+ function endsParagraph(text, from, to, index) {
19236
+ if (hasBlankLine(text.slice(from, to))) return true;
19237
+ const { lines, facts, contained } = index;
19238
+ const openLine = lineAt(lines, from);
19239
+ const { baseIndent, depth: openDepth } = contained[openLine];
19240
+ for (let i = openLine + 1; i < lines.length && lines[i][0] < to; i++) {
19241
+ const f = facts[i];
19242
+ if (f.rest.trim() === "") return true;
19243
+ if (f.depth > openDepth) return true;
19244
+ if (f.depth < openDepth) {
19245
+ if (f.atDepth) return true;
19246
+ continue;
19247
+ }
19248
+ const indent = indentWidth(f.rest, f.col) - baseIndent;
19249
+ if (startsBlock(" ".repeat(Math.max(0, indent)) + f.rest.trimStart(), indent >= 0, indent < 0)) return true;
19250
+ }
19251
+ return false;
19252
+ }
19253
+ /**
19254
+ * Offsets of Markdown inline code spans, [start, end) each, matching what the markdown renderer
19255
+ * turns into <code> and the backend skips (dsh/collab/mentions.mjs codeSpanRanges — keep them in
19256
+ * step). A span is a run of backticks closed by a run of the same length inside the same
19257
+ * paragraph; it may hold single line breaks but nothing that ends the paragraph (a blank line
19258
+ * #245, or a block-level structure #259). A lone backtick stays literal text, and runs of three
19259
+ * or more are fences, left to fencedRanges().
19260
+ */
19261
+ function codeSpanRanges(text) {
19262
+ const runs = [];
19263
+ for (let i = 0; i < text.length;) {
19264
+ if (text[i] !== "`") {
19265
+ i++;
19266
+ continue;
19267
+ }
19268
+ let j = i;
19269
+ while (j < text.length && text[j] === "`") j++;
19270
+ runs.push({
19271
+ start: i,
19272
+ len: j - i
19273
+ });
19274
+ i = j;
19275
+ }
19276
+ const ranges = [];
19277
+ let index;
19278
+ for (let k = 0; k < runs.length; k++) {
19279
+ const { start, len } = runs[k];
19280
+ if (len >= 3) continue;
19281
+ for (let c = k + 1; c < runs.length; c++) {
19282
+ if (runs[c].len !== len) continue;
19283
+ if (endsParagraph(text, start + len, runs[c].start, index ??= lineIndex(text))) break;
19284
+ ranges.push([start + len, runs[c].start]);
19285
+ k = c;
19286
+ break;
19287
+ }
19288
+ }
19289
+ return ranges;
19290
+ }
19291
+ /** True when [index, index + len) overlaps any excluded range. */
19292
+ function overlaps(ranges, index, len) {
19293
+ return ranges.some(([start, end]) => index < end && index + len > start);
19294
+ }
19295
+ /**
18817
19296
  * Builds a regex matcher and lookup map for channel member mention aliases.
18818
19297
  * Longest aliases are prioritized so e.g. "@阿柚子" matches before "@阿柚".
18819
19298
  */
@@ -18846,7 +19325,287 @@ function buildMentionMatcher(members) {
18846
19325
  };
18847
19326
  }
18848
19327
  /**
18849
- * Splits plain text into non-mention and mention segments.
19328
+ * Offsets of ``` fenced blocks, [start, end) each, the way the backend reads them
19329
+ * (dsh/collab/mentions.mjs split(): text.split('```') and odd parts are inside a fence).
19330
+ * An unterminated fence runs to the end of the text, as it does there.
19331
+ */
19332
+ function fencedRanges(text) {
19333
+ const ranges = [];
19334
+ let open = -1;
19335
+ let at = text.indexOf(FENCE);
19336
+ while (at >= 0) {
19337
+ if (open < 0) open = at + 3;
19338
+ else {
19339
+ ranges.push([open, at]);
19340
+ open = -1;
19341
+ }
19342
+ at = text.indexOf(FENCE, at + 3);
19343
+ }
19344
+ if (open >= 0) ranges.push([open, text.length]);
19345
+ return ranges;
19346
+ }
19347
+ /** A definition line: `[^label]:` at 0-3 columns, the label holding no space or bracket. */
19348
+ const FOOTNOTE_DEF = /^ {0,3}\[\^([^\]\s]+)\]:/;
19349
+ /** A line that opens an HTML block (CommonMark types 1-6): its lines are raw until a blank one. */
19350
+ const HTML_OPEN = new RegExp(`^ {0,3}(?:<(?:script|pre|style|textarea)(?:[ \\t>]|$)|<!--|<\\?|<![A-Za-z]|<!\\[CDATA\\[|</?(?:${HTML_BLOCK_TAGS})(?:[ \\t>]|/?>|$))`, "i");
19351
+ /**
19352
+ * True when a line at 0-3 columns opens a block, so it ends a footnote body before it. A setext
19353
+ * underline (`===`, `--`) is absorbed by the definition's own paragraph and does not end it, while
19354
+ * a bare `-` or `1.` does, because it opens a list. A tilde fence is left out on purpose: it ends a
19355
+ * body in CommonMark, but the backend reads only ``` fences (#259), and the footnote rule stays on
19356
+ * the same side of that gap.
19357
+ */
19358
+ function endsDefinitionBody(rest) {
19359
+ if (indentWidth(rest) >= 4) return false;
19360
+ const c = rest.replace(/^[ \t]*/, "");
19361
+ if (/^(?:[*\-_][ \t]*){3,}$/.test(c)) return true;
19362
+ if (/^(?:[-*+]|\d{1,9}[.)])(?:[ \t]|$)/.test(c)) return true;
19363
+ if (/^(?:=+|-+)[ \t]*$/.test(c)) return false;
19364
+ return /^#{1,6}(?:[ \t]|$)/.test(c) || /^\$\$/.test(c) || /^ {0,3}`{3,}[^`]*$/.test(c) || /^>/.test(c) || /^ {0,3}<(?:script|pre|style|textarea)(?:[ \t>]|$)/i.test(c) || /^ {0,3}<!--/.test(c) || /^ {0,3}<\?/.test(c) || /^ {0,3}<![A-Za-z]/.test(c) || /^ {0,3}<!\[CDATA\[/.test(c) || HTML_BLOCK_TAG.test(c) || HTML_ANY_TAG.test(c);
19365
+ }
19366
+ /**
19367
+ * Ranges whose lines the renderer does not read as Markdown at all, so a `[^x]:` inside one is
19368
+ * plain text and not a definition: backtick fences, `~~~` fences and `$$` math blocks.
19369
+ */
19370
+ function footnoteOpaqueRanges(text) {
19371
+ const ranges = [...fencedRanges(text)];
19372
+ for (const open of [/^ {0,3}~{3,}/, /^ {0,3}\$\$/]) {
19373
+ let start = -1;
19374
+ let at = 0;
19375
+ for (const line of text.split("\n")) {
19376
+ if (open.test(line)) {
19377
+ if (start < 0) start = at;
19378
+ else {
19379
+ ranges.push([start, at + line.length]);
19380
+ start = -1;
19381
+ }
19382
+ }
19383
+ at += line.length + 1;
19384
+ }
19385
+ if (start >= 0) ranges.push([start, text.length]);
19386
+ }
19387
+ return ranges;
19388
+ }
19389
+ /** Lines of an HTML block: from its opening line to the line before the next blank one. */
19390
+ function htmlBlockRegions(text, lines) {
19391
+ const regions = [];
19392
+ for (let i = 0; i < lines.length; i++) {
19393
+ if (!HTML_OPEN.test(text.slice(lines[i][0], lines[i][1]))) continue;
19394
+ let end = i;
19395
+ while (end + 1 < lines.length && text.slice(lines[end + 1][0], lines[end + 1][1]).trim() !== "") end++;
19396
+ regions.push([lines[i][0], lines[end][1]]);
19397
+ i = end;
19398
+ }
19399
+ return regions;
19400
+ }
19401
+ /**
19402
+ * Every footnote definition in the text with the container it sits in: `depth` quote markers and
19403
+ * `base` the content indent of the list item that holds it (0 at the top level). Read from the
19404
+ * first line only, which is enough to walk the body.
19405
+ *
19406
+ * `marker` is where the `[^label]:` marker of the line ends. Only that prefix is invisible on the
19407
+ * page; the text after it is the definition's own body and shows up in the footnote section, so a
19408
+ * reference there is a reference a reader can see (#271).
19409
+ */
19410
+ function footnoteDefs(text, lines) {
19411
+ const defs = [];
19412
+ const opaque = [...footnoteOpaqueRanges(text), ...htmlBlockRegions(text, lines)];
19413
+ const inside = (offset) => opaque.some(([start, end]) => offset >= start && offset < end);
19414
+ for (let i = 0; i < lines.length; i++) {
19415
+ if (inside(lines[i][0])) continue;
19416
+ const { rest, depth, col } = stripQuotes(text.slice(lines[i][0], lines[i][1]));
19417
+ let m = FOOTNOTE_DEF.exec(rest);
19418
+ if (m) {
19419
+ defs.push({
19420
+ line: i,
19421
+ label: m[1],
19422
+ depth,
19423
+ base: 0,
19424
+ marker: lines[i][1] - rest.length + m[0].length
19425
+ });
19426
+ continue;
19427
+ }
19428
+ const marker = LIST_MARKER.exec(rest);
19429
+ if (!marker) continue;
19430
+ const after = rest.slice(marker[0].length);
19431
+ const gap = /^[ \t]*/.exec(after)[0];
19432
+ if (gap === "") continue;
19433
+ const indent = indentWidth(gap, col + marker[0].length);
19434
+ const content = after.slice(gap.length);
19435
+ const pad = content.length < 4 ? Math.min(indent, 3) : 0;
19436
+ m = FOOTNOTE_DEF.exec(" ".repeat(pad) + content);
19437
+ if (m && indent < 4) defs.push({
19438
+ line: i,
19439
+ label: m[1],
19440
+ depth,
19441
+ base: indent,
19442
+ marker: lines[i][1] - content.length + m[0].length - pad
19443
+ });
19444
+ }
19445
+ return defs;
19446
+ }
19447
+ /**
19448
+ * Last line of the body of `def`, walking the lines its paragraph covers.
19449
+ *
19450
+ * Two collected definitions can never sit inside one body: mdast nests a second definition inside
19451
+ * the first only when its line is indented four or more columns past the first one's content
19452
+ * column, and such a line is never collected as a definition (footnoteDefs() reads `[^x]:` at 0-3
19453
+ * columns only, like every other list marker). A line it does collect therefore opens a block of
19454
+ * its own, so the walk stops there with the last line it really covered — no shortcut needed, and
19455
+ * no re-walking either: both bodies end before the next definition line, which keeps the whole
19456
+ * pass linear in the text. This says nothing about a *nested* definition the page still renders:
19457
+ * that one is not collected here at all, and its page semantics stay a known deviation below.
19458
+ */
19459
+ function definitionBodyEnd(text, lines, def, next) {
19460
+ let last = def.line;
19461
+ let open = text.slice(def.marker, lines[def.line][1]).trim() !== "";
19462
+ for (let j = def.line + 1; j < lines.length; j++) {
19463
+ if (j === next) break;
19464
+ const { rest, depth, col } = stripQuotes(text.slice(lines[j][0], lines[j][1]));
19465
+ if (rest.trim() === "") {
19466
+ let k = j;
19467
+ while (k < lines.length) {
19468
+ if (stripQuotes(text.slice(lines[k][0], lines[k][1])).rest.trim() !== "") break;
19469
+ k++;
19470
+ }
19471
+ if (k < lines.length) {
19472
+ const r = stripQuotes(text.slice(lines[k][0], lines[k][1]));
19473
+ if (r.depth >= def.depth && indentWidth(r.rest, r.col) - def.base >= 4) {
19474
+ j = k - 1;
19475
+ last = k - 1;
19476
+ open = true;
19477
+ continue;
19478
+ }
19479
+ }
19480
+ break;
19481
+ }
19482
+ if (depth > def.depth) break;
19483
+ if (depth < def.depth) {
19484
+ if (!open || endsDefinitionBody(rest)) break;
19485
+ last = j;
19486
+ continue;
19487
+ }
19488
+ if (indentWidth(rest, col) - def.base >= 4) {
19489
+ last = j;
19490
+ open = true;
19491
+ continue;
19492
+ }
19493
+ if (endsDefinitionBody(rest)) break;
19494
+ if (!open) break;
19495
+ last = j;
19496
+ }
19497
+ return last;
19498
+ }
19499
+ /** Ranges sorted and merged, so overlapping and stacked ranges cost one pass. */
19500
+ function mergeRanges(ranges) {
19501
+ const sorted = [...ranges].sort((a, b) => a[0] - b[0] || a[1] - b[1]);
19502
+ const out = [];
19503
+ for (const [start, end] of sorted) {
19504
+ const last = out[out.length - 1];
19505
+ if (last && start <= last[1]) last[1] = Math.max(last[1], end);
19506
+ else out.push([start, end]);
19507
+ }
19508
+ return out;
19509
+ }
19510
+ /** `text` with every `[start, end)` blanked out, line endings kept so offsets stay put. */
19511
+ function maskText(text, ranges) {
19512
+ const chars = text.split("");
19513
+ for (const [start, end] of mergeRanges(ranges)) for (let i = start; i < end && i < chars.length; i++) if (chars[i] !== "\n" && chars[i] !== "\r") chars[i] = " ";
19514
+ return chars.join("");
19515
+ }
19516
+ /**
19517
+ * [start, end) of every hidden footnote definition: the definition line and the lines that
19518
+ * continue it, for each label nothing readable refers to. A repeated label keeps only its first
19519
+ * definition (the renderer shows that one and drops the rest), and a reference counts only where a
19520
+ * reader can see it — not inside a fence, an inline code span, an HTML comment, the `[^x]:` marker
19521
+ * of a definition line or another hidden body. The text after the marker of a definition line is
19522
+ * the body the page prints in the footnote section, so a reference there does count. The backend
19523
+ * applies the same rule in mentions(), so the page and the gate agree on what was called.
19524
+ *
19525
+ * The early return keeps the cost off ordinary text: without `[^` nothing is scanned at all.
19526
+ */
19527
+ function footnoteRanges(text, codeSpans) {
19528
+ if (!text.includes("[^")) return [];
19529
+ const spans = codeSpans ?? codeSpanRanges(text);
19530
+ const lines = splitLines(text);
19531
+ const defs = footnoteDefs(text, lines);
19532
+ if (defs.length === 0) return [];
19533
+ const ends = defs.map((def, k) => definitionBodyEnd(text, lines, def, k + 1 < defs.length ? defs[k + 1].line : void 0));
19534
+ const bodies = defs.map((def, k) => [lines[def.line][0], lines[ends[k]][1]]);
19535
+ const blind = [
19536
+ ...spans,
19537
+ ...footnoteOpaqueRanges(text),
19538
+ ...htmlBlockRegions(text, lines)
19539
+ ];
19540
+ for (const def of defs) blind.push([lines[def.line][0], def.marker]);
19541
+ for (const m of text.matchAll(/<!--[\s\S]*?-->/g)) blind.push([m.index, m.index + m[0].length]);
19542
+ const searchable = maskText(text, blind);
19543
+ const first = /* @__PURE__ */ new Map();
19544
+ defs.forEach((def, i) => {
19545
+ const key = def.label.toLowerCase();
19546
+ if (!first.has(key)) first.set(key, i);
19547
+ });
19548
+ const calledOutside = /* @__PURE__ */ new Set();
19549
+ const insideBody = defs.map(() => /* @__PURE__ */ new Set());
19550
+ let body = 0;
19551
+ for (const m of searchable.matchAll(/\[\^([^\]\s]+)\]/g)) {
19552
+ let slashes = 0;
19553
+ for (let i = m.index - 1; i >= 0 && searchable[i] === "\\"; i--) slashes++;
19554
+ if (slashes % 2 !== 0) continue;
19555
+ while (body < bodies.length && bodies[body][1] <= m.index) body++;
19556
+ const owner = body < bodies.length && m.index >= bodies[body][0] ? body : -1;
19557
+ (owner < 0 ? calledOutside : insideBody[owner]).add(m[1].toLowerCase());
19558
+ }
19559
+ const shown = /* @__PURE__ */ new Set();
19560
+ const pending = [];
19561
+ const open = (labels) => {
19562
+ for (const label of labels) {
19563
+ const i = first.get(label);
19564
+ if (i === void 0 || shown.has(i)) continue;
19565
+ shown.add(i);
19566
+ pending.push(i);
19567
+ }
19568
+ };
19569
+ open(calledOutside);
19570
+ while (pending.length > 0) open(insideBody[pending.pop()]);
19571
+ const hidden = [];
19572
+ defs.forEach((def, i) => {
19573
+ if (!shown.has(i)) hidden.push([lines[def.line][0], lines[ends[i]][1]]);
19574
+ });
19575
+ return mergeRanges(hidden);
19576
+ }
19577
+ /**
19578
+ * Known deviations from the page, kept on purpose (#259, #271). Each one showed the same answer
19579
+ * before this code was written, so the list is the honest edge of this rule, not a regression:
19580
+ *
19581
+ * - `~~~` fences: the page renders them as code, the backend reads only ```, so a name inside one
19582
+ * is coloured nowhere and called there.
19583
+ * - `$$` math blocks: the page ends a paragraph at one, the backend does not, so a code span that
19584
+ * crosses `$$` holds there and breaks here (nobody called, page colours both names).
19585
+ * - A GFM table delimiter row (`|---|`): same shape — the page ends the paragraph, the backend
19586
+ * keeps the span, so nobody is called while the page colours both names.
19587
+ * - A four-column indented code block: the page renders it as code and colours nothing, the
19588
+ * backend has no indented-code reader and calls the name. The footnote rule below shares it: a
19589
+ * `[^x]:` line indented four columns is a code block on the page and hidden there, and it is
19590
+ * not a definition here either, so a name on that line is a call there. Likewise a `[^2]` written
19591
+ * only on a four-column line is not a reference on the page, while this backend reads it as one
19592
+ * and shows the `[^2]:` definition the page keeps hidden.
19593
+ * - A nested definition — a `[^x]:` line indented four or more columns past the outer body's
19594
+ * content column. The page nests it under the outer footnote and shows it only when its own
19595
+ * label is called; this splitter collects definitions at 0-3 columns only, so that line is never
19596
+ * a definition here. Both matchers then give the same answer, and it is not the page's, in both
19597
+ * directions: `[^1]: a` / four-column `[^2]: 注 @name` / `见 [^1]` colours the name here while
19598
+ * the page renders the outer footnote as `a` with no badge, and with `见 [^2]` nothing is
19599
+ * coloured here while the page does show the badge. Same on bdd67b4 — not a regression of #271,
19600
+ * and #323 corrected the notes instead of widening the implementation.
19601
+ * - A code span opened on a block line (`# ` + backtick + name): the paragraph already ended
19602
+ * before the opener, so the page never makes it a span and colours the names; endsParagraph()
19603
+ * only reads the lines between the runs, so the span still holds here.
19604
+ *
19605
+ * Splits plain text into non-mention and mention segments. An @ inside a ``` fence, an inline
19606
+ * code span or a hidden footnote definition is left as text: the backend does not call anyone
19607
+ * there (dsh/collab/mentions.mjs), so colouring it would promise a call that never happens (#237,
19608
+ * #271).
18850
19609
  */
18851
19610
  function splitMentions(text, members) {
18852
19611
  if (!text) return [];
@@ -18854,10 +19613,17 @@ function splitMentions(text, members) {
18854
19613
  if (!matcher) return [{ text }];
18855
19614
  const { regex, aliasMap } = matcher;
18856
19615
  const segments = [];
19616
+ const codeSpans = codeSpanRanges(text);
19617
+ const skip = [
19618
+ ...fencedRanges(text),
19619
+ ...codeSpans,
19620
+ ...footnoteRanges(text, codeSpans)
19621
+ ];
18857
19622
  let lastIndex = 0;
18858
19623
  for (const match of text.matchAll(regex)) {
18859
19624
  const matchText = match[0];
18860
19625
  const startIndex = match.index ?? 0;
19626
+ if (overlaps(skip, startIndex, matchText.length)) continue;
18861
19627
  if (startIndex > lastIndex) segments.push({ text: text.slice(lastIndex, startIndex) });
18862
19628
  const member = aliasMap.get(matchText);
18863
19629
  segments.push({
@@ -18999,13 +19765,14 @@ const AVATARS = [
18999
19765
  /**
19000
19766
  * Image source for a member avatar.
19001
19767
  * @param avatar - built-in slug, http(s) URL announced by a bot, or empty.
19768
+ * @param url - #236 path mapper of the panel (a paired computer's panel reads its avatars).
19002
19769
  * @returns a URL relative to the document base, the absolute URL, or undefined for the initial badge.
19003
19770
  */
19004
- function avatarSrc(avatar) {
19771
+ function avatarSrc(avatar, url = (path) => path) {
19005
19772
  if (avatar === void 0 || avatar === "") return void 0;
19006
- if (/^upload:[a-z0-9-]+\.png$/.test(avatar)) return `collab/avatars/uploads/${avatar.slice(7)}`;
19773
+ if (/^upload:[a-z0-9-]+\.png$/.test(avatar)) return url(`collab/avatars/uploads/${avatar.slice(7)}`);
19007
19774
  if (/^https?:\/\//.test(avatar)) return avatar;
19008
- return AVATARS.includes(avatar) ? `collab/avatars/${avatar}.png` : void 0;
19775
+ return AVATARS.includes(avatar) ? url(`collab/avatars/${avatar}.png`) : void 0;
19009
19776
  }
19010
19777
  // src/client/Avatar.tsx
19011
19778
  /** Member portrait: a built-in or bot-announced image over a colored initial badge. */
@@ -19026,7 +19793,7 @@ function color(id) {
19026
19793
  }
19027
19794
  /** Member portrait, or a colored initial badge when there is none or the image fails to load. */
19028
19795
  function Avatar({ id, name, avatar, avatarVersion, small }) {
19029
- const base = avatarSrc(avatar);
19796
+ const base = avatarSrc(avatar, useCollabUrl());
19030
19797
  const src = base && avatar?.startsWith("upload:") && avatarVersion ? `${base}?v=${avatarVersion}` : base;
19031
19798
  const [broken, setBroken] = (0, react.useState)(void 0);
19032
19799
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
@@ -19116,8 +19883,8 @@ function avatarPng(image, rect) {
19116
19883
  if (bytes > 262144) throw new AvatarOutputSizeError(bytes);
19117
19884
  return data;
19118
19885
  }
19119
- async function uploadAvatar(id, png) {
19120
- const response = await fetch(`collab/api/members/${encodeURIComponent(id)}/avatar`, {
19886
+ async function uploadAvatar(id, png, url = (path) => path) {
19887
+ const response = await fetch(url(`collab/api/members/${encodeURIComponent(id)}/avatar`), {
19121
19888
  method: png === void 0 ? "DELETE" : "POST",
19122
19889
  headers: { "content-type": "application/json" },
19123
19890
  ...png === void 0 ? {} : { body: JSON.stringify({ png }) }
@@ -19336,6 +20103,7 @@ const DEFAULT_PRESET = "workspace-write";
19336
20103
  * @returns a modal form.
19337
20104
  */
19338
20105
  function MemberDialog({ member, members = NO_MEMBERS, listModels, listClis, listPersonas, onSubmit, onClose, t }) {
20106
+ const collabUrl = useCollabUrl();
19339
20107
  const [name, setName] = (0, react.useState)(member?.name ?? "DSH");
19340
20108
  const [nameCustomized, setNameCustomized] = (0, react.useState)(member === void 0 ? false : member.nameCustomized);
19341
20109
  const [keepName, setKeepName] = (0, react.useState)(true);
@@ -19375,7 +20143,7 @@ function MemberDialog({ member, members = NO_MEMBERS, listModels, listClis, list
19375
20143
  setError(void 0);
19376
20144
  try {
19377
20145
  if (member) {
19378
- const updated = await uploadAvatar(member.id, png);
20146
+ const updated = await uploadAvatar(member.id, png, collabUrl);
19379
20147
  setAvatar(updated.avatar ?? "");
19380
20148
  } else {
19381
20149
  setPendingPng(png);
@@ -19384,7 +20152,7 @@ function MemberDialog({ member, members = NO_MEMBERS, listModels, listClis, list
19384
20152
  setPreview(png ? `data:image/png;base64,${png}` : void 0);
19385
20153
  } catch (reason) {
19386
20154
  const message = reason instanceof Error ? reason.message : String(reason);
19387
- setError(message === "avatar-png" ? t("memberAvatarPngError") : message === "avatar-size" ? t("memberAvatarSizeError") : message === "avatar-convert" ? t("memberAvatarConvertError") : message);
20155
+ setError(message === "avatar-png" ? t("memberAvatarPngError") : message === "avatar-size" ? t("memberAvatarSizeError") : message === "avatar-convert" ? t("memberAvatarConvertError") : errorText(reason, t));
19388
20156
  } finally {
19389
20157
  setBusy(false);
19390
20158
  }
@@ -19417,7 +20185,7 @@ function MemberDialog({ member, members = NO_MEMBERS, listModels, listClis, list
19417
20185
  }).catch((reason) => {
19418
20186
  if (live) {
19419
20187
  setRoutes([]);
19420
- setError(reason instanceof Error ? reason.message : String(reason));
20188
+ setError(errorText(reason, t));
19421
20189
  }
19422
20190
  });
19423
20191
  return () => {
@@ -19435,7 +20203,7 @@ function MemberDialog({ member, members = NO_MEMBERS, listModels, listClis, list
19435
20203
  }).catch((reason) => {
19436
20204
  if (live) {
19437
20205
  setClis([]);
19438
- setError(reason instanceof Error ? reason.message : String(reason));
20206
+ setError(errorText(reason, t));
19439
20207
  }
19440
20208
  });
19441
20209
  return () => {
@@ -19449,7 +20217,7 @@ function MemberDialog({ member, members = NO_MEMBERS, listModels, listClis, list
19449
20217
  setBusy(true);
19450
20218
  setError(void 0);
19451
20219
  const identity = nameCustomized === void 0 ? {} : { nameCustomized };
19452
- onSubmit(type === "cli" ? {
20220
+ const input = type === "cli" ? {
19453
20221
  name: name.trim(),
19454
20222
  ...identity,
19455
20223
  persona,
@@ -19467,8 +20235,9 @@ function MemberDialog({ member, members = NO_MEMBERS, listModels, listClis, list
19467
20235
  provider,
19468
20236
  model
19469
20237
  } : null
19470
- }).then(onClose).catch((reason) => {
19471
- setError(reason instanceof Error ? reason.message : String(reason));
20238
+ };
20239
+ onSubmit(input).then(onClose).catch((reason) => {
20240
+ setError(errorText(reason, t, "member", input.name));
19472
20241
  }).finally(() => {
19473
20242
  setBusy(false);
19474
20243
  });
@@ -19865,7 +20634,7 @@ function ChannelSettingsDialog({ room, members, effectiveLead, renameRoom, setDi
19865
20634
  } catch (error) {
19866
20635
  setErrors((previous) => ({
19867
20636
  ...previous,
19868
- [target]: error instanceof Error ? error.message : String(error)
20637
+ [target]: errorText(error, t, target === "basic" ? "room" : "other", name)
19869
20638
  }));
19870
20639
  } finally {
19871
20640
  setSaving((previous) => ({
@@ -20087,7 +20856,7 @@ function ChannelSettingsDialog({ room, members, effectiveLead, renameRoom, setDi
20087
20856
  }).catch((error) => {
20088
20857
  setErrors((previous) => ({
20089
20858
  ...previous,
20090
- workspace: error instanceof Error ? error.message : String(error)
20859
+ workspace: errorText(error, t)
20091
20860
  }));
20092
20861
  }).finally(() => {
20093
20862
  setRenewing(false);
@@ -20602,6 +21371,20 @@ function KindTag({ kind, cli, name, t }) {
20602
21371
  function isImeEnter(event) {
20603
21372
  return Reflect.get(event.nativeEvent, "isComposing") === true || Reflect.get(event.nativeEvent, "keyCode") === 229;
20604
21373
  }
21374
+ /**
21375
+ * #197: an object URL for an image the composer is about to send, so no base64 copy is
21376
+ * held for the thumbnail. A browser or test environment without createObjectURL simply
21377
+ * shows the 📎 instead of a preview.
21378
+ */
21379
+ function previewOf(file) {
21380
+ if (!/^image\/(png|jpeg|gif|webp)$/.test(file.type) || file.size > 8388608) return void 0;
21381
+ if (typeof URL.createObjectURL !== "function") return void 0;
21382
+ try {
21383
+ return URL.createObjectURL(file);
21384
+ } catch {
21385
+ return;
21386
+ }
21387
+ }
20605
21388
  /** Touch or narrow screens get the short composer placeholder (the long one wraps beside the send button). */
20606
21389
  function compactComposer() {
20607
21390
  return typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(hover: none), (max-width: 600px)").matches;
@@ -20698,6 +21481,26 @@ function clockOf(seconds) {
20698
21481
  minute: "2-digit"
20699
21482
  });
20700
21483
  }
21484
+ /**
21485
+ * #216: fill the "held by another DSH" notice from the holder record. A record written by an
21486
+ * older build may miss a field, so each one falls back to its own unknown placeholder rather
21487
+ * than printing `undefined`. `dataDir` and `lock` come from the refused instance too: a holder
21488
+ * that wrote no record still leaves the page able to name the contended directory and file.
21489
+ */
21490
+ function lockHolderText(holder, dataDir, lockPath, t) {
21491
+ const unknown = t("lockedUnknown");
21492
+ return {
21493
+ pid: holder?.pid ?? unknown,
21494
+ started: holder?.startedAt === void 0 ? unknown : new Date(holder.startedAt).toLocaleString([], {
21495
+ month: "numeric",
21496
+ day: "numeric",
21497
+ hour: "2-digit",
21498
+ minute: "2-digit"
21499
+ }),
21500
+ dataDir: holder?.dataDir ?? dataDir ?? unknown,
21501
+ lock: lockPath ?? unknown
21502
+ };
21503
+ }
20701
21504
  /** #1020: the memory entries a reply used — a small badge that opens to their titles. */
20702
21505
  function MemoryBadge({ items, t }) {
20703
21506
  const [open, setOpen] = (0, react.useState)(false);
@@ -20740,6 +21543,7 @@ function MemoryBadge({ items, t }) {
20740
21543
  }
20741
21544
  const LONG_PRESS_MS = 450;
20742
21545
  function MessageRow({ message, member, members, t, onConfigure, menuOpen, onAvatar, onCloseMenu, onMention, onDm, onReview, onDecide, onReply, onTask, onRetry, retrying, tasks, focused, cardView, onCardView, own, grouped, enter, queuedFor, taskCardShown = true, toolsOpen = false, onLongPress }) {
21546
+ const collabUrl = useCollabUrl();
20743
21547
  const labels = (0, react.useMemo)(() => ({
20744
21548
  code: {
20745
21549
  copyLabel: t("copyCode"),
@@ -20899,7 +21703,7 @@ function MessageRow({ message, member, members, t, onConfigure, menuOpen, onAvat
20899
21703
  const taskCards = anchored.filter((task) => task.parent_task === null || !anchoredIds.has(task.parent_task));
20900
21704
  const progressLines = role === "progress" ? shown.split("\n") : [];
20901
21705
  const deliveredFor = deliveredTasks(message, tasks);
20902
- const deliveredPage = deliveredFor.length > 0 ? deliverableOf(message) : void 0;
21706
+ const deliveredPage = deliveredFor.length > 0 ? deliverableOf(message, collabUrl) : void 0;
20903
21707
  const delivered = deliveredPage === void 0 ? void 0 : {
20904
21708
  page: deliveredPage,
20905
21709
  task: deliveredFor.find((task) => task.status === "returned") ?? deliveredFor[0]
@@ -21465,7 +22269,7 @@ function MemberGroup({ title, members, busy, onPick, onEdit, onRemove, onDm, t }
21465
22269
  * @param props - framework, injected, and locale shares.
21466
22270
  * @returns the three-column channel view.
21467
22271
  */
21468
- function ChannelsPage({ useChannels, selectRoom, send, reviewTask, dispatchTask, openDm, closeDm, createRoom, renameRoom, listModels, listClis, listPersonas, addMember, updateMember, removeMember, setLead, setWorkspacePath, renewRoom, setDispatchMode, setMaxRelay, decidePermission, retryMessage, editMessage, withdrawMessage, loadOlder, loadNewer, keepLatest, showLatest, openModelSettings, answerTask, t }) {
22272
+ function ChannelsPage({ useChannels, selectRoom, send, uploadAttachment, reviewTask, dispatchTask, openDm, closeDm, createRoom, renameRoom, listModels, listClis, listPersonas, addMember, updateMember, removeMember, setLead, setWorkspacePath, renewRoom, setDispatchMode, setMaxRelay, decidePermission, retryMessage, editMessage, withdrawMessage, loadOlder, loadNewer, keepLatest, showLatest, openModelSettings, answerTask, t }) {
21469
22273
  const scheme = useScheme();
21470
22274
  const state = useChannels((snapshot) => snapshot);
21471
22275
  const [editing, setEditing] = (0, react.useState)(void 0);
@@ -21476,28 +22280,92 @@ function ChannelsPage({ useChannels, selectRoom, send, reviewTask, dispatchTask,
21476
22280
  const [sending, setSending] = (0, react.useState)({});
21477
22281
  const [replies, setReplies] = (0, react.useState)({});
21478
22282
  const [pendingFiles, setPendingFiles] = (0, react.useState)({});
21479
- const attach = useComposerAttachments((files) => {
21480
- const roomId = state.roomId;
21481
- if (roomId === void 0) return;
21482
- const next = [...pendingFiles[roomId] ?? [], ...files];
21483
- if (messageTooLarge(drafts[roomId] ?? "", next)) {
21484
- setErrors((previous) => ({
21485
- ...previous,
21486
- [roomId]: t("attachmentsTooLarge", { limit: `${MAX_MESSAGE_BODY / 1024 / 1024} MiB` })
21487
- }));
21488
- return;
21489
- }
21490
- setPendingFiles((previous) => ({
22283
+ const pendingRef = (0, react.useRef)(pendingFiles);
22284
+ const updateFiles = (update) => {
22285
+ pendingRef.current = update(pendingRef.current);
22286
+ setPendingFiles(pendingRef.current);
22287
+ };
22288
+ const uploading = (0, react.useRef)(/* @__PURE__ */ new Map());
22289
+ const patchFile = (roomId, key, change) => {
22290
+ updateFiles((previous) => ({
21491
22291
  ...previous,
21492
- [roomId]: next
22292
+ [roomId]: (previous[roomId] ?? []).map((file) => file.key === key ? change(file) : file)
21493
22293
  }));
21494
- }, (message) => {
22294
+ };
22295
+ const limit = state.maxUploadBytes ?? 1073741824;
22296
+ const attach = useComposerAttachments((picked) => {
21495
22297
  const roomId = state.roomId;
21496
- if (roomId !== void 0) setErrors((previous) => ({
22298
+ if (roomId === void 0) return;
22299
+ const added = picked.map((file) => {
22300
+ const preview = previewOf(file);
22301
+ return {
22302
+ key: `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
22303
+ name: file.name || "pasted",
22304
+ mime: file.type || "application/octet-stream",
22305
+ size: file.size,
22306
+ progress: 0,
22307
+ ...preview === void 0 ? {} : { preview },
22308
+ ...uploadAttachment === void 0 ? { error: t("uploadUnsupported") } : file.size > limit ? { error: t("attachmentTooLarge", {
22309
+ name: file.name || "pasted",
22310
+ size: formatBytes(file.size),
22311
+ limit: formatBytes(limit)
22312
+ }) } : {}
22313
+ };
22314
+ });
22315
+ updateFiles((previous) => ({
21497
22316
  ...previous,
21498
- [roomId]: t("sendFailed", { message })
22317
+ [roomId]: [...previous[roomId] ?? [], ...added]
21499
22318
  }));
22319
+ picked.forEach((file, index) => {
22320
+ const entry = added[index];
22321
+ if (entry.error !== void 0 || uploadAttachment === void 0) return;
22322
+ const controller = new AbortController();
22323
+ const done = uploadAttachment(file, (sent, total) => {
22324
+ patchFile(roomId, entry.key, (current) => ({
22325
+ ...current,
22326
+ progress: total === 0 ? 1 : Math.min(1, sent / total)
22327
+ }));
22328
+ }, controller.signal).then((attachment) => {
22329
+ patchFile(roomId, entry.key, (current) => ({
22330
+ ...current,
22331
+ progress: 1,
22332
+ attachment
22333
+ }));
22334
+ }).catch((error) => {
22335
+ patchFile(roomId, entry.key, (current) => ({
22336
+ ...current,
22337
+ error: error instanceof UploadTooLarge ? t("attachmentTooLarge", {
22338
+ name: error.fileName,
22339
+ size: formatBytes(error.size),
22340
+ limit: formatBytes(error.limit)
22341
+ }) : t("uploadFailed", {
22342
+ name: current.name,
22343
+ message: error instanceof Error ? error.message : String(error)
22344
+ })
22345
+ }));
22346
+ }).finally(() => {
22347
+ uploading.current.delete(entry.key);
22348
+ });
22349
+ uploading.current.set(entry.key, {
22350
+ done,
22351
+ controller
22352
+ });
22353
+ });
21500
22354
  });
22355
+ const removeFile = (roomId, key) => {
22356
+ const gone = (pendingRef.current[roomId] ?? []).find((file) => file.key === key);
22357
+ if (gone?.preview !== void 0) URL.revokeObjectURL(gone.preview);
22358
+ uploading.current.get(key)?.controller.abort();
22359
+ uploading.current.delete(key);
22360
+ updateFiles((previous) => ({
22361
+ ...previous,
22362
+ [roomId]: (previous[roomId] ?? []).filter((file) => file.key !== key)
22363
+ }));
22364
+ };
22365
+ (0, react.useEffect)(() => () => {
22366
+ for (const job of uploading.current.values()) job.controller.abort();
22367
+ for (const room of Object.values(pendingRef.current)) for (const file of room) if (file.preview !== void 0) URL.revokeObjectURL(file.preview);
22368
+ }, []);
21501
22369
  const pendingRooms = (0, react.useRef)(/* @__PURE__ */ new Set());
21502
22370
  const draft = state.roomId === void 0 ? "" : drafts[state.roomId] ?? "";
21503
22371
  const sendError = state.roomId === void 0 ? void 0 : errors[state.roomId];
@@ -21519,6 +22387,24 @@ function ChannelsPage({ useChannels, selectRoom, send, reviewTask, dispatchTask,
21519
22387
  pendingWithdrawRef.current?.commit();
21520
22388
  }, []);
21521
22389
  const inputRef = (0, react.useRef)(null);
22390
+ const inputHighlightsRef = (0, react.useRef)(null);
22391
+ const [composing, setComposing] = (0, react.useState)(false);
22392
+ const syncInputHighlights = () => {
22393
+ const input = inputRef.current;
22394
+ const highlights = inputHighlightsRef.current;
22395
+ if (!input || !highlights) return;
22396
+ highlights.style.width = `${input.getBoundingClientRect().width - (input.offsetWidth - input.clientWidth)}px`;
22397
+ highlights.scrollTop = input.scrollTop;
22398
+ highlights.scrollLeft = input.scrollLeft;
22399
+ };
22400
+ (0, react.useLayoutEffect)(() => {
22401
+ syncInputHighlights();
22402
+ const input = inputRef.current;
22403
+ if (!input || typeof ResizeObserver === "undefined") return;
22404
+ const observer = new ResizeObserver(syncInputHighlights);
22405
+ observer.observe(input);
22406
+ return () => observer.disconnect();
22407
+ }, [draft, state.roomId]);
21522
22408
  const [caret, setCaret] = (0, react.useState)(0);
21523
22409
  const [dismissedAt, setDismissedAt] = (0, react.useState)(void 0);
21524
22410
  const [highlight, setHighlight] = (0, react.useState)(0);
@@ -21871,7 +22757,7 @@ function ChannelsPage({ useChannels, selectRoom, send, reviewTask, dispatchTask,
21871
22757
  };
21872
22758
  }, [stopping, stillAnswering]);
21873
22759
  if (state.phase !== "ready") {
21874
- const notice = state.phase === "unavailable" ? t("unavailable") : state.phase === "unauthorized" ? t("unauthorized") : state.phase === "error" ? t("error", { message: state.error ?? "" }) : t("loading");
22760
+ const notice = state.phase === "locked" ? state.lockFree === true ? t("lockedFree") : state.lockHolder === void 0 ? t("lockedUnnamed", lockHolderText(void 0, state.lockDataDir, state.lockPath, t)) : t("locked", lockHolderText(state.lockHolder, state.lockDataDir, state.lockPath, t)) : state.phase === "unavailable" ? t("unavailable") : state.phase === "unauthorized" ? t("unauthorized") : state.phase === "error" ? t("error", { message: state.error ?? "" }) : t("loading");
21875
22761
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
21876
22762
  className: ChannelsPage_module_default.page,
21877
22763
  "data-dc-scheme": scheme,
@@ -21936,7 +22822,7 @@ function ChannelsPage({ useChannels, selectRoom, send, reviewTask, dispatchTask,
21936
22822
  const slashCommands = slash === void 0 || capabilitiesDismissed || popupOpen ? [] : matchCommands(slash, (key) => t(key)).filter((c) => dmWith === void 0 || c.name !== "stop all" && c.name !== "board");
21937
22823
  const slashOpen = slashCommands.length > 0;
21938
22824
  const slashSelected = Math.min(slashHighlight, Math.max(slashCommands.length - 1, 0));
21939
- const workingBots = (state.roomId === void 0 ? [] : state.thinking[String(state.roomId)] ?? []).map((id) => byId.get(id)).filter((m) => m !== void 0 && m.kind === "bot");
22825
+ const workingBots = (state.roomId === void 0 ? [] : state.thinking[String(state.roomId)] ?? []).map((id) => byId.get(id)).filter((m) => m !== void 0 && (m.kind === "bot" || m.kind === "dsh"));
21940
22826
  const stopTarget = workingBots.find((m) => m.id === commandTarget?.id) ?? workingBots[0];
21941
22827
  const roomFiles = state.roomId === void 0 ? [] : pendingFiles[state.roomId] ?? [];
21942
22828
  const stopMode = (stopTarget !== void 0 || stopping?.phase === "stopping") && draft.trim() === "" && roomFiles.length === 0;
@@ -22007,7 +22893,7 @@ function ChannelsPage({ useChannels, selectRoom, send, reviewTask, dispatchTask,
22007
22893
  createRoom(name).then(() => {
22008
22894
  setNewRoom(void 0);
22009
22895
  }).catch((error) => {
22010
- setRoomError(error instanceof Error ? error.message : String(error));
22896
+ setRoomError(errorText(error, t, "room", name));
22011
22897
  });
22012
22898
  };
22013
22899
  const ownActions = (m) => {
@@ -22082,7 +22968,7 @@ function ChannelsPage({ useChannels, selectRoom, send, reviewTask, dispatchTask,
22082
22968
  if (!window.confirm(t("removeConfirm", { name: member.name }))) return;
22083
22969
  setMemberError(void 0);
22084
22970
  removeMember(member.id).catch((error) => {
22085
- setMemberError(error instanceof Error ? error.message : String(error));
22971
+ setMemberError(errorText(error, t, "member", member.name));
22086
22972
  });
22087
22973
  };
22088
22974
  const openPicker = () => {
@@ -22192,12 +23078,20 @@ function ChannelsPage({ useChannels, selectRoom, send, reviewTask, dispatchTask,
22192
23078
  const submit = () => {
22193
23079
  const roomId = state.roomId;
22194
23080
  const text = addressCommand(draft.trim(), commandTarget?.name);
22195
- const files = roomId === void 0 ? [] : pendingFiles[roomId] ?? [];
22196
- if (!text && files.length === 0 || roomId === void 0 || pendingRooms.current.has(roomId)) return;
22197
- if (files.length > 0 && messageTooLarge(text, files)) {
23081
+ const held = roomId === void 0 ? [] : pendingRef.current[roomId] ?? [];
23082
+ if (!text && held.length === 0 || roomId === void 0 || pendingRooms.current.has(roomId)) return;
23083
+ const refused = held.filter((file) => file.error !== void 0);
23084
+ if (refused.length > 0) {
23085
+ setErrors((previous) => ({
23086
+ ...previous,
23087
+ [roomId]: refused[0]?.error
23088
+ }));
23089
+ return;
23090
+ }
23091
+ if (messageTooLarge(text, [])) {
22198
23092
  setErrors((previous) => ({
22199
23093
  ...previous,
22200
- [roomId]: t("attachmentsTooLarge", { limit: `${MAX_MESSAGE_BODY / 1024 / 1024} MiB` })
23094
+ [roomId]: t("messageTooLarge", { limit: formatBytes(MAX_MESSAGE_BODY) })
22201
23095
  }));
22202
23096
  return;
22203
23097
  }
@@ -22214,31 +23108,54 @@ function ChannelsPage({ useChannels, selectRoom, send, reviewTask, dispatchTask,
22214
23108
  if (state.hasMoreNewer === true) showLatest?.();
22215
23109
  setUnread(void 0);
22216
23110
  const replyTo = replies[roomId]?.id;
22217
- (files.length > 0 ? send(text, replyTo, files) : replyTo === void 0 ? send(text) : send(text, replyTo)).then(() => {
22218
- setDrafts((previous) => ({
22219
- ...previous,
22220
- [roomId]: ""
22221
- }));
22222
- setPendingFiles((previous) => ({
22223
- ...previous,
22224
- [roomId]: []
22225
- }));
22226
- setReplies((previous) => ({
22227
- ...previous,
22228
- [roomId]: void 0
22229
- }));
22230
- }).catch((error) => {
22231
- setErrors((previous) => ({
22232
- ...previous,
22233
- [roomId]: t("sendFailed", { message: error instanceof Error ? error.message : String(error) })
22234
- }));
22235
- }).finally(() => {
23111
+ /** Post the message; a file that failed while it streamed is reported instead of sent. */
23112
+ const go = () => {
23113
+ const keys = new Set(held.map((file) => file.key));
23114
+ const ready = (pendingRef.current[roomId] ?? []).filter((file) => keys.has(file.key));
23115
+ const broken = ready.find((file) => file.error !== void 0);
23116
+ if (broken?.error !== void 0) {
23117
+ setErrors((previous) => ({
23118
+ ...previous,
23119
+ [roomId]: broken.error
23120
+ }));
23121
+ return Promise.resolve();
23122
+ }
23123
+ const files = ready.map((file) => file.attachment).filter((a) => a !== void 0);
23124
+ if (!text && ready.length === 0) return Promise.resolve();
23125
+ return send(text, replyTo, files.length > 0 ? files : void 0, roomId).then(() => {
23126
+ for (const file of ready) if (file.preview !== void 0) URL.revokeObjectURL(file.preview);
23127
+ setDrafts((previous) => ({
23128
+ ...previous,
23129
+ [roomId]: ""
23130
+ }));
23131
+ updateFiles((previous) => ({
23132
+ ...previous,
23133
+ [roomId]: (previous[roomId] ?? []).filter((file) => !keys.has(file.key))
23134
+ }));
23135
+ setReplies((previous) => ({
23136
+ ...previous,
23137
+ [roomId]: void 0
23138
+ }));
23139
+ }).catch((error) => {
23140
+ setErrors((previous) => ({
23141
+ ...previous,
23142
+ [roomId]: t("sendFailed", { message: error instanceof Error ? error.message : String(error) })
23143
+ }));
23144
+ });
23145
+ };
23146
+ const settle = () => {
22236
23147
  pendingRooms.current.delete(roomId);
22237
23148
  setSending((previous) => ({
22238
23149
  ...previous,
22239
23150
  [roomId]: false
22240
23151
  }));
22241
- });
23152
+ };
23153
+ const waits = held.map((file) => uploading.current.get(file.key)?.done).filter((job) => job !== void 0);
23154
+ if (waits.length === 0) {
23155
+ go().finally(settle);
23156
+ return;
23157
+ }
23158
+ Promise.all(waits).then(go).finally(settle);
22242
23159
  };
22243
23160
  const startReply = (message) => {
22244
23161
  const roomId = state.roomId;
@@ -22876,6 +23793,7 @@ function ChannelsPage({ useChannels, selectRoom, send, reviewTask, dispatchTask,
22876
23793
  commands: slashCommands,
22877
23794
  selected: slashSelected,
22878
23795
  target: commandTarget?.name,
23796
+ leadName: dmWith === void 0 && commandTarget === void 0 ? lead?.name : void 0,
22879
23797
  dmName: dmWith === void 0 ? void 0 : dmPeer?.name ?? room?.name,
22880
23798
  disabled: (c) => commandTarget === void 0 && needsTarget(c),
22881
23799
  grouped: slash === "",
@@ -22972,47 +23890,61 @@ function ChannelsPage({ useChannels, selectRoom, send, reviewTask, dispatchTask,
22972
23890
  state.roomId !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PendingAttachments, {
22973
23891
  files: pendingFiles[state.roomId] ?? [],
22974
23892
  removeLabel: t("removeAttachment"),
22975
- onRemove: (index) => {
22976
- const roomId = state.roomId;
22977
- setPendingFiles((previous) => ({
22978
- ...previous,
22979
- [roomId]: (previous[roomId] ?? []).filter((_, i) => i !== index)
22980
- }));
22981
- }
22982
- }),
22983
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
22984
- ref: inputRef,
22985
- className: ChannelsPage_module_default.input,
22986
- rows: 1,
22987
- enterKeyHint: "send",
22988
- value: draft,
22989
- disabled: state.roomId === void 0 || sending[state.roomId] === true,
22990
- placeholder,
22991
- role: "combobox",
22992
- "aria-expanded": popupOpen || slashOpen,
22993
- "aria-controls": slashOpen ? "channel-slash-list" : "channel-mention-list",
22994
- "aria-autocomplete": "list",
22995
- "aria-activedescendant": popupOpen ? `channel-mention-${candidates[selected].id}` : slashOpen ? `channel-slash-${slashSelected}` : void 0,
22996
- onChange: (event) => {
22997
- const roomId = state.roomId;
22998
- const value = event.target.value;
22999
- if (roomId !== void 0) setDrafts((previous) => ({
23000
- ...previous,
23001
- [roomId]: value
23002
- }));
23003
- setCapabilitiesDismissed(false);
23004
- setHelpOpen(false);
23005
- setCaret(event.target.selectionStart);
23006
- setHighlight(0);
23007
- setSlashHighlight(0);
23893
+ labels: {
23894
+ uploading: t("attachmentUploading"),
23895
+ queued: t("attachmentQueued")
23008
23896
  },
23009
- onSelect: (event) => {
23010
- setCaret(event.currentTarget.selectionStart);
23011
- },
23012
- onKeyDown,
23013
- onPaste: attach.onPaste,
23014
- onDragOver: attach.onDragOver,
23015
- onDrop: attach.onDrop
23897
+ onRemove: (key) => removeFile(state.roomId, key)
23898
+ }),
23899
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
23900
+ className: composing ? `${ChannelsPage_module_default.inputSurface} ${ChannelsPage_module_default.inputComposing}` : ChannelsPage_module_default.inputSurface,
23901
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
23902
+ ref: inputRef,
23903
+ className: ChannelsPage_module_default.input,
23904
+ rows: 1,
23905
+ enterKeyHint: "send",
23906
+ value: draft,
23907
+ disabled: state.roomId === void 0 || sending[state.roomId] === true,
23908
+ placeholder,
23909
+ role: "combobox",
23910
+ "aria-expanded": popupOpen || slashOpen,
23911
+ "aria-controls": slashOpen ? "channel-slash-list" : "channel-mention-list",
23912
+ "aria-autocomplete": "list",
23913
+ "aria-activedescendant": popupOpen ? `channel-mention-${candidates[selected].id}` : slashOpen ? `channel-slash-${slashSelected}` : void 0,
23914
+ onChange: (event) => {
23915
+ const roomId = state.roomId;
23916
+ const value = event.target.value;
23917
+ if (roomId !== void 0) setDrafts((previous) => ({
23918
+ ...previous,
23919
+ [roomId]: value
23920
+ }));
23921
+ setCapabilitiesDismissed(false);
23922
+ setHelpOpen(false);
23923
+ setCaret(event.target.selectionStart);
23924
+ setHighlight(0);
23925
+ setSlashHighlight(0);
23926
+ },
23927
+ onSelect: (event) => {
23928
+ setCaret(event.currentTarget.selectionStart);
23929
+ },
23930
+ onScroll: syncInputHighlights,
23931
+ onCompositionStart: () => setComposing(true),
23932
+ onCompositionEnd: () => setComposing(false),
23933
+ onKeyDown,
23934
+ onPaste: attach.onPaste,
23935
+ onDragOver: attach.onDragOver,
23936
+ onDrop: attach.onDrop
23937
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
23938
+ ref: inputHighlightsRef,
23939
+ className: ChannelsPage_module_default.inputHighlights,
23940
+ "data-composer-highlights": true,
23941
+ "aria-hidden": "true",
23942
+ children: [splitMentions(draft, visibleMembers).map((segment, index) => segment.member ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
23943
+ className: `${ChannelsPage_module_default.mentionBadge} ${ChannelsPage_module_default.inputMention}`,
23944
+ "data-mention": segment.member.id,
23945
+ children: segment.text
23946
+ }, index) : segment.text), "\n"]
23947
+ })]
23016
23948
  }),
23017
23949
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
23018
23950
  className: ChannelsPage_module_default.composerToolbar,
@@ -23279,6 +24211,34 @@ function ChannelsPage({ useChannels, selectRoom, send, reviewTask, dispatchTask,
23279
24211
  ]
23280
24212
  });
23281
24213
  }
24214
+ // src/client/RemoteChannelsPage.tsx
24215
+ const BELOW_BAR = { "--dsh-frame-top-clearance": "0px" };
24216
+ function RemoteChannelsPage(props) {
24217
+ const { remoteName, collabUrl, back, t } = props;
24218
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CollabUrlContext.Provider, {
24219
+ value: collabUrl,
24220
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
24221
+ className: PanelPages_module_default.remote,
24222
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
24223
+ className: PanelPages_module_default.remoteBar,
24224
+ role: "status",
24225
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
24226
+ className: PanelPages_module_default.remoteName,
24227
+ children: t("remoteViewing", { name: remoteName })
24228
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
24229
+ type: "button",
24230
+ className: PanelPages_module_default.remoteBack,
24231
+ onClick: back,
24232
+ children: t("remoteBack")
24233
+ })]
24234
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
24235
+ className: PanelPages_module_default.remoteBody,
24236
+ style: BELOW_BAR,
24237
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChannelsPage, { ...props })
24238
+ })]
24239
+ })
24240
+ });
24241
+ }
23282
24242
  // src/client/locales.ts
23283
24243
  /** Channel panel dictionaries. */
23284
24244
  /** Locale namespace owned by the channel panel. */
@@ -23351,6 +24311,8 @@ const zh = {
23351
24311
  panelGalaxy: "Wiki 星河",
23352
24312
  panelBothouse: "bothouse",
23353
24313
  panelDevices: "其他电脑",
24314
+ remoteViewing: "正在用「{name}」的频道(那台电脑上的成员和消息)",
24315
+ remoteBack: "返回其他电脑",
23354
24316
  channelSettings: "频道设置",
23355
24317
  settingsBasic: "基本",
23356
24318
  settingsDispatch: "派活",
@@ -23369,6 +24331,12 @@ const zh = {
23369
24331
  channelName: "频道名称",
23370
24332
  channelNameHint: "1–32 个字符,不能含空白。",
23371
24333
  workspaceNameFixed: "工作区名称由系统分配,不能修改。",
24334
+ channelNameReserved: "「{name}」是工作区占用的名字,换个频道名吧。",
24335
+ channelNameTaken: "已经有频道叫「{name}」了,换个名字吧。",
24336
+ channelNameInvalid: "频道名要 1–32 个字符,不能含空白。",
24337
+ memberNameTaken: "已经有成员叫「{name}」了,换个名字吧。",
24338
+ memberNameInvalid: "成员名要 1–32 个字符,不能含空白、@ 或 <>(Claude Code 除外)。",
24339
+ actionFailed: "没成功:{message}",
23372
24340
  slashTitle: "命令",
23373
24341
  slashTitleLead: "发给 {name} 的命令",
23374
24342
  slashTitleNoLead: "命令 · 先在频道设置里选主角色,才能用这些命令",
@@ -23534,6 +24502,10 @@ const zh = {
23534
24502
  placeholder: "发消息到 #{room},@成员 派活(回车发送,Shift+回车换行)",
23535
24503
  loading: "正在连接频道服务…",
23536
24504
  unavailable: "频道服务未启用:在 collab.yml 中配置服务后,用 --patch collab.yml 启动 DSH。",
24505
+ locked: "频道服务没有启动:这台电脑上已经有另一个 DSH 在用同一份频道数据(进程 {pid},{started} 打开,数据目录 {dataDir})。直接用已经打开的那个就行;要换成本页这个 DSH,先把那个关掉,再把本页这个 DSH 关掉重开——只刷新页面不会把频道接上。",
24506
+ lockedUnnamed: "频道服务没有启动:这台电脑上已经有另一个 DSH 在用同一份频道数据(数据目录 {dataDir},进程 {pid})——它没留下是哪个进程的记录,通常是因为那个 DSH 是旧版本,或者刚打开还没写记录。别去改配置:先看谁占着这个文件:macOS 或 Linux 上用 lsof {lock},Windows 上在资源监视器的磁盘活动里搜这个文件名;找到那个 DSH 后关掉它,再关掉并重开本页这个 DSH,频道就能接上(只刷新页面不行)。",
24507
+ lockedFree: "频道服务还是没有启动:刚才占着频道数据的那个 DSH 已经关掉了,锁是空的;但本页的频道插件是在它占着的时候启动失败的,不会自己回来。把本页这个 DSH 关掉重开,频道就能接上。",
24508
+ lockedUnknown: "未知",
23537
24509
  unauthorized: "还没有登录 DSH,请刷新页面。",
23538
24510
  error: "频道服务出错:{message}",
23539
24511
  empty: "这里还没有消息。@一个成员开始吧。",
@@ -23547,6 +24519,12 @@ const zh = {
23547
24519
  attachButton: "添加图片或文件",
23548
24520
  removeAttachment: "移除附件",
23549
24521
  attachmentsTooLarge: "附件太大:一条消息合计不能超过 {limit}",
24522
+ messageTooLarge: "消息太长:一条消息不能超过 {limit}",
24523
+ attachmentTooLarge: "「{name}」{size},超过单个文件上限 {limit}",
24524
+ attachmentUploading: "上传中",
24525
+ attachmentQueued: "等待上传",
24526
+ uploadFailed: "「{name}」上传失败:{message}",
24527
+ uploadUnsupported: "这个页面不能上传文件,请刷新后再试",
23550
24528
  mentionPick: "在输入框里 @{name}",
23551
24529
  memberMenu: "{name} 的成员操作",
23552
24530
  avatarMention: "@ TA",
@@ -23746,6 +24724,8 @@ const en = {
23746
24724
  panelGalaxy: "Wiki galaxy",
23747
24725
  panelBothouse: "bothouse",
23748
24726
  panelDevices: "Other computers",
24727
+ remoteViewing: "Channels on “{name}” (members and messages of that computer)",
24728
+ remoteBack: "Back to other computers",
23749
24729
  channelSettings: "Channel settings",
23750
24730
  settingsBasic: "Basic",
23751
24731
  settingsDispatch: "Dispatch",
@@ -23764,6 +24744,12 @@ const en = {
23764
24744
  channelName: "Channel name",
23765
24745
  channelNameHint: "1–32 characters, without whitespace.",
23766
24746
  workspaceNameFixed: "Workspace names are assigned by the system and cannot be changed.",
24747
+ channelNameReserved: "\"{name}\" is a workspace name; pick another channel name.",
24748
+ channelNameTaken: "A channel named \"{name}\" already exists; pick another name.",
24749
+ channelNameInvalid: "A channel name is 1–32 characters and contains no whitespace.",
24750
+ memberNameTaken: "A member named \"{name}\" already exists; pick another name.",
24751
+ memberNameInvalid: "A member name is 1–32 characters, without whitespace, @ or <> (Claude Code excepted).",
24752
+ actionFailed: "That did not work: {message}",
23767
24753
  slashTitle: "Commands",
23768
24754
  slashTitleLead: "Commands to {name}",
23769
24755
  slashTitleNoLead: "Commands · pick a primary role in channel settings to use these",
@@ -23884,6 +24870,10 @@ const en = {
23884
24870
  placeholder: "Message #{room}; @ a member to put it to work (Enter sends, Shift+Enter for a new line)",
23885
24871
  loading: "Connecting to the channel service…",
23886
24872
  unavailable: "The channel service is off: configure it in collab.yml, then start DSH with --patch collab.yml.",
24873
+ locked: "The channel service did not start: another DSH on this machine is already using the same channel data (process {pid}, opened {started}, data directory {dataDir}). Keep using the DSH you already have open; to switch to this one, quit that one, then quit and reopen this DSH — reloading the page will not reconnect the channel.",
24874
+ lockedUnnamed: "The channel service did not start: another DSH on this machine is already using the same channel data (data directory {dataDir}, process {pid}) and left no record of which process it is — usually because that DSH is an older build, or has only just started. Do not touch the configuration: first see what holds the lock file — lsof {lock} on macOS or Linux, or search that file name in Resource Monitor on Windows; then quit that DSH, quit and reopen this one, and the channel reconnects (reloading the page will not).",
24875
+ lockedFree: "The channel service still did not start: the DSH that held the channel data has quit and the lock is free, but this page's channel plugin refused at startup and does not come back by itself. Quit and reopen this DSH to reconnect the channel.",
24876
+ lockedUnknown: "unknown",
23887
24877
  unauthorized: "Not signed in to DSH; reload the page.",
23888
24878
  error: "Channel service error: {message}",
23889
24879
  empty: "No messages yet. @ a member to start.",
@@ -23897,6 +24887,12 @@ const en = {
23897
24887
  attachButton: "Attach images or files",
23898
24888
  removeAttachment: "Remove attachment",
23899
24889
  attachmentsTooLarge: "Attachments too large: one message can carry at most {limit} in total",
24890
+ messageTooLarge: "Message too long: one message can hold at most {limit}",
24891
+ attachmentTooLarge: "\"{name}\" is {size}, over the per-file limit of {limit}",
24892
+ attachmentUploading: "Uploading",
24893
+ attachmentQueued: "Waiting to upload",
24894
+ uploadFailed: "\"{name}\" failed to upload: {message}",
24895
+ uploadUnsupported: "This page cannot upload files; reload and try again",
23900
24896
  mentionPick: "Mention {name} in the message box",
23901
24897
  memberMenu: "Member actions for {name}",
23902
24898
  avatarMention: "Mention",
@@ -23985,6 +24981,10 @@ const en = {
23985
24981
  };
23986
24982
  // src/client/index.ts
23987
24983
  const PANEL_ID = "channels";
24984
+ const REMOTE_PANEL_ID = "remote-channels";
24985
+ const DEVICES_PANEL_ID = "collab-devices";
24986
+ /** Global the 其他电脑 page (same origin, in an iframe) calls to open a link's channels here. */
24987
+ const OPEN_REMOTE = "__bothouseOpenRemoteChannels";
23988
24988
  /** Required browser services. */
23989
24989
  const inject = [
23990
24990
  "slots",
@@ -24003,11 +25003,13 @@ function apply(ctx) {
24003
25003
  const t = ctx.locale.bind(NS);
24004
25004
  const channels = createChannelSource(browserTransport());
24005
25005
  ctx.effect(() => channels.dispose, "client-ui-discord: channel stream");
24006
- const injected = (openModelSettings) => ({
25006
+ const injected = (openModelSettings) => injectedFor(channels, openModelSettings);
25007
+ const injectedFor = (channels, openModelSettings) => ({
24007
25008
  openModelSettings,
24008
25009
  hooks: { channels: channels.source },
24009
25010
  selectRoom: channels.actions.selectRoom,
24010
25011
  send: channels.actions.send,
25012
+ uploadAttachment: channels.actions.uploadAttachment,
24011
25013
  reviewTask: channels.actions.reviewTask,
24012
25014
  dispatchTask: channels.actions.dispatchTask,
24013
25015
  openDm: channels.actions.openDm,
@@ -24068,6 +25070,47 @@ function apply(ctx) {
24068
25070
  disposePanel?.();
24069
25071
  };
24070
25072
  });
25073
+ ctx.slots.inject("main", () => {
25074
+ let remote;
25075
+ const close = () => {
25076
+ remote?.dispose();
25077
+ remote = void 0;
25078
+ };
25079
+ const open = (link, name) => {
25080
+ const url = remoteCollabUrl(link);
25081
+ if (remote?.link !== link) {
25082
+ close();
25083
+ const source = createChannelSource(mappedTransport(browserTransport(), url));
25084
+ const unregister = ctx.slots.register({
25085
+ name: "main",
25086
+ key: REMOTE_PANEL_ID,
25087
+ locale: NS,
25088
+ inject: () => ({
25089
+ ...injectedFor(source, () => false),
25090
+ remoteName: name,
25091
+ collabUrl: url,
25092
+ back: () => {
25093
+ ctx.layout.selectPanel(DEVICES_PANEL_ID);
25094
+ }
25095
+ })
25096
+ }, RemoteChannelsPage);
25097
+ remote = {
25098
+ link,
25099
+ dispose: () => {
25100
+ unregister();
25101
+ source.dispose();
25102
+ }
25103
+ };
25104
+ }
25105
+ ctx.layout.selectPanel(REMOTE_PANEL_ID);
25106
+ return true;
25107
+ };
25108
+ Reflect.set(globalThis, OPEN_REMOTE, open);
25109
+ return () => {
25110
+ if (Reflect.get(globalThis, "__bothouseOpenRemoteChannels") === open) Reflect.deleteProperty(globalThis, OPEN_REMOTE);
25111
+ close();
25112
+ };
25113
+ });
24071
25114
  if (typeof ctx.inject === "function") ctx.inject(["theme"], (themed) => {
24072
25115
  const theme = Reflect.get(themed, "theme");
24073
25116
  if (theme === void 0) return;
@@ -24088,6 +25131,7 @@ function apply(ctx) {
24088
25131
  label: () => t("panel")
24089
25132
  }, ChannelsIcon));
24090
25133
  }
25134
+ exports.OPEN_REMOTE = OPEN_REMOTE;
24091
25135
  exports.apply = apply;
24092
25136
  exports.inject = inject;
24093
25137