@consilioweb/payload-support 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +525 -0
  3. package/dist/client.cjs +7 -0
  4. package/dist/client.d.cts +3 -0
  5. package/dist/client.d.ts +3 -0
  6. package/dist/client.js +5 -0
  7. package/dist/index.cjs +7766 -0
  8. package/dist/index.d.cts +384 -0
  9. package/dist/index.d.ts +384 -0
  10. package/dist/index.js +7730 -0
  11. package/dist/views.d.cts +30 -0
  12. package/dist/views.d.ts +30 -0
  13. package/package.json +131 -0
  14. package/src/client.ts +1 -0
  15. package/src/collections/AuthLogs.ts +65 -0
  16. package/src/collections/CannedResponses.ts +69 -0
  17. package/src/collections/ChatMessages.ts +98 -0
  18. package/src/collections/EmailLogs.ts +94 -0
  19. package/src/collections/KnowledgeBase.ts +99 -0
  20. package/src/collections/Macros.ts +98 -0
  21. package/src/collections/PendingEmails.ts +122 -0
  22. package/src/collections/SatisfactionSurveys.ts +98 -0
  23. package/src/collections/SlaPolicies.ts +123 -0
  24. package/src/collections/SupportClients.ts +210 -0
  25. package/src/collections/TicketActivityLog.ts +81 -0
  26. package/src/collections/TicketMessages.ts +364 -0
  27. package/src/collections/TicketStatuses.ts +108 -0
  28. package/src/collections/Tickets.ts +704 -0
  29. package/src/collections/TimeEntries.ts +105 -0
  30. package/src/collections/WebhookEndpoints.ts +96 -0
  31. package/src/collections/index.ts +16 -0
  32. package/src/components/TicketConversation/components/AISummaryPanel.tsx +85 -0
  33. package/src/components/TicketConversation/components/ActionPanels.tsx +140 -0
  34. package/src/components/TicketConversation/components/ActivityLog.tsx +39 -0
  35. package/src/components/TicketConversation/components/ClientBar.tsx +37 -0
  36. package/src/components/TicketConversation/components/ClientHistory.tsx +117 -0
  37. package/src/components/TicketConversation/components/CodeBlock.tsx +186 -0
  38. package/src/components/TicketConversation/components/CodeBlockInserter.tsx +166 -0
  39. package/src/components/TicketConversation/components/QuickActions.tsx +82 -0
  40. package/src/components/TicketConversation/components/TicketHeader.tsx +91 -0
  41. package/src/components/TicketConversation/components/TimeTrackingPanel.tsx +161 -0
  42. package/src/components/TicketConversation/config.ts +82 -0
  43. package/src/components/TicketConversation/constants.ts +74 -0
  44. package/src/components/TicketConversation/context.ts +63 -0
  45. package/src/components/TicketConversation/hooks/useAI.ts +180 -0
  46. package/src/components/TicketConversation/hooks/useMessageActions.ts +131 -0
  47. package/src/components/TicketConversation/hooks/useReply.ts +190 -0
  48. package/src/components/TicketConversation/hooks/useTicketActions.ts +205 -0
  49. package/src/components/TicketConversation/hooks/useTimeTracking.ts +107 -0
  50. package/src/components/TicketConversation/hooks/useTranslation.ts +116 -0
  51. package/src/components/TicketConversation/index.tsx +1110 -0
  52. package/src/components/TicketConversation/locales/en.json +878 -0
  53. package/src/components/TicketConversation/locales/fr.json +878 -0
  54. package/src/components/TicketConversation/types.ts +54 -0
  55. package/src/components/TicketConversation/utils.ts +25 -0
  56. package/src/endpoints/admin-chat-stream.ts +238 -0
  57. package/src/endpoints/admin-chat.ts +263 -0
  58. package/src/endpoints/admin-stats.ts +200 -0
  59. package/src/endpoints/ai.ts +199 -0
  60. package/src/endpoints/apply-macro.ts +144 -0
  61. package/src/endpoints/auth-2fa.ts +163 -0
  62. package/src/endpoints/auto-close.ts +175 -0
  63. package/src/endpoints/billing.ts +167 -0
  64. package/src/endpoints/bulk-action.ts +103 -0
  65. package/src/endpoints/chat-stream.ts +127 -0
  66. package/src/endpoints/chat.ts +188 -0
  67. package/src/endpoints/chatbot.ts +113 -0
  68. package/src/endpoints/delete-account.ts +129 -0
  69. package/src/endpoints/email-stats.ts +109 -0
  70. package/src/endpoints/export-csv.ts +84 -0
  71. package/src/endpoints/export-data.ts +104 -0
  72. package/src/endpoints/import-conversation.ts +307 -0
  73. package/src/endpoints/index.ts +154 -0
  74. package/src/endpoints/login.ts +92 -0
  75. package/src/endpoints/merge-clients.ts +132 -0
  76. package/src/endpoints/merge-tickets.ts +137 -0
  77. package/src/endpoints/oauth-google.ts +179 -0
  78. package/src/endpoints/pending-emails-process.ts +224 -0
  79. package/src/endpoints/presence.ts +104 -0
  80. package/src/endpoints/process-scheduled.ts +144 -0
  81. package/src/endpoints/purge-logs.ts +58 -0
  82. package/src/endpoints/resend-notification.ts +99 -0
  83. package/src/endpoints/round-robin-config.ts +92 -0
  84. package/src/endpoints/satisfaction.ts +93 -0
  85. package/src/endpoints/search.ts +106 -0
  86. package/src/endpoints/seed-kb.ts +153 -0
  87. package/src/endpoints/settings.ts +144 -0
  88. package/src/endpoints/signature.ts +93 -0
  89. package/src/endpoints/sla-check.ts +124 -0
  90. package/src/endpoints/split-ticket.ts +131 -0
  91. package/src/endpoints/statuses.ts +45 -0
  92. package/src/endpoints/track-open.ts +154 -0
  93. package/src/endpoints/typing.ts +101 -0
  94. package/src/endpoints/user-prefs.ts +125 -0
  95. package/src/hooks/checkSLA.ts +414 -0
  96. package/src/hooks/ticketStatusEmail.ts +182 -0
  97. package/src/index.ts +51 -0
  98. package/src/plugin.ts +157 -0
  99. package/src/portal/LiveChat.tsx +1353 -0
  100. package/src/portal/auth/ChatWidget.tsx +350 -0
  101. package/src/portal/auth/ChatbotWidget.tsx +285 -0
  102. package/src/portal/auth/SupportHeader.tsx +409 -0
  103. package/src/portal/auth/dashboard/DashboardClient.tsx +650 -0
  104. package/src/portal/auth/dashboard/page.tsx +84 -0
  105. package/src/portal/auth/faq/FAQSearch.tsx +117 -0
  106. package/src/portal/auth/faq/page.tsx +199 -0
  107. package/src/portal/auth/layout.tsx +61 -0
  108. package/src/portal/auth/profile/page.tsx +705 -0
  109. package/src/portal/auth/tickets/detail/CloseTicketButton.tsx +74 -0
  110. package/src/portal/auth/tickets/detail/CollapsibleMessages.tsx +46 -0
  111. package/src/portal/auth/tickets/detail/MarkSolutionButton.tsx +50 -0
  112. package/src/portal/auth/tickets/detail/MessageActions.tsx +158 -0
  113. package/src/portal/auth/tickets/detail/PrintButton.tsx +16 -0
  114. package/src/portal/auth/tickets/detail/ReadReceipt.tsx +34 -0
  115. package/src/portal/auth/tickets/detail/ReopenTicketButton.tsx +74 -0
  116. package/src/portal/auth/tickets/detail/SatisfactionForm.tsx +156 -0
  117. package/src/portal/auth/tickets/detail/TicketPolling.tsx +57 -0
  118. package/src/portal/auth/tickets/detail/TicketReplyForm.tsx +294 -0
  119. package/src/portal/auth/tickets/detail/TypingIndicator.tsx +58 -0
  120. package/src/portal/auth/tickets/detail/page.tsx +738 -0
  121. package/src/portal/auth/tickets/new/page.tsx +515 -0
  122. package/src/portal/forgot-password/page.tsx +114 -0
  123. package/src/portal/layout.tsx +26 -0
  124. package/src/portal/locales/en.json +374 -0
  125. package/src/portal/locales/fr.json +374 -0
  126. package/src/portal/login/page.tsx +351 -0
  127. package/src/portal/page.tsx +162 -0
  128. package/src/portal/register/page.tsx +281 -0
  129. package/src/portal/reset-password/page.tsx +152 -0
  130. package/src/styles/BillingView.module.scss +311 -0
  131. package/src/styles/ChatView.module.scss +438 -0
  132. package/src/styles/CommandPalette.module.scss +160 -0
  133. package/src/styles/CrmView.module.scss +554 -0
  134. package/src/styles/EmailTracking.module.scss +238 -0
  135. package/src/styles/ImportConversation.module.scss +267 -0
  136. package/src/styles/Layout.module.scss +55 -0
  137. package/src/styles/Logs.module.scss +164 -0
  138. package/src/styles/NewTicket.module.scss +143 -0
  139. package/src/styles/PendingEmails.module.scss +629 -0
  140. package/src/styles/SupportDashboard.module.scss +649 -0
  141. package/src/styles/TicketDetail.module.scss +1043 -0
  142. package/src/styles/TicketInbox.module.scss +296 -0
  143. package/src/styles/TicketingSettings.module.scss +358 -0
  144. package/src/styles/TimeDashboard.module.scss +287 -0
  145. package/src/styles/_tokens.scss +78 -0
  146. package/src/styles/theme.css +633 -0
  147. package/src/types.ts +255 -0
  148. package/src/utils/adminNotification.ts +38 -0
  149. package/src/utils/auth.ts +46 -0
  150. package/src/utils/emailTemplate.ts +343 -0
  151. package/src/utils/fireWebhooks.ts +84 -0
  152. package/src/utils/index.ts +22 -0
  153. package/src/utils/rateLimiter.ts +52 -0
  154. package/src/utils/readSettings.ts +67 -0
  155. package/src/utils/slugs.ts +54 -0
  156. package/src/utils/webhookDispatcher.ts +120 -0
  157. package/src/views/BillingView/client.tsx +137 -0
  158. package/src/views/BillingView/index.tsx +33 -0
  159. package/src/views/ChatView/client.tsx +294 -0
  160. package/src/views/ChatView/index.tsx +33 -0
  161. package/src/views/CrmView/client.tsx +206 -0
  162. package/src/views/CrmView/index.tsx +33 -0
  163. package/src/views/EmailTrackingView/client.tsx +124 -0
  164. package/src/views/EmailTrackingView/index.tsx +33 -0
  165. package/src/views/ImportConversationView/client.tsx +133 -0
  166. package/src/views/ImportConversationView/index.tsx +33 -0
  167. package/src/views/LogsView/client.tsx +151 -0
  168. package/src/views/LogsView/index.tsx +30 -0
  169. package/src/views/NewTicketView/client.tsx +227 -0
  170. package/src/views/NewTicketView/index.tsx +30 -0
  171. package/src/views/PendingEmailsView/client.tsx +177 -0
  172. package/src/views/PendingEmailsView/index.tsx +33 -0
  173. package/src/views/SupportDashboardView/client.tsx +424 -0
  174. package/src/views/SupportDashboardView/index.tsx +33 -0
  175. package/src/views/TicketDetailView/client.tsx +775 -0
  176. package/src/views/TicketDetailView/index.tsx +33 -0
  177. package/src/views/TicketInboxView/client.tsx +313 -0
  178. package/src/views/TicketInboxView/index.tsx +30 -0
  179. package/src/views/TicketingSettingsView/client.tsx +866 -0
  180. package/src/views/TicketingSettingsView/index.tsx +33 -0
  181. package/src/views/TimeDashboardView/client.tsx +144 -0
  182. package/src/views/TimeDashboardView/index.tsx +33 -0
  183. package/src/views/shared/AdminViewHeader.tsx +69 -0
  184. package/src/views/shared/ErrorBoundary.tsx +68 -0
  185. package/src/views/shared/Skeleton.tsx +125 -0
  186. package/src/views/shared/adminTokens.ts +37 -0
  187. package/src/views/shared/config.ts +82 -0
  188. package/src/views/shared/index.ts +6 -0
  189. package/src/views.ts +16 -0
@@ -0,0 +1,1043 @@
1
+ // TicketDetail — Premium helpdesk UI inspired by HelpScout/Linear 2026
2
+ // Uses Payload CMS CSS variables for dark mode compatibility
3
+
4
+ .page {
5
+ max-width: 1920px;
6
+ margin: 0 auto;
7
+ padding: 0 24px 60px;
8
+ font-family: -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', system-ui, sans-serif;
9
+ }
10
+
11
+ // ─── TOP BAR ───
12
+ .topBar {
13
+ display: flex;
14
+ align-items: center;
15
+ gap: 14px;
16
+ padding: 16px 0 14px;
17
+ border-bottom: 1px solid var(--theme-elevation-150, #f1f5f9);
18
+ margin-bottom: 20px;
19
+ }
20
+
21
+ .backLink {
22
+ color: var(--theme-elevation-500);
23
+ text-decoration: none;
24
+ font-size: 22px;
25
+ line-height: 1;
26
+ display: flex;
27
+ align-items: center;
28
+ transition: color 100ms;
29
+ &:hover { color: var(--theme-text); }
30
+ }
31
+
32
+ .ticketMeta {
33
+ display: flex;
34
+ flex-direction: column;
35
+ gap: 2px;
36
+ flex: 1;
37
+ min-width: 0;
38
+ }
39
+
40
+ .ticketNumber {
41
+ font-size: 12px;
42
+ font-weight: 500;
43
+ color: var(--theme-elevation-500);
44
+ font-family: 'SF Mono', 'Fira Code', 'JetBrains Mono', 'Cascadia Code', monospace;
45
+ letter-spacing: 0.02em;
46
+ }
47
+
48
+ .ticketSubject {
49
+ font-size: 18px;
50
+ font-weight: 700;
51
+ color: var(--theme-text);
52
+ overflow: hidden;
53
+ text-overflow: ellipsis;
54
+ white-space: nowrap;
55
+ line-height: 1.3;
56
+ }
57
+
58
+ .topBarRight {
59
+ display: flex;
60
+ align-items: center;
61
+ gap: 10px;
62
+ flex-shrink: 0;
63
+ }
64
+
65
+ .statusChip {
66
+ padding: 5px 14px;
67
+ border-radius: 20px;
68
+ font-size: 12px;
69
+ font-weight: 700;
70
+ border: 1px solid transparent;
71
+ cursor: pointer;
72
+ transition: all 100ms;
73
+ appearance: none;
74
+ -webkit-appearance: none;
75
+ }
76
+
77
+ .sentimentBadge {
78
+ font-size: 12px;
79
+ font-weight: 600;
80
+ display: inline-flex;
81
+ align-items: center;
82
+ gap: 4px;
83
+ padding: 4px 10px;
84
+ border-radius: 20px;
85
+ }
86
+
87
+ .moreBtn {
88
+ width: 36px;
89
+ height: 36px;
90
+ border-radius: 8px;
91
+ border: 1px solid var(--theme-elevation-200);
92
+ background: none;
93
+ cursor: pointer;
94
+ font-size: 18px;
95
+ color: var(--theme-elevation-500);
96
+ display: flex;
97
+ align-items: center;
98
+ justify-content: center;
99
+ transition: all 100ms;
100
+ &:hover { background: var(--theme-elevation-100); color: var(--theme-text); }
101
+ }
102
+
103
+ // ─── LAYOUT ───
104
+ .layout {
105
+ display: grid;
106
+ grid-template-columns: 1fr 300px;
107
+ gap: 24px;
108
+ align-items: start;
109
+ @media (max-width: 1060px) { grid-template-columns: 1fr; }
110
+ }
111
+
112
+ .conversationCol {
113
+ min-width: 0;
114
+ }
115
+
116
+ .sidebar {
117
+ border: 1px solid var(--theme-elevation-150, #f1f5f9);
118
+ border-radius: 12px;
119
+ overflow: hidden;
120
+ position: sticky;
121
+ top: 72px;
122
+ @media (max-width: 1060px) { position: static; }
123
+ }
124
+
125
+ // ─── SIDEBAR SECTIONS ───
126
+ .sideSection {
127
+ padding: 16px;
128
+ border-bottom: 1px solid var(--theme-elevation-150, #f1f5f9);
129
+ &:last-child { border-bottom: none; }
130
+ }
131
+
132
+ .sideSectionTitle {
133
+ font-size: 10px;
134
+ font-weight: 700;
135
+ text-transform: uppercase;
136
+ letter-spacing: 0.06em;
137
+ color: var(--theme-elevation-500);
138
+ margin: 0 0 12px;
139
+ display: flex;
140
+ justify-content: space-between;
141
+ align-items: center;
142
+ }
143
+
144
+ .sideField {
145
+ display: flex;
146
+ justify-content: space-between;
147
+ align-items: center;
148
+ padding: 4px 0;
149
+ font-size: 13px;
150
+ }
151
+
152
+ .sideLabel { color: var(--theme-elevation-500); font-weight: 500; }
153
+ .sideValue { color: var(--theme-text); font-weight: 600; }
154
+
155
+ // Inline select for sidebar editable fields (#1)
156
+ .sideSelect {
157
+ padding: 2px 6px;
158
+ border-radius: 6px;
159
+ border: 1px solid transparent;
160
+ background: none;
161
+ font-size: 13px;
162
+ font-weight: 600;
163
+ color: var(--theme-text);
164
+ cursor: pointer;
165
+ transition: all 100ms;
166
+ text-align: right;
167
+ max-width: 140px;
168
+
169
+ &:hover { border-color: var(--theme-elevation-200); background: var(--theme-elevation-50); }
170
+ &:focus { border-color: #2563eb; outline: none; box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.12); }
171
+ }
172
+
173
+ // Client card
174
+ .clientCard {
175
+ display: flex;
176
+ align-items: center;
177
+ gap: 12px;
178
+ }
179
+
180
+ .clientAvatar {
181
+ width: 40px;
182
+ height: 40px;
183
+ border-radius: 50%;
184
+ background: linear-gradient(135deg, #e0e7ff, #c7d2fe);
185
+ display: flex;
186
+ align-items: center;
187
+ justify-content: center;
188
+ font-size: 14px;
189
+ font-weight: 700;
190
+ color: #4338ca;
191
+ flex-shrink: 0;
192
+ }
193
+
194
+ .clientInfo { flex: 1; min-width: 0; }
195
+ .clientName { font-size: 14px; font-weight: 700; color: var(--theme-text); }
196
+ .clientCompany { font-size: 12px; color: var(--theme-elevation-500); margin-top: 1px; }
197
+
198
+ .clientEmail {
199
+ font-size: 12px;
200
+ color: #2563eb;
201
+ text-decoration: none;
202
+ margin-top: 2px;
203
+ display: block;
204
+ &:hover { text-decoration: underline; }
205
+ }
206
+
207
+ .clientActions {
208
+ display: flex;
209
+ gap: 6px;
210
+ margin-top: 10px;
211
+ }
212
+
213
+ .smallBtn {
214
+ padding: 5px 12px;
215
+ border-radius: 6px;
216
+ border: 1px solid var(--theme-elevation-200);
217
+ background: none;
218
+ font-size: 11px;
219
+ font-weight: 600;
220
+ color: var(--theme-elevation-500);
221
+ cursor: pointer;
222
+ text-decoration: none;
223
+ transition: all 100ms;
224
+ &:hover { background: var(--theme-elevation-100); color: var(--theme-text); }
225
+ }
226
+
227
+ // ─── MESSAGES ───
228
+ .thread {
229
+ display: flex;
230
+ flex-direction: column;
231
+ gap: 0;
232
+ margin-bottom: 12px;
233
+ }
234
+
235
+ .dateSeparator {
236
+ display: flex;
237
+ align-items: center;
238
+ gap: 16px;
239
+ padding: 12px 0 6px;
240
+ &::before, &::after {
241
+ content: '';
242
+ flex: 1;
243
+ height: 1px;
244
+ background: var(--theme-elevation-150, #f1f5f9);
245
+ }
246
+ }
247
+
248
+ .dateSeparatorText {
249
+ font-size: 11px;
250
+ font-weight: 600;
251
+ color: var(--theme-elevation-500);
252
+ white-space: nowrap;
253
+ padding: 3px 12px;
254
+ background: var(--theme-elevation-50);
255
+ border-radius: 10px;
256
+ }
257
+
258
+ // #4 — Message separation
259
+ .message + .message {
260
+ border-top: 1px solid var(--theme-elevation-100);
261
+ }
262
+
263
+ .message {
264
+ display: flex;
265
+ gap: 12px;
266
+ padding: 14px 12px;
267
+ border-radius: 10px;
268
+ position: relative;
269
+ transition: background 80ms;
270
+
271
+ &:hover { background: var(--theme-elevation-50); }
272
+ }
273
+
274
+ .messageInternal {
275
+ background: #fefce8;
276
+ border-left: 3px dashed #d97706;
277
+ &:hover { background: #fef9c3; }
278
+ }
279
+
280
+ .avatar {
281
+ flex-shrink: 0;
282
+ width: 32px;
283
+ height: 32px;
284
+ border-radius: 50%;
285
+ display: flex;
286
+ align-items: center;
287
+ justify-content: center;
288
+ font-size: 11px;
289
+ font-weight: 700;
290
+ color: #fff;
291
+ margin-top: 2px;
292
+ }
293
+
294
+ .messageContent { flex: 1; min-width: 0; }
295
+
296
+ .messageHeader {
297
+ display: flex;
298
+ align-items: center;
299
+ gap: 8px;
300
+ margin-bottom: 4px;
301
+ flex-wrap: wrap;
302
+ }
303
+
304
+ .messageAuthor { font-size: 13px; font-weight: 700; color: var(--theme-text); }
305
+
306
+ .messageTime {
307
+ font-size: 11px;
308
+ color: var(--theme-elevation-500);
309
+ font-weight: 500;
310
+ }
311
+
312
+ .badge {
313
+ display: inline-flex;
314
+ align-items: center;
315
+ padding: 2px 8px;
316
+ border-radius: 4px;
317
+ font-size: 10px;
318
+ font-weight: 700;
319
+ letter-spacing: 0.02em;
320
+ }
321
+
322
+ .messageMeta {
323
+ margin-left: auto;
324
+ display: flex;
325
+ gap: 6px;
326
+ align-items: center;
327
+ font-size: 10px;
328
+ font-weight: 600;
329
+ }
330
+
331
+ // #11 — Message font size 14px
332
+ .messageBody {
333
+ font-size: 14px;
334
+ line-height: 1.7;
335
+ color: var(--theme-text);
336
+ white-space: pre-wrap;
337
+ word-break: break-word;
338
+ }
339
+
340
+ .messageActions {
341
+ display: flex;
342
+ gap: 4px;
343
+ margin-top: 6px;
344
+ }
345
+
346
+ .actionIcon {
347
+ width: 28px;
348
+ height: 28px;
349
+ border: none;
350
+ background: none;
351
+ cursor: pointer;
352
+ border-radius: 4px;
353
+ font-size: 13px;
354
+ color: var(--theme-elevation-500);
355
+ display: flex;
356
+ align-items: center;
357
+ justify-content: center;
358
+ transition: all 80ms;
359
+ &:hover { background: var(--theme-elevation-100); color: var(--theme-text); }
360
+ &.danger:hover { color: #ef4444; }
361
+ }
362
+
363
+ // ─── TYPING ───
364
+ .typing {
365
+ display: flex;
366
+ align-items: center;
367
+ gap: 8px;
368
+ padding: 8px 14px;
369
+ font-size: 12px;
370
+ color: #7c3aed;
371
+ font-weight: 500;
372
+ }
373
+
374
+ .typingDots {
375
+ display: flex;
376
+ gap: 3px;
377
+ span {
378
+ width: 5px; height: 5px; border-radius: 50%; background: #7c3aed;
379
+ animation: bounce 1.2s infinite;
380
+ &:nth-child(2) { animation-delay: 150ms; }
381
+ &:nth-child(3) { animation-delay: 300ms; }
382
+ }
383
+ }
384
+
385
+ @keyframes bounce {
386
+ 0%, 60%, 100% { transform: translateY(0); }
387
+ 30% { transform: translateY(-4px); }
388
+ }
389
+
390
+ // ─── COMPOSER ───
391
+ .composer {
392
+ border: 1px solid var(--theme-elevation-200);
393
+ border-radius: 12px;
394
+ overflow: visible;
395
+ position: relative;
396
+ background: var(--theme-elevation-0, #fff);
397
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
398
+ transition: border-color 150ms, box-shadow 150ms;
399
+
400
+ &:focus-within {
401
+ border-color: #2563eb;
402
+ box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.08);
403
+ }
404
+ }
405
+
406
+ .composerInternal {
407
+ border-color: #d97706;
408
+ border-style: dashed;
409
+ &:focus-within { border-color: #d97706; box-shadow: 0 0 0 3px rgba(217, 119, 6, 0.08); }
410
+ }
411
+
412
+ // #5 — Drag & drop highlight
413
+ .composerDragOver {
414
+ border-color: #2563eb;
415
+ background: rgba(37, 99, 235, 0.04);
416
+ box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12);
417
+ }
418
+
419
+ .composerToolbar {
420
+ display: flex;
421
+ gap: 2px;
422
+ padding: 8px 12px;
423
+ border-bottom: 1px solid var(--theme-elevation-100, #f8fafc);
424
+ align-items: center;
425
+ }
426
+
427
+ .toolbarBtn {
428
+ width: 32px;
429
+ height: 32px;
430
+ border-radius: 6px;
431
+ border: none;
432
+ background: none;
433
+ cursor: pointer;
434
+ font-size: 15px;
435
+ color: var(--theme-elevation-500);
436
+ display: flex;
437
+ align-items: center;
438
+ justify-content: center;
439
+ transition: all 80ms;
440
+ position: relative;
441
+
442
+ &:hover {
443
+ background: var(--theme-elevation-100);
444
+ color: var(--theme-text);
445
+ }
446
+
447
+ &:disabled { opacity: 0.3; cursor: not-allowed; }
448
+
449
+ // Tooltip
450
+ &::after {
451
+ content: attr(data-tooltip);
452
+ position: absolute;
453
+ bottom: -28px;
454
+ left: 50%;
455
+ transform: translateX(-50%);
456
+ padding: 3px 8px;
457
+ border-radius: 4px;
458
+ background: var(--theme-text);
459
+ color: var(--theme-elevation-0, #fff);
460
+ font-size: 10px;
461
+ font-weight: 600;
462
+ white-space: nowrap;
463
+ opacity: 0;
464
+ pointer-events: none;
465
+ transition: opacity 100ms;
466
+ }
467
+ &:hover::after { opacity: 1; }
468
+ }
469
+
470
+ .toolbarDivider {
471
+ width: 1px;
472
+ height: 20px;
473
+ background: var(--theme-elevation-200);
474
+ margin: 0 4px;
475
+ }
476
+
477
+ .cannedSelect {
478
+ padding: 4px 8px;
479
+ border-radius: 6px;
480
+ border: 1px solid var(--theme-elevation-200);
481
+ background: none;
482
+ font-size: 11px;
483
+ font-weight: 600;
484
+ color: var(--theme-elevation-500);
485
+ cursor: pointer;
486
+ margin-left: auto;
487
+ &:hover { background: var(--theme-elevation-100); }
488
+ }
489
+
490
+ .composerFooter {
491
+ display: flex;
492
+ justify-content: space-between;
493
+ align-items: center;
494
+ padding: 10px 14px;
495
+ border-top: 1px solid var(--theme-elevation-100, #f8fafc);
496
+ }
497
+
498
+ .composerOptions {
499
+ display: flex;
500
+ gap: 16px;
501
+ align-items: center;
502
+ font-size: 12px;
503
+ color: var(--theme-elevation-500);
504
+
505
+ label {
506
+ display: flex;
507
+ align-items: center;
508
+ gap: 6px;
509
+ cursor: pointer;
510
+ font-weight: 500;
511
+ user-select: none;
512
+ }
513
+
514
+ // Custom toggle switch
515
+ input[type="checkbox"] {
516
+ appearance: none;
517
+ -webkit-appearance: none;
518
+ width: 34px;
519
+ height: 20px;
520
+ border-radius: 10px;
521
+ background: var(--theme-elevation-300);
522
+ position: relative;
523
+ cursor: pointer;
524
+ transition: background 150ms;
525
+
526
+ &::after {
527
+ content: '';
528
+ position: absolute;
529
+ top: 2px;
530
+ left: 2px;
531
+ width: 16px;
532
+ height: 16px;
533
+ border-radius: 50%;
534
+ background: #fff;
535
+ transition: transform 150ms;
536
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
537
+ }
538
+
539
+ &:checked {
540
+ background: #2563eb;
541
+ &::after { transform: translateX(14px); }
542
+ }
543
+ }
544
+ }
545
+
546
+ .sendBtn {
547
+ padding: 8px 22px;
548
+ border-radius: 8px;
549
+ border: none;
550
+ background: #2563eb;
551
+ color: #fff;
552
+ font-size: 13px;
553
+ font-weight: 700;
554
+ cursor: pointer;
555
+ transition: background 100ms;
556
+ display: flex;
557
+ align-items: center;
558
+ gap: 6px;
559
+
560
+ &:hover { background: #1d4ed8; }
561
+ &:disabled { opacity: 0.4; cursor: not-allowed; }
562
+ }
563
+
564
+ .sendBtnInternal {
565
+ background: #d97706;
566
+ &:hover { background: #b45309; }
567
+ }
568
+
569
+ // ─── ATTACHMENTS ───
570
+ .attachments {
571
+ display: flex;
572
+ gap: 8px;
573
+ flex-wrap: wrap;
574
+ margin-top: 8px;
575
+ }
576
+
577
+ .attachmentImg {
578
+ max-width: 220px;
579
+ max-height: 180px;
580
+ border-radius: 8px;
581
+ border: 1px solid var(--theme-elevation-200);
582
+ object-fit: cover;
583
+ cursor: pointer;
584
+ transition: opacity 100ms;
585
+ &:hover { opacity: 0.85; }
586
+ }
587
+
588
+ .attachmentFile {
589
+ display: inline-flex;
590
+ align-items: center;
591
+ gap: 4px;
592
+ padding: 5px 10px;
593
+ border-radius: 6px;
594
+ border: 1px solid var(--theme-elevation-200);
595
+ font-size: 11px;
596
+ font-weight: 600;
597
+ color: var(--theme-text);
598
+ text-decoration: none;
599
+ background: var(--theme-elevation-50);
600
+ transition: background 80ms;
601
+ &:hover { background: var(--theme-elevation-100); }
602
+ }
603
+
604
+ // Timer in sidebar
605
+ .timer {
606
+ display: flex;
607
+ align-items: center;
608
+ gap: 10px;
609
+ }
610
+
611
+ .timerDisplay {
612
+ font-family: 'SF Mono', 'Fira Code', 'JetBrains Mono', 'Cascadia Code', monospace;
613
+ font-size: 20px;
614
+ font-weight: 700;
615
+ color: var(--theme-text);
616
+ letter-spacing: 0.02em;
617
+
618
+ &.timerActive { color: #dc2626; }
619
+ }
620
+
621
+ .timerBtn {
622
+ padding: 5px 14px;
623
+ border-radius: 6px;
624
+ border: 1px solid var(--theme-elevation-200);
625
+ background: none;
626
+ font-size: 12px;
627
+ font-weight: 700;
628
+ cursor: pointer;
629
+ transition: all 80ms;
630
+ &:hover { background: var(--theme-elevation-100); }
631
+ }
632
+
633
+ // Activity in sidebar
634
+ .collapseBtn {
635
+ background: none;
636
+ border: none;
637
+ cursor: pointer;
638
+ color: var(--theme-elevation-500);
639
+ font-size: 13px;
640
+ font-weight: 600;
641
+ padding: 0;
642
+ display: flex;
643
+ align-items: center;
644
+ gap: 4px;
645
+ &:hover { color: var(--theme-text); }
646
+ }
647
+
648
+ .activityItem {
649
+ font-size: 12px;
650
+ padding: 6px 0;
651
+ border-bottom: 1px solid var(--theme-elevation-100, #f8fafc);
652
+ display: flex;
653
+ gap: 8px;
654
+ align-items: flex-start;
655
+
656
+ &:last-child { border-bottom: none; }
657
+ }
658
+
659
+ .activityDot {
660
+ width: 8px;
661
+ height: 8px;
662
+ border-radius: 50%;
663
+ margin-top: 4px;
664
+ flex-shrink: 0;
665
+ }
666
+
667
+ .activityContent { flex: 1; min-width: 0; }
668
+ .activityText { font-weight: 500; color: var(--theme-text); font-size: 12px; }
669
+ .activityTime { font-size: 11px; color: var(--theme-elevation-500); margin-top: 1px; }
670
+
671
+ // ─── DROPDOWN ───
672
+ .dropdown { position: relative; display: inline-block; }
673
+
674
+ .dropdownMenu {
675
+ position: absolute;
676
+ top: calc(100% + 6px);
677
+ right: 0;
678
+ z-index: 50;
679
+ min-width: 200px;
680
+ padding: 6px;
681
+ border-radius: 10px;
682
+ border: 1px solid var(--theme-elevation-200);
683
+ background: var(--theme-elevation-0, #fff);
684
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
685
+ }
686
+
687
+ .dropdownItem {
688
+ display: block;
689
+ width: 100%;
690
+ padding: 8px 12px;
691
+ border: none;
692
+ background: none;
693
+ text-align: left;
694
+ font-size: 13px;
695
+ font-weight: 500;
696
+ color: var(--theme-text);
697
+ cursor: pointer;
698
+ border-radius: 6px;
699
+ text-decoration: none;
700
+ &:hover { background: var(--theme-elevation-100); }
701
+ }
702
+
703
+ // RTE
704
+ .rteDisplay {
705
+ :global {
706
+ blockquote { border-left: 3px solid #2563eb; margin: 8px 0; padding: 8px 16px; background: var(--theme-elevation-50); border-radius: 0 6px 6px 0; }
707
+ img { max-width: 100%; height: auto; border-radius: 8px; margin: 8px 0; }
708
+ a { color: #2563eb; text-decoration: underline; }
709
+ ul, ol { margin: 8px 0; padding-left: 24px; }
710
+ li { margin: 2px 0; }
711
+ p { margin: 0 0 6px 0; }
712
+ }
713
+ }
714
+
715
+ // ─── UNDO TOAST (#2) ───
716
+ .undoToast {
717
+ position: fixed;
718
+ bottom: 24px;
719
+ left: 50%;
720
+ transform: translateX(-50%);
721
+ z-index: 100;
722
+ display: flex;
723
+ align-items: center;
724
+ gap: 12px;
725
+ padding: 12px 20px;
726
+ border-radius: 10px;
727
+ background: var(--theme-text, #1e293b);
728
+ color: var(--theme-elevation-0, #fff);
729
+ font-size: 13px;
730
+ font-weight: 600;
731
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
732
+ animation: toastIn 200ms ease-out;
733
+ }
734
+
735
+ .undoBtn {
736
+ padding: 4px 14px;
737
+ border-radius: 6px;
738
+ border: 1px solid rgba(255, 255, 255, 0.3);
739
+ background: rgba(255, 255, 255, 0.12);
740
+ color: #fff;
741
+ font-size: 12px;
742
+ font-weight: 700;
743
+ cursor: pointer;
744
+ transition: background 100ms;
745
+ &:hover { background: rgba(255, 255, 255, 0.25); }
746
+ }
747
+
748
+ @keyframes toastIn {
749
+ from { opacity: 0; transform: translateX(-50%) translateY(12px); }
750
+ to { opacity: 1; transform: translateX(-50%) translateY(0); }
751
+ }
752
+
753
+ // ─── SPLIT MODAL (#2) ───
754
+ .splitOverlay {
755
+ position: fixed;
756
+ inset: 0;
757
+ z-index: 90;
758
+ background: rgba(0, 0, 0, 0.3);
759
+ display: flex;
760
+ align-items: center;
761
+ justify-content: center;
762
+ animation: fadeIn 150ms ease-out;
763
+ }
764
+
765
+ .splitModal {
766
+ background: var(--theme-elevation-0, #fff);
767
+ border-radius: 12px;
768
+ border: 1px solid var(--theme-elevation-200);
769
+ box-shadow: 0 16px 48px rgba(0, 0, 0, 0.15);
770
+ width: 440px;
771
+ max-width: 90vw;
772
+ padding: 24px;
773
+ }
774
+
775
+ .splitTitle {
776
+ font-size: 16px;
777
+ font-weight: 700;
778
+ color: var(--theme-text);
779
+ margin: 0 0 8px;
780
+ }
781
+
782
+ .splitPreview {
783
+ font-size: 12px;
784
+ color: var(--theme-elevation-500);
785
+ margin: 0 0 16px;
786
+ line-height: 1.5;
787
+ max-height: 80px;
788
+ overflow: hidden;
789
+ padding: 8px;
790
+ border-radius: 6px;
791
+ background: var(--theme-elevation-50);
792
+ }
793
+
794
+ .splitInput {
795
+ width: 100%;
796
+ padding: 10px 14px;
797
+ border-radius: 8px;
798
+ border: 1px solid var(--theme-elevation-200);
799
+ font-size: 14px;
800
+ color: var(--theme-text);
801
+ background: var(--theme-elevation-0, #fff);
802
+ margin-bottom: 16px;
803
+ transition: border-color 100ms;
804
+
805
+ &:focus { border-color: #2563eb; outline: none; box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1); }
806
+ }
807
+
808
+ .splitActions {
809
+ display: flex;
810
+ justify-content: flex-end;
811
+ gap: 8px;
812
+ }
813
+
814
+ .splitCancelBtn {
815
+ padding: 8px 16px;
816
+ border-radius: 8px;
817
+ border: 1px solid var(--theme-elevation-200);
818
+ background: none;
819
+ font-size: 13px;
820
+ font-weight: 600;
821
+ color: var(--theme-elevation-500);
822
+ cursor: pointer;
823
+ &:hover { background: var(--theme-elevation-100); }
824
+ }
825
+
826
+ .splitConfirmBtn {
827
+ padding: 8px 16px;
828
+ border-radius: 8px;
829
+ border: none;
830
+ background: #2563eb;
831
+ color: #fff;
832
+ font-size: 13px;
833
+ font-weight: 700;
834
+ cursor: pointer;
835
+ &:hover { background: #1d4ed8; }
836
+ &:disabled { opacity: 0.4; cursor: not-allowed; }
837
+ }
838
+
839
+ @keyframes fadeIn {
840
+ from { opacity: 0; }
841
+ to { opacity: 1; }
842
+ }
843
+
844
+ // ─── TAGS (#6) ───
845
+ .tagsWrap {
846
+ display: flex;
847
+ flex-wrap: wrap;
848
+ gap: 6px;
849
+ margin-top: 4px;
850
+ }
851
+
852
+ .tagChip {
853
+ display: inline-flex;
854
+ align-items: center;
855
+ gap: 4px;
856
+ padding: 3px 10px;
857
+ border-radius: 20px;
858
+ background: var(--theme-elevation-100);
859
+ font-size: 11px;
860
+ font-weight: 600;
861
+ color: var(--theme-text);
862
+ }
863
+
864
+ .tagRemove {
865
+ background: none;
866
+ border: none;
867
+ cursor: pointer;
868
+ font-size: 14px;
869
+ line-height: 1;
870
+ color: var(--theme-elevation-400);
871
+ padding: 0;
872
+ display: flex;
873
+ align-items: center;
874
+ transition: color 80ms;
875
+ &:hover { color: #ef4444; }
876
+ }
877
+
878
+ .tagAddBtn {
879
+ padding: 3px 10px;
880
+ border-radius: 20px;
881
+ border: 1px dashed var(--theme-elevation-300);
882
+ background: none;
883
+ font-size: 11px;
884
+ font-weight: 600;
885
+ color: var(--theme-elevation-400);
886
+ cursor: pointer;
887
+ transition: all 80ms;
888
+ &:hover { border-color: #2563eb; color: #2563eb; background: rgba(37, 99, 235, 0.04); }
889
+ }
890
+
891
+ .tagInput {
892
+ padding: 3px 8px;
893
+ border-radius: 20px;
894
+ border: 1px solid #2563eb;
895
+ font-size: 11px;
896
+ font-weight: 600;
897
+ color: var(--theme-text);
898
+ background: var(--theme-elevation-0, #fff);
899
+ width: 100px;
900
+ &:focus { outline: none; }
901
+ }
902
+
903
+ // ─── FILE UPLOAD PREVIEW (#5) ───
904
+ .uploadPreview {
905
+ display: flex;
906
+ flex-wrap: wrap;
907
+ gap: 8px;
908
+ padding: 8px 12px;
909
+ border-top: 1px solid var(--theme-elevation-100);
910
+ }
911
+
912
+ .uploadPreviewItem {
913
+ display: flex;
914
+ align-items: center;
915
+ gap: 6px;
916
+ padding: 4px 10px;
917
+ border-radius: 6px;
918
+ background: var(--theme-elevation-50);
919
+ border: 1px solid var(--theme-elevation-200);
920
+ font-size: 11px;
921
+ font-weight: 600;
922
+ color: var(--theme-text);
923
+ }
924
+
925
+ .uploadRemoveBtn {
926
+ background: none;
927
+ border: none;
928
+ cursor: pointer;
929
+ font-size: 14px;
930
+ line-height: 1;
931
+ color: var(--theme-elevation-400);
932
+ padding: 0;
933
+ &:hover { color: #ef4444; }
934
+ }
935
+
936
+ // Hidden file input
937
+ .hiddenFileInput {
938
+ display: none;
939
+ }
940
+
941
+ // ─── RESPONSIVE BREAKPOINTS (#8) ───
942
+ @media (max-width: 768px) {
943
+ .page {
944
+ padding: 0 12px 40px;
945
+ }
946
+
947
+ .topBar {
948
+ gap: 10px;
949
+ padding: 12px 0 10px;
950
+ flex-wrap: wrap;
951
+ }
952
+
953
+ .ticketSubject {
954
+ font-size: 15px;
955
+ }
956
+
957
+ .topBarRight {
958
+ gap: 6px;
959
+ }
960
+
961
+ .sentimentBadge {
962
+ display: none;
963
+ }
964
+
965
+ .message {
966
+ padding: 10px 8px;
967
+ }
968
+
969
+ .composerToolbar {
970
+ flex-wrap: wrap;
971
+ gap: 4px;
972
+ }
973
+
974
+ .composerFooter {
975
+ flex-direction: column;
976
+ gap: 10px;
977
+ align-items: stretch;
978
+ }
979
+
980
+ .composerOptions {
981
+ justify-content: center;
982
+ }
983
+
984
+ .sendBtn {
985
+ justify-content: center;
986
+ width: 100%;
987
+ }
988
+
989
+ .sidebar {
990
+ border-radius: 8px;
991
+ }
992
+ }
993
+
994
+ @media (max-width: 480px) {
995
+ .page {
996
+ padding: 0 8px 32px;
997
+ }
998
+
999
+ .topBar {
1000
+ gap: 8px;
1001
+ }
1002
+
1003
+ .ticketSubject {
1004
+ font-size: 14px;
1005
+ }
1006
+
1007
+ .ticketNumber {
1008
+ font-size: 10px;
1009
+ }
1010
+
1011
+ .statusChip {
1012
+ font-size: 11px;
1013
+ padding: 4px 10px;
1014
+ }
1015
+
1016
+ .avatar {
1017
+ width: 28px;
1018
+ height: 28px;
1019
+ font-size: 10px;
1020
+ }
1021
+
1022
+ .messageAuthor {
1023
+ font-size: 12px;
1024
+ }
1025
+
1026
+ .messageBody {
1027
+ font-size: 13px;
1028
+ }
1029
+
1030
+ .attachmentImg {
1031
+ max-width: 160px;
1032
+ max-height: 120px;
1033
+ }
1034
+
1035
+ .composerOptions {
1036
+ flex-direction: column;
1037
+ gap: 8px;
1038
+ }
1039
+
1040
+ .sideField {
1041
+ font-size: 12px;
1042
+ }
1043
+ }