zero-query 1.1.1 → 1.2.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.
Files changed (154) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +2 -0
  3. package/cli/args.js +33 -33
  4. package/cli/commands/build-api.js +443 -442
  5. package/cli/commands/build.js +254 -247
  6. package/cli/commands/bundle.js +1228 -1224
  7. package/cli/commands/create.js +137 -121
  8. package/cli/commands/dev/devtools/index.js +56 -56
  9. package/cli/commands/dev/devtools/js/components.js +49 -49
  10. package/cli/commands/dev/devtools/js/core.js +423 -423
  11. package/cli/commands/dev/devtools/js/elements.js +421 -421
  12. package/cli/commands/dev/devtools/js/network.js +166 -166
  13. package/cli/commands/dev/devtools/js/performance.js +73 -73
  14. package/cli/commands/dev/devtools/js/router.js +105 -105
  15. package/cli/commands/dev/devtools/js/source.js +132 -132
  16. package/cli/commands/dev/devtools/js/stats.js +35 -35
  17. package/cli/commands/dev/devtools/js/tabs.js +79 -79
  18. package/cli/commands/dev/devtools/panel.html +95 -95
  19. package/cli/commands/dev/devtools/styles.css +244 -244
  20. package/cli/commands/dev/index.js +107 -107
  21. package/cli/commands/dev/logger.js +75 -75
  22. package/cli/commands/dev/overlay.js +858 -858
  23. package/cli/commands/dev/server.js +220 -220
  24. package/cli/commands/dev/validator.js +94 -94
  25. package/cli/commands/dev/watcher.js +172 -172
  26. package/cli/help.js +114 -112
  27. package/cli/index.js +52 -52
  28. package/cli/scaffold/default/LICENSE +21 -21
  29. package/cli/scaffold/default/app/app.js +207 -207
  30. package/cli/scaffold/default/app/components/about.js +201 -201
  31. package/cli/scaffold/default/app/components/api-demo.js +143 -143
  32. package/cli/scaffold/default/app/components/contact-card.js +231 -231
  33. package/cli/scaffold/default/app/components/contacts/contacts.css +706 -706
  34. package/cli/scaffold/default/app/components/contacts/contacts.html +200 -200
  35. package/cli/scaffold/default/app/components/contacts/contacts.js +196 -196
  36. package/cli/scaffold/default/app/components/counter.js +127 -127
  37. package/cli/scaffold/default/app/components/home.js +249 -249
  38. package/cli/scaffold/default/app/components/not-found.js +16 -16
  39. package/cli/scaffold/default/app/components/playground/playground.css +115 -115
  40. package/cli/scaffold/default/app/components/playground/playground.html +161 -161
  41. package/cli/scaffold/default/app/components/playground/playground.js +116 -116
  42. package/cli/scaffold/default/app/components/todos.js +225 -225
  43. package/cli/scaffold/default/app/components/toolkit/toolkit.css +97 -97
  44. package/cli/scaffold/default/app/components/toolkit/toolkit.html +146 -146
  45. package/cli/scaffold/default/app/components/toolkit/toolkit.js +280 -280
  46. package/cli/scaffold/default/app/routes.js +15 -15
  47. package/cli/scaffold/default/app/store.js +101 -101
  48. package/cli/scaffold/default/global.css +552 -552
  49. package/cli/scaffold/default/index.html +99 -99
  50. package/cli/scaffold/minimal/app/app.js +85 -85
  51. package/cli/scaffold/minimal/app/components/about.js +68 -68
  52. package/cli/scaffold/minimal/app/components/counter.js +122 -122
  53. package/cli/scaffold/minimal/app/components/home.js +68 -68
  54. package/cli/scaffold/minimal/app/components/not-found.js +16 -16
  55. package/cli/scaffold/minimal/app/routes.js +9 -9
  56. package/cli/scaffold/minimal/app/store.js +36 -36
  57. package/cli/scaffold/minimal/global.css +300 -300
  58. package/cli/scaffold/minimal/index.html +44 -44
  59. package/cli/scaffold/ssr/app/app.js +41 -41
  60. package/cli/scaffold/ssr/app/components/about.js +55 -55
  61. package/cli/scaffold/ssr/app/components/blog/index.js +65 -65
  62. package/cli/scaffold/ssr/app/components/blog/post.js +86 -86
  63. package/cli/scaffold/ssr/app/components/home.js +37 -37
  64. package/cli/scaffold/ssr/app/components/not-found.js +15 -15
  65. package/cli/scaffold/ssr/app/routes.js +8 -8
  66. package/cli/scaffold/ssr/global.css +228 -228
  67. package/cli/scaffold/ssr/index.html +37 -37
  68. package/cli/scaffold/ssr/package.json +8 -8
  69. package/cli/scaffold/ssr/server/data/posts.js +144 -144
  70. package/cli/scaffold/ssr/server/index.js +213 -213
  71. package/cli/scaffold/webrtc/app/app.js +11 -0
  72. package/cli/scaffold/webrtc/app/components/video-room.js +295 -0
  73. package/cli/scaffold/webrtc/app/lib/room.js +252 -0
  74. package/cli/scaffold/webrtc/assets/.gitkeep +0 -0
  75. package/cli/scaffold/webrtc/global.css +250 -0
  76. package/cli/scaffold/webrtc/index.html +21 -0
  77. package/cli/utils.js +305 -287
  78. package/dist/API.md +661 -0
  79. package/dist/zquery.dist.zip +0 -0
  80. package/dist/zquery.js +10313 -6614
  81. package/dist/zquery.min.js +8 -631
  82. package/index.d.ts +570 -371
  83. package/index.js +311 -240
  84. package/package.json +76 -70
  85. package/src/component.js +1709 -1691
  86. package/src/core.js +921 -921
  87. package/src/diff.js +497 -497
  88. package/src/errors.js +209 -209
  89. package/src/expression.js +922 -922
  90. package/src/http.js +242 -242
  91. package/src/package.json +1 -1
  92. package/src/reactive.js +255 -255
  93. package/src/router.js +843 -843
  94. package/src/ssr.js +418 -418
  95. package/src/store.js +318 -318
  96. package/src/utils.js +515 -515
  97. package/src/webrtc/e2ee.js +351 -0
  98. package/src/webrtc/errors.js +116 -0
  99. package/src/webrtc/ice.js +301 -0
  100. package/src/webrtc/index.js +131 -0
  101. package/src/webrtc/joinToken.js +119 -0
  102. package/src/webrtc/observe.js +172 -0
  103. package/src/webrtc/peer.js +351 -0
  104. package/src/webrtc/reactive.js +268 -0
  105. package/src/webrtc/room.js +625 -0
  106. package/src/webrtc/sdp.js +302 -0
  107. package/src/webrtc/sfu/index.js +43 -0
  108. package/src/webrtc/sfu/livekit.js +131 -0
  109. package/src/webrtc/sfu/mediasoup.js +150 -0
  110. package/src/webrtc/signaling.js +373 -0
  111. package/src/webrtc/turn.js +237 -0
  112. package/tests/_helpers/webrtcFakes.js +289 -0
  113. package/tests/audit.test.js +4158 -4158
  114. package/tests/cli.test.js +1136 -1103
  115. package/tests/compare.test.js +497 -486
  116. package/tests/component.test.js +3969 -3938
  117. package/tests/core.test.js +1910 -1910
  118. package/tests/dev-server.test.js +489 -489
  119. package/tests/diff.test.js +1416 -1416
  120. package/tests/docs.test.js +1664 -1650
  121. package/tests/electron-features.test.js +864 -864
  122. package/tests/errors.test.js +619 -619
  123. package/tests/expression.test.js +1056 -1056
  124. package/tests/http.test.js +648 -648
  125. package/tests/reactive.test.js +819 -819
  126. package/tests/router.test.js +2327 -2327
  127. package/tests/ssr.test.js +870 -870
  128. package/tests/store.test.js +830 -830
  129. package/tests/test-minifier.js +153 -153
  130. package/tests/test-ssr.js +27 -27
  131. package/tests/utils.test.js +1377 -1377
  132. package/tests/webrtc/e2ee.test.js +283 -0
  133. package/tests/webrtc/ice.test.js +202 -0
  134. package/tests/webrtc/joinToken.test.js +89 -0
  135. package/tests/webrtc/observe.test.js +111 -0
  136. package/tests/webrtc/peer.test.js +373 -0
  137. package/tests/webrtc/reactive.test.js +235 -0
  138. package/tests/webrtc/room.test.js +406 -0
  139. package/tests/webrtc/sdp.test.js +151 -0
  140. package/tests/webrtc/sfu-livekit.test.js +119 -0
  141. package/tests/webrtc/sfu.test.js +160 -0
  142. package/tests/webrtc/signaling.test.js +251 -0
  143. package/tests/webrtc/turn.test.js +256 -0
  144. package/types/collection.d.ts +383 -383
  145. package/types/component.d.ts +186 -186
  146. package/types/errors.d.ts +135 -135
  147. package/types/http.d.ts +92 -92
  148. package/types/misc.d.ts +201 -201
  149. package/types/reactive.d.ts +98 -98
  150. package/types/router.d.ts +190 -190
  151. package/types/ssr.d.ts +102 -102
  152. package/types/store.d.ts +146 -146
  153. package/types/utils.d.ts +245 -245
  154. package/types/webrtc.d.ts +653 -0
@@ -1,706 +1,706 @@
1
- /* contacts.css - scoped styles for contacts-page component
2
- *
3
- * Loaded via styleUrl - these styles are automatically scoped
4
- * to the contacts-page component by zQuery.
5
- */
6
-
7
- /* -- Toolbar -- */
8
- .ct-bar {
9
- display: flex;
10
- align-items: center;
11
- justify-content: space-between;
12
- gap: 0.75rem;
13
- flex-wrap: wrap;
14
- margin-bottom: 1rem;
15
- }
16
-
17
- .ct-bar-left {
18
- display: flex;
19
- align-items: center;
20
- gap: 0.75rem;
21
- }
22
-
23
- .ct-bar-right {
24
- display: flex;
25
- align-items: center;
26
- gap: 0.5rem;
27
- }
28
-
29
- .ct-badges {
30
- display: flex;
31
- gap: 0.4rem;
32
- }
33
-
34
- .ct-badge {
35
- display: inline-flex;
36
- align-items: center;
37
- gap: 0.25rem;
38
- padding: 0.2rem 0.55rem;
39
- border-radius: 999px;
40
- font-size: 0.75rem;
41
- color: var(--text-muted);
42
- background: var(--bg-hover);
43
- border: 1px solid var(--border);
44
- }
45
-
46
- .ct-badge strong {
47
- color: var(--text);
48
- font-variant-numeric: tabular-nums;
49
- }
50
-
51
- .ct-badge-accent {
52
- border-color: rgba(88, 166, 255, 0.2);
53
- background: rgba(88, 166, 255, 0.06);
54
- }
55
-
56
- .ct-badge-accent strong {
57
- color: var(--accent);
58
- }
59
-
60
- .ct-search {
61
- padding: 0.4rem 0.75rem;
62
- font-size: 0.82rem;
63
- background: var(--bg-surface);
64
- border: 1px solid var(--border);
65
- border-radius: var(--radius);
66
- color: var(--text);
67
- outline: none;
68
- width: 160px;
69
- font-family: inherit;
70
- transition: border-color 0.15s ease, box-shadow 0.15s ease;
71
- }
72
-
73
- .ct-search:focus {
74
- border-color: var(--accent);
75
- box-shadow: 0 0 0 2px rgba(88, 166, 255, 0.1);
76
- }
77
-
78
- /* -- Filter chips -- */
79
- .ct-chips {
80
- display: flex;
81
- gap: 0.35rem;
82
- margin-bottom: 1rem;
83
- flex-wrap: wrap;
84
- }
85
-
86
- .ct-chip {
87
- padding: 0.25rem 0.7rem;
88
- font-size: 0.75rem;
89
- font-weight: 500;
90
- border-radius: 999px;
91
- border: 1px solid var(--border);
92
- background: transparent;
93
- color: var(--text-muted);
94
- cursor: pointer;
95
- font-family: inherit;
96
- transition: all 0.12s ease;
97
- }
98
-
99
- .ct-chip:hover {
100
- border-color: var(--accent);
101
- color: var(--text);
102
- }
103
-
104
- .ct-chip.active {
105
- background: var(--accent-soft);
106
- border-color: var(--accent);
107
- color: var(--accent);
108
- font-weight: 600;
109
- }
110
-
111
- /* -- Buttons -- */
112
- .ct-btn {
113
- display: inline-flex;
114
- align-items: center;
115
- gap: 0.3rem;
116
- padding: 0.45rem 1rem;
117
- font-size: 0.82rem;
118
- font-weight: 500;
119
- font-family: inherit;
120
- border: none;
121
- border-radius: var(--radius);
122
- cursor: pointer;
123
- transition: all 0.12s ease;
124
- }
125
-
126
- .ct-btn:active { transform: scale(0.97); }
127
-
128
- .ct-btn-accent {
129
- background: var(--accent);
130
- color: #fff;
131
- }
132
-
133
- .ct-btn-accent:hover {
134
- background: var(--accent-hover);
135
- box-shadow: 0 0 16px rgba(88, 166, 255, 0.15);
136
- }
137
-
138
- .ct-btn-add {
139
- white-space: nowrap;
140
- flex-shrink: 0;
141
- }
142
-
143
- .ct-btn-ghost {
144
- background: transparent;
145
- color: var(--text-muted);
146
- border: 1px solid var(--border);
147
- }
148
-
149
- .ct-btn-ghost:hover {
150
- color: var(--text);
151
- border-color: var(--text-muted);
152
- background: var(--bg-hover);
153
- }
154
-
155
- .ct-btn-danger {
156
- background: var(--danger);
157
- color: #fff;
158
- }
159
-
160
- .ct-btn-danger:hover {
161
- opacity: 0.85;
162
- }
163
-
164
- .ct-btn-sm {
165
- padding: 0.3rem 0.7rem;
166
- font-size: 0.78rem;
167
- }
168
-
169
- /* -- Contact Grid -- */
170
- .ct-grid {
171
- display: grid;
172
- grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
173
- gap: 0.85rem;
174
- }
175
-
176
- .ct-card {
177
- position: relative;
178
- display: flex;
179
- flex-direction: column;
180
- align-items: center;
181
- text-align: center;
182
- padding: 1.5rem 1rem 1.15rem;
183
- background: var(--bg-card);
184
- border: 1px solid var(--border);
185
- border-radius: var(--radius-lg);
186
- cursor: pointer;
187
- transition: all 0.18s ease;
188
- overflow: hidden;
189
- backdrop-filter: blur(8px);
190
- -webkit-backdrop-filter: blur(8px);
191
- }
192
-
193
- .ct-card:hover {
194
- border-color: rgba(88, 166, 255, 0.25);
195
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18), 0 0 0 1px rgba(88, 166, 255, 0.06);
196
- transform: translateY(-2px);
197
- }
198
-
199
- .ct-card-fav {
200
- border-color: rgba(88, 166, 255, 0.15);
201
- }
202
-
203
- /* Status bar at top */
204
- .ct-card-status {
205
- position: absolute;
206
- top: 0;
207
- left: 0;
208
- right: 0;
209
- height: 3px;
210
- background: var(--text-muted);
211
- opacity: 0.3;
212
- transition: background 0.3s ease, box-shadow 0.3s ease, opacity 0.3s ease;
213
- }
214
-
215
- .ct-card-status-online {
216
- background: var(--success);
217
- opacity: 1;
218
- box-shadow: 0 0 8px rgba(63, 185, 80, 0.4);
219
- }
220
-
221
- .ct-card-status-away {
222
- background: var(--warning);
223
- opacity: 0.8;
224
- }
225
-
226
- .ct-card-status-offline {
227
- background: var(--text-muted);
228
- opacity: 0.2;
229
- }
230
-
231
- /* Card avatar */
232
- .ct-card-avatar {
233
- width: 52px;
234
- height: 52px;
235
- border-radius: 50%;
236
- display: flex;
237
- align-items: center;
238
- justify-content: center;
239
- font-weight: 700;
240
- font-size: 1.15rem;
241
- color: #fff;
242
- text-transform: uppercase;
243
- margin-bottom: 0.65rem;
244
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
245
- }
246
-
247
- /* Card text */
248
- .ct-card-info {
249
- display: contents;
250
- }
251
-
252
- .ct-card-name {
253
- font-size: 0.9rem;
254
- font-weight: 600;
255
- margin-bottom: 0.1rem;
256
- white-space: nowrap;
257
- overflow: hidden;
258
- text-overflow: ellipsis;
259
- max-width: 100%;
260
- }
261
-
262
- .ct-card-email {
263
- font-size: 0.75rem;
264
- color: var(--text-muted);
265
- margin-bottom: 0.6rem;
266
- white-space: nowrap;
267
- overflow: hidden;
268
- text-overflow: ellipsis;
269
- max-width: 100%;
270
- }
271
-
272
- .ct-card-role {
273
- font-size: 0.68rem;
274
- font-weight: 600;
275
- padding: 0.18rem 0.55rem;
276
- border-radius: 999px;
277
- text-transform: uppercase;
278
- letter-spacing: 0.04em;
279
- }
280
-
281
- /* Role colors */
282
- .ct-role-developer { background: rgba(96, 165, 250, 0.12); color: #60a5fa; }
283
- .ct-role-designer { background: rgba(168, 85, 247, 0.12); color: #a855f7; }
284
- .ct-role-manager { background: rgba(52, 211, 153, 0.12); color: #34d399; }
285
- .ct-role-qa { background: rgba(251, 191, 36, 0.12); color: #fbbf24; }
286
-
287
- /* Fav button on card */
288
- .ct-card-fav-btn {
289
- position: absolute;
290
- top: 0.55rem;
291
- right: 0.55rem;
292
- background: none;
293
- border: none;
294
- font-size: 1rem;
295
- cursor: pointer;
296
- color: var(--text-muted);
297
- opacity: 0;
298
- transition: all 0.12s ease;
299
- line-height: 1;
300
- padding: 0.15rem;
301
- }
302
-
303
- .ct-card:hover .ct-card-fav-btn {
304
- opacity: 0.6;
305
- }
306
-
307
- .ct-card-fav-btn:hover {
308
- opacity: 1 !important;
309
- transform: scale(1.2);
310
- }
311
-
312
- .ct-card-fav-btn.is-fav {
313
- color: var(--accent);
314
- opacity: 1;
315
- }
316
-
317
- /* -- Empty -- */
318
- .ct-empty-card {
319
- text-align: center;
320
- padding: 3rem 1rem;
321
- color: var(--text-muted);
322
- }
323
-
324
- .ct-empty-icon {
325
- margin-bottom: 0.75rem;
326
- }
327
-
328
- .ct-empty-card p {
329
- font-size: 0.9rem;
330
- }
331
-
332
- /* ═══ Modal (shared) ═══ */
333
- .ct-overlay {
334
- position: fixed;
335
- inset: 0;
336
- background: rgba(0, 0, 0, 0.55);
337
- backdrop-filter: blur(4px);
338
- -webkit-backdrop-filter: blur(4px);
339
- z-index: 200;
340
- display: flex;
341
- align-items: center;
342
- justify-content: center;
343
- animation: ct-fade-in 0.15s ease;
344
- }
345
-
346
- @keyframes ct-fade-in {
347
- from { opacity: 0; }
348
- to { opacity: 1; }
349
- }
350
-
351
- .ct-modal {
352
- position: relative;
353
- width: 420px;
354
- max-width: calc(100vw - 2rem);
355
- max-height: calc(100vh - 4rem);
356
- overflow-y: auto;
357
- background: var(--bg-surface);
358
- border: 1px solid var(--border);
359
- border-radius: var(--radius-lg);
360
- box-shadow: 0 24px 64px rgba(0, 0, 0, 0.35);
361
- animation: ct-modal-in 0.2s var(--ease-out);
362
- }
363
-
364
- .ct-modal-form {
365
- width: 480px;
366
- }
367
-
368
- @keyframes ct-modal-in {
369
- from { opacity: 0; transform: scale(0.95) translateY(10px); }
370
- to { opacity: 1; transform: scale(1) translateY(0); }
371
- }
372
-
373
- .ct-modal-strip {
374
- height: 4px;
375
- border-radius: var(--radius-lg) var(--radius-lg) 0 0;
376
- transition: background 0.3s ease, box-shadow 0.3s ease, opacity 0.3s ease;
377
- }
378
-
379
- .ct-modal-strip-online { background: var(--success); box-shadow: 0 0 12px rgba(63, 185, 80, 0.3); }
380
- .ct-modal-strip-away { background: var(--warning); }
381
- .ct-modal-strip-offline { background: var(--text-muted); opacity: 0.3; }
382
- .ct-modal-strip-accent { background: var(--accent); box-shadow: 0 0 12px rgba(88, 166, 255, 0.2); }
383
-
384
- .ct-modal-close {
385
- position: absolute;
386
- top: 0.75rem;
387
- right: 0.75rem;
388
- width: 28px;
389
- height: 28px;
390
- border-radius: 50%;
391
- border: none;
392
- background: var(--bg-hover);
393
- color: var(--text-muted);
394
- font-size: 0.85rem;
395
- cursor: pointer;
396
- display: flex;
397
- align-items: center;
398
- justify-content: center;
399
- transition: all 0.12s ease;
400
- z-index: 1;
401
- }
402
-
403
- .ct-modal-close:hover {
404
- background: var(--danger);
405
- color: #fff;
406
- }
407
-
408
- /* -- Add-contact modal heading -- */
409
- .ct-modal-heading {
410
- padding: 1.25rem 1.5rem 0;
411
- }
412
-
413
- .ct-modal-heading h2 {
414
- font-size: 1.1rem;
415
- font-weight: 700;
416
- margin: 0 0 0.2rem;
417
- }
418
-
419
- .ct-modal-heading .muted {
420
- font-size: 0.82rem;
421
- color: var(--text-muted);
422
- }
423
-
424
- /* -- Form inside modal -- */
425
- .ct-form {
426
- display: flex;
427
- flex-direction: column;
428
- gap: 0.85rem;
429
- padding: 1rem 1.5rem 1.25rem;
430
- }
431
-
432
- .ct-form-row {
433
- display: flex;
434
- gap: 0.75rem;
435
- }
436
-
437
- .ct-form-grow {
438
- flex: 1;
439
- }
440
-
441
- .ct-form-field {
442
- display: flex;
443
- flex-direction: column;
444
- gap: 0.3rem;
445
- position: relative;
446
- }
447
-
448
- .ct-form-field label {
449
- font-size: 0.75rem;
450
- font-weight: 600;
451
- color: var(--text-muted);
452
- text-transform: uppercase;
453
- letter-spacing: 0.04em;
454
- }
455
-
456
- .ct-req { color: var(--danger); }
457
- .ct-opt { font-weight: 400; text-transform: none; font-size: 0.7rem; letter-spacing: 0; opacity: 0.6; }
458
-
459
- .ct-input {
460
- padding: 0.5rem 0.75rem;
461
- font-size: 0.85rem;
462
- background: var(--bg);
463
- border: 1px solid var(--border);
464
- border-radius: var(--radius);
465
- color: var(--text);
466
- font-family: inherit;
467
- outline: none;
468
- transition: border-color 0.15s ease, box-shadow 0.15s ease;
469
- }
470
-
471
- .ct-input:focus {
472
- border-color: var(--accent);
473
- box-shadow: 0 0 0 2px rgba(88, 166, 255, 0.1);
474
- }
475
-
476
- .ct-err {
477
- color: var(--danger);
478
- font-size: 0.72rem;
479
- position: absolute;
480
- bottom: -0.95rem;
481
- left: 0;
482
- }
483
-
484
- .ct-form-actions {
485
- display: flex;
486
- gap: 0.5rem;
487
- justify-content: flex-end;
488
- padding-top: 0.35rem;
489
- }
490
-
491
- /* -- Detail modal: profile -- */
492
- .ct-modal-profile {
493
- display: flex;
494
- flex-direction: column;
495
- align-items: center;
496
- padding: 1.75rem 1.5rem 1rem;
497
- position: relative;
498
- }
499
-
500
- .ct-modal-avatar {
501
- width: 72px;
502
- height: 72px;
503
- border-radius: 50%;
504
- display: flex;
505
- align-items: center;
506
- justify-content: center;
507
- font-weight: 700;
508
- font-size: 1.6rem;
509
- color: #fff;
510
- text-transform: uppercase;
511
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
512
- margin-bottom: 0.75rem;
513
- position: relative;
514
- }
515
-
516
- .ct-modal-status-dot {
517
- width: 14px;
518
- height: 14px;
519
- border-radius: 50%;
520
- border: 3px solid var(--bg-surface);
521
- position: absolute;
522
- top: calc(1.75rem + 56px);
523
- left: calc(50% + 22px);
524
- transition: background 0.3s ease, box-shadow 0.3s ease;
525
- }
526
-
527
- .ct-dot-online { background: var(--success); box-shadow: 0 0 8px rgba(63, 185, 80, 0.5); }
528
- .ct-dot-away { background: var(--warning); }
529
- .ct-dot-offline { background: var(--text-muted); }
530
-
531
- .ct-modal-profile h2 {
532
- font-size: 1.2rem;
533
- font-weight: 700;
534
- margin: 0 0 0.25rem;
535
- }
536
-
537
- .ct-modal-role {
538
- font-size: 0.72rem;
539
- font-weight: 600;
540
- padding: 0.2rem 0.6rem;
541
- border-radius: 999px;
542
- text-transform: uppercase;
543
- letter-spacing: 0.04em;
544
- }
545
-
546
- /* Detail fields */
547
- .ct-modal-details {
548
- display: grid;
549
- grid-template-columns: 1fr 1fr;
550
- gap: 0.75rem;
551
- padding: 0 1.5rem;
552
- margin-top: 0.5rem;
553
- }
554
-
555
- .ct-modal-field {
556
- display: flex;
557
- flex-direction: column;
558
- gap: 0.15rem;
559
- }
560
-
561
- .ct-modal-label {
562
- font-size: 0.68rem;
563
- font-weight: 600;
564
- text-transform: uppercase;
565
- letter-spacing: 0.04em;
566
- color: var(--text-muted);
567
- }
568
-
569
- .ct-modal-value {
570
- font-size: 0.85rem;
571
- color: var(--text);
572
- word-break: break-word;
573
- }
574
-
575
- .ct-modal-status-text {
576
- text-transform: capitalize;
577
- transition: color 0.3s ease;
578
- }
579
-
580
- .ct-modal-bio {
581
- padding: 0.75rem 1.5rem 0;
582
- }
583
-
584
- .ct-modal-bio p {
585
- font-size: 0.85rem;
586
- color: var(--text-muted);
587
- line-height: 1.5;
588
- margin-top: 0.2rem;
589
- }
590
-
591
- /* Modal actions */
592
- .ct-modal-actions {
593
- display: flex;
594
- gap: 0.4rem;
595
- padding: 1rem 1.5rem 1.25rem;
596
- flex-wrap: wrap;
597
- }
598
-
599
- .ct-confirm-group {
600
- display: inline-flex;
601
- align-items: center;
602
- gap: 0.3rem;
603
- }
604
-
605
- .ct-confirm-text {
606
- font-size: 0.78rem;
607
- color: var(--danger);
608
- font-weight: 500;
609
- }
610
-
611
- /* -- Responsive -- */
612
- @media (max-width: 768px) {
613
- .ct-bar {
614
- flex-direction: column;
615
- align-items: stretch;
616
- }
617
-
618
- .ct-bar-left,
619
- .ct-bar-right {
620
- justify-content: space-between;
621
- }
622
-
623
- .ct-search {
624
- flex: 1;
625
- }
626
-
627
- .ct-form-row {
628
- flex-direction: column;
629
- }
630
-
631
- .ct-grid {
632
- grid-template-columns: 1fr;
633
- gap: 0.5rem;
634
- }
635
-
636
- /* Compact horizontal card layout */
637
- .ct-card {
638
- flex-direction: row;
639
- align-items: center;
640
- text-align: left;
641
- padding: 0.75rem 1rem;
642
- gap: 0.75rem;
643
- }
644
-
645
- .ct-card:hover {
646
- transform: none;
647
- }
648
-
649
- .ct-card-status {
650
- top: 0;
651
- bottom: 0;
652
- left: 0;
653
- right: auto;
654
- width: 3px;
655
- height: auto;
656
- }
657
-
658
- .ct-card-avatar {
659
- width: 40px;
660
- height: 40px;
661
- font-size: 0.95rem;
662
- margin-bottom: 0;
663
- flex-shrink: 0;
664
- }
665
-
666
- .ct-card-info {
667
- display: flex;
668
- flex-direction: column;
669
- align-items: flex-start;
670
- min-width: 0;
671
- flex: 1;
672
- }
673
-
674
- .ct-card-name {
675
- font-size: 0.88rem;
676
- margin-bottom: 0;
677
- }
678
-
679
- .ct-card-email {
680
- margin-bottom: 0.25rem;
681
- }
682
-
683
- .ct-card-fav-btn {
684
- position: static;
685
- opacity: 1;
686
- flex-shrink: 0;
687
- margin-left: auto;
688
- }
689
-
690
- .ct-modal,
691
- .ct-modal-form {
692
- width: calc(100vw - 1.5rem);
693
- }
694
-
695
- .ct-modal-details {
696
- grid-template-columns: 1fr;
697
- }
698
- }
699
-
700
- @media (max-width: 480px) {
701
- .ct-card-avatar {
702
- width: 36px;
703
- height: 36px;
704
- font-size: 0.85rem;
705
- }
706
- }
1
+ /* contacts.css - scoped styles for contacts-page component
2
+ *
3
+ * Loaded via styleUrl - these styles are automatically scoped
4
+ * to the contacts-page component by zQuery.
5
+ */
6
+
7
+ /* -- Toolbar -- */
8
+ .ct-bar {
9
+ display: flex;
10
+ align-items: center;
11
+ justify-content: space-between;
12
+ gap: 0.75rem;
13
+ flex-wrap: wrap;
14
+ margin-bottom: 1rem;
15
+ }
16
+
17
+ .ct-bar-left {
18
+ display: flex;
19
+ align-items: center;
20
+ gap: 0.75rem;
21
+ }
22
+
23
+ .ct-bar-right {
24
+ display: flex;
25
+ align-items: center;
26
+ gap: 0.5rem;
27
+ }
28
+
29
+ .ct-badges {
30
+ display: flex;
31
+ gap: 0.4rem;
32
+ }
33
+
34
+ .ct-badge {
35
+ display: inline-flex;
36
+ align-items: center;
37
+ gap: 0.25rem;
38
+ padding: 0.2rem 0.55rem;
39
+ border-radius: 999px;
40
+ font-size: 0.75rem;
41
+ color: var(--text-muted);
42
+ background: var(--bg-hover);
43
+ border: 1px solid var(--border);
44
+ }
45
+
46
+ .ct-badge strong {
47
+ color: var(--text);
48
+ font-variant-numeric: tabular-nums;
49
+ }
50
+
51
+ .ct-badge-accent {
52
+ border-color: rgba(88, 166, 255, 0.2);
53
+ background: rgba(88, 166, 255, 0.06);
54
+ }
55
+
56
+ .ct-badge-accent strong {
57
+ color: var(--accent);
58
+ }
59
+
60
+ .ct-search {
61
+ padding: 0.4rem 0.75rem;
62
+ font-size: 0.82rem;
63
+ background: var(--bg-surface);
64
+ border: 1px solid var(--border);
65
+ border-radius: var(--radius);
66
+ color: var(--text);
67
+ outline: none;
68
+ width: 160px;
69
+ font-family: inherit;
70
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
71
+ }
72
+
73
+ .ct-search:focus {
74
+ border-color: var(--accent);
75
+ box-shadow: 0 0 0 2px rgba(88, 166, 255, 0.1);
76
+ }
77
+
78
+ /* -- Filter chips -- */
79
+ .ct-chips {
80
+ display: flex;
81
+ gap: 0.35rem;
82
+ margin-bottom: 1rem;
83
+ flex-wrap: wrap;
84
+ }
85
+
86
+ .ct-chip {
87
+ padding: 0.25rem 0.7rem;
88
+ font-size: 0.75rem;
89
+ font-weight: 500;
90
+ border-radius: 999px;
91
+ border: 1px solid var(--border);
92
+ background: transparent;
93
+ color: var(--text-muted);
94
+ cursor: pointer;
95
+ font-family: inherit;
96
+ transition: all 0.12s ease;
97
+ }
98
+
99
+ .ct-chip:hover {
100
+ border-color: var(--accent);
101
+ color: var(--text);
102
+ }
103
+
104
+ .ct-chip.active {
105
+ background: var(--accent-soft);
106
+ border-color: var(--accent);
107
+ color: var(--accent);
108
+ font-weight: 600;
109
+ }
110
+
111
+ /* -- Buttons -- */
112
+ .ct-btn {
113
+ display: inline-flex;
114
+ align-items: center;
115
+ gap: 0.3rem;
116
+ padding: 0.45rem 1rem;
117
+ font-size: 0.82rem;
118
+ font-weight: 500;
119
+ font-family: inherit;
120
+ border: none;
121
+ border-radius: var(--radius);
122
+ cursor: pointer;
123
+ transition: all 0.12s ease;
124
+ }
125
+
126
+ .ct-btn:active { transform: scale(0.97); }
127
+
128
+ .ct-btn-accent {
129
+ background: var(--accent);
130
+ color: #fff;
131
+ }
132
+
133
+ .ct-btn-accent:hover {
134
+ background: var(--accent-hover);
135
+ box-shadow: 0 0 16px rgba(88, 166, 255, 0.15);
136
+ }
137
+
138
+ .ct-btn-add {
139
+ white-space: nowrap;
140
+ flex-shrink: 0;
141
+ }
142
+
143
+ .ct-btn-ghost {
144
+ background: transparent;
145
+ color: var(--text-muted);
146
+ border: 1px solid var(--border);
147
+ }
148
+
149
+ .ct-btn-ghost:hover {
150
+ color: var(--text);
151
+ border-color: var(--text-muted);
152
+ background: var(--bg-hover);
153
+ }
154
+
155
+ .ct-btn-danger {
156
+ background: var(--danger);
157
+ color: #fff;
158
+ }
159
+
160
+ .ct-btn-danger:hover {
161
+ opacity: 0.85;
162
+ }
163
+
164
+ .ct-btn-sm {
165
+ padding: 0.3rem 0.7rem;
166
+ font-size: 0.78rem;
167
+ }
168
+
169
+ /* -- Contact Grid -- */
170
+ .ct-grid {
171
+ display: grid;
172
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
173
+ gap: 0.85rem;
174
+ }
175
+
176
+ .ct-card {
177
+ position: relative;
178
+ display: flex;
179
+ flex-direction: column;
180
+ align-items: center;
181
+ text-align: center;
182
+ padding: 1.5rem 1rem 1.15rem;
183
+ background: var(--bg-card);
184
+ border: 1px solid var(--border);
185
+ border-radius: var(--radius-lg);
186
+ cursor: pointer;
187
+ transition: all 0.18s ease;
188
+ overflow: hidden;
189
+ backdrop-filter: blur(8px);
190
+ -webkit-backdrop-filter: blur(8px);
191
+ }
192
+
193
+ .ct-card:hover {
194
+ border-color: rgba(88, 166, 255, 0.25);
195
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18), 0 0 0 1px rgba(88, 166, 255, 0.06);
196
+ transform: translateY(-2px);
197
+ }
198
+
199
+ .ct-card-fav {
200
+ border-color: rgba(88, 166, 255, 0.15);
201
+ }
202
+
203
+ /* Status bar at top */
204
+ .ct-card-status {
205
+ position: absolute;
206
+ top: 0;
207
+ left: 0;
208
+ right: 0;
209
+ height: 3px;
210
+ background: var(--text-muted);
211
+ opacity: 0.3;
212
+ transition: background 0.3s ease, box-shadow 0.3s ease, opacity 0.3s ease;
213
+ }
214
+
215
+ .ct-card-status-online {
216
+ background: var(--success);
217
+ opacity: 1;
218
+ box-shadow: 0 0 8px rgba(63, 185, 80, 0.4);
219
+ }
220
+
221
+ .ct-card-status-away {
222
+ background: var(--warning);
223
+ opacity: 0.8;
224
+ }
225
+
226
+ .ct-card-status-offline {
227
+ background: var(--text-muted);
228
+ opacity: 0.2;
229
+ }
230
+
231
+ /* Card avatar */
232
+ .ct-card-avatar {
233
+ width: 52px;
234
+ height: 52px;
235
+ border-radius: 50%;
236
+ display: flex;
237
+ align-items: center;
238
+ justify-content: center;
239
+ font-weight: 700;
240
+ font-size: 1.15rem;
241
+ color: #fff;
242
+ text-transform: uppercase;
243
+ margin-bottom: 0.65rem;
244
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
245
+ }
246
+
247
+ /* Card text */
248
+ .ct-card-info {
249
+ display: contents;
250
+ }
251
+
252
+ .ct-card-name {
253
+ font-size: 0.9rem;
254
+ font-weight: 600;
255
+ margin-bottom: 0.1rem;
256
+ white-space: nowrap;
257
+ overflow: hidden;
258
+ text-overflow: ellipsis;
259
+ max-width: 100%;
260
+ }
261
+
262
+ .ct-card-email {
263
+ font-size: 0.75rem;
264
+ color: var(--text-muted);
265
+ margin-bottom: 0.6rem;
266
+ white-space: nowrap;
267
+ overflow: hidden;
268
+ text-overflow: ellipsis;
269
+ max-width: 100%;
270
+ }
271
+
272
+ .ct-card-role {
273
+ font-size: 0.68rem;
274
+ font-weight: 600;
275
+ padding: 0.18rem 0.55rem;
276
+ border-radius: 999px;
277
+ text-transform: uppercase;
278
+ letter-spacing: 0.04em;
279
+ }
280
+
281
+ /* Role colors */
282
+ .ct-role-developer { background: rgba(96, 165, 250, 0.12); color: #60a5fa; }
283
+ .ct-role-designer { background: rgba(168, 85, 247, 0.12); color: #a855f7; }
284
+ .ct-role-manager { background: rgba(52, 211, 153, 0.12); color: #34d399; }
285
+ .ct-role-qa { background: rgba(251, 191, 36, 0.12); color: #fbbf24; }
286
+
287
+ /* Fav button on card */
288
+ .ct-card-fav-btn {
289
+ position: absolute;
290
+ top: 0.55rem;
291
+ right: 0.55rem;
292
+ background: none;
293
+ border: none;
294
+ font-size: 1rem;
295
+ cursor: pointer;
296
+ color: var(--text-muted);
297
+ opacity: 0;
298
+ transition: all 0.12s ease;
299
+ line-height: 1;
300
+ padding: 0.15rem;
301
+ }
302
+
303
+ .ct-card:hover .ct-card-fav-btn {
304
+ opacity: 0.6;
305
+ }
306
+
307
+ .ct-card-fav-btn:hover {
308
+ opacity: 1 !important;
309
+ transform: scale(1.2);
310
+ }
311
+
312
+ .ct-card-fav-btn.is-fav {
313
+ color: var(--accent);
314
+ opacity: 1;
315
+ }
316
+
317
+ /* -- Empty -- */
318
+ .ct-empty-card {
319
+ text-align: center;
320
+ padding: 3rem 1rem;
321
+ color: var(--text-muted);
322
+ }
323
+
324
+ .ct-empty-icon {
325
+ margin-bottom: 0.75rem;
326
+ }
327
+
328
+ .ct-empty-card p {
329
+ font-size: 0.9rem;
330
+ }
331
+
332
+ /* ═══ Modal (shared) ═══ */
333
+ .ct-overlay {
334
+ position: fixed;
335
+ inset: 0;
336
+ background: rgba(0, 0, 0, 0.55);
337
+ backdrop-filter: blur(4px);
338
+ -webkit-backdrop-filter: blur(4px);
339
+ z-index: 200;
340
+ display: flex;
341
+ align-items: center;
342
+ justify-content: center;
343
+ animation: ct-fade-in 0.15s ease;
344
+ }
345
+
346
+ @keyframes ct-fade-in {
347
+ from { opacity: 0; }
348
+ to { opacity: 1; }
349
+ }
350
+
351
+ .ct-modal {
352
+ position: relative;
353
+ width: 420px;
354
+ max-width: calc(100vw - 2rem);
355
+ max-height: calc(100vh - 4rem);
356
+ overflow-y: auto;
357
+ background: var(--bg-surface);
358
+ border: 1px solid var(--border);
359
+ border-radius: var(--radius-lg);
360
+ box-shadow: 0 24px 64px rgba(0, 0, 0, 0.35);
361
+ animation: ct-modal-in 0.2s var(--ease-out);
362
+ }
363
+
364
+ .ct-modal-form {
365
+ width: 480px;
366
+ }
367
+
368
+ @keyframes ct-modal-in {
369
+ from { opacity: 0; transform: scale(0.95) translateY(10px); }
370
+ to { opacity: 1; transform: scale(1) translateY(0); }
371
+ }
372
+
373
+ .ct-modal-strip {
374
+ height: 4px;
375
+ border-radius: var(--radius-lg) var(--radius-lg) 0 0;
376
+ transition: background 0.3s ease, box-shadow 0.3s ease, opacity 0.3s ease;
377
+ }
378
+
379
+ .ct-modal-strip-online { background: var(--success); box-shadow: 0 0 12px rgba(63, 185, 80, 0.3); }
380
+ .ct-modal-strip-away { background: var(--warning); }
381
+ .ct-modal-strip-offline { background: var(--text-muted); opacity: 0.3; }
382
+ .ct-modal-strip-accent { background: var(--accent); box-shadow: 0 0 12px rgba(88, 166, 255, 0.2); }
383
+
384
+ .ct-modal-close {
385
+ position: absolute;
386
+ top: 0.75rem;
387
+ right: 0.75rem;
388
+ width: 28px;
389
+ height: 28px;
390
+ border-radius: 50%;
391
+ border: none;
392
+ background: var(--bg-hover);
393
+ color: var(--text-muted);
394
+ font-size: 0.85rem;
395
+ cursor: pointer;
396
+ display: flex;
397
+ align-items: center;
398
+ justify-content: center;
399
+ transition: all 0.12s ease;
400
+ z-index: 1;
401
+ }
402
+
403
+ .ct-modal-close:hover {
404
+ background: var(--danger);
405
+ color: #fff;
406
+ }
407
+
408
+ /* -- Add-contact modal heading -- */
409
+ .ct-modal-heading {
410
+ padding: 1.25rem 1.5rem 0;
411
+ }
412
+
413
+ .ct-modal-heading h2 {
414
+ font-size: 1.1rem;
415
+ font-weight: 700;
416
+ margin: 0 0 0.2rem;
417
+ }
418
+
419
+ .ct-modal-heading .muted {
420
+ font-size: 0.82rem;
421
+ color: var(--text-muted);
422
+ }
423
+
424
+ /* -- Form inside modal -- */
425
+ .ct-form {
426
+ display: flex;
427
+ flex-direction: column;
428
+ gap: 0.85rem;
429
+ padding: 1rem 1.5rem 1.25rem;
430
+ }
431
+
432
+ .ct-form-row {
433
+ display: flex;
434
+ gap: 0.75rem;
435
+ }
436
+
437
+ .ct-form-grow {
438
+ flex: 1;
439
+ }
440
+
441
+ .ct-form-field {
442
+ display: flex;
443
+ flex-direction: column;
444
+ gap: 0.3rem;
445
+ position: relative;
446
+ }
447
+
448
+ .ct-form-field label {
449
+ font-size: 0.75rem;
450
+ font-weight: 600;
451
+ color: var(--text-muted);
452
+ text-transform: uppercase;
453
+ letter-spacing: 0.04em;
454
+ }
455
+
456
+ .ct-req { color: var(--danger); }
457
+ .ct-opt { font-weight: 400; text-transform: none; font-size: 0.7rem; letter-spacing: 0; opacity: 0.6; }
458
+
459
+ .ct-input {
460
+ padding: 0.5rem 0.75rem;
461
+ font-size: 0.85rem;
462
+ background: var(--bg);
463
+ border: 1px solid var(--border);
464
+ border-radius: var(--radius);
465
+ color: var(--text);
466
+ font-family: inherit;
467
+ outline: none;
468
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
469
+ }
470
+
471
+ .ct-input:focus {
472
+ border-color: var(--accent);
473
+ box-shadow: 0 0 0 2px rgba(88, 166, 255, 0.1);
474
+ }
475
+
476
+ .ct-err {
477
+ color: var(--danger);
478
+ font-size: 0.72rem;
479
+ position: absolute;
480
+ bottom: -0.95rem;
481
+ left: 0;
482
+ }
483
+
484
+ .ct-form-actions {
485
+ display: flex;
486
+ gap: 0.5rem;
487
+ justify-content: flex-end;
488
+ padding-top: 0.35rem;
489
+ }
490
+
491
+ /* -- Detail modal: profile -- */
492
+ .ct-modal-profile {
493
+ display: flex;
494
+ flex-direction: column;
495
+ align-items: center;
496
+ padding: 1.75rem 1.5rem 1rem;
497
+ position: relative;
498
+ }
499
+
500
+ .ct-modal-avatar {
501
+ width: 72px;
502
+ height: 72px;
503
+ border-radius: 50%;
504
+ display: flex;
505
+ align-items: center;
506
+ justify-content: center;
507
+ font-weight: 700;
508
+ font-size: 1.6rem;
509
+ color: #fff;
510
+ text-transform: uppercase;
511
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
512
+ margin-bottom: 0.75rem;
513
+ position: relative;
514
+ }
515
+
516
+ .ct-modal-status-dot {
517
+ width: 14px;
518
+ height: 14px;
519
+ border-radius: 50%;
520
+ border: 3px solid var(--bg-surface);
521
+ position: absolute;
522
+ top: calc(1.75rem + 56px);
523
+ left: calc(50% + 22px);
524
+ transition: background 0.3s ease, box-shadow 0.3s ease;
525
+ }
526
+
527
+ .ct-dot-online { background: var(--success); box-shadow: 0 0 8px rgba(63, 185, 80, 0.5); }
528
+ .ct-dot-away { background: var(--warning); }
529
+ .ct-dot-offline { background: var(--text-muted); }
530
+
531
+ .ct-modal-profile h2 {
532
+ font-size: 1.2rem;
533
+ font-weight: 700;
534
+ margin: 0 0 0.25rem;
535
+ }
536
+
537
+ .ct-modal-role {
538
+ font-size: 0.72rem;
539
+ font-weight: 600;
540
+ padding: 0.2rem 0.6rem;
541
+ border-radius: 999px;
542
+ text-transform: uppercase;
543
+ letter-spacing: 0.04em;
544
+ }
545
+
546
+ /* Detail fields */
547
+ .ct-modal-details {
548
+ display: grid;
549
+ grid-template-columns: 1fr 1fr;
550
+ gap: 0.75rem;
551
+ padding: 0 1.5rem;
552
+ margin-top: 0.5rem;
553
+ }
554
+
555
+ .ct-modal-field {
556
+ display: flex;
557
+ flex-direction: column;
558
+ gap: 0.15rem;
559
+ }
560
+
561
+ .ct-modal-label {
562
+ font-size: 0.68rem;
563
+ font-weight: 600;
564
+ text-transform: uppercase;
565
+ letter-spacing: 0.04em;
566
+ color: var(--text-muted);
567
+ }
568
+
569
+ .ct-modal-value {
570
+ font-size: 0.85rem;
571
+ color: var(--text);
572
+ word-break: break-word;
573
+ }
574
+
575
+ .ct-modal-status-text {
576
+ text-transform: capitalize;
577
+ transition: color 0.3s ease;
578
+ }
579
+
580
+ .ct-modal-bio {
581
+ padding: 0.75rem 1.5rem 0;
582
+ }
583
+
584
+ .ct-modal-bio p {
585
+ font-size: 0.85rem;
586
+ color: var(--text-muted);
587
+ line-height: 1.5;
588
+ margin-top: 0.2rem;
589
+ }
590
+
591
+ /* Modal actions */
592
+ .ct-modal-actions {
593
+ display: flex;
594
+ gap: 0.4rem;
595
+ padding: 1rem 1.5rem 1.25rem;
596
+ flex-wrap: wrap;
597
+ }
598
+
599
+ .ct-confirm-group {
600
+ display: inline-flex;
601
+ align-items: center;
602
+ gap: 0.3rem;
603
+ }
604
+
605
+ .ct-confirm-text {
606
+ font-size: 0.78rem;
607
+ color: var(--danger);
608
+ font-weight: 500;
609
+ }
610
+
611
+ /* -- Responsive -- */
612
+ @media (max-width: 768px) {
613
+ .ct-bar {
614
+ flex-direction: column;
615
+ align-items: stretch;
616
+ }
617
+
618
+ .ct-bar-left,
619
+ .ct-bar-right {
620
+ justify-content: space-between;
621
+ }
622
+
623
+ .ct-search {
624
+ flex: 1;
625
+ }
626
+
627
+ .ct-form-row {
628
+ flex-direction: column;
629
+ }
630
+
631
+ .ct-grid {
632
+ grid-template-columns: 1fr;
633
+ gap: 0.5rem;
634
+ }
635
+
636
+ /* Compact horizontal card layout */
637
+ .ct-card {
638
+ flex-direction: row;
639
+ align-items: center;
640
+ text-align: left;
641
+ padding: 0.75rem 1rem;
642
+ gap: 0.75rem;
643
+ }
644
+
645
+ .ct-card:hover {
646
+ transform: none;
647
+ }
648
+
649
+ .ct-card-status {
650
+ top: 0;
651
+ bottom: 0;
652
+ left: 0;
653
+ right: auto;
654
+ width: 3px;
655
+ height: auto;
656
+ }
657
+
658
+ .ct-card-avatar {
659
+ width: 40px;
660
+ height: 40px;
661
+ font-size: 0.95rem;
662
+ margin-bottom: 0;
663
+ flex-shrink: 0;
664
+ }
665
+
666
+ .ct-card-info {
667
+ display: flex;
668
+ flex-direction: column;
669
+ align-items: flex-start;
670
+ min-width: 0;
671
+ flex: 1;
672
+ }
673
+
674
+ .ct-card-name {
675
+ font-size: 0.88rem;
676
+ margin-bottom: 0;
677
+ }
678
+
679
+ .ct-card-email {
680
+ margin-bottom: 0.25rem;
681
+ }
682
+
683
+ .ct-card-fav-btn {
684
+ position: static;
685
+ opacity: 1;
686
+ flex-shrink: 0;
687
+ margin-left: auto;
688
+ }
689
+
690
+ .ct-modal,
691
+ .ct-modal-form {
692
+ width: calc(100vw - 1.5rem);
693
+ }
694
+
695
+ .ct-modal-details {
696
+ grid-template-columns: 1fr;
697
+ }
698
+ }
699
+
700
+ @media (max-width: 480px) {
701
+ .ct-card-avatar {
702
+ width: 36px;
703
+ height: 36px;
704
+ font-size: 0.85rem;
705
+ }
706
+ }