zero-query 0.9.6 → 0.9.8

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 (59) hide show
  1. package/README.md +36 -8
  2. package/cli/commands/build.js +50 -3
  3. package/cli/commands/create.js +22 -9
  4. package/cli/help.js +2 -0
  5. package/cli/scaffold/default/app/app.js +211 -0
  6. package/cli/scaffold/default/app/components/about.js +201 -0
  7. package/cli/scaffold/default/app/components/api-demo.js +143 -0
  8. package/cli/scaffold/default/app/components/contact-card.js +231 -0
  9. package/cli/scaffold/default/app/components/contacts/contacts.css +706 -0
  10. package/cli/scaffold/default/app/components/contacts/contacts.html +200 -0
  11. package/cli/scaffold/default/app/components/contacts/contacts.js +196 -0
  12. package/cli/scaffold/default/app/components/counter.js +127 -0
  13. package/cli/scaffold/default/app/components/home.js +249 -0
  14. package/cli/scaffold/{app → default/app}/components/not-found.js +2 -2
  15. package/cli/scaffold/default/app/components/playground/playground.css +116 -0
  16. package/cli/scaffold/default/app/components/playground/playground.html +162 -0
  17. package/cli/scaffold/default/app/components/playground/playground.js +117 -0
  18. package/cli/scaffold/default/app/components/todos.js +225 -0
  19. package/cli/scaffold/default/app/components/toolkit/toolkit.css +97 -0
  20. package/cli/scaffold/default/app/components/toolkit/toolkit.html +146 -0
  21. package/cli/scaffold/default/app/components/toolkit/toolkit.js +280 -0
  22. package/cli/scaffold/default/app/routes.js +15 -0
  23. package/cli/scaffold/{app → default/app}/store.js +15 -10
  24. package/cli/scaffold/{global.css → default/global.css} +238 -252
  25. package/cli/scaffold/{index.html → default/index.html} +35 -0
  26. package/cli/scaffold/{app → minimal/app}/app.js +37 -39
  27. package/cli/scaffold/minimal/app/components/about.js +68 -0
  28. package/cli/scaffold/minimal/app/components/counter.js +122 -0
  29. package/cli/scaffold/minimal/app/components/home.js +68 -0
  30. package/cli/scaffold/minimal/app/components/not-found.js +16 -0
  31. package/cli/scaffold/minimal/app/routes.js +9 -0
  32. package/cli/scaffold/minimal/app/store.js +36 -0
  33. package/cli/scaffold/minimal/assets/.gitkeep +0 -0
  34. package/cli/scaffold/minimal/global.css +291 -0
  35. package/cli/scaffold/minimal/index.html +44 -0
  36. package/dist/zquery.dist.zip +0 -0
  37. package/dist/zquery.js +1949 -1894
  38. package/dist/zquery.min.js +2 -2
  39. package/index.d.ts +10 -1
  40. package/index.js +5 -3
  41. package/package.json +1 -1
  42. package/src/component.js +6 -3
  43. package/src/diff.js +15 -2
  44. package/src/http.js +37 -0
  45. package/tests/cli.test.js +304 -0
  46. package/tests/http.test.js +200 -0
  47. package/types/http.d.ts +15 -4
  48. package/cli/scaffold/app/components/about.js +0 -131
  49. package/cli/scaffold/app/components/api-demo.js +0 -103
  50. package/cli/scaffold/app/components/contacts/contacts.css +0 -246
  51. package/cli/scaffold/app/components/contacts/contacts.html +0 -140
  52. package/cli/scaffold/app/components/contacts/contacts.js +0 -153
  53. package/cli/scaffold/app/components/counter.js +0 -85
  54. package/cli/scaffold/app/components/home.js +0 -137
  55. package/cli/scaffold/app/components/todos.js +0 -131
  56. package/cli/scaffold/app/routes.js +0 -13
  57. /package/cli/scaffold/{LICENSE → default/LICENSE} +0 -0
  58. /package/cli/scaffold/{assets → default/assets}/.gitkeep +0 -0
  59. /package/cli/scaffold/{favicon.ico → default/favicon.ico} +0 -0
@@ -6,46 +6,54 @@
6
6
 
7
7
  /* -- Theme Variables -- */
8
8
  :root {
9
- --bg: #13141f;
10
- --bg-surface: #1b1d2e;
11
- --bg-card: #222438;
12
- --bg-hover: #2a2d45;
13
- --border: #2e3150;
14
- --text: #e2e4f0;
15
- --text-muted: #8b8ea8;
16
- --accent: #7c5cfc;
17
- --accent-hover:#9b7eff;
18
- --accent-soft: rgba(124, 92, 252, 0.12);
19
- --success: #34d399;
20
- --danger: #f87171;
21
- --info: #60a5fa;
9
+ --bg: #0d1117;
10
+ --bg-surface: #161b22;
11
+ --bg-card: rgba(22, 27, 34, 0.55);
12
+ --bg-hover: #21262d;
13
+ --border: rgba(48, 54, 61, 0.45);
14
+ --text: #e6edf3;
15
+ --text-muted: #7d8590;
16
+ --accent: #58a6ff;
17
+ --accent-hover:#79c0ff;
18
+ --accent-soft: rgba(88, 166, 255, 0.10);
19
+ --accent-glow: rgba(88, 166, 255, 0.06);
20
+ --success: #3fb950;
21
+ --danger: #f85149;
22
+ --info: #58a6ff;
23
+ --warning: #d29922;
22
24
  --radius: 8px;
23
25
  --radius-lg: 12px;
24
26
  --sidebar-w: 240px;
25
27
  --topbar-h: 56px;
26
28
  --font: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
29
+ --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
27
30
  }
28
31
 
29
32
  [data-theme="light"] {
30
- --bg: #f5f5f9;
33
+ --bg: #f6f8fa;
31
34
  --bg-surface: #ffffff;
32
- --bg-card: #ffffff;
33
- --bg-hover: #f0f0f5;
34
- --border: #e0e0e8;
35
- --text: #1e1e2e;
36
- --text-muted: #6b6e8a;
37
- --accent: #6244e0;
38
- --accent-hover:#7c5cfc;
39
- --accent-soft: rgba(98, 68, 224, 0.08);
40
- --success: #16a34a;
41
- --danger: #dc2626;
42
- --info: #2563eb;
35
+ --bg-card: rgba(255, 255, 255, 0.8);
36
+ --bg-hover: #eaeef2;
37
+ --border: rgba(208, 215, 222, 0.65);
38
+ --text: #1f2328;
39
+ --text-muted: #656d76;
40
+ --accent: #0969da;
41
+ --accent-hover:#0550ae;
42
+ --accent-soft: rgba(9,105,218,0.08);
43
+ --accent-glow: rgba(9,105,218,0.04);
44
+ --success: #1a7f37;
45
+ --danger: #cf222e;
46
+ --info: #0969da;
47
+ --warning: #9a6700;
43
48
  }
44
49
 
45
50
  /* -- Reset -- */
46
51
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
47
-
48
- html { scroll-behavior: smooth; }
52
+ html { scroll-behavior: smooth; scrollbar-width: thin; scrollbar-color: #30363d transparent; }
53
+ ::-webkit-scrollbar { width: 6px; height: 4px; }
54
+ ::-webkit-scrollbar-track { background: transparent; }
55
+ ::-webkit-scrollbar-thumb { background: #30363d; border-radius: 4px; }
56
+ ::-webkit-scrollbar-thumb:hover { background: #484f58; }
49
57
 
50
58
  body {
51
59
  font-family: var(--font);
@@ -56,7 +64,7 @@ body {
56
64
  overflow-x: hidden;
57
65
  }
58
66
 
59
- a { color: var(--accent); text-decoration: none; }
67
+ a { color: var(--accent); text-decoration: none; transition: color .15s; }
60
68
  a:hover { color: var(--accent-hover); }
61
69
  code { background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-size: 0.85em; }
62
70
 
@@ -70,7 +78,7 @@ code { background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-s
70
78
  display: flex;
71
79
  flex-direction: column;
72
80
  z-index: 100;
73
- transition: transform 0.3s ease;
81
+ transition: transform 0.3s var(--ease-out);
74
82
  }
75
83
 
76
84
  .sidebar-header {
@@ -126,6 +134,159 @@ code { background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-s
126
134
  font-size: 0.8rem;
127
135
  }
128
136
 
137
+ /* -- Sidebar Contacts (live status) -- */
138
+ .sidebar-contacts {
139
+ border-top: 1px solid var(--border);
140
+ padding: 0.5rem 0;
141
+ }
142
+
143
+ .sc-header {
144
+ display: flex;
145
+ align-items: center;
146
+ gap: 0.35rem;
147
+ padding: 0.25rem 1.25rem 0.45rem;
148
+ font-size: 0.72rem;
149
+ font-weight: 600;
150
+ text-transform: uppercase;
151
+ letter-spacing: 0.04em;
152
+ color: var(--text-muted);
153
+ }
154
+
155
+ .sc-list {
156
+ display: flex;
157
+ flex-direction: column;
158
+ gap: 1px;
159
+ }
160
+
161
+ .sc-item {
162
+ display: flex;
163
+ align-items: center;
164
+ gap: 0.55rem;
165
+ padding: 0.3rem 1.25rem;
166
+ position: relative;
167
+ cursor: pointer;
168
+ border-radius: var(--radius);
169
+ transition: background 0.15s ease;
170
+ }
171
+
172
+ .sc-item:hover {
173
+ background: var(--bg-hover);
174
+ }
175
+
176
+ .sc-avatar {
177
+ width: 22px;
178
+ height: 22px;
179
+ border-radius: 50%;
180
+ display: flex;
181
+ align-items: center;
182
+ justify-content: center;
183
+ font-size: 0.6rem;
184
+ font-weight: 700;
185
+ color: #fff;
186
+ flex-shrink: 0;
187
+ }
188
+
189
+ .sc-dot {
190
+ width: 7px;
191
+ height: 7px;
192
+ border-radius: 50%;
193
+ flex-shrink: 0;
194
+ margin-left: -14px;
195
+ margin-top: 12px;
196
+ position: relative;
197
+ z-index: 1;
198
+ border: 1.5px solid var(--bg-surface);
199
+ }
200
+
201
+ .sc-dot-online { background: var(--success); box-shadow: 0 0 4px rgba(63, 185, 80, 0.5); }
202
+ .sc-dot-away { background: var(--warning); }
203
+ .sc-dot-offline { background: var(--text-muted); opacity: 0.4; }
204
+
205
+ .sc-name {
206
+ font-size: 0.8rem;
207
+ color: var(--text);
208
+ white-space: nowrap;
209
+ overflow: hidden;
210
+ text-overflow: ellipsis;
211
+ }
212
+
213
+ /* -- Sidebar Stats Panel -- */
214
+ .sidebar-stats {
215
+ border-top: 1px solid var(--border);
216
+ }
217
+
218
+ .sidebar-stats-toggle {
219
+ display: flex;
220
+ align-items: center;
221
+ gap: 0.45rem;
222
+ width: 100%;
223
+ padding: 0.6rem 1.25rem;
224
+ background: none;
225
+ border: none;
226
+ color: var(--text-muted);
227
+ font-size: 0.78rem;
228
+ font-weight: 600;
229
+ font-family: inherit;
230
+ text-transform: uppercase;
231
+ letter-spacing: 0.04em;
232
+ cursor: pointer;
233
+ transition: all 0.15s ease;
234
+ }
235
+
236
+ .sidebar-stats-toggle:hover {
237
+ color: var(--text);
238
+ background: var(--bg-hover);
239
+ }
240
+
241
+ .sidebar-stats-arrow {
242
+ margin-left: auto;
243
+ font-size: 0.7rem;
244
+ transition: transform 0.15s ease;
245
+ }
246
+
247
+ .sidebar-stats-arrow.open {
248
+ transform: rotate(90deg);
249
+ }
250
+
251
+ .sidebar-stats-body {
252
+ padding: 0.25rem 1.25rem 0.65rem;
253
+ }
254
+
255
+ .ss-group-label {
256
+ font-size: 0.68rem;
257
+ font-weight: 600;
258
+ text-transform: uppercase;
259
+ letter-spacing: 0.05em;
260
+ color: var(--text-muted);
261
+ opacity: 0.6;
262
+ padding: 0.4rem 0 0.1rem;
263
+ margin-top: 0.15rem;
264
+ border-top: 1px solid rgba(255,255,255,0.04);
265
+ }
266
+
267
+ .ss-row {
268
+ display: flex;
269
+ justify-content: space-between;
270
+ align-items: center;
271
+ padding: 0.2rem 0;
272
+ }
273
+
274
+ .ss-row.ss-indent {
275
+ padding-left: 0.5rem;
276
+ }
277
+
278
+ .ss-label {
279
+ font-size: 0.78rem;
280
+ color: var(--text-muted);
281
+ }
282
+
283
+ .ss-value {
284
+ font-size: 0.8rem;
285
+ font-weight: 600;
286
+ color: var(--accent);
287
+ font-variant-numeric: tabular-nums;
288
+ }
289
+
129
290
  /* -- Mobile Top Bar -- */
130
291
  .topbar {
131
292
  display: none;
@@ -164,7 +325,7 @@ code { background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-s
164
325
  height: 2px;
165
326
  background: var(--text);
166
327
  border-radius: 2px;
167
- transition: all 0.25s ease;
328
+ transition: all 0.25s var(--ease-out);
168
329
  }
169
330
 
170
331
  .hamburger.active span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
@@ -186,15 +347,16 @@ code { background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-s
186
347
 
187
348
  /* -- Main Content -- */
188
349
  .content {
189
- margin-left: var(--sidebar-w);
190
- padding: 2rem 2.5rem;
350
+ margin-left: auto;
351
+ margin-right: auto;
352
+ padding: 2.5rem 3rem 2.5rem calc(var(--sidebar-w) + 3rem);
353
+ max-width: calc(1010px + var(--sidebar-w));
191
354
  min-height: 100vh;
192
- max-width: 900px;
193
355
  }
194
356
 
195
357
  /* -- Page Header -- */
196
- .page-header { margin-bottom: 1.75rem; }
197
- .page-header h1 { font-size: 1.75rem; font-weight: 700; margin-bottom: 0.25rem; }
358
+ .page-header { margin-bottom: 2rem; }
359
+ .page-header h1 { font-size: 1.85rem; font-weight: 700; margin-bottom: 0.35rem; letter-spacing: -0.02em; }
198
360
  .page-header.center { text-align: center; padding: 4rem 1rem; }
199
361
  .subtitle { color: var(--text-muted); font-size: 0.95rem; }
200
362
 
@@ -205,17 +367,26 @@ code { background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-s
205
367
  border-radius: var(--radius-lg);
206
368
  padding: 1.5rem;
207
369
  margin-bottom: 1.25rem;
370
+ backdrop-filter: blur(8px);
371
+ -webkit-backdrop-filter: blur(8px);
372
+ transition: border-color .2s ease, box-shadow .2s ease;
373
+ min-width: 0;
374
+ }
375
+
376
+ .card:hover {
377
+ border-color: rgba(88, 166, 255, 0.15);
378
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15), 0 0 0 1px rgba(88, 166, 255, 0.04);
208
379
  }
209
380
 
210
381
  .card h3 { font-size: 1.1rem; margin-bottom: 0.5rem; }
211
382
  .card p { color: var(--text-muted); font-size: 0.9rem; margin-bottom: 0.75rem; }
212
383
  .card-accent { border-left: 3px solid var(--accent); }
213
- .card-muted { background: var(--bg-surface); }
384
+ .card-muted { background: var(--bg-surface); backdrop-filter: none; }
214
385
  .card-error { background: rgba(248,113,113,0.08); border-color: var(--danger); color: var(--danger); }
215
386
 
216
387
  .card-grid {
217
388
  display: grid;
218
- grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
389
+ grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr));
219
390
  gap: 1rem;
220
391
  margin-bottom: 1.25rem;
221
392
  }
@@ -223,12 +394,13 @@ code { background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-s
223
394
  .card-grid > .card {
224
395
  display: flex;
225
396
  flex-direction: column;
397
+ margin-bottom: 0;
226
398
  }
227
399
 
228
400
  .card-grid > .card > .btn,
229
401
  .card-grid > .card > a.btn {
230
402
  margin-top: auto;
231
- align-self: flex-end;
403
+ align-self: flex-start;
232
404
  }
233
405
 
234
406
  /* -- Buttons -- */
@@ -244,10 +416,13 @@ code { background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-s
244
416
  cursor: pointer;
245
417
  transition: all 0.15s ease;
246
418
  text-decoration: none;
419
+ font-family: inherit;
247
420
  }
248
421
 
422
+ .btn:active { transform: scale(0.97); }
423
+
249
424
  .btn-primary { background: var(--accent); color: #fff; }
250
- .btn-primary:hover { background: var(--accent-hover); color: #fff; }
425
+ .btn-primary:hover { background: var(--accent-hover); color: #fff; box-shadow: 0 0 20px var(--accent-glow); }
251
426
 
252
427
  .btn-outline { background: transparent; border: 1px solid var(--border); color: var(--accent); }
253
428
  .btn-outline:hover { border-color: var(--accent); background: var(--accent-soft); }
@@ -255,9 +430,6 @@ code { background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-s
255
430
  .btn-ghost { background: transparent; color: var(--text-muted); }
256
431
  .btn-ghost:hover { color: var(--text); background: var(--bg-hover); }
257
432
 
258
- .btn-danger { background: var(--danger); color: #fff; }
259
- .btn-danger:hover { opacity: 0.85; }
260
-
261
433
  .btn-sm { padding: 0.35rem 0.75rem; font-size: 0.82rem; }
262
434
 
263
435
  /* -- Inputs -- */
@@ -271,207 +443,15 @@ code { background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-s
271
443
  font-size: 0.9rem;
272
444
  font-family: inherit;
273
445
  outline: none;
274
- transition: border-color 0.15s ease;
446
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
275
447
  }
276
448
 
277
- .input:focus { border-color: var(--accent); }
449
+ .input:hover { border-color: rgba(88,166,255,0.2); }
450
+ .input:focus { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(88,166,255,0.1), 0 0 12px var(--accent-glow); }
278
451
  .input-sm { width: auto; padding: 0.35rem 0.6rem; font-size: 0.82rem; }
279
452
 
280
- /* -- Counter -- */
281
- .counter-card { text-align: center; }
282
- .counter-display { padding: 1.5rem 0 1rem; }
283
- .counter-value { font-size: 3.5rem; font-weight: 700; font-variant-numeric: tabular-nums; }
284
- .counter-value.negative { color: var(--danger); }
285
- .counter-controls { display: flex; justify-content: center; gap: 0.75rem; margin-bottom: 1.25rem; }
286
- .counter-step { display: flex; align-items: center; justify-content: center; gap: 1rem; }
287
- .counter-step label { display: flex; align-items: center; gap: 0.5rem; color: var(--text-muted); font-size: 0.9rem; }
288
- .counter-step .input-sm { width: 70px; text-align: center; }
289
-
290
- .history-list { display: flex; flex-wrap: wrap; gap: 0.5rem; }
291
- .history-item {
292
- background: var(--bg-hover);
293
- padding: 0.3rem 0.65rem;
294
- border-radius: var(--radius);
295
- font-size: 0.82rem;
296
- font-variant-numeric: tabular-nums;
297
- }
298
-
299
- /* -- Todos -- */
300
- .todo-form { display: flex; gap: 0.75rem; }
301
- .todo-form .input { flex: 1; }
302
-
303
- .todo-toolbar { display: flex; justify-content: space-between; align-items: center; gap: 0.75rem; margin-bottom: 1rem; flex-wrap: wrap; }
304
- .todo-filters { display: flex; gap: 0.35rem; }
305
-
306
- .todo-list { list-style: none; }
307
- .todo-item {
308
- display: flex;
309
- align-items: center;
310
- gap: 0.6rem;
311
- padding: 0.6rem 0;
312
- border-bottom: 1px solid var(--border);
313
- }
314
- .todo-item:last-child { border-bottom: none; }
315
- .todo-item.done .todo-text { text-decoration: line-through; color: var(--text-muted); }
316
-
317
- .todo-check {
318
- width: 22px;
319
- height: 22px;
320
- border-radius: 50%;
321
- border: 2px solid var(--border);
322
- background: transparent;
323
- cursor: pointer;
324
- display: flex;
325
- align-items: center;
326
- justify-content: center;
327
- flex-shrink: 0;
328
- font-size: 0;
329
- transition: all 0.15s ease;
330
- padding: 0;
331
- }
332
- .todo-check:hover {
333
- border-color: var(--accent);
334
- }
335
- .todo-item.done .todo-check {
336
- background: var(--accent);
337
- border-color: var(--accent);
338
- }
339
- .todo-item.done .todo-check::after {
340
- content: '✓';
341
- font-size: 13px;
342
- color: #fff;
343
- line-height: 1;
344
- }
345
-
346
- .todo-text { flex: 1; font-size: 0.9rem; }
347
-
348
- .todo-remove {
349
- background: none;
350
- border: none;
351
- color: var(--text-muted);
352
- cursor: pointer;
353
- font-size: 0.9rem;
354
- padding: 0.2rem 0.4rem;
355
- border-radius: 4px;
356
- }
357
- .todo-remove:hover { color: var(--danger); background: rgba(248,113,113,0.1); }
358
-
359
- .todo-footer { padding-top: 0.75rem; border-top: 1px solid var(--border); margin-top: 0.75rem; }
360
- .empty-state { text-align: center; padding: 2rem 0; color: var(--text-muted); }
361
-
362
- /* -- Signal Demo -- */
363
- .signal-demo { display: flex; align-items: center; gap: 1rem; margin-top: 0.75rem; }
364
- .signal-value { font-weight: 600; font-size: 1.1rem; color: var(--accent); font-variant-numeric: tabular-nums; }
365
- .signal-demo .btn-sm {
366
- background: var(--accent);
367
- color: #fff;
368
- border: none;
369
- padding: 0.4rem 1rem;
370
- border-radius: var(--radius);
371
- font-weight: 500;
372
- cursor: pointer;
373
- transition: opacity 0.15s ease, transform 0.1s ease;
374
- }
375
- .signal-demo .btn-sm:hover { opacity: 0.85; }
376
- .signal-demo .btn-sm:active { transform: scale(0.96); }
377
-
378
- /* -- Stats -- */
379
- .stats-row { display: flex; gap: 2rem; margin: 0.75rem 0; }
380
- .stat { display: flex; flex-direction: column; }
381
- .stat-value { font-size: 1.5rem; font-weight: 700; color: var(--accent); font-variant-numeric: tabular-nums; }
382
- .stat-label { font-size: 0.8rem; color: var(--text-muted); }
383
-
384
- /* -- Stats Groups -- */
385
- .stats-grid {
386
- display: grid;
387
- grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
388
- gap: 1rem;
389
- margin: 1rem 0 0.75rem;
390
- }
391
-
392
- .stat-group {
393
- background: var(--bg-card);
394
- border: 1px solid var(--border);
395
- border-radius: var(--radius-lg);
396
- padding: 1.15rem 1.25rem;
397
- display: flex;
398
- flex-direction: column;
399
- gap: 0.65rem;
400
- }
401
-
402
- .stat-group-title {
403
- font-size: 0.78rem;
404
- font-weight: 600;
405
- text-transform: uppercase;
406
- letter-spacing: 0.04em;
407
- color: var(--text-muted);
408
- }
409
-
410
- .stat-group-values {
411
- display: flex;
412
- gap: 1.5rem;
413
- justify-content: center;
414
- }
415
-
416
- .stat-group-values .stat {
417
- align-items: center;
418
- }
419
-
420
- .stat-group .stat-value {
421
- font-size: 1.35rem;
422
- }
423
-
424
- .stat-group .stat-label {
425
- font-size: 0.75rem;
426
- }
427
-
428
- /* -- API Demo -- */
429
- .user-grid {
430
- display: grid;
431
- grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
432
- gap: 0.75rem;
433
- margin-top: 0.75rem;
434
- }
435
-
436
- .user-card {
437
- display: flex;
438
- flex-direction: column;
439
- gap: 0.15rem;
440
- padding: 0.85rem;
441
- background: var(--bg-hover);
442
- border: 1px solid var(--border);
443
- border-radius: var(--radius);
444
- cursor: pointer;
445
- text-align: left;
446
- font-family: inherit;
447
- color: var(--text);
448
- transition: all 0.15s ease;
449
- }
450
-
451
- .user-card:hover { border-color: var(--accent); background: var(--accent-soft); }
452
- .user-card strong { font-size: 0.9rem; }
453
- .user-card small { font-size: 0.8rem; color: var(--text-muted); }
454
-
455
- .user-detail-header { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; }
456
-
457
- .posts-list { display: flex; flex-direction: column; gap: 1rem; margin-top: 0.75rem; }
458
- .post-item { border-left: 3px solid var(--border); padding-left: 1rem; }
459
- .post-item h4 { font-size: 0.95rem; margin-bottom: 0.25rem; text-transform: capitalize; }
460
- .post-item p { color: var(--text-muted); font-size: 0.85rem; }
461
-
462
- /* Loading bar */
463
- .loading-bar {
464
- height: 3px;
465
- background: linear-gradient(90deg, transparent, var(--accent), transparent);
466
- border-radius: 2px;
467
- margin-bottom: 1rem;
468
- animation: loading 1.2s ease-in-out infinite;
469
- }
470
- @keyframes loading { 0%,100% { opacity: 0.3; } 50% { opacity: 1; } }
471
-
472
453
  /* -- About -- */
473
- .theme-toggle { display: flex; align-items: center; gap: 1rem; }
474
- .feature-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 0.5rem; }
454
+ .feature-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr)); gap: 0.5rem; }
475
455
  .feature-item {
476
456
  display: flex;
477
457
  flex-direction: column;
@@ -479,7 +459,9 @@ code { background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-s
479
459
  background: var(--bg-hover);
480
460
  border-radius: var(--radius);
481
461
  font-size: 0.85rem;
462
+ transition: background .15s;
482
463
  }
464
+ .feature-item:hover { background: var(--accent-soft); }
483
465
  .feature-item strong { color: var(--accent); font-size: 0.82rem; margin-bottom: 0.1rem; }
484
466
  .feature-item span { color: var(--text-muted); font-size: 0.8rem; }
485
467
 
@@ -507,21 +489,22 @@ code { background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-s
507
489
  font-size: 0.85rem;
508
490
  font-weight: 500;
509
491
  color: #fff;
510
- animation: toast-in 0.3s ease;
492
+ animation: toast-in 0.3s var(--ease-out);
511
493
  pointer-events: auto;
494
+ backdrop-filter: blur(8px);
512
495
  }
513
496
 
514
- .toast-success { background: var(--success); }
515
- .toast-error { background: var(--danger); }
516
- .toast-info { background: var(--info); }
497
+ .toast-success { background: rgba(63,185,80,0.9); }
498
+ .toast-error { background: rgba(248,81,73,0.9); }
499
+ .toast-info { background: rgba(88,166,255,0.9); }
517
500
 
518
501
  .toast-exit { animation: toast-out 0.3s ease forwards; }
519
502
 
520
- @keyframes toast-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
521
- @keyframes toast-out { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-10px); } }
503
+ @keyframes toast-in { from { opacity: 0; transform: translateY(10px) scale(0.95); } to { opacity: 1; transform: translateY(0) scale(1); } }
504
+ @keyframes toast-out { from { opacity: 1; transform: translateY(0) scale(1); } to { opacity: 0; transform: translateY(-10px) scale(0.95); } }
522
505
 
523
506
  /* -- Route Transition -- */
524
- #app { animation: fade-in 0.25s ease; }
507
+ #app { animation: fade-in 0.25s var(--ease-out); }
525
508
  @keyframes fade-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
526
509
 
527
510
  /* -- Responsive: Mobile -- */
@@ -538,20 +521,23 @@ code { background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-s
538
521
  margin-left: 0;
539
522
  padding: 1.25rem;
540
523
  padding-top: calc(var(--topbar-h) + 1.25rem);
524
+ max-width: 100%;
525
+ overflow-x: hidden;
541
526
  }
542
527
 
528
+ .card { padding: 1.15rem; }
543
529
  .card-grid { grid-template-columns: 1fr; }
544
- .user-grid { grid-template-columns: 1fr 1fr; }
545
530
  .feature-grid { grid-template-columns: 1fr; }
546
- .stats-row { gap: 1.25rem; }
547
531
 
548
532
  .page-header h1 { font-size: 1.4rem; }
549
- .counter-value { font-size: 2.75rem; }
533
+ .page-header.center { padding: 2rem 0.75rem; }
534
+
535
+ .toast-container { right: 0.75rem; left: 0.75rem; align-items: flex-end; }
550
536
  }
551
537
 
552
538
  @media (max-width: 480px) {
553
- .content { padding: 1rem; padding-top: calc(var(--topbar-h) + 1rem); }
554
- .user-grid { grid-template-columns: 1fr; }
555
- .todo-toolbar { flex-direction: column; align-items: stretch; }
556
- .todo-toolbar .input-sm { width: 100%; }
539
+ .content { padding: 0.75rem; padding-top: calc(var(--topbar-h) + 0.75rem); }
540
+ .card { padding: 1rem; }
541
+ .page-header h1 { font-size: 1.25rem; }
542
+ .subtitle { font-size: 0.85rem; }
557
543
  }
@@ -33,10 +33,42 @@
33
33
  <a z-link="/api" class="nav-link">
34
34
  <span class="nav-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21a9.004 9.004 0 0 1-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 0 1 7.843 4.582M12 3a8.997 8.997 0 0 0-7.843 4.582m15.686 0A11.953 11.953 0 0 1 12 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0 1 21 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0 1 12 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 0 1 3 12c0-1.605.42-3.113 1.157-4.418"/></svg></span> API Demo
35
35
  </a>
36
+ <a z-link="/playground" class="nav-link">
37
+ <span class="nav-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="m21 7.5-9-5.25L3 7.5m18 0-9 5.25m9-5.25v9l-9 5.25M3 7.5l9 5.25M3 7.5v9l9 5.25m0-9v9"/></svg></span> Playground
38
+ </a>
39
+ <a z-link="/toolkit" class="nav-link">
40
+ <span class="nav-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M21.75 6.75a4.5 4.5 0 0 1-4.884 4.484c-1.076-.091-2.264.071-2.95.904l-7.152 8.684a2.548 2.548 0 1 1-3.586-3.586l8.684-7.152c.833-.686.995-1.874.904-2.95a4.5 4.5 0 0 1 6.336-4.486l-3.276 3.276a3.004 3.004 0 0 0 2.25 2.25l3.276-3.276c.256.565.398 1.192.398 1.852Z"/></svg></span> Toolkit
41
+ </a>
36
42
  <a z-link="/about" class="nav-link">
37
43
  <span class="nav-icon"><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 18v-5.25m0 0a6.01 6.01 0 0 0 1.5-.189m-1.5.189a6.01 6.01 0 0 1-1.5-.189m3.75 7.478a12.06 12.06 0 0 1-4.5 0m3.75 2.383a14.406 14.406 0 0 1-3 0M14.25 18v-.192c0-.983.658-1.823 1.508-2.316a7.5 7.5 0 1 0-7.517 0c.85.493 1.509 1.333 1.509 2.316V18"/></svg></span> About
38
44
  </a>
39
45
  </nav>
46
+ <div class="sidebar-contacts" id="sidebar-contacts">
47
+ <div class="sc-header">
48
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" style="width:13px;height:13px;"><path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 0 0 2.625.372 9.337 9.337 0 0 0 4.121-.952 4.125 4.125 0 0 0-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 0 1 8.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0 1 11.964-3.07M12 6.375a3.375 3.375 0 1 1-6.75 0 3.375 3.375 0 0 1 6.75 0Zm8.25 2.25a2.625 2.625 0 1 1-5.25 0 2.625 2.625 0 0 1 5.25 0Z"/></svg>
49
+ Contacts
50
+ </div>
51
+ <div class="sc-list" id="sc-list">
52
+ <!-- Populated from $.store('main') by app.js -->
53
+ </div>
54
+ </div>
55
+ <div class="sidebar-stats" id="sidebar-stats">
56
+ <button class="sidebar-stats-toggle" id="stats-toggle">
57
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" style="width:14px;height:14px;"><path stroke-linecap="round" stroke-linejoin="round" d="M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 0 1 3 19.875v-6.75ZM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V8.625ZM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V4.125Z"/></svg>
58
+ Stats
59
+ <span class="sidebar-stats-arrow open" id="stats-arrow">▸</span>
60
+ </button>
61
+ <div class="sidebar-stats-body" id="stats-body">
62
+ <div class="ss-row"><span class="ss-label">Page Views</span><span class="ss-value" id="ss-visits">0</span></div>
63
+ <div class="ss-group-label">Todos</div>
64
+ <div class="ss-row ss-indent"><span class="ss-label">Total</span><span class="ss-value" id="ss-todos">0</span></div>
65
+ <div class="ss-row ss-indent"><span class="ss-label">Pending</span><span class="ss-value" id="ss-pending">0</span></div>
66
+ <div class="ss-row ss-indent"><span class="ss-label">Done</span><span class="ss-value" id="ss-done">0</span></div>
67
+ <div class="ss-group-label">Contacts</div>
68
+ <div class="ss-row ss-indent"><span class="ss-label">Total</span><span class="ss-value" id="ss-contacts">0</span></div>
69
+ <div class="ss-row ss-indent"><span class="ss-label">Favorited</span><span class="ss-value" id="ss-favorites">0</span></div>
70
+ </div>
71
+ </div>
40
72
  <div class="sidebar-footer">
41
73
  <small>zQuery <span id="nav-version"></span></small>
42
74
  </div>
@@ -60,5 +92,8 @@
60
92
  <!-- Toast container for notifications -->
61
93
  <div class="toast-container" id="toasts"></div>
62
94
 
95
+ <!-- Global contact card popup (works from any page) -->
96
+ <contact-card></contact-card>
97
+
63
98
  </body>
64
99
  </html>