@vicket/create-support 1.1.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 (55) hide show
  1. package/README.md +52 -0
  2. package/bin/create-vicket-support.js +389 -0
  3. package/package.json +18 -0
  4. package/templates/next/src/app/api/vicket/[...path]/route.ts +59 -0
  5. package/templates/next/src/app/components/vicket/TicketDialog.tsx +514 -0
  6. package/templates/next/src/app/support/page.tsx +358 -0
  7. package/templates/next/src/app/ticket/page.tsx +483 -0
  8. package/templates/next/src/app/utils/vicket/api.ts +149 -0
  9. package/templates/next/src/app/utils/vicket/types.ts +85 -0
  10. package/templates/next/src/app/utils/vicket/utils.ts +49 -0
  11. package/templates/next/src/app/vicket.css +1325 -0
  12. package/templates/nuxt/app/assets/css/vicket.css +1325 -0
  13. package/templates/nuxt/app/components/VicketTicketDialog.vue +499 -0
  14. package/templates/nuxt/app/composables/useVicket.ts +274 -0
  15. package/templates/nuxt/app/pages/support.vue +303 -0
  16. package/templates/nuxt/app/pages/ticket.vue +434 -0
  17. package/templates/nuxt/server/api/vicket/[...path].ts +85 -0
  18. package/templates/sveltekit/src/lib/vicket/TicketDialog.svelte +459 -0
  19. package/templates/sveltekit/src/lib/vicket/api.ts +162 -0
  20. package/templates/sveltekit/src/lib/vicket/types.ts +87 -0
  21. package/templates/sveltekit/src/lib/vicket/utils.ts +55 -0
  22. package/templates/sveltekit/src/lib/vicket.css +1325 -0
  23. package/templates/sveltekit/src/routes/api/vicket/[...path]/+server.ts +77 -0
  24. package/templates/sveltekit/src/routes/support/+page.svelte +316 -0
  25. package/templates/sveltekit/src/routes/ticket/+page.svelte +418 -0
  26. package/templates-tailwind/next/src/app/api/vicket/init/route.ts +24 -0
  27. package/templates-tailwind/next/src/app/api/vicket/messages/route.ts +36 -0
  28. package/templates-tailwind/next/src/app/api/vicket/thread/route.ts +27 -0
  29. package/templates-tailwind/next/src/app/api/vicket/tickets/route.ts +37 -0
  30. package/templates-tailwind/next/src/app/support/page.tsx +5 -0
  31. package/templates-tailwind/next/src/app/ticket/page.tsx +10 -0
  32. package/templates-tailwind/next/src/components/vicket/support-page.tsx +359 -0
  33. package/templates-tailwind/next/src/components/vicket/ticket-dialog.tsx +306 -0
  34. package/templates-tailwind/next/src/components/vicket/ticket-page.tsx +425 -0
  35. package/templates-tailwind/next/src/lib/vicket.ts +257 -0
  36. package/templates-tailwind/nuxt/app/components/VicketSupportPage.vue +317 -0
  37. package/templates-tailwind/nuxt/app/components/VicketTicketDialog.vue +444 -0
  38. package/templates-tailwind/nuxt/app/components/VicketTicketPage.vue +449 -0
  39. package/templates-tailwind/nuxt/app/composables/use-vicket.ts +249 -0
  40. package/templates-tailwind/nuxt/app/pages/support.vue +3 -0
  41. package/templates-tailwind/nuxt/app/pages/ticket.vue +3 -0
  42. package/templates-tailwind/nuxt/server/api/vicket/init.get.ts +22 -0
  43. package/templates-tailwind/nuxt/server/api/vicket/messages.post.ts +56 -0
  44. package/templates-tailwind/nuxt/server/api/vicket/thread.get.ts +26 -0
  45. package/templates-tailwind/nuxt/server/api/vicket/tickets.post.ts +53 -0
  46. package/templates-tailwind/sveltekit/src/lib/vicket/SupportPage.svelte +395 -0
  47. package/templates-tailwind/sveltekit/src/lib/vicket/TicketDialog.svelte +406 -0
  48. package/templates-tailwind/sveltekit/src/lib/vicket/TicketPage.svelte +465 -0
  49. package/templates-tailwind/sveltekit/src/lib/vicket/index.ts +257 -0
  50. package/templates-tailwind/sveltekit/src/routes/api/vicket/init/+server.ts +22 -0
  51. package/templates-tailwind/sveltekit/src/routes/api/vicket/messages/+server.ts +40 -0
  52. package/templates-tailwind/sveltekit/src/routes/api/vicket/thread/+server.ts +25 -0
  53. package/templates-tailwind/sveltekit/src/routes/api/vicket/tickets/+server.ts +37 -0
  54. package/templates-tailwind/sveltekit/src/routes/support/+page.svelte +5 -0
  55. package/templates-tailwind/sveltekit/src/routes/ticket/+page.svelte +5 -0
@@ -0,0 +1,1325 @@
1
+ :root {
2
+ --vk-bg: #f8fafc;
3
+ --vk-surface: #ffffff;
4
+ --vk-surface-muted: #f1f5f9;
5
+ --vk-border: rgba(148, 163, 184, 0.3);
6
+ --vk-border-strong: rgba(148, 163, 184, 0.5);
7
+ --vk-text: #0f172a;
8
+ --vk-text-muted: #64748b;
9
+ --vk-primary: #2563eb;
10
+ --vk-primary-hover: #1d4ed8;
11
+ --vk-primary-contrast: #ffffff;
12
+ --vk-primary-light: #eff6ff;
13
+ --vk-danger: #dc2626;
14
+ --vk-success: #16a34a;
15
+ --vk-radius: 12px;
16
+ --vk-radius-lg: 16px;
17
+ --vk-shadow: 0 1px 3px rgba(0, 0, 0, 0.05), 0 10px 30px rgba(0, 0, 0, 0.04);
18
+ --vk-avatar-reporter: #3b82f6;
19
+ --vk-avatar-user: #10b981;
20
+ --vk-avatar-system: #94a3b8;
21
+ }
22
+
23
+ *,
24
+ *::before,
25
+ *::after {
26
+ box-sizing: border-box;
27
+ }
28
+
29
+ /* ── Shell ───────────────────────────────── */
30
+
31
+ .vk-shell {
32
+ min-height: 100vh;
33
+ background: var(--vk-bg);
34
+ color: var(--vk-text);
35
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
36
+ -webkit-font-smoothing: antialiased;
37
+ -moz-osx-font-smoothing: grayscale;
38
+ }
39
+
40
+ /* ── Page Container ──────────────────────── */
41
+
42
+ .vk-page {
43
+ width: min(1100px, 100%);
44
+ margin: 0 auto;
45
+ padding: 0 24px;
46
+ }
47
+
48
+ /* ── Hero (2 columns) ────────────────────── */
49
+
50
+ .vk-hero-row {
51
+ display: flex;
52
+ flex-direction: column;
53
+ gap: 16px;
54
+ padding: 48px 0 32px;
55
+ }
56
+
57
+ @media (min-width: 768px) {
58
+ .vk-hero-row {
59
+ flex-direction: row;
60
+ align-items: center;
61
+ justify-content: space-between;
62
+ }
63
+ }
64
+
65
+ .vk-hero-title {
66
+ margin: 0;
67
+ font-size: clamp(1.5rem, 4vw, 2rem);
68
+ font-weight: 700;
69
+ letter-spacing: -0.02em;
70
+ line-height: 1.2;
71
+ }
72
+
73
+ .vk-hero-subtitle {
74
+ margin: 6px 0 0;
75
+ color: var(--vk-text-muted);
76
+ font-size: 1rem;
77
+ }
78
+
79
+ .vk-hero-cta {
80
+ display: flex;
81
+ align-items: center;
82
+ gap: 12px;
83
+ flex-shrink: 0;
84
+ }
85
+
86
+ .vk-hero-cta-hint {
87
+ display: none;
88
+ font-size: 0.875rem;
89
+ color: var(--vk-text-muted);
90
+ }
91
+
92
+ @media (min-width: 768px) {
93
+ .vk-hero-cta-hint {
94
+ display: block;
95
+ }
96
+ }
97
+
98
+ /* ── Search ──────────────────────────────── */
99
+
100
+ .vk-search-wrap {
101
+ position: relative;
102
+ padding-bottom: 32px;
103
+ }
104
+
105
+ .vk-search-icon {
106
+ position: absolute;
107
+ left: 14px;
108
+ top: 14px;
109
+ color: var(--vk-text-muted);
110
+ pointer-events: none;
111
+ line-height: 0;
112
+ }
113
+
114
+ .vk-search-input {
115
+ width: 100%;
116
+ border: 1px solid var(--vk-border);
117
+ background: var(--vk-surface);
118
+ color: var(--vk-text);
119
+ border-radius: var(--vk-radius);
120
+ font: inherit;
121
+ font-size: 0.875rem;
122
+ padding: 12px 16px 12px 44px;
123
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
124
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
125
+ }
126
+
127
+ .vk-search-input:focus {
128
+ outline: none;
129
+ border-color: var(--vk-primary);
130
+ box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
131
+ }
132
+
133
+ .vk-search-input::placeholder {
134
+ color: var(--vk-text-muted);
135
+ opacity: 0.6;
136
+ }
137
+
138
+ /* ── Content Grid ────────────────────────── */
139
+
140
+ .vk-content-grid {
141
+ display: grid;
142
+ grid-template-columns: 1fr;
143
+ gap: 40px;
144
+ padding-bottom: 48px;
145
+ }
146
+
147
+ @media (min-width: 768px) {
148
+ .vk-content-grid {
149
+ grid-template-columns: 1fr 1fr;
150
+ gap: 48px;
151
+ }
152
+ }
153
+
154
+ .vk-section-title-row {
155
+ display: flex;
156
+ align-items: center;
157
+ gap: 8px;
158
+ margin-bottom: 16px;
159
+ }
160
+
161
+ .vk-section-title-icon {
162
+ color: var(--vk-primary);
163
+ line-height: 0;
164
+ }
165
+
166
+ .vk-section-title {
167
+ margin: 0;
168
+ font-size: 1rem;
169
+ font-weight: 700;
170
+ letter-spacing: -0.01em;
171
+ }
172
+
173
+ /* ── Article List ────────────────────────── */
174
+
175
+ .vk-article-list {
176
+ display: grid;
177
+ gap: 4px;
178
+ }
179
+
180
+ .vk-article-card {
181
+ display: flex;
182
+ align-items: flex-start;
183
+ gap: 12px;
184
+ padding: 12px;
185
+ border-radius: var(--vk-radius);
186
+ border: 1px solid transparent;
187
+ text-decoration: none;
188
+ color: var(--vk-text);
189
+ background: none;
190
+ font: inherit;
191
+ cursor: pointer;
192
+ text-align: left;
193
+ width: 100%;
194
+ transition: background 0.15s ease, border-color 0.15s ease;
195
+ }
196
+
197
+ .vk-article-card:hover {
198
+ background: rgba(255, 255, 255, 0.6);
199
+ border-color: var(--vk-border);
200
+ }
201
+
202
+ .vk-article-icon {
203
+ width: 36px;
204
+ height: 36px;
205
+ min-width: 36px;
206
+ display: flex;
207
+ align-items: center;
208
+ justify-content: center;
209
+ border-radius: 8px;
210
+ background: var(--vk-primary-light);
211
+ color: var(--vk-primary);
212
+ line-height: 0;
213
+ }
214
+
215
+ .vk-article-title {
216
+ margin: 0;
217
+ font-size: 0.875rem;
218
+ font-weight: 600;
219
+ line-height: 1.4;
220
+ }
221
+
222
+ .vk-article-card:hover .vk-article-title {
223
+ color: var(--vk-primary);
224
+ }
225
+
226
+ .vk-article-preview {
227
+ margin: 2px 0 0;
228
+ font-size: 0.8rem;
229
+ color: var(--vk-text-muted);
230
+ line-height: 1.5;
231
+ display: -webkit-box;
232
+ -webkit-line-clamp: 2;
233
+ -webkit-box-orient: vertical;
234
+ overflow: hidden;
235
+ }
236
+
237
+ /* ── Article Viewer ──────────────────────── */
238
+
239
+ .vk-article-viewer {
240
+ padding-bottom: 48px;
241
+ }
242
+
243
+ .vk-article-viewer-card {
244
+ background: var(--vk-surface);
245
+ border: 1px solid var(--vk-border);
246
+ border-radius: var(--vk-radius-lg);
247
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
248
+ padding: 24px;
249
+ }
250
+
251
+ @media (min-width: 768px) {
252
+ .vk-article-viewer-card {
253
+ padding: 32px;
254
+ }
255
+ }
256
+
257
+ .vk-article-viewer-title {
258
+ margin: 0;
259
+ font-size: 1.25rem;
260
+ font-weight: 700;
261
+ letter-spacing: -0.01em;
262
+ }
263
+
264
+ @media (min-width: 768px) {
265
+ .vk-article-viewer-title {
266
+ font-size: 1.5rem;
267
+ }
268
+ }
269
+
270
+ .vk-article-viewer-content {
271
+ margin-top: 20px;
272
+ font-size: 0.875rem;
273
+ line-height: 1.7;
274
+ color: var(--vk-text-muted);
275
+ }
276
+
277
+ /* ── FAQ ─────────────────────────────────── */
278
+
279
+ .vk-faq-list {
280
+ display: grid;
281
+ gap: 8px;
282
+ }
283
+
284
+ .vk-faq-item {
285
+ background: rgba(255, 255, 255, 0.5);
286
+ border: 1px solid var(--vk-border);
287
+ border-radius: var(--vk-radius);
288
+ overflow: hidden;
289
+ transition: background 0.15s ease;
290
+ }
291
+
292
+ .vk-faq-item:hover {
293
+ background: rgba(255, 255, 255, 0.8);
294
+ }
295
+
296
+ .vk-faq-question {
297
+ width: 100%;
298
+ display: flex;
299
+ align-items: center;
300
+ justify-content: space-between;
301
+ gap: 12px;
302
+ padding: 14px 16px;
303
+ border: none;
304
+ background: none;
305
+ font: inherit;
306
+ font-size: 0.875rem;
307
+ font-weight: 600;
308
+ color: var(--vk-text);
309
+ cursor: pointer;
310
+ text-align: left;
311
+ }
312
+
313
+ .vk-faq-chevron {
314
+ flex-shrink: 0;
315
+ color: var(--vk-text-muted);
316
+ transition: transform 0.2s ease;
317
+ line-height: 0;
318
+ }
319
+
320
+ .vk-faq-chevron.open {
321
+ transform: rotate(180deg);
322
+ }
323
+
324
+ .vk-faq-body {
325
+ display: grid;
326
+ grid-template-rows: 0fr;
327
+ transition: grid-template-rows 0.25s ease;
328
+ }
329
+
330
+ .vk-faq-body.open {
331
+ grid-template-rows: 1fr;
332
+ }
333
+
334
+ .vk-faq-body > div {
335
+ overflow: hidden;
336
+ }
337
+
338
+ .vk-faq-answer {
339
+ padding: 0 16px 14px;
340
+ font-size: 0.875rem;
341
+ color: var(--vk-text-muted);
342
+ line-height: 1.6;
343
+ white-space: pre-wrap;
344
+ }
345
+
346
+ /* ── Dialog ──────────────────────────────── */
347
+
348
+ .vk-dialog-overlay {
349
+ position: fixed;
350
+ inset: 0;
351
+ z-index: 50;
352
+ display: flex;
353
+ align-items: center;
354
+ justify-content: center;
355
+ background: rgba(0, 0, 0, 0.4);
356
+ backdrop-filter: blur(4px);
357
+ animation: vk-fade-in 0.15s ease-out;
358
+ }
359
+
360
+ .vk-dialog {
361
+ position: relative;
362
+ width: min(480px, calc(100% - 32px));
363
+ max-height: calc(100vh - 64px);
364
+ overflow-y: auto;
365
+ background: var(--vk-surface);
366
+ border: 1px solid var(--vk-border);
367
+ border-radius: var(--vk-radius-lg);
368
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
369
+ animation: vk-slide-up 0.2s ease-out;
370
+ }
371
+
372
+ .vk-dialog-close {
373
+ position: absolute;
374
+ top: 16px;
375
+ right: 16px;
376
+ z-index: 10;
377
+ width: 32px;
378
+ height: 32px;
379
+ display: flex;
380
+ align-items: center;
381
+ justify-content: center;
382
+ border: none;
383
+ background: transparent;
384
+ color: var(--vk-text-muted);
385
+ border-radius: 8px;
386
+ cursor: pointer;
387
+ transition: background 0.15s ease, color 0.15s ease;
388
+ line-height: 0;
389
+ }
390
+
391
+ .vk-dialog-close:hover {
392
+ background: var(--vk-surface-muted);
393
+ color: var(--vk-text);
394
+ }
395
+
396
+ .vk-dialog-body {
397
+ padding: 24px;
398
+ }
399
+
400
+ .vk-dialog-title {
401
+ margin: 0;
402
+ font-size: 1.125rem;
403
+ font-weight: 700;
404
+ }
405
+
406
+ .vk-dialog-subtitle {
407
+ margin: 4px 0 0;
408
+ color: var(--vk-text-muted);
409
+ font-size: 0.875rem;
410
+ }
411
+
412
+ /* ── Radio Card ──────────────────────────── */
413
+
414
+ .vk-radio-card {
415
+ display: flex;
416
+ align-items: flex-start;
417
+ gap: 12px;
418
+ width: 100%;
419
+ text-align: left;
420
+ border: 1px solid var(--vk-border);
421
+ background: var(--vk-surface-muted);
422
+ color: var(--vk-text);
423
+ border-radius: var(--vk-radius);
424
+ padding: 14px;
425
+ cursor: pointer;
426
+ font: inherit;
427
+ transition: border-color 0.15s ease;
428
+ }
429
+
430
+ .vk-radio-card:hover {
431
+ border-color: var(--vk-border-strong);
432
+ }
433
+
434
+ .vk-radio-card.active {
435
+ border-color: var(--vk-primary);
436
+ background: var(--vk-primary-light);
437
+ }
438
+
439
+ .vk-radio-dot {
440
+ width: 16px;
441
+ height: 16px;
442
+ min-width: 16px;
443
+ border-radius: 50%;
444
+ border: 2px solid var(--vk-border-strong);
445
+ margin-top: 2px;
446
+ display: flex;
447
+ align-items: center;
448
+ justify-content: center;
449
+ transition: border-color 0.15s ease, background 0.15s ease;
450
+ }
451
+
452
+ .vk-radio-card.active .vk-radio-dot {
453
+ border-color: var(--vk-primary);
454
+ background: var(--vk-primary);
455
+ }
456
+
457
+ .vk-radio-dot-inner {
458
+ width: 6px;
459
+ height: 6px;
460
+ border-radius: 50%;
461
+ background: white;
462
+ display: none;
463
+ }
464
+
465
+ .vk-radio-card.active .vk-radio-dot-inner {
466
+ display: block;
467
+ }
468
+
469
+ .vk-radio-name {
470
+ display: block;
471
+ font-size: 0.875rem;
472
+ font-weight: 600;
473
+ }
474
+
475
+ .vk-radio-description {
476
+ display: block;
477
+ margin-top: 2px;
478
+ font-size: 0.8rem;
479
+ color: var(--vk-text-muted);
480
+ }
481
+
482
+ /* ── Form Fields ─────────────────────────── */
483
+
484
+ .vk-field {
485
+ display: grid;
486
+ gap: 6px;
487
+ }
488
+
489
+ .vk-label {
490
+ font-size: 0.875rem;
491
+ font-weight: 600;
492
+ }
493
+
494
+ .vk-label.required::after {
495
+ content: " *";
496
+ color: var(--vk-danger);
497
+ }
498
+
499
+
500
+ .vk-input,
501
+ .vk-textarea,
502
+ .vk-select {
503
+ width: 100%;
504
+ border: 1px solid var(--vk-border);
505
+ background: var(--vk-surface-muted);
506
+ color: var(--vk-text);
507
+ border-radius: 8px;
508
+ font: inherit;
509
+ font-size: 0.875rem;
510
+ padding: 10px 12px;
511
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
512
+ }
513
+
514
+ .vk-input:focus,
515
+ .vk-textarea:focus,
516
+ .vk-select:focus {
517
+ outline: none;
518
+ border-color: var(--vk-primary);
519
+ box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
520
+ }
521
+
522
+ .vk-textarea {
523
+ min-height: 100px;
524
+ resize: vertical;
525
+ }
526
+
527
+ .vk-input-icon-wrap {
528
+ position: relative;
529
+ }
530
+
531
+ .vk-input-icon {
532
+ position: absolute;
533
+ left: 12px;
534
+ top: 50%;
535
+ transform: translateY(-50%);
536
+ color: var(--vk-text-muted);
537
+ pointer-events: none;
538
+ line-height: 0;
539
+ }
540
+
541
+ .vk-input-icon-wrap .vk-input {
542
+ padding-left: 40px;
543
+ }
544
+
545
+ .vk-hint {
546
+ margin: 2px 0 0;
547
+ font-size: 0.75rem;
548
+ color: var(--vk-text-muted);
549
+ }
550
+
551
+ .vk-checkbox-list {
552
+ display: grid;
553
+ gap: 8px;
554
+ }
555
+
556
+ .vk-checkbox-item {
557
+ display: flex;
558
+ align-items: center;
559
+ gap: 8px;
560
+ font-size: 0.875rem;
561
+ }
562
+
563
+ .vk-stack {
564
+ display: grid;
565
+ gap: 16px;
566
+ }
567
+
568
+ .vk-grid {
569
+ display: grid;
570
+ gap: 12px;
571
+ }
572
+
573
+ /* ── Buttons ─────────────────────────────── */
574
+
575
+ .vk-button {
576
+ display: inline-flex;
577
+ align-items: center;
578
+ justify-content: center;
579
+ gap: 8px;
580
+ border: 1px solid var(--vk-border);
581
+ background: var(--vk-surface);
582
+ color: var(--vk-text);
583
+ border-radius: 8px;
584
+ padding: 10px 16px;
585
+ font: inherit;
586
+ font-size: 0.875rem;
587
+ font-weight: 600;
588
+ cursor: pointer;
589
+ transition: background 0.15s ease, border-color 0.15s ease;
590
+ }
591
+
592
+ .vk-button:hover {
593
+ background: var(--vk-surface-muted);
594
+ border-color: var(--vk-border-strong);
595
+ }
596
+
597
+ .vk-button.primary {
598
+ border-color: var(--vk-primary);
599
+ background: var(--vk-primary);
600
+ color: var(--vk-primary-contrast);
601
+ }
602
+
603
+ .vk-button.primary:hover {
604
+ background: var(--vk-primary-hover);
605
+ border-color: var(--vk-primary-hover);
606
+ }
607
+
608
+ .vk-button:disabled {
609
+ opacity: 0.6;
610
+ cursor: not-allowed;
611
+ }
612
+
613
+ .vk-button.pill {
614
+ border-radius: 999px;
615
+ padding: 12px 28px;
616
+ }
617
+
618
+ .vk-button.full {
619
+ width: 100%;
620
+ }
621
+
622
+ .vk-button.ghost {
623
+ border: none;
624
+ background: none;
625
+ color: var(--vk-text-muted);
626
+ padding: 6px 10px;
627
+ border-radius: 6px;
628
+ }
629
+
630
+ .vk-button.ghost:hover {
631
+ background: var(--vk-surface-muted);
632
+ color: var(--vk-text);
633
+ }
634
+
635
+ /* ── Alerts ──────────────────────────────── */
636
+
637
+ .vk-alert {
638
+ border-radius: var(--vk-radius);
639
+ border: 1px solid var(--vk-border);
640
+ background: var(--vk-surface-muted);
641
+ padding: 12px 16px;
642
+ font-size: 0.875rem;
643
+ display: flex;
644
+ align-items: flex-start;
645
+ gap: 12px;
646
+ }
647
+
648
+ .vk-alert.error {
649
+ border-color: #fecaca;
650
+ background: #fef2f2;
651
+ color: #991b1b;
652
+ }
653
+
654
+ .vk-alert.success {
655
+ border-color: #bbf7d0;
656
+ background: #f0fdf4;
657
+ color: #166534;
658
+ }
659
+
660
+ .vk-alert-dismiss {
661
+ flex-shrink: 0;
662
+ border: none;
663
+ background: none;
664
+ cursor: pointer;
665
+ opacity: 0.5;
666
+ padding: 0;
667
+ color: inherit;
668
+ line-height: 0;
669
+ transition: opacity 0.15s ease;
670
+ }
671
+
672
+ .vk-alert-dismiss:hover {
673
+ opacity: 1;
674
+ }
675
+
676
+ /* ── Badge ───────────────────────────────── */
677
+
678
+ .vk-badge {
679
+ display: inline-flex;
680
+ align-items: center;
681
+ border-radius: 999px;
682
+ font-size: 0.75rem;
683
+ font-weight: 600;
684
+ padding: 3px 10px;
685
+ }
686
+
687
+ .vk-badge.status {
688
+ border: 1px solid rgba(37, 99, 235, 0.2);
689
+ background: var(--vk-primary-light);
690
+ color: var(--vk-primary);
691
+ }
692
+
693
+ .vk-badge.priority {
694
+ border: 1px solid #fde68a;
695
+ background: #fffbeb;
696
+ color: #a16207;
697
+ }
698
+
699
+ .vk-badge.id {
700
+ border: 1px solid var(--vk-border);
701
+ background: var(--vk-surface-muted);
702
+ color: var(--vk-text-muted);
703
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
704
+ }
705
+
706
+ /* ── Back Link ───────────────────────────── */
707
+
708
+ .vk-back-link {
709
+ display: inline-flex;
710
+ align-items: center;
711
+ gap: 6px;
712
+ color: var(--vk-text-muted);
713
+ text-decoration: none;
714
+ font-size: 0.875rem;
715
+ font-weight: 500;
716
+ transition: color 0.15s ease;
717
+ }
718
+
719
+ .vk-back-link:hover {
720
+ color: var(--vk-text);
721
+ }
722
+
723
+ .vk-back-button {
724
+ display: inline-flex;
725
+ align-items: center;
726
+ gap: 4px;
727
+ border: none;
728
+ background: none;
729
+ color: var(--vk-text-muted);
730
+ font: inherit;
731
+ font-size: 0.875rem;
732
+ font-weight: 500;
733
+ cursor: pointer;
734
+ padding: 4px 8px;
735
+ margin: -4px -8px;
736
+ border-radius: 6px;
737
+ transition: color 0.15s ease, background 0.15s ease;
738
+ }
739
+
740
+ .vk-back-button:hover {
741
+ color: var(--vk-text);
742
+ background: var(--vk-surface-muted);
743
+ }
744
+
745
+ /* ── Ticket Header ───────────────────────── */
746
+
747
+ .vk-ticket-header {
748
+ display: flex;
749
+ align-items: flex-start;
750
+ justify-content: space-between;
751
+ gap: 12px;
752
+ flex-wrap: wrap;
753
+ }
754
+
755
+ .vk-ticket-title {
756
+ margin: 0;
757
+ font-size: 1.25rem;
758
+ font-weight: 600;
759
+ letter-spacing: -0.01em;
760
+ line-height: 1.3;
761
+ }
762
+
763
+ @media (min-width: 640px) {
764
+ .vk-ticket-title {
765
+ font-size: 1.5rem;
766
+ }
767
+ }
768
+
769
+ .vk-ticket-badges {
770
+ display: flex;
771
+ flex-wrap: wrap;
772
+ align-items: center;
773
+ gap: 8px;
774
+ margin-top: 10px;
775
+ }
776
+
777
+ /* ── Section Card ────────────────────────── */
778
+
779
+ .vk-section-card {
780
+ background: var(--vk-surface);
781
+ border: 1px solid var(--vk-border);
782
+ border-radius: var(--vk-radius-lg);
783
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
784
+ overflow: hidden;
785
+ }
786
+
787
+ .vk-section-header {
788
+ display: flex;
789
+ align-items: center;
790
+ gap: 8px;
791
+ padding: 14px 20px;
792
+ border-bottom: 1px solid var(--vk-border);
793
+ font-size: 0.875rem;
794
+ font-weight: 600;
795
+ color: var(--vk-text);
796
+ }
797
+
798
+ .vk-section-header-icon {
799
+ color: var(--vk-text-muted);
800
+ line-height: 0;
801
+ }
802
+
803
+ .vk-section-body {
804
+ padding: 20px;
805
+ }
806
+
807
+ /* ── Description Card ────────────────────── */
808
+
809
+ .vk-description-content {
810
+ font-size: 0.875rem;
811
+ line-height: 1.6;
812
+ color: var(--vk-text-muted);
813
+ }
814
+
815
+ .vk-summary-list {
816
+ display: grid;
817
+ gap: 12px;
818
+ }
819
+
820
+ .vk-summary-item {
821
+ border: 1px solid var(--vk-border);
822
+ border-radius: 10px;
823
+ background: var(--vk-surface-muted);
824
+ padding: 12px;
825
+ }
826
+
827
+ .vk-summary-label {
828
+ margin: 0 0 8px;
829
+ font-size: 0.75rem;
830
+ font-weight: 600;
831
+ color: var(--vk-text-muted);
832
+ }
833
+
834
+ .vk-summary-value {
835
+ margin: 0;
836
+ font-size: 0.875rem;
837
+ line-height: 1.6;
838
+ color: var(--vk-text);
839
+ white-space: pre-wrap;
840
+ word-break: break-word;
841
+ }
842
+
843
+ .vk-summary-value.muted {
844
+ color: var(--vk-text-muted);
845
+ font-style: italic;
846
+ }
847
+
848
+ /* reuse vk-message-html styles for description too */
849
+
850
+ /* ── Compose Area ────────────────────────── */
851
+
852
+ .vk-compose {
853
+ padding: 20px;
854
+ border-bottom: 1px solid var(--vk-border);
855
+ }
856
+
857
+ .vk-compose-row {
858
+ display: flex;
859
+ flex-wrap: wrap;
860
+ align-items: center;
861
+ justify-content: space-between;
862
+ gap: 12px;
863
+ margin-top: 12px;
864
+ }
865
+
866
+ .vk-compose-files {
867
+ display: flex;
868
+ flex-wrap: wrap;
869
+ align-items: center;
870
+ gap: 8px;
871
+ }
872
+
873
+ .vk-browse-btn {
874
+ display: inline-flex;
875
+ align-items: center;
876
+ gap: 6px;
877
+ border: 1px solid var(--vk-border);
878
+ background: var(--vk-surface-muted);
879
+ border-radius: 8px;
880
+ padding: 6px 12px;
881
+ font: inherit;
882
+ font-size: 0.75rem;
883
+ font-weight: 500;
884
+ color: var(--vk-text-muted);
885
+ cursor: pointer;
886
+ transition: border-color 0.15s ease, color 0.15s ease;
887
+ }
888
+
889
+ .vk-browse-btn:hover {
890
+ border-color: var(--vk-border-strong);
891
+ color: var(--vk-text);
892
+ }
893
+
894
+ .vk-browse-btn input[type="file"] {
895
+ display: none;
896
+ }
897
+
898
+ /* ── Message Thread ──────────────────────── */
899
+
900
+ .vk-message-list {
901
+ display: flex;
902
+ flex-direction: column;
903
+ }
904
+
905
+ .vk-message-divider {
906
+ height: 1px;
907
+ background: var(--vk-border);
908
+ margin: 0;
909
+ border: none;
910
+ }
911
+
912
+ .vk-message {
913
+ display: flex;
914
+ gap: 12px;
915
+ padding: 14px 20px;
916
+ }
917
+
918
+ /* ── Avatars ─────────────────────────────── */
919
+
920
+ .vk-avatar {
921
+ width: 28px;
922
+ height: 28px;
923
+ min-width: 28px;
924
+ border-radius: 50%;
925
+ display: flex;
926
+ align-items: center;
927
+ justify-content: center;
928
+ font-size: 0.65rem;
929
+ font-weight: 700;
930
+ line-height: 1;
931
+ margin-top: 2px;
932
+ }
933
+
934
+ .vk-avatar-reporter {
935
+ background: rgba(59, 130, 246, 0.15);
936
+ color: var(--vk-avatar-reporter);
937
+ }
938
+
939
+ .vk-avatar-user {
940
+ background: rgba(16, 185, 129, 0.15);
941
+ color: var(--vk-avatar-user);
942
+ }
943
+
944
+ .vk-avatar-system {
945
+ background: rgba(148, 163, 184, 0.2);
946
+ color: var(--vk-avatar-system);
947
+ }
948
+
949
+ /* ── Message Content ─────────────────────── */
950
+
951
+ .vk-message-content {
952
+ flex: 1;
953
+ min-width: 0;
954
+ }
955
+
956
+ .vk-message-meta {
957
+ display: flex;
958
+ gap: 8px;
959
+ flex-wrap: wrap;
960
+ align-items: baseline;
961
+ }
962
+
963
+ .vk-author-name {
964
+ font-size: 0.875rem;
965
+ font-weight: 600;
966
+ color: var(--vk-text);
967
+ }
968
+
969
+ .vk-author-name.system {
970
+ font-size: 0.75rem;
971
+ font-weight: 500;
972
+ color: var(--vk-text-muted);
973
+ }
974
+
975
+ .vk-message-time {
976
+ font-size: 0.75rem;
977
+ color: var(--vk-text-muted);
978
+ opacity: 0.5;
979
+ }
980
+
981
+ .vk-message-bubble {
982
+ border: 1px solid var(--vk-border);
983
+ background: var(--vk-surface-muted);
984
+ border-radius: var(--vk-radius);
985
+ padding: 12px 16px;
986
+ margin-top: 6px;
987
+ }
988
+
989
+ .vk-message-bubble.support {
990
+ border-color: rgba(37, 99, 235, 0.1);
991
+ background: var(--vk-primary-light);
992
+ }
993
+
994
+ .vk-message-html {
995
+ font-size: 0.875rem;
996
+ line-height: 1.6;
997
+ word-break: break-word;
998
+ }
999
+
1000
+ .vk-message-html p { margin: 0 0 0.5em; }
1001
+ .vk-message-html p:last-child { margin-bottom: 0; }
1002
+ .vk-message-html a { color: var(--vk-primary); text-decoration: underline; }
1003
+ .vk-message-html ul,
1004
+ .vk-message-html ol { margin: 0.25em 0; padding-left: 1.5em; }
1005
+ .vk-message-html pre {
1006
+ background: var(--vk-surface-muted);
1007
+ border-radius: 6px;
1008
+ padding: 8px 12px;
1009
+ overflow-x: auto;
1010
+ font-size: 0.8rem;
1011
+ }
1012
+ .vk-message-html code {
1013
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
1014
+ font-size: 0.85em;
1015
+ }
1016
+
1017
+ .vk-system-text {
1018
+ font-size: 0.75rem;
1019
+ font-style: italic;
1020
+ color: var(--vk-text-muted);
1021
+ margin-top: 4px;
1022
+ }
1023
+
1024
+ /* ── Attachments ─────────────────────────── */
1025
+
1026
+ .vk-attachments {
1027
+ margin-top: 8px;
1028
+ display: flex;
1029
+ gap: 6px;
1030
+ flex-wrap: wrap;
1031
+ }
1032
+
1033
+ .vk-attachment {
1034
+ display: inline-flex;
1035
+ align-items: center;
1036
+ gap: 6px;
1037
+ border: 1px solid var(--vk-border);
1038
+ background: var(--vk-surface);
1039
+ border-radius: 999px;
1040
+ padding: 4px 12px;
1041
+ font-size: 0.75rem;
1042
+ color: var(--vk-text-muted);
1043
+ text-decoration: none;
1044
+ transition: color 0.15s ease, border-color 0.15s ease;
1045
+ line-height: 0;
1046
+ }
1047
+
1048
+ .vk-attachment span {
1049
+ line-height: 1.4;
1050
+ }
1051
+
1052
+ .vk-attachment:hover {
1053
+ color: var(--vk-text);
1054
+ border-color: var(--vk-border-strong);
1055
+ }
1056
+
1057
+ /* ── File Chips ──────────────────────────── */
1058
+
1059
+ .vk-file-chip {
1060
+ display: inline-flex;
1061
+ align-items: center;
1062
+ gap: 6px;
1063
+ background: var(--vk-surface-muted);
1064
+ border: 1px solid var(--vk-border);
1065
+ border-radius: 999px;
1066
+ padding: 4px 10px;
1067
+ font-size: 0.75rem;
1068
+ color: var(--vk-text-muted);
1069
+ max-width: 160px;
1070
+ }
1071
+
1072
+ .vk-file-chip-name {
1073
+ overflow: hidden;
1074
+ text-overflow: ellipsis;
1075
+ white-space: nowrap;
1076
+ }
1077
+
1078
+ .vk-file-chip button {
1079
+ border: none;
1080
+ background: none;
1081
+ cursor: pointer;
1082
+ color: var(--vk-text-muted);
1083
+ padding: 0;
1084
+ line-height: 0;
1085
+ display: flex;
1086
+ align-items: center;
1087
+ }
1088
+
1089
+ .vk-file-chip button:hover {
1090
+ color: var(--vk-danger);
1091
+ }
1092
+
1093
+ /* -- Image Upload Grid ------------------------ */
1094
+
1095
+ .vk-image-grid {
1096
+ display: grid;
1097
+ grid-template-columns: repeat(3, 1fr);
1098
+ gap: 8px;
1099
+ }
1100
+
1101
+ .vk-image-thumb {
1102
+ position: relative;
1103
+ aspect-ratio: 1;
1104
+ overflow: hidden;
1105
+ border-radius: 8px;
1106
+ border: 1px solid var(--vk-border);
1107
+ background: var(--vk-surface-muted);
1108
+ }
1109
+
1110
+ .vk-image-thumb img {
1111
+ width: 100%;
1112
+ height: 100%;
1113
+ object-fit: cover;
1114
+ display: block;
1115
+ }
1116
+
1117
+ .vk-image-thumb-remove {
1118
+ position: absolute;
1119
+ top: 4px;
1120
+ right: 4px;
1121
+ width: 22px;
1122
+ height: 22px;
1123
+ display: flex;
1124
+ align-items: center;
1125
+ justify-content: center;
1126
+ border-radius: 50%;
1127
+ background: rgba(0, 0, 0, 0.6);
1128
+ color: #fff;
1129
+ border: none;
1130
+ cursor: pointer;
1131
+ font-size: 12px;
1132
+ line-height: 0;
1133
+ opacity: 0;
1134
+ transition: opacity 0.15s;
1135
+ }
1136
+
1137
+ .vk-image-thumb:hover .vk-image-thumb-remove {
1138
+ opacity: 1;
1139
+ }
1140
+
1141
+ .vk-image-thumb-remove:hover {
1142
+ background: rgba(0, 0, 0, 0.8);
1143
+ }
1144
+
1145
+ .vk-image-thumb-name {
1146
+ position: absolute;
1147
+ bottom: 0;
1148
+ left: 0;
1149
+ right: 0;
1150
+ background: rgba(0, 0, 0, 0.5);
1151
+ padding: 2px 6px;
1152
+ font-size: 10px;
1153
+ color: #fff;
1154
+ white-space: nowrap;
1155
+ overflow: hidden;
1156
+ text-overflow: ellipsis;
1157
+ }
1158
+
1159
+ .vk-add-image-btn {
1160
+ display: flex;
1161
+ width: 100%;
1162
+ align-items: center;
1163
+ justify-content: center;
1164
+ gap: 8px;
1165
+ border: 2px dashed var(--vk-border);
1166
+ border-radius: 8px;
1167
+ background: var(--vk-surface-muted);
1168
+ padding: 12px 16px;
1169
+ font-size: 0.8125rem;
1170
+ color: var(--vk-text-muted);
1171
+ cursor: pointer;
1172
+ transition: border-color 0.15s, background 0.15s;
1173
+ }
1174
+
1175
+ .vk-add-image-btn:hover {
1176
+ border-color: var(--vk-border-strong);
1177
+ background: var(--vk-surface);
1178
+ }
1179
+
1180
+ /* ── Empty State ─────────────────────────── */
1181
+
1182
+ .vk-empty-state {
1183
+ text-align: center;
1184
+ padding: 40px 16px;
1185
+ }
1186
+
1187
+ .vk-empty-icon {
1188
+ width: 40px;
1189
+ height: 40px;
1190
+ margin: 0 auto 12px;
1191
+ display: flex;
1192
+ align-items: center;
1193
+ justify-content: center;
1194
+ border-radius: 50%;
1195
+ background: var(--vk-surface-muted);
1196
+ color: var(--vk-text-muted);
1197
+ line-height: 0;
1198
+ }
1199
+
1200
+ .vk-empty-text {
1201
+ margin: 0;
1202
+ font-size: 0.875rem;
1203
+ color: var(--vk-text-muted);
1204
+ }
1205
+
1206
+ /* ── CTA (empty state support page) ──────── */
1207
+
1208
+ .vk-cta-card {
1209
+ max-width: 360px;
1210
+ margin: 0 auto;
1211
+ background: var(--vk-surface);
1212
+ border: 1px solid var(--vk-border);
1213
+ border-radius: var(--vk-radius-lg);
1214
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
1215
+ padding: 32px;
1216
+ text-align: center;
1217
+ }
1218
+
1219
+ .vk-cta-icon {
1220
+ width: 48px;
1221
+ height: 48px;
1222
+ margin: 0 auto 16px;
1223
+ display: flex;
1224
+ align-items: center;
1225
+ justify-content: center;
1226
+ border-radius: 50%;
1227
+ background: var(--vk-primary-light);
1228
+ color: var(--vk-primary);
1229
+ line-height: 0;
1230
+ }
1231
+
1232
+ .vk-cta-text {
1233
+ margin: 0;
1234
+ font-size: 0.875rem;
1235
+ font-weight: 500;
1236
+ }
1237
+
1238
+ /* ── Success State ───────────────────────── */
1239
+
1240
+ .vk-success-icon {
1241
+ width: 56px;
1242
+ height: 56px;
1243
+ margin: 0 auto 20px;
1244
+ display: flex;
1245
+ align-items: center;
1246
+ justify-content: center;
1247
+ border-radius: 50%;
1248
+ background: #f0fdf4;
1249
+ color: var(--vk-success);
1250
+ line-height: 0;
1251
+ }
1252
+
1253
+ /* ── No Results ──────────────────────────── */
1254
+
1255
+ .vk-no-results {
1256
+ text-align: center;
1257
+ padding: 0 0 48px;
1258
+ color: var(--vk-text-muted);
1259
+ font-size: 0.875rem;
1260
+ }
1261
+
1262
+ /* ── Spinner ─────────────────────────────── */
1263
+
1264
+ .vk-spinner {
1265
+ display: inline-block;
1266
+ width: 16px;
1267
+ height: 16px;
1268
+ border: 2px solid var(--vk-border);
1269
+ border-top-color: var(--vk-primary);
1270
+ border-radius: 50%;
1271
+ animation: vk-spin 0.6s linear infinite;
1272
+ }
1273
+
1274
+ /* ── Skeleton ────────────────────────────── */
1275
+
1276
+ .vk-skeleton {
1277
+ background: linear-gradient(90deg, var(--vk-surface-muted) 25%, #e2e8f0 50%, var(--vk-surface-muted) 75%);
1278
+ background-size: 200% 100%;
1279
+ animation: vk-skeleton-shimmer 1.8s ease-in-out infinite;
1280
+ border-radius: 8px;
1281
+ }
1282
+
1283
+ /* ── Animations ──────────────────────────── */
1284
+
1285
+ @keyframes vk-fade-in {
1286
+ from { opacity: 0; }
1287
+ to { opacity: 1; }
1288
+ }
1289
+
1290
+ @keyframes vk-slide-up {
1291
+ from { opacity: 0; transform: translateY(12px); }
1292
+ to { opacity: 1; transform: translateY(0); }
1293
+ }
1294
+
1295
+ @keyframes vk-spin {
1296
+ to { transform: rotate(360deg); }
1297
+ }
1298
+
1299
+ @keyframes vk-skeleton-shimmer {
1300
+ 0% { background-position: 200% 0; }
1301
+ 100% { background-position: -200% 0; }
1302
+ }
1303
+
1304
+ .vk-animate-in {
1305
+ animation: vk-fade-in 0.3s ease-out;
1306
+ }
1307
+
1308
+ .vk-slide-up {
1309
+ animation: vk-slide-up 0.35s ease-out both;
1310
+ }
1311
+
1312
+ /* ── Utility ─────────────────────────────── */
1313
+
1314
+ .vk-sr-only {
1315
+ position: absolute;
1316
+ width: 1px;
1317
+ height: 1px;
1318
+ padding: 0;
1319
+ margin: -1px;
1320
+ overflow: hidden;
1321
+ clip: rect(0, 0, 0, 0);
1322
+ white-space: nowrap;
1323
+ border: 0;
1324
+ }
1325
+