discord-transcript-ui 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1896 @@
1
+ /*!
2
+ * discord-transcript-ui v1.0.0 — single stylesheet for Discord chat transcripts
3
+ * MIT licensed. Light DOM only: no Shadow DOM, no build step required to use.
4
+ *
5
+ * Recovery information for archived transcripts lives in the HTML file itself
6
+ * (asset URLs + sha256 + mirrors). See docs/CDN-STRATEGY.md in the source repo.
7
+ *
8
+ * Contents
9
+ * 1 tokens 6 inline text 11 embeds
10
+ * 2 base 7 code 12 attachments
11
+ * 3 page shell 8 system/command 13 reactions
12
+ * 4 messages 9 threads 14 action row
13
+ * 5 message 10 reply 15 a11y + print
14
+ *
15
+ * Everything is themed through --dt-* custom properties: override them on
16
+ * :root, on discord-messages, or per element. Markup contract: docs/SPEC.md.
17
+ */
18
+
19
+ /* ==========================================================================
20
+ 1. TOKENS — dark by default, light opt-in
21
+ ========================================================================== */
22
+
23
+ /* Tokens live on :root so every component inherits them, and on
24
+ discord-messages so a transcript can be re-themed without touching the page. */
25
+ :root {
26
+ --dt-font: 'gg sans', 'Noto Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
27
+ --dt-font-mono:
28
+ 'gg mono', 'Source Code Pro', Consolas, 'Andale Mono WT', 'Andale Mono', 'Lucida Console',
29
+ 'DejaVu Sans Mono', 'Liberation Mono', 'Nimbus Mono L', Monaco, 'Courier New', Courier, monospace;
30
+ --dt-font-size: 1rem;
31
+ --dt-line-height: 1.375rem;
32
+ --dt-radius-sm: 4px;
33
+ --dt-radius-md: 8px;
34
+ --dt-radius-lg: 12px;
35
+
36
+ /* Discord's 2024+ "visual refresh" palette, taken from its live token sheet.
37
+ See docs/DESIGN-TOKENS.md for every value, source URL and open question. */
38
+ --dt-bg-primary: #323339;
39
+ --dt-bg-secondary: #393a41;
40
+ --dt-bg-tertiary: #2c2d32;
41
+ --dt-bg-embed: #393a41;
42
+ --dt-bg-code: #323339;
43
+ --dt-bg-inline-code: rgba(88, 101, 242, 0.078);
44
+ --dt-bg-modifier-hover: rgba(151, 151, 159, 0.122);
45
+ --dt-bg-modifier-active: rgba(151, 151, 159, 0.161);
46
+ --dt-bg-message-hover: rgba(151, 151, 159, 0.039);
47
+ --dt-bg-mentioned: rgba(248, 163, 0, 0.078);
48
+ --dt-bg-scrollbar-thumb: #767780;
49
+ --dt-bg-scrollbar-track: transparent;
50
+
51
+ --dt-text-normal: #f3f3f4;
52
+ --dt-text-strong: #ffffff;
53
+ --dt-text-subtle: #c5c6ca;
54
+ --dt-text-muted: #9d9ea5;
55
+ --dt-text-link: #76aff6;
56
+ --dt-text-on-brand: #ffffff;
57
+ --dt-status-online: #3d9e60;
58
+ --dt-status-idle: #ffcb6e;
59
+ --dt-status-dnd: #dc4247;
60
+ --dt-status-offline: #9d9ea5;
61
+
62
+ --dt-border: rgba(151, 151, 159, 0.122);
63
+ --dt-border-strong: rgba(151, 151, 159, 0.2);
64
+ --dt-brand: #5865f2;
65
+ --dt-accent-bar: var(--dt-brand);
66
+ --dt-role-default: #f3f3f4;
67
+ --dt-embed-default-color: #4f545c;
68
+ --dt-divider: rgba(151, 151, 159, 0.122);
69
+ --dt-line-color: #595a63;
70
+
71
+ --dt-mention-bg: rgba(88, 101, 242, 0.239);
72
+ --dt-mention-text: #cdd7ff;
73
+ --dt-mention-role-color: var(--dt-role-default);
74
+ --dt-mention-channel-bg: rgba(151, 151, 159, 0.122);
75
+ --dt-mention-channel-text: var(--dt-text-normal);
76
+
77
+ --dt-spoiler-bg: #7d7e87;
78
+ --dt-spoiler-revealed-bg: rgba(151, 151, 159, 0.078);
79
+
80
+ --dt-gutter: 16px;
81
+ --dt-avatar-size: 40px;
82
+ --dt-avatar-gap: 16px;
83
+ --dt-msg-padding-right: 48px;
84
+ --dt-reply-avatar-size: 16px;
85
+
86
+ --dt-button-secondary: rgba(151, 151, 159, 0.122);
87
+ --dt-button-secondary-hover: rgba(151, 151, 159, 0.2);
88
+ --dt-button-primary: #5865f2;
89
+ --dt-button-primary-hover: #4654c0;
90
+ --dt-button-success: #248046;
91
+ --dt-button-danger: #da3e44;
92
+ --dt-button-link: rgba(151, 151, 159, 0.122);
93
+
94
+ --dt-reaction-bg: rgba(151, 151, 159, 0.122);
95
+ --dt-reaction-border: rgba(151, 151, 159, 0.122);
96
+ --dt-reaction-bg-reacted: rgba(88, 101, 242, 0.239);
97
+ --dt-reaction-border-reacted: #5865f2;
98
+ --dt-reaction-text-reacted: #dfe4ff;
99
+
100
+ --dt-focus-ring: #76aff6;
101
+ --dt-transition: 120ms ease;
102
+ }
103
+
104
+ /* Light theme: set light-theme on discord-messages, data-theme, or the page root. */
105
+ discord-messages[light-theme],
106
+ discord-messages[data-theme='light'],
107
+ :root[data-theme='light'] {
108
+ --dt-bg-primary: #ffffff;
109
+ --dt-bg-secondary: #ffffff;
110
+ --dt-bg-tertiary: #f3f3f4;
111
+ --dt-bg-embed: #ffffff;
112
+ --dt-bg-code: #f3f3f4;
113
+ --dt-bg-inline-code: rgba(88, 101, 242, 0.078);
114
+ --dt-bg-modifier-hover: rgba(151, 151, 159, 0.122);
115
+ --dt-bg-modifier-active: rgba(151, 151, 159, 0.161);
116
+ --dt-bg-message-hover: rgba(151, 151, 159, 0.078);
117
+ --dt-bg-mentioned: rgba(248, 163, 0, 0.1);
118
+ --dt-bg-scrollbar-thumb: #8b8c94;
119
+ --dt-bg-scrollbar-track: transparent;
120
+
121
+ --dt-text-normal: #2e2e34;
122
+ --dt-text-strong: #28282d;
123
+ --dt-text-subtle: #595a63;
124
+ --dt-text-muted: #6c6d76;
125
+ --dt-text-link: #006dd4;
126
+ --dt-role-default: #2e2e34;
127
+
128
+ --dt-border: rgba(151, 151, 159, 0.278);
129
+ --dt-border-strong: rgba(151, 151, 159, 0.4);
130
+ --dt-divider: rgba(151, 151, 159, 0.278);
131
+ --dt-line-color: #c5c6ca;
132
+ --dt-embed-default-color: #d4d7dc;
133
+
134
+ --dt-mention-bg: rgba(88, 101, 242, 0.15);
135
+ --dt-mention-text: #2e3c88;
136
+ --dt-mention-channel-bg: rgba(151, 151, 159, 0.122);
137
+ --dt-mention-channel-text: #2e2e34;
138
+
139
+ --dt-spoiler-bg: #8f9097;
140
+ --dt-spoiler-revealed-bg: #ebeced;
141
+
142
+ --dt-reaction-border: rgba(151, 151, 159, 0.278);
143
+ --dt-reaction-text-reacted: #273478;
144
+ --dt-status-online: #01783e;
145
+ --dt-status-idle: #faaa00;
146
+ --dt-status-dnd: #d22d39;
147
+ --dt-status-offline: #5f606a;
148
+ --dt-focus-ring: #006dd4;
149
+ }
150
+
151
+ /* Explicit dark still wins inside a light scope. */
152
+ discord-messages[data-theme='dark'] {
153
+ --dt-bg-primary: #323339;
154
+ --dt-bg-secondary: #393a41;
155
+ --dt-bg-tertiary: #2c2d32;
156
+ --dt-bg-embed: #393a41;
157
+ --dt-bg-code: #323339;
158
+ --dt-bg-inline-code: rgba(88, 101, 242, 0.078);
159
+ --dt-bg-modifier-hover: rgba(151, 151, 159, 0.122);
160
+ --dt-bg-modifier-active: rgba(151, 151, 159, 0.161);
161
+ --dt-bg-message-hover: rgba(151, 151, 159, 0.039);
162
+ --dt-bg-mentioned: rgba(248, 163, 0, 0.078);
163
+ --dt-bg-scrollbar-thumb: #767780;
164
+ --dt-bg-scrollbar-track: transparent;
165
+ --dt-text-normal: #f3f3f4;
166
+ --dt-text-strong: #ffffff;
167
+ --dt-text-subtle: #c5c6ca;
168
+ --dt-text-muted: #9d9ea5;
169
+ --dt-text-link: #76aff6;
170
+ --dt-role-default: #f3f3f4;
171
+ --dt-border: rgba(151, 151, 159, 0.122);
172
+ --dt-border-strong: rgba(151, 151, 159, 0.2);
173
+ --dt-divider: rgba(151, 151, 159, 0.122);
174
+ --dt-line-color: #595a63;
175
+ --dt-embed-default-color: #4f545c;
176
+ --dt-mention-bg: rgba(88, 101, 242, 0.239);
177
+ --dt-mention-text: #cdd7ff;
178
+ --dt-mention-channel-bg: rgba(151, 151, 159, 0.122);
179
+ --dt-mention-channel-text: #f3f3f4;
180
+ --dt-spoiler-bg: #7d7e87;
181
+ --dt-spoiler-revealed-bg: rgba(151, 151, 159, 0.078);
182
+ --dt-reaction-border: rgba(151, 151, 159, 0.122);
183
+ --dt-reaction-text-reacted: #dfe4ff;
184
+ --dt-status-online: #3d9e60;
185
+ --dt-status-idle: #ffcb6e;
186
+ --dt-status-dnd: #dc4247;
187
+ --dt-status-offline: #9d9ea5;
188
+ --dt-focus-ring: #76aff6;
189
+ }
190
+
191
+ /* ==========================================================================
192
+ 2. BASE
193
+ ========================================================================== */
194
+
195
+ :where(
196
+ discord-messages,
197
+ discord-message,
198
+ discord-author-info,
199
+ discord-reply,
200
+ discord-embed,
201
+ discord-embed-description,
202
+ discord-embed-fields,
203
+ discord-embed-field,
204
+ discord-embed-footer,
205
+ discord-attachments,
206
+ discord-image-attachment,
207
+ discord-file-attachment,
208
+ discord-audio-attachment,
209
+ discord-video-attachment,
210
+ discord-reactions,
211
+ discord-reaction,
212
+ discord-spoiler,
213
+ discord-time,
214
+ discord-mention,
215
+ discord-custom-emoji,
216
+ discord-code,
217
+ discord-pre,
218
+ discord-quote,
219
+ discord-list-item,
220
+ discord-unordered-list,
221
+ discord-ordered-list,
222
+ discord-header,
223
+ discord-command,
224
+ discord-system-message,
225
+ discord-thread,
226
+ discord-thread-message,
227
+ discord-action-row,
228
+ discord-button,
229
+ discord-verified-author-tag
230
+ ) {
231
+ box-sizing: border-box;
232
+ }
233
+
234
+ :where(
235
+ discord-messages,
236
+ discord-message,
237
+ discord-embed,
238
+ discord-attachments,
239
+ discord-reactions,
240
+ discord-reply,
241
+ discord-system-message,
242
+ discord-command,
243
+ discord-thread,
244
+ discord-thread-message,
245
+ discord-action-row,
246
+ discord-pre,
247
+ discord-quote,
248
+ discord-unordered-list,
249
+ discord-ordered-list,
250
+ discord-header
251
+ ) {
252
+ display: block;
253
+ font-family: var(--dt-font);
254
+ font-size: var(--dt-font-size);
255
+ line-height: var(--dt-line-height);
256
+ color: var(--dt-text-normal);
257
+ text-align: left;
258
+ }
259
+
260
+ :where(discord-message, discord-reply, discord-embed, discord-attachments, discord-reactions) {
261
+ -webkit-text-size-adjust: 100%;
262
+ word-wrap: break-word;
263
+ overflow-wrap: anywhere;
264
+ }
265
+
266
+ /* Inline formatting */
267
+ :where(discord-bold) {
268
+ font-weight: 700;
269
+ }
270
+
271
+ :where(discord-italic) {
272
+ font-style: italic;
273
+ }
274
+
275
+ :where(discord-underlined) {
276
+ text-decoration: underline;
277
+ }
278
+
279
+ :where(discord-strikethrough) {
280
+ text-decoration: line-through;
281
+ }
282
+
283
+ :where(discord-subscript) {
284
+ font-size: 0.8125rem;
285
+ vertical-align: sub;
286
+ }
287
+
288
+ /* Markdown headings */
289
+ :where(discord-header) {
290
+ display: block;
291
+ margin: 8px 0 0;
292
+ font-weight: 600;
293
+ line-height: 1.375em;
294
+ }
295
+
296
+ :where(discord-header[level='1']) {
297
+ font-size: 1.5rem;
298
+ }
299
+
300
+ :where(discord-header[level='2']) {
301
+ font-size: 1.25rem;
302
+ }
303
+
304
+ :where(discord-header[level='3']) {
305
+ font-size: 1rem;
306
+ }
307
+
308
+ /* Blockquote */
309
+ :where(discord-quote) {
310
+ display: block;
311
+ margin: 4px 0;
312
+ padding: 0 8px 0 12px;
313
+ color: var(--dt-text-subtle);
314
+ border-left: 4px solid var(--dt-line-color);
315
+ border-radius: var(--dt-radius-sm);
316
+ }
317
+
318
+ /* Lists */
319
+ :where(discord-unordered-list, discord-ordered-list) {
320
+ margin: 0;
321
+ padding-left: 1.375em;
322
+ }
323
+
324
+ :where(discord-list-item) {
325
+ display: list-item;
326
+ margin: 0 0 4px;
327
+ padding: 0;
328
+ }
329
+
330
+ :where(discord-unordered-list) > discord-list-item {
331
+ list-style: disc outside;
332
+ }
333
+
334
+ :where(discord-ordered-list) > discord-list-item {
335
+ list-style: decimal outside;
336
+ }
337
+
338
+ /* Links */
339
+ :where(discord-link) {
340
+ color: var(--dt-text-link);
341
+ text-decoration: none;
342
+ }
343
+
344
+ :where(discord-link):hover {
345
+ text-decoration: underline;
346
+ }
347
+
348
+ :where(discord-message, discord-embed, discord-embed-description, discord-embed-field, discord-reply, discord-quote)
349
+ a:not([class]) {
350
+ color: var(--dt-text-link);
351
+ text-decoration: none;
352
+ }
353
+
354
+ :where(discord-message, discord-embed, discord-embed-description, discord-embed-field, discord-reply, discord-quote)
355
+ a:not([class]):hover {
356
+ text-decoration: underline;
357
+ }
358
+
359
+ /* ==========================================================================
360
+ 3. PAGE SHELL (optional)
361
+ ========================================================================== */
362
+
363
+ .dt-page {
364
+ min-height: 100vh;
365
+ margin: 0;
366
+ background: var(--dt-bg-primary);
367
+ color: var(--dt-text-normal);
368
+ font-family: var(--dt-font);
369
+ font-size: var(--dt-font-size);
370
+ line-height: var(--dt-line-height);
371
+ -webkit-font-smoothing: antialiased;
372
+ }
373
+
374
+ .dt-page__inner {
375
+ max-width: 100%;
376
+ margin: 0 auto;
377
+ padding: 1rem 0 4rem;
378
+ }
379
+
380
+ .dt-page__title {
381
+ margin: 0 0 1rem;
382
+ padding: 0 16px;
383
+ font-size: 1.25rem;
384
+ font-weight: 700;
385
+ color: var(--dt-text-strong);
386
+ }
387
+
388
+ .dt-page__meta {
389
+ margin: 0 0 1.5rem;
390
+ padding: 0 16px;
391
+ font-size: 0.875rem;
392
+ color: var(--dt-text-muted);
393
+ }
394
+
395
+ /* ==========================================================================
396
+ 4. MESSAGE LIST
397
+ ========================================================================== */
398
+
399
+ :where(discord-messages) {
400
+ display: block;
401
+ position: relative;
402
+ margin: 0 auto;
403
+ padding: 8px 0 16px;
404
+ background: var(--dt-bg-primary);
405
+ color: var(--dt-text-normal);
406
+ font-family: var(--dt-font);
407
+ line-height: var(--dt-line-height);
408
+ overflow-x: hidden;
409
+ overflow-y: auto;
410
+ scrollbar-color: var(--dt-bg-scrollbar-thumb) var(--dt-bg-scrollbar-track);
411
+ }
412
+
413
+ :where(discord-messages[no-background]) {
414
+ background: transparent;
415
+ padding: 0;
416
+ }
417
+
418
+ :where(discord-messages[channel-name])::before {
419
+ content: attr(channel-name);
420
+ display: block;
421
+ margin: 0 0 8px;
422
+ padding: 4px 16px 12px;
423
+ border-bottom: 1px solid var(--dt-divider);
424
+ font-size: 1.25rem;
425
+ font-weight: 700;
426
+ color: var(--dt-text-strong);
427
+ }
428
+
429
+ discord-messages[channel-type='text'][channel-name]::before,
430
+ discord-messages[channel-type='voice'][channel-name]::before,
431
+ discord-messages[channel-type='thread'][channel-name]::before,
432
+ discord-messages[channel-type='forum'][channel-name]::before,
433
+ discord-messages[channel-type='locked'][channel-name]::before {
434
+ content: '#\00a0' attr(channel-name);
435
+ }
436
+
437
+ discord-messages ::-webkit-scrollbar {
438
+ width: 16px;
439
+ height: 16px;
440
+ }
441
+
442
+ discord-messages ::-webkit-scrollbar-thumb {
443
+ background: var(--dt-bg-scrollbar-thumb);
444
+ border: 4px solid transparent;
445
+ background-clip: padding-box;
446
+ border-radius: 8px;
447
+ }
448
+
449
+ discord-messages ::-webkit-scrollbar-track {
450
+ background: var(--dt-bg-scrollbar-track);
451
+ }
452
+
453
+ /* ==========================================================================
454
+ 5. MESSAGE
455
+ ========================================================================== */
456
+
457
+ :where(discord-message) {
458
+ position: relative;
459
+ display: block;
460
+ margin: 0;
461
+ padding: 2px var(--dt-msg-padding-right) 2px var(--dt-gutter);
462
+ color: var(--dt-text-normal);
463
+ font-family: var(--dt-font);
464
+ font-size: var(--dt-font-size);
465
+ line-height: var(--dt-line-height);
466
+ -webkit-user-select: text;
467
+ user-select: text;
468
+ }
469
+
470
+ :where(discord-message:hover) {
471
+ background: var(--dt-bg-message-hover);
472
+ }
473
+
474
+ /* Pre-upgrade fallback: no avatar or header yet, but the author name and the
475
+ message text are both visible, so a JS-less or CSS-only view stays readable. */
476
+ discord-message:not([data-dt-ready])::before {
477
+ content: attr(author) '\00a0';
478
+ font-weight: 600;
479
+ color: var(--dt-role-default);
480
+ }
481
+
482
+ discord-message:not([data-dt-ready]):not([author])::before,
483
+ discord-message:not([data-dt-ready])[author='']::before {
484
+ content: '';
485
+ }
486
+
487
+ /* Structure built by discord-transcript.js */
488
+ .dt-msg {
489
+ display: grid;
490
+ grid-template-columns: var(--dt-avatar-size) minmax(0, 1fr);
491
+ column-gap: var(--dt-avatar-gap);
492
+ align-items: start;
493
+ }
494
+
495
+ .dt-avatar {
496
+ grid-column: 1;
497
+ width: var(--dt-avatar-size);
498
+ height: var(--dt-avatar-size);
499
+ margin-top: 2px;
500
+ border-radius: 50%;
501
+ overflow: hidden;
502
+ background: var(--dt-bg-tertiary);
503
+ }
504
+
505
+ .dt-avatar img {
506
+ display: block;
507
+ width: 100%;
508
+ height: 100%;
509
+ object-fit: cover;
510
+ }
511
+
512
+ .dt-content {
513
+ grid-column: 2;
514
+ min-width: 0;
515
+ }
516
+
517
+ .dt-header {
518
+ display: flex;
519
+ flex-wrap: wrap;
520
+ align-items: center;
521
+ min-height: 1.375rem;
522
+ }
523
+
524
+ .dt-author {
525
+ margin-right: 8px;
526
+ font-weight: 500;
527
+ color: var(--dt-role-default);
528
+ text-decoration: none;
529
+ }
530
+
531
+ .dt-author--interactive:hover {
532
+ text-decoration: underline;
533
+ cursor: pointer;
534
+ }
535
+
536
+ .dt-badges {
537
+ display: inline-flex;
538
+ align-items: center;
539
+ gap: 4px;
540
+ margin-right: 8px;
541
+ }
542
+
543
+ .dt-badge {
544
+ display: inline-flex;
545
+ align-items: center;
546
+ justify-content: center;
547
+ height: 15px;
548
+ padding: 0 4px;
549
+ border-radius: 3px;
550
+ background: var(--dt-brand);
551
+ color: var(--dt-text-on-brand);
552
+ font-size: 0.625rem;
553
+ font-weight: 600;
554
+ line-height: 1;
555
+ letter-spacing: 0.02em;
556
+ text-transform: uppercase;
557
+ }
558
+
559
+ .dt-badge--verified {
560
+ width: 15px;
561
+ padding: 0;
562
+ border-radius: 50%;
563
+ }
564
+
565
+ .dt-badge--verified::after {
566
+ content: '\2713';
567
+ font-size: 9px;
568
+ }
569
+
570
+ .dt-badge--server {
571
+ background: #3ba55c;
572
+ }
573
+
574
+ .dt-badge--official {
575
+ background: #1abc84;
576
+ }
577
+
578
+ .dt-timestamp {
579
+ font-size: 0.75rem;
580
+ line-height: 1.375rem;
581
+ color: var(--dt-text-muted);
582
+ white-space: nowrap;
583
+ }
584
+
585
+ .dt-timestamp:hover {
586
+ text-decoration: underline;
587
+ }
588
+
589
+ .dt-edited {
590
+ margin-left: 4px;
591
+ font-size: 0.625rem;
592
+ color: var(--dt-text-muted);
593
+ }
594
+
595
+ .dt-body {
596
+ display: block;
597
+ min-width: 0;
598
+ }
599
+
600
+ .dt-body > :first-child {
601
+ margin-top: 0;
602
+ }
603
+
604
+ /* Emoji-only messages render larger. */
605
+ .dt-jumbo {
606
+ display: flex;
607
+ flex-wrap: wrap;
608
+ align-items: center;
609
+ gap: 2px;
610
+ }
611
+
612
+ .dt-jumbo discord-custom-emoji img,
613
+ .dt-jumbo > img.emoji {
614
+ width: 48px;
615
+ height: 48px;
616
+ }
617
+
618
+ /* States */
619
+ discord-message[highlight],
620
+ discord-message[ephemeral],
621
+ discord-message[mentioned] {
622
+ background: var(--dt-bg-mentioned);
623
+ }
624
+
625
+ discord-message[highlight]::after,
626
+ discord-message[ephemeral]::after,
627
+ discord-message[mentioned]::after {
628
+ content: '';
629
+ position: absolute;
630
+ top: 0;
631
+ bottom: 0;
632
+ left: 0;
633
+ width: 2px;
634
+ background: var(--dt-accent-bar);
635
+ pointer-events: none;
636
+ }
637
+
638
+ discord-message[ephemeral] {
639
+ background: rgba(88, 101, 242, 0.08);
640
+ }
641
+
642
+ discord-message[highlight]:hover,
643
+ discord-message[mentioned]:hover {
644
+ background: var(--dt-bg-mentioned);
645
+ }
646
+
647
+ /* Continuation rows (same author as the previous message), detected by JS or
648
+ forced by the parser with message-body-only. */
649
+ discord-message[data-dt-continuation] .dt-avatar,
650
+ discord-message[message-body-only] .dt-avatar {
651
+ visibility: hidden;
652
+ }
653
+
654
+ discord-message[data-dt-continuation] .dt-header,
655
+ discord-message[message-body-only] .dt-header {
656
+ display: none;
657
+ }
658
+
659
+ discord-message[data-dt-continuation]:hover::before,
660
+ discord-message[data-dt-continuation]:focus-within::before {
661
+ content: attr(data-dt-short-time);
662
+ position: absolute;
663
+ top: 3px;
664
+ left: var(--dt-gutter);
665
+ width: calc(var(--dt-avatar-size) - 4px);
666
+ font-size: 0.6875rem;
667
+ line-height: 1.375rem;
668
+ color: var(--dt-text-muted);
669
+ white-space: nowrap;
670
+ overflow: hidden;
671
+ pointer-events: none;
672
+ }
673
+
674
+ discord-message[data-dt-group-start] {
675
+ margin-top: 1.0625rem;
676
+ }
677
+
678
+ discord-message:first-child {
679
+ margin-top: 0;
680
+ }
681
+
682
+ /* Compact mode */
683
+ discord-messages[compact-mode],
684
+ discord-message[compact-mode] {
685
+ --dt-avatar-size: 16px;
686
+ --dt-avatar-gap: 8px;
687
+ --dt-gutter: 16px;
688
+ --dt-msg-padding-right: 16px;
689
+ }
690
+
691
+ discord-messages[compact-mode] discord-message {
692
+ padding-top: 1px;
693
+ padding-bottom: 1px;
694
+ }
695
+
696
+ discord-messages[compact-mode] .dt-avatar {
697
+ margin-top: 0.25rem;
698
+ }
699
+
700
+ discord-messages[compact-mode] .dt-header {
701
+ display: inline;
702
+ margin-right: 8px;
703
+ }
704
+
705
+ discord-messages[compact-mode] .dt-author {
706
+ margin-right: 6px;
707
+ }
708
+
709
+ discord-messages[compact-mode] .dt-body {
710
+ display: inline;
711
+ }
712
+
713
+ discord-messages[compact-mode] .dt-timestamp {
714
+ margin-right: 6px;
715
+ font-size: 0.6875rem;
716
+ }
717
+
718
+ /* ==========================================================================
719
+ 6. AUTHOR INFO, MENTION, EMOJI, TIME, SPOILER
720
+ ========================================================================== */
721
+
722
+ :where(discord-author-info) {
723
+ display: inline-flex;
724
+ align-items: center;
725
+ gap: 4px;
726
+ font-weight: 500;
727
+ color: var(--dt-role-default);
728
+ }
729
+
730
+ discord-author-info:not([data-dt-ready])::before {
731
+ content: attr(author);
732
+ }
733
+
734
+ :where(discord-author-info[bot], discord-author-info[server], discord-author-info[official-app], discord-author-info[op])
735
+ ::after {
736
+ margin-left: 4px;
737
+ padding: 0 4px;
738
+ border-radius: 3px;
739
+ background: var(--dt-brand);
740
+ color: var(--dt-text-on-brand);
741
+ font-size: 0.625rem;
742
+ font-weight: 600;
743
+ line-height: 15px;
744
+ }
745
+
746
+ :where(discord-author-info[bot])::after {
747
+ content: 'BOT';
748
+ }
749
+
750
+ :where(discord-author-info[server])::after {
751
+ content: 'SERVER';
752
+ background: #3ba55c;
753
+ }
754
+
755
+ :where(discord-author-info[official-app])::after {
756
+ content: 'OFFICIAL';
757
+ background: #1abc84;
758
+ }
759
+
760
+ :where(discord-author-info[op])::after {
761
+ content: 'OP';
762
+ }
763
+
764
+ /* Mentions */
765
+ :where(discord-mention) {
766
+ display: inline;
767
+ padding: 0 2px;
768
+ border-radius: 3px;
769
+ background: var(--dt-mention-bg);
770
+ color: var(--dt-mention-text);
771
+ font-weight: 500;
772
+ cursor: pointer;
773
+ }
774
+
775
+ :where(discord-mention):hover {
776
+ background: var(--dt-bg-modifier-active);
777
+ }
778
+
779
+ :where(discord-mention[type='channel']),
780
+ :where(discord-mention[type='voice']),
781
+ :where(discord-mention[type='thread']),
782
+ :where(discord-mention[type='forum']),
783
+ :where(discord-mention[type='locked']) {
784
+ background: var(--dt-mention-channel-bg);
785
+ color: var(--dt-mention-channel-text);
786
+ }
787
+
788
+ :where(discord-mention[type='role']) {
789
+ background: var(--dt-mention-bg);
790
+ color: var(--dt-mention-role-color);
791
+ }
792
+
793
+ /* Prefixes, so the parser does not have to repeat "@" and "#" per mention. */
794
+ discord-mention:not([no-prefix])::before {
795
+ content: '@';
796
+ }
797
+
798
+ discord-mention:not([no-prefix])[type='channel']::before,
799
+ discord-mention:not([no-prefix])[type='voice']::before,
800
+ discord-mention:not([no-prefix])[type='thread']::before,
801
+ discord-mention:not([no-prefix])[type='forum']::before,
802
+ discord-mention:not([no-prefix])[type='locked']::before {
803
+ content: '#';
804
+ }
805
+
806
+ /* Custom emoji */
807
+ :where(discord-custom-emoji) {
808
+ display: inline-block;
809
+ vertical-align: -0.25em;
810
+ }
811
+
812
+ :where(discord-custom-emoji) img {
813
+ display: inline-block;
814
+ width: 1.375em;
815
+ height: 1.375em;
816
+ object-fit: contain;
817
+ vertical-align: middle;
818
+ }
819
+
820
+ discord-custom-emoji:not([data-dt-ready]):not(:has(img))::before {
821
+ content: attr(name);
822
+ font-size: 0.75rem;
823
+ color: var(--dt-text-muted);
824
+ }
825
+
826
+ /* Inline timestamp chip */
827
+ :where(discord-time) {
828
+ display: inline;
829
+ padding: 0 2px;
830
+ border-radius: 3px;
831
+ background: var(--dt-bg-modifier-hover);
832
+ font-size: 0.875rem;
833
+ white-space: nowrap;
834
+ }
835
+
836
+ :where(discord-time):hover {
837
+ background: var(--dt-bg-modifier-active);
838
+ }
839
+
840
+ /* Spoiler */
841
+ :where(discord-spoiler) {
842
+ display: inline;
843
+ border-radius: var(--dt-radius-sm);
844
+ background: var(--dt-spoiler-bg);
845
+ color: transparent;
846
+ cursor: pointer;
847
+ transition:
848
+ background var(--dt-transition),
849
+ color var(--dt-transition);
850
+ }
851
+
852
+ :where(discord-spoiler)::selection {
853
+ background: transparent;
854
+ color: transparent;
855
+ }
856
+
857
+ :where(discord-spoiler[activated]),
858
+ :where(discord-spoiler[revealed]),
859
+ :where(discord-spoiler[data-dt-revealed]) {
860
+ background: var(--dt-spoiler-revealed-bg);
861
+ color: inherit;
862
+ cursor: auto;
863
+ }
864
+
865
+ /* No-JS safety valve: hovering peeks instead of hiding content forever. */
866
+ discord-spoiler:not([data-dt-ready]):hover {
867
+ background: var(--dt-spoiler-revealed-bg);
868
+ color: inherit;
869
+ }
870
+
871
+ discord-spoiler[data-dt-ready] {
872
+ outline: none;
873
+ }
874
+
875
+ discord-spoiler[data-dt-ready]:focus-visible {
876
+ box-shadow: 0 0 0 2px var(--dt-focus-ring);
877
+ }
878
+
879
+ /* ==========================================================================
880
+ 7. CODE
881
+ ========================================================================== */
882
+
883
+ :where(discord-code) {
884
+ display: inline;
885
+ padding: 0 2px;
886
+ border-radius: var(--dt-radius-sm);
887
+ background: var(--dt-bg-inline-code);
888
+ border: 1px solid var(--dt-border-strong);
889
+ font-family: var(--dt-font-mono);
890
+ font-size: 0.85em;
891
+ white-space: pre-wrap;
892
+ word-break: break-word;
893
+ }
894
+
895
+ :where(discord-code[multiline]) {
896
+ display: block;
897
+ margin: 6px 0 0;
898
+ padding: 8px 12px;
899
+ border: 1px solid var(--dt-border);
900
+ border-radius: var(--dt-radius-sm);
901
+ background: var(--dt-bg-code);
902
+ font-size: 0.75rem;
903
+ line-height: 1rem;
904
+ white-space: pre;
905
+ overflow-x: auto;
906
+ tab-size: 4;
907
+ }
908
+
909
+ :where(discord-pre) {
910
+ position: relative;
911
+ display: block;
912
+ margin: 6px 0 0;
913
+ padding: 0;
914
+ border: 1px solid var(--dt-border);
915
+ border-radius: var(--dt-radius-sm);
916
+ background: var(--dt-bg-code);
917
+ overflow: hidden;
918
+ }
919
+
920
+ :where(discord-pre) > :where(discord-code),
921
+ :where(discord-pre) pre {
922
+ display: block;
923
+ margin: 0;
924
+ padding: 8px 12px;
925
+ border: 0;
926
+ border-radius: 0;
927
+ background: none;
928
+ font-family: var(--dt-font-mono);
929
+ font-size: 0.75rem;
930
+ line-height: 1rem;
931
+ white-space: pre;
932
+ overflow-x: auto;
933
+ tab-size: 4;
934
+ }
935
+
936
+ :where(discord-pre) code {
937
+ font-family: inherit;
938
+ }
939
+
940
+ .dt-code-lang {
941
+ display: block;
942
+ padding: 6px 12px 0;
943
+ font-family: var(--dt-font);
944
+ font-size: 0.75rem;
945
+ color: var(--dt-text-muted);
946
+ }
947
+
948
+ .dt-copy {
949
+ position: absolute;
950
+ top: 6px;
951
+ right: 8px;
952
+ display: none;
953
+ padding: 2px 8px;
954
+ border: 1px solid var(--dt-border-strong);
955
+ border-radius: var(--dt-radius-sm);
956
+ background: var(--dt-bg-primary);
957
+ color: var(--dt-text-normal);
958
+ font-family: var(--dt-font);
959
+ font-size: 0.75rem;
960
+ cursor: pointer;
961
+ }
962
+
963
+ discord-pre:hover .dt-copy,
964
+ .dt-copy:focus-visible {
965
+ display: block;
966
+ }
967
+
968
+ .dt-copy:hover {
969
+ background: var(--dt-bg-modifier-hover);
970
+ }
971
+
972
+ /* ==========================================================================
973
+ 8. SYSTEM MESSAGE + SLASH COMMAND
974
+ ========================================================================== */
975
+
976
+ /* System messages render entirely from markup and attributes: no JS needed. */
977
+ :where(discord-system-message) {
978
+ position: relative;
979
+ display: block;
980
+ margin: 0;
981
+ padding: 2px var(--dt-msg-padding-right) 2px
982
+ calc(var(--dt-gutter) + var(--dt-avatar-size) + var(--dt-avatar-gap));
983
+ background: transparent;
984
+ color: var(--dt-text-muted);
985
+ font-size: 0.9375rem;
986
+ }
987
+
988
+ :where(discord-system-message)::before {
989
+ content: '';
990
+ position: absolute;
991
+ top: 7px;
992
+ left: calc(var(--dt-gutter) + (var(--dt-avatar-size) - 16px) / 2);
993
+ width: 16px;
994
+ height: 16px;
995
+ border-radius: 50%;
996
+ background: var(--dt-bg-modifier-hover);
997
+ }
998
+
999
+ discord-system-message[type='join']::before {
1000
+ background: var(--dt-status-online);
1001
+ }
1002
+
1003
+ discord-system-message[type='leave']::before,
1004
+ discord-system-message[type='missed-call']::before,
1005
+ discord-system-message[type='alert']::before,
1006
+ discord-system-message[type='error']::before {
1007
+ background: var(--dt-status-dnd);
1008
+ }
1009
+
1010
+ discord-system-message[type='boost']::before {
1011
+ background: #ff73fa;
1012
+ }
1013
+
1014
+ discord-system-message[type='pin']::before {
1015
+ background: var(--dt-status-idle);
1016
+ }
1017
+
1018
+ discord-system-message[type='upgrade']::before,
1019
+ discord-system-message[type='thread']::before,
1020
+ discord-system-message[type='edit']::before,
1021
+ discord-system-message[type='call']::before {
1022
+ background: var(--dt-brand);
1023
+ }
1024
+
1025
+ discord-system-message a,
1026
+ discord-system-message :where(discord-link) {
1027
+ color: var(--dt-text-muted);
1028
+ font-weight: 500;
1029
+ }
1030
+
1031
+ discord-system-message .dt-system-time {
1032
+ margin-left: 4px;
1033
+ font-size: 0.75rem;
1034
+ color: var(--dt-text-muted);
1035
+ }
1036
+
1037
+ /* Slash / context command rows */
1038
+ :where(discord-command) {
1039
+ position: relative;
1040
+ display: block;
1041
+ margin: 0 0 2px;
1042
+ padding: 0;
1043
+ font-size: 0.9375rem;
1044
+ }
1045
+
1046
+ discord-command:not([data-dt-ready])::before {
1047
+ content: attr(author) ' used /' attr(command) '\00a0';
1048
+ font-weight: 500;
1049
+ color: var(--dt-text-normal);
1050
+ }
1051
+
1052
+ /* Avatar placeholder used when no avatar can be resolved, so an archived
1053
+ transcript never depends on a remote image to render its gutter. */
1054
+ .dt-avatar--initials {
1055
+ display: flex;
1056
+ align-items: center;
1057
+ justify-content: center;
1058
+ color: #ffffff;
1059
+ font-size: 0.875rem;
1060
+ font-weight: 600;
1061
+ text-transform: uppercase;
1062
+ }
1063
+
1064
+ /* ==========================================================================
1065
+ 9. THREADS
1066
+ ========================================================================== */
1067
+
1068
+ :where(discord-thread) {
1069
+ position: relative;
1070
+ display: block;
1071
+ margin: 4px 0 0;
1072
+ padding: 4px 120px 4px 12px;
1073
+ border-left: 2px solid var(--dt-line-color);
1074
+ font-size: 0.875rem;
1075
+ color: var(--dt-text-muted);
1076
+ }
1077
+
1078
+ discord-thread:not([data-dt-ready])::before {
1079
+ content: attr(name);
1080
+ font-weight: 500;
1081
+ color: var(--dt-text-normal);
1082
+ }
1083
+
1084
+ discord-thread[cta]::after {
1085
+ content: attr(cta) ' ' '\203a';
1086
+ position: absolute;
1087
+ top: 4px;
1088
+ right: 8px;
1089
+ font-size: 0.875rem;
1090
+ font-weight: 500;
1091
+ color: var(--dt-text-muted);
1092
+ pointer-events: none;
1093
+ }
1094
+
1095
+ discord-thread-message {
1096
+ display: block;
1097
+ margin: 2px 0;
1098
+ font-size: 0.875rem;
1099
+ }
1100
+
1101
+ discord-thread-message:not([data-dt-ready])::before {
1102
+ content: attr(author) '\00a0';
1103
+ font-weight: 500;
1104
+ color: var(--dt-role-default);
1105
+ }
1106
+
1107
+ /* ==========================================================================
1108
+ 10. REPLY
1109
+ ========================================================================== */
1110
+
1111
+ :where(discord-reply) {
1112
+ position: relative;
1113
+ display: block;
1114
+ margin: 0 0 2px;
1115
+ color: var(--dt-text-normal);
1116
+ font-size: 0.875rem;
1117
+ line-height: 1.125rem;
1118
+ min-height: 1.125rem;
1119
+ }
1120
+
1121
+ discord-reply:not([data-dt-ready])::before {
1122
+ content: attr(author) '\00a0';
1123
+ font-weight: 500;
1124
+ color: var(--dt-role-default);
1125
+ }
1126
+
1127
+ discord-reply[mentions]:not([data-dt-ready])::before {
1128
+ content: '@' attr(author) '\00a0';
1129
+ }
1130
+
1131
+ discord-reply[deleted] > * {
1132
+ display: none;
1133
+ }
1134
+
1135
+ discord-reply[deleted]::before {
1136
+ content: 'Original message was deleted';
1137
+ font-style: italic;
1138
+ font-weight: 400;
1139
+ color: var(--dt-text-muted);
1140
+ }
1141
+
1142
+ /* Curved connector, drawn only once the reply sits in the content column. */
1143
+ discord-message[data-dt-ready] :where(discord-reply)::after {
1144
+ content: '';
1145
+ position: absolute;
1146
+ left: -36px;
1147
+ bottom: -2px;
1148
+ width: 36px;
1149
+ height: 12px;
1150
+ border-left: 2px solid var(--dt-line-color);
1151
+ border-top: 2px solid var(--dt-line-color);
1152
+ border-top-left-radius: 6px;
1153
+ pointer-events: none;
1154
+ }
1155
+
1156
+ discord-reply[data-dt-ready] .dt-reply-avatar {
1157
+ display: inline-block;
1158
+ width: var(--dt-reply-avatar-size);
1159
+ height: var(--dt-reply-avatar-size);
1160
+ margin-right: 4px;
1161
+ border-radius: 50%;
1162
+ overflow: hidden;
1163
+ vertical-align: -3px;
1164
+ background: var(--dt-bg-tertiary);
1165
+ }
1166
+
1167
+ discord-reply[data-dt-ready] .dt-reply-avatar img {
1168
+ display: block;
1169
+ width: 100%;
1170
+ height: 100%;
1171
+ object-fit: cover;
1172
+ }
1173
+
1174
+ discord-reply[data-dt-ready] .dt-reply-author {
1175
+ margin-right: 4px;
1176
+ font-weight: 500;
1177
+ color: var(--dt-role-default);
1178
+ }
1179
+
1180
+ discord-reply[data-dt-ready] .dt-reply-author:hover {
1181
+ text-decoration: underline;
1182
+ cursor: pointer;
1183
+ }
1184
+
1185
+ discord-reply[data-dt-ready] .dt-reply-avatar,
1186
+ discord-reply[data-dt-ready] .dt-reply-author {
1187
+ -webkit-user-select: none;
1188
+ user-select: none;
1189
+ }
1190
+
1191
+ discord-messages[compact-mode] :where(discord-reply)::after {
1192
+ display: none;
1193
+ }
1194
+
1195
+ /* ==========================================================================
1196
+ 11. EMBEDS
1197
+ ========================================================================== */
1198
+
1199
+ :where(discord-embed) {
1200
+ position: relative;
1201
+ display: block;
1202
+ margin: 8px 0 0;
1203
+ padding: 2px 16px 16px 12px;
1204
+ border: 1px solid var(--dt-border);
1205
+ border-left: 4px solid var(--dt-embed-color, var(--dt-embed-default-color));
1206
+ border-radius: var(--dt-radius-sm);
1207
+ background: var(--dt-bg-embed);
1208
+ max-width: 516px;
1209
+ color: var(--dt-text-normal);
1210
+ font-size: 0.875rem;
1211
+ line-height: 1.125rem;
1212
+ }
1213
+
1214
+ .dt-embed-content {
1215
+ min-width: 0;
1216
+ }
1217
+
1218
+ discord-embed[thumbnail] .dt-embed-content,
1219
+ discord-embed[data-dt-thumbnail] .dt-embed-content,
1220
+ discord-embed:has(.dt-embed-thumbnail) .dt-embed-content {
1221
+ padding-right: 96px;
1222
+ }
1223
+
1224
+ /* Without the JS-built wrapper, inset the whole embed body instead. */
1225
+ discord-embed[thumbnail]:not(:has(.dt-embed-content)),
1226
+ discord-embed[data-dt-thumbnail]:not(:has(.dt-embed-content)),
1227
+ discord-embed:has(.dt-embed-thumbnail):not(:has(.dt-embed-content)) {
1228
+ padding-right: 104px;
1229
+ }
1230
+
1231
+ /* Attribute-only embed header, so a title survives without JavaScript.
1232
+ Preferred durable form: emit <span class="dt-embed-author"> and
1233
+ <span class="dt-embed-title"> markup instead (see docs/SPEC.md). */
1234
+ discord-embed:not([data-dt-ready])[embed-title]::before {
1235
+ content: attr(embed-title);
1236
+ display: block;
1237
+ margin: 0 0 8px;
1238
+ font-size: 1rem;
1239
+ font-weight: 600;
1240
+ line-height: 1.375rem;
1241
+ color: var(--dt-text-strong);
1242
+ }
1243
+
1244
+ discord-embed:not([data-dt-ready]):not([embed-title])[author-name]::before {
1245
+ content: attr(author-name);
1246
+ display: block;
1247
+ margin: 0 0 8px;
1248
+ font-weight: 600;
1249
+ line-height: 1.125rem;
1250
+ }
1251
+
1252
+ .dt-embed-provider {
1253
+ display: block;
1254
+ margin-bottom: 8px;
1255
+ color: var(--dt-text-normal);
1256
+ }
1257
+
1258
+ .dt-embed-author {
1259
+ display: flex;
1260
+ align-items: center;
1261
+ gap: 8px;
1262
+ margin-bottom: 8px;
1263
+ font-size: 0.875rem;
1264
+ font-weight: 600;
1265
+ line-height: 1.125rem;
1266
+ }
1267
+
1268
+ .dt-embed-author img {
1269
+ width: 24px;
1270
+ height: 24px;
1271
+ border-radius: 50%;
1272
+ object-fit: cover;
1273
+ }
1274
+
1275
+ .dt-embed-author a {
1276
+ color: var(--dt-text-normal);
1277
+ text-decoration: none;
1278
+ }
1279
+
1280
+ .dt-embed-author a:hover {
1281
+ text-decoration: underline;
1282
+ }
1283
+
1284
+ .dt-embed-title {
1285
+ display: block;
1286
+ margin: 0 0 8px;
1287
+ font-size: 1rem;
1288
+ font-weight: 600;
1289
+ line-height: 1.375rem;
1290
+ color: var(--dt-text-strong);
1291
+ text-decoration: none;
1292
+ }
1293
+
1294
+ .dt-embed-title--link,
1295
+ a.dt-embed-title:hover,
1296
+ .dt-embed-title a:hover {
1297
+ text-decoration: underline;
1298
+ }
1299
+
1300
+ a.dt-embed-title {
1301
+ color: var(--dt-text-link);
1302
+ }
1303
+
1304
+ .dt-embed-thumbnail {
1305
+ position: absolute;
1306
+ top: 8px;
1307
+ right: 16px;
1308
+ width: 80px;
1309
+ height: 80px;
1310
+ border-radius: var(--dt-radius-sm);
1311
+ overflow: hidden;
1312
+ background: var(--dt-bg-tertiary);
1313
+ }
1314
+
1315
+ .dt-embed-thumbnail img {
1316
+ display: block;
1317
+ width: 100%;
1318
+ height: 100%;
1319
+ object-fit: cover;
1320
+ }
1321
+
1322
+ :where(discord-embed-description) {
1323
+ display: block;
1324
+ margin: 0;
1325
+ font-size: 0.875rem;
1326
+ line-height: 1.125rem;
1327
+ white-space: pre-line;
1328
+ }
1329
+
1330
+ :where(discord-embed-fields) {
1331
+ display: grid;
1332
+ grid-template-columns: repeat(12, minmax(0, 1fr));
1333
+ gap: 8px;
1334
+ margin-top: 8px;
1335
+ }
1336
+
1337
+ :where(discord-embed-field) {
1338
+ grid-column: 1 / -1;
1339
+ min-width: 0;
1340
+ font-size: 0.875rem;
1341
+ line-height: 1.125rem;
1342
+ }
1343
+
1344
+ :where(discord-embed-field[inline]) {
1345
+ grid-column: span 4;
1346
+ }
1347
+
1348
+ discord-embed[thumbnail] :where(discord-embed-field[inline]),
1349
+ discord-embed[data-dt-thumbnail] :where(discord-embed-field[inline]) {
1350
+ grid-column: span 6;
1351
+ }
1352
+
1353
+ .dt-embed-field-title {
1354
+ display: block;
1355
+ margin: 0 0 2px;
1356
+ font-weight: 600;
1357
+ color: var(--dt-text-strong);
1358
+ }
1359
+
1360
+ discord-embed-field:not([data-dt-ready]):not(:has(.dt-embed-field-title))::before {
1361
+ content: attr(field-title);
1362
+ display: block;
1363
+ margin-bottom: 2px;
1364
+ font-weight: 600;
1365
+ color: var(--dt-text-strong);
1366
+ }
1367
+
1368
+ .dt-embed-image {
1369
+ display: block;
1370
+ margin-top: 16px;
1371
+ }
1372
+
1373
+ .dt-embed-image img,
1374
+ .dt-embed-image video {
1375
+ display: block;
1376
+ max-width: 100%;
1377
+ max-height: 300px;
1378
+ border-radius: var(--dt-radius-sm);
1379
+ object-fit: contain;
1380
+ }
1381
+
1382
+ :where(discord-embed-footer) {
1383
+ display: flex;
1384
+ align-items: center;
1385
+ gap: 8px;
1386
+ margin-top: 8px;
1387
+ font-size: 0.75rem;
1388
+ line-height: 1rem;
1389
+ color: var(--dt-text-muted);
1390
+ }
1391
+
1392
+ discord-embed-footer:empty::before {
1393
+ content: attr(footer);
1394
+ }
1395
+
1396
+ .dt-embed-footer-icon {
1397
+ width: 20px;
1398
+ height: 20px;
1399
+ border-radius: 50%;
1400
+ overflow: hidden;
1401
+ background: var(--dt-bg-tertiary);
1402
+ }
1403
+
1404
+ .dt-embed-footer-icon img {
1405
+ display: block;
1406
+ width: 100%;
1407
+ height: 100%;
1408
+ object-fit: cover;
1409
+ }
1410
+
1411
+ .dt-embed-footer-sep {
1412
+ display: inline-block;
1413
+ width: 4px;
1414
+ height: 4px;
1415
+ border-radius: 50%;
1416
+ background: var(--dt-text-muted);
1417
+ opacity: 0.6;
1418
+ }
1419
+
1420
+ /* ==========================================================================
1421
+ 12. ATTACHMENTS
1422
+ ========================================================================== */
1423
+
1424
+ :where(discord-attachments) {
1425
+ display: flex;
1426
+ flex-direction: column;
1427
+ align-items: flex-start;
1428
+ gap: 8px;
1429
+ margin-top: 8px;
1430
+ max-width: 550px;
1431
+ }
1432
+
1433
+ :where(discord-attachments:empty) {
1434
+ display: none;
1435
+ }
1436
+
1437
+ /* --- images ------------------------------------------------------------- */
1438
+
1439
+ :where(discord-image-attachment) {
1440
+ position: relative;
1441
+ display: block;
1442
+ max-width: 100%;
1443
+ border-radius: var(--dt-radius-md);
1444
+ overflow: hidden;
1445
+ line-height: 0;
1446
+ }
1447
+
1448
+ :where(discord-image-attachment) img {
1449
+ display: block;
1450
+ max-width: 100%;
1451
+ max-height: 350px;
1452
+ border-radius: var(--dt-radius-md);
1453
+ object-fit: contain;
1454
+ cursor: pointer;
1455
+ }
1456
+
1457
+ :where(discord-image-attachment) a {
1458
+ display: block;
1459
+ }
1460
+
1461
+ /* Attribute-only form, filled in by JS; visible placeholder if JS never runs. */
1462
+ discord-image-attachment[url]:not([data-dt-ready]):not(:has(img)) {
1463
+ min-width: 220px;
1464
+ min-height: 120px;
1465
+ border: 1px dashed var(--dt-border-strong);
1466
+ }
1467
+
1468
+ /* --- spoiler-wrapped media --------------------------------------------- */
1469
+
1470
+ discord-image-attachment[spoiler] img,
1471
+ discord-video-attachment[spoiler] video {
1472
+ filter: blur(44px);
1473
+ transition: filter var(--dt-transition);
1474
+ }
1475
+
1476
+ discord-image-attachment[spoiler][data-dt-revealed] img,
1477
+ discord-video-attachment[spoiler][data-dt-revealed] video {
1478
+ filter: none;
1479
+ }
1480
+
1481
+ .dt-spoiler-overlay {
1482
+ position: absolute;
1483
+ inset: 0;
1484
+ z-index: 1;
1485
+ display: flex;
1486
+ align-items: center;
1487
+ justify-content: center;
1488
+ border: 0;
1489
+ border-radius: var(--dt-radius-md);
1490
+ background: rgba(0, 0, 0, 0.35);
1491
+ color: #ffffff;
1492
+ font-family: var(--dt-font);
1493
+ font-size: 0.75rem;
1494
+ font-weight: 700;
1495
+ letter-spacing: 0.08em;
1496
+ text-transform: uppercase;
1497
+ cursor: pointer;
1498
+ }
1499
+
1500
+ .dt-spoiler-overlay:hover {
1501
+ background: rgba(0, 0, 0, 0.45);
1502
+ }
1503
+
1504
+ discord-image-attachment[data-dt-revealed] > .dt-spoiler-overlay,
1505
+ discord-video-attachment[data-dt-revealed] > .dt-spoiler-overlay {
1506
+ display: none;
1507
+ }
1508
+
1509
+ /* --- files -------------------------------------------------------------- */
1510
+
1511
+ :where(discord-file-attachment) {
1512
+ display: flex;
1513
+ align-items: center;
1514
+ gap: 12px;
1515
+ width: 100%;
1516
+ max-width: 420px;
1517
+ padding: 12px;
1518
+ border: 1px solid var(--dt-border);
1519
+ border-radius: var(--dt-radius-md);
1520
+ background: var(--dt-bg-secondary);
1521
+ }
1522
+
1523
+ :where(discord-file-attachment) a {
1524
+ display: flex;
1525
+ align-items: center;
1526
+ gap: 12px;
1527
+ width: 100%;
1528
+ color: inherit;
1529
+ text-decoration: none;
1530
+ }
1531
+
1532
+ /* Attribute-only form: renders name and size with zero JavaScript. */
1533
+ discord-file-attachment:empty {
1534
+ display: grid;
1535
+ grid-template-columns: 30px minmax(0, 1fr);
1536
+ align-content: center;
1537
+ column-gap: 12px;
1538
+ }
1539
+
1540
+ discord-file-attachment:empty::before {
1541
+ grid-column: 1;
1542
+ grid-row: 1 / span 2;
1543
+ content: 'FILE';
1544
+ display: flex;
1545
+ align-items: center;
1546
+ justify-content: center;
1547
+ width: 30px;
1548
+ height: 30px;
1549
+ border-radius: var(--dt-radius-sm);
1550
+ background: var(--dt-bg-modifier-hover);
1551
+ color: var(--dt-text-muted);
1552
+ font-size: 0.5625rem;
1553
+ font-weight: 700;
1554
+ }
1555
+
1556
+ discord-file-attachment[type]:empty::before {
1557
+ content: attr(type);
1558
+ }
1559
+
1560
+ discord-file-attachment:empty::after {
1561
+ grid-column: 2;
1562
+ content: attr(name) '\A' attr(bytes) ' ' attr(bytes-unit);
1563
+ white-space: pre-line;
1564
+ line-height: 1.25rem;
1565
+ }
1566
+
1567
+ discord-file-attachment[bytes='']:empty::after,
1568
+ discord-file-attachment:not([bytes]):empty::after {
1569
+ content: attr(name);
1570
+ }
1571
+
1572
+ .dt-file-icon {
1573
+ display: flex;
1574
+ align-items: center;
1575
+ justify-content: center;
1576
+ width: 30px;
1577
+ height: 30px;
1578
+ border-radius: var(--dt-radius-sm);
1579
+ background: var(--dt-bg-modifier-hover);
1580
+ color: var(--dt-text-muted);
1581
+ font-size: 0.5625rem;
1582
+ font-weight: 700;
1583
+ text-transform: uppercase;
1584
+ flex: none;
1585
+ }
1586
+
1587
+ .dt-file-meta {
1588
+ display: flex;
1589
+ flex-direction: column;
1590
+ min-width: 0;
1591
+ }
1592
+
1593
+ .dt-file-name {
1594
+ font-size: 0.875rem;
1595
+ font-weight: 500;
1596
+ color: var(--dt-text-strong);
1597
+ overflow: hidden;
1598
+ text-overflow: ellipsis;
1599
+ white-space: nowrap;
1600
+ }
1601
+
1602
+ .dt-file-size {
1603
+ font-size: 0.75rem;
1604
+ color: var(--dt-text-muted);
1605
+ }
1606
+
1607
+ /* --- audio / video ------------------------------------------------------ */
1608
+
1609
+ :where(discord-audio-attachment) {
1610
+ display: block;
1611
+ width: 100%;
1612
+ max-width: 420px;
1613
+ }
1614
+
1615
+ :where(discord-audio-attachment) audio {
1616
+ display: block;
1617
+ width: 100%;
1618
+ max-width: 420px;
1619
+ border-radius: var(--dt-radius-md);
1620
+ outline: none;
1621
+ }
1622
+
1623
+ :where(discord-video-attachment) {
1624
+ position: relative;
1625
+ display: block;
1626
+ max-width: 100%;
1627
+ border-radius: var(--dt-radius-md);
1628
+ overflow: hidden;
1629
+ background: #000000;
1630
+ line-height: 0;
1631
+ }
1632
+
1633
+ :where(discord-video-attachment) video {
1634
+ display: block;
1635
+ max-width: 100%;
1636
+ max-height: 400px;
1637
+ border-radius: var(--dt-radius-md);
1638
+ }
1639
+
1640
+ :where(discord-video-attachment) video:focus-visible,
1641
+ :where(discord-audio-attachment) audio:focus-visible {
1642
+ box-shadow: 0 0 0 2px var(--dt-focus-ring);
1643
+ }
1644
+
1645
+ /* ==========================================================================
1646
+ 13. REACTIONS
1647
+ ========================================================================== */
1648
+
1649
+ :where(discord-reactions) {
1650
+ display: flex;
1651
+ flex-wrap: wrap;
1652
+ align-items: center;
1653
+ gap: 4px;
1654
+ margin-top: 8px;
1655
+ }
1656
+
1657
+ :where(discord-reactions:empty) {
1658
+ display: none;
1659
+ }
1660
+
1661
+ :where(discord-reaction) {
1662
+ display: inline-flex;
1663
+ align-items: center;
1664
+ gap: 6px;
1665
+ min-width: 36px;
1666
+ height: 24px;
1667
+ padding: 2px 6px;
1668
+ border: 1px solid var(--dt-reaction-border);
1669
+ border-radius: var(--dt-radius-md);
1670
+ background: var(--dt-reaction-bg);
1671
+ color: var(--dt-text-normal);
1672
+ font-family: var(--dt-font);
1673
+ font-size: 0.875rem;
1674
+ line-height: 1;
1675
+ cursor: pointer;
1676
+ -webkit-user-select: none;
1677
+ user-select: none;
1678
+ transition:
1679
+ background var(--dt-transition),
1680
+ border-color var(--dt-transition);
1681
+ }
1682
+
1683
+ :where(discord-reaction:hover) {
1684
+ border-color: var(--dt-border-strong);
1685
+ }
1686
+
1687
+ :where(discord-reaction[reacted]) {
1688
+ background: var(--dt-reaction-bg-reacted);
1689
+ border-color: var(--dt-reaction-border-reacted);
1690
+ color: var(--dt-reaction-text-reacted);
1691
+ }
1692
+
1693
+ /* Attribute-only form: emoji and count straight from attributes. */
1694
+ discord-reaction:not([data-dt-ready])::before {
1695
+ content: attr(emoji);
1696
+ font-size: 1rem;
1697
+ line-height: 1;
1698
+ }
1699
+
1700
+ discord-reaction[emoji^='http']:not([data-dt-ready])::before,
1701
+ discord-reaction[emoji^='/']:not([data-dt-ready])::before,
1702
+ discord-reaction[emoji^='./']:not([data-dt-ready])::before,
1703
+ discord-reaction:not([emoji]):not([data-dt-ready])::before {
1704
+ content: none;
1705
+ }
1706
+
1707
+ discord-reaction:not([data-dt-ready])::after {
1708
+ content: attr(count);
1709
+ font-size: 0.875rem;
1710
+ font-weight: 500;
1711
+ line-height: 1;
1712
+ }
1713
+
1714
+ discord-reaction:not([count]):not([data-dt-ready])::after,
1715
+ discord-reaction[count='1']:not([data-dt-ready])::after {
1716
+ content: none;
1717
+ }
1718
+
1719
+ :where(discord-reaction) img,
1720
+ .dt-reaction-emoji {
1721
+ display: inline-block;
1722
+ width: 1rem;
1723
+ height: 1rem;
1724
+ object-fit: contain;
1725
+ vertical-align: middle;
1726
+ }
1727
+
1728
+ .dt-reaction-count {
1729
+ font-size: 0.75rem;
1730
+ font-weight: 600;
1731
+ line-height: 1;
1732
+ color: inherit;
1733
+ }
1734
+
1735
+ /* ==========================================================================
1736
+ 14. ACTION ROW + BUTTONS
1737
+ ========================================================================== */
1738
+
1739
+ :where(discord-action-row) {
1740
+ display: flex;
1741
+ flex-wrap: wrap;
1742
+ gap: 8px;
1743
+ margin-top: 8px;
1744
+ max-width: 600px;
1745
+ }
1746
+
1747
+ :where(discord-button) {
1748
+ display: inline-flex;
1749
+ align-items: center;
1750
+ justify-content: center;
1751
+ gap: 6px;
1752
+ min-height: 32px;
1753
+ padding: 2px 16px;
1754
+ border: 0;
1755
+ border-radius: var(--dt-radius-sm);
1756
+ background: var(--dt-button-secondary);
1757
+ color: #ffffff;
1758
+ font-family: var(--dt-font);
1759
+ font-size: 0.875rem;
1760
+ font-weight: 500;
1761
+ line-height: 1rem;
1762
+ white-space: nowrap;
1763
+ cursor: pointer;
1764
+ transition: background var(--dt-transition);
1765
+ }
1766
+
1767
+ :where(discord-button):hover {
1768
+ background: var(--dt-button-secondary-hover);
1769
+ }
1770
+
1771
+ :where(discord-button[type='primary']) {
1772
+ background: var(--dt-button-primary);
1773
+ }
1774
+
1775
+ :where(discord-button[type='primary']):hover {
1776
+ background: var(--dt-button-primary-hover);
1777
+ }
1778
+
1779
+ :where(discord-button[type='success']) {
1780
+ background: var(--dt-button-success);
1781
+ }
1782
+
1783
+ :where(discord-button[type='destructive'], discord-button[type='danger']) {
1784
+ background: var(--dt-button-danger);
1785
+ }
1786
+
1787
+ :where(discord-button[type='link']) {
1788
+ background: var(--dt-button-link);
1789
+ }
1790
+
1791
+ :where(discord-button[disabled]) {
1792
+ opacity: 0.5;
1793
+ cursor: not-allowed;
1794
+ }
1795
+
1796
+ .dt-button-emoji {
1797
+ width: 1rem;
1798
+ height: 1rem;
1799
+ object-fit: contain;
1800
+ }
1801
+
1802
+ .dt-button-link-icon {
1803
+ width: 12px;
1804
+ height: 12px;
1805
+ opacity: 0.9;
1806
+ }
1807
+
1808
+ /* Verified author tag (used inside author info) */
1809
+ :where(discord-verified-author-tag) {
1810
+ display: inline-flex;
1811
+ align-items: center;
1812
+ justify-content: center;
1813
+ width: 15px;
1814
+ height: 15px;
1815
+ border-radius: 50%;
1816
+ background: var(--dt-brand);
1817
+ color: var(--dt-text-on-brand);
1818
+ font-size: 9px;
1819
+ vertical-align: -2px;
1820
+ }
1821
+
1822
+ :where(discord-verified-author-tag)::after {
1823
+ content: '\2713';
1824
+ }
1825
+
1826
+ /* ==========================================================================
1827
+ 15. A11Y + PRINT
1828
+ ========================================================================== */
1829
+
1830
+ .dt-divider {
1831
+ height: 1px;
1832
+ margin: 8px 0;
1833
+ border: 0;
1834
+ background: var(--dt-divider);
1835
+ }
1836
+
1837
+ .dt-sr-only {
1838
+ position: absolute;
1839
+ width: 1px;
1840
+ height: 1px;
1841
+ margin: -1px;
1842
+ padding: 0;
1843
+ overflow: hidden;
1844
+ clip: rect(0, 0, 0, 0);
1845
+ white-space: nowrap;
1846
+ border: 0;
1847
+ }
1848
+
1849
+ :where(discord-message, discord-embed, discord-attachments, discord-reactions) :focus-visible {
1850
+ outline: none;
1851
+ box-shadow: 0 0 0 2px var(--dt-focus-ring);
1852
+ }
1853
+
1854
+ @media (prefers-reduced-motion: reduce) {
1855
+ :where(discord-spoiler),
1856
+ :where(discord-reaction),
1857
+ :where(discord-button),
1858
+ discord-image-attachment img {
1859
+ transition: none;
1860
+ }
1861
+ }
1862
+
1863
+ @media (max-width: 480px) {
1864
+ :where(discord-messages) {
1865
+ --dt-msg-padding-right: 16px;
1866
+ }
1867
+
1868
+ :where(discord-embed),
1869
+ :where(discord-attachments) {
1870
+ max-width: 100%;
1871
+ }
1872
+ }
1873
+
1874
+ @media print {
1875
+ :root,
1876
+ discord-messages,
1877
+ discord-message {
1878
+ --dt-bg-primary: #ffffff;
1879
+ --dt-bg-secondary: #f2f3f5;
1880
+ --dt-bg-embed: #f2f3f5;
1881
+ --dt-bg-code: #f2f3f5;
1882
+ --dt-text-normal: #000000;
1883
+ --dt-text-strong: #000000;
1884
+ --dt-text-muted: #444444;
1885
+ }
1886
+
1887
+ :where(discord-spoiler) {
1888
+ background: none;
1889
+ color: inherit;
1890
+ }
1891
+
1892
+ .dt-copy,
1893
+ .dt-spoiler-overlay {
1894
+ display: none !important;
1895
+ }
1896
+ }