stem-lab-toolkit 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/css/style.css ADDED
@@ -0,0 +1,602 @@
1
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
2
+
3
+ :root {
4
+ --accent: #2563eb;
5
+ --accent-h: #1d4ed8;
6
+ --text: #111827;
7
+ --muted: #6b7280;
8
+ --border: #e5e7eb;
9
+ --surface: #f9fafb;
10
+ --radius: 10px;
11
+ --shadow: 0 1px 3px rgba(0,0,0,.08), 0 1px 2px rgba(0,0,0,.05);
12
+ --shadow-lg: 0 4px 20px rgba(0,0,0,.10);
13
+ }
14
+
15
+ body {
16
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
17
+ color: var(--text);
18
+ background: #fff;
19
+ line-height: 1.5;
20
+ }
21
+
22
+ a { color: inherit; text-decoration: none; }
23
+
24
+ /* ── Header ── */
25
+ .site-header {
26
+ position: sticky;
27
+ top: 0;
28
+ z-index: 100;
29
+ background: #fff;
30
+ border-bottom: 1px solid var(--border);
31
+ padding: 0 24px;
32
+ }
33
+
34
+ .header-inner {
35
+ max-width: 1200px;
36
+ margin: 0 auto;
37
+ height: 56px;
38
+ display: flex;
39
+ align-items: center;
40
+ gap: 20px;
41
+ }
42
+
43
+ .logo-link {
44
+ display: flex;
45
+ align-items: center;
46
+ gap: 10px;
47
+ font-weight: 700;
48
+ font-size: 1.1rem;
49
+ letter-spacing: -0.02em;
50
+ }
51
+
52
+ .logo-img {
53
+ height: 28px;
54
+ width: auto;
55
+ }
56
+
57
+ .site-nav {
58
+ margin-left: auto;
59
+ display: flex;
60
+ align-items: center;
61
+ gap: 8px;
62
+ }
63
+
64
+ .site-nav a {
65
+ padding: 6px 14px;
66
+ border-radius: 6px;
67
+ font-size: 0.875rem;
68
+ font-weight: 500;
69
+ color: var(--muted);
70
+ transition: background .15s, color .15s;
71
+ }
72
+
73
+ .site-nav a:hover,
74
+ .site-nav a.active {
75
+ background: var(--surface);
76
+ color: var(--text);
77
+ }
78
+
79
+ /* ── Search ── */
80
+ .search-wrap {
81
+ position: relative;
82
+ max-width: 480px;
83
+ width: 100%;
84
+ }
85
+
86
+ .search-wrap svg {
87
+ position: absolute;
88
+ left: 12px;
89
+ top: 50%;
90
+ transform: translateY(-50%);
91
+ color: var(--muted);
92
+ pointer-events: none;
93
+ }
94
+
95
+ .search-input {
96
+ width: 100%;
97
+ padding: 10px 14px 10px 40px;
98
+ border: 1.5px solid var(--border);
99
+ border-radius: 8px;
100
+ font-size: 0.9rem;
101
+ outline: none;
102
+ transition: border-color .15s, box-shadow .15s;
103
+ background: var(--surface);
104
+ }
105
+
106
+ .search-input:focus {
107
+ border-color: var(--accent);
108
+ box-shadow: 0 0 0 3px rgba(37,99,235,.12);
109
+ background: #fff;
110
+ }
111
+
112
+ /* ── Category filter ── */
113
+ .category-filters {
114
+ display: flex;
115
+ gap: 8px;
116
+ flex-wrap: wrap;
117
+ }
118
+
119
+ .cat-btn {
120
+ padding: 6px 16px;
121
+ border-radius: 999px;
122
+ border: 1.5px solid var(--border);
123
+ background: #fff;
124
+ font-size: 0.82rem;
125
+ font-weight: 500;
126
+ color: var(--muted);
127
+ cursor: pointer;
128
+ transition: all .15s;
129
+ }
130
+
131
+ .cat-btn:hover {
132
+ border-color: var(--accent);
133
+ color: var(--accent);
134
+ }
135
+
136
+ .cat-btn.active {
137
+ background: var(--accent);
138
+ border-color: var(--accent);
139
+ color: #fff;
140
+ }
141
+
142
+ /* ── Game grid ── */
143
+ .game-grid {
144
+ display: grid;
145
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
146
+ gap: 16px;
147
+ }
148
+
149
+ .game-card {
150
+ border-radius: var(--radius);
151
+ overflow: hidden;
152
+ border: 1px solid var(--border);
153
+ transition: transform .15s, box-shadow .15s;
154
+ cursor: pointer;
155
+ background: #fff;
156
+ }
157
+
158
+ .game-card:hover {
159
+ transform: translateY(-2px);
160
+ box-shadow: var(--shadow-lg);
161
+ }
162
+
163
+ .game-card-thumb {
164
+ width: 100%;
165
+ aspect-ratio: 4/3;
166
+ object-fit: cover;
167
+ background: var(--surface);
168
+ display: block;
169
+ }
170
+
171
+ .game-card-thumb-placeholder {
172
+ width: 100%;
173
+ aspect-ratio: 4/3;
174
+ background: linear-gradient(135deg, #e0e7ff 0%, #dbeafe 100%);
175
+ display: flex;
176
+ align-items: center;
177
+ justify-content: center;
178
+ font-size: 2rem;
179
+ }
180
+
181
+ .game-card-body {
182
+ padding: 10px 12px 12px;
183
+ }
184
+
185
+ .game-card-name {
186
+ font-size: 0.875rem;
187
+ font-weight: 600;
188
+ margin-bottom: 4px;
189
+ white-space: nowrap;
190
+ overflow: hidden;
191
+ text-overflow: ellipsis;
192
+ }
193
+
194
+ .cat-badge {
195
+ display: inline-block;
196
+ padding: 2px 8px;
197
+ border-radius: 999px;
198
+ font-size: 0.72rem;
199
+ font-weight: 600;
200
+ text-transform: uppercase;
201
+ letter-spacing: .04em;
202
+ }
203
+
204
+ .cat-badge.Action { background: #fee2e2; color: #b91c1c; }
205
+ .cat-badge.Sports { background: #d1fae5; color: #065f46; }
206
+ .cat-badge.Racing { background: #fef3c7; color: #92400e; }
207
+ .cat-badge.Multiplayer { background: #ede9fe; color: #5b21b6; }
208
+ .cat-badge.Puzzle { background: #dbeafe; color: #1e40af; }
209
+ .cat-badge.Casual { background: #fce7f3; color: #9d174d; }
210
+
211
+ /* ── Game of the Day ── */
212
+ .gotd-card {
213
+ display: flex;
214
+ align-items: center;
215
+ gap: 20px;
216
+ padding: 20px;
217
+ border-radius: var(--radius);
218
+ border: 1px solid var(--border);
219
+ background: linear-gradient(135deg, #eff6ff 0%, #f0fdf4 100%);
220
+ text-decoration: none;
221
+ color: var(--text);
222
+ transition: box-shadow .15s;
223
+ }
224
+
225
+ .gotd-card:hover { box-shadow: var(--shadow-lg); }
226
+
227
+ .gotd-thumb {
228
+ width: 140px;
229
+ height: 105px;
230
+ object-fit: cover;
231
+ border-radius: 8px;
232
+ flex-shrink: 0;
233
+ background: var(--surface);
234
+ }
235
+
236
+ .gotd-thumb-placeholder {
237
+ width: 140px;
238
+ height: 105px;
239
+ border-radius: 8px;
240
+ background: linear-gradient(135deg, #c7d2fe 0%, #bfdbfe 100%);
241
+ display: flex;
242
+ align-items: center;
243
+ justify-content: center;
244
+ font-size: 2.5rem;
245
+ flex-shrink: 0;
246
+ }
247
+
248
+ .gotd-label {
249
+ font-size: 0.72rem;
250
+ font-weight: 700;
251
+ text-transform: uppercase;
252
+ letter-spacing: .08em;
253
+ color: var(--accent);
254
+ margin-bottom: 6px;
255
+ }
256
+
257
+ .gotd-name {
258
+ font-size: 1.3rem;
259
+ font-weight: 700;
260
+ letter-spacing: -0.02em;
261
+ margin-bottom: 6px;
262
+ }
263
+
264
+ .gotd-play-btn {
265
+ display: inline-flex;
266
+ align-items: center;
267
+ gap: 6px;
268
+ padding: 8px 18px;
269
+ background: var(--accent);
270
+ color: #fff;
271
+ border-radius: 8px;
272
+ font-size: 0.875rem;
273
+ font-weight: 600;
274
+ margin-top: 8px;
275
+ transition: background .15s;
276
+ }
277
+
278
+ .gotd-play-btn:hover { background: var(--accent-h); }
279
+
280
+ /* ── Containers ── */
281
+ .container {
282
+ max-width: 1200px;
283
+ margin: 0 auto;
284
+ padding: 0 24px;
285
+ }
286
+
287
+ .section { margin-bottom: 40px; }
288
+
289
+ .section-title {
290
+ font-size: 0.75rem;
291
+ font-weight: 700;
292
+ text-transform: uppercase;
293
+ letter-spacing: .08em;
294
+ color: var(--muted);
295
+ margin-bottom: 12px;
296
+ }
297
+
298
+ /* ── Modal / PIN overlay ── */
299
+ .pin-overlay {
300
+ position: fixed;
301
+ inset: 0;
302
+ background: rgba(0,0,0,.5);
303
+ display: flex;
304
+ align-items: center;
305
+ justify-content: center;
306
+ z-index: 999;
307
+ backdrop-filter: blur(4px);
308
+ }
309
+
310
+ .pin-overlay.hidden { display: none; }
311
+
312
+ .pin-box {
313
+ background: #fff;
314
+ border-radius: 16px;
315
+ padding: 32px;
316
+ width: 320px;
317
+ box-shadow: 0 24px 60px rgba(0,0,0,.2);
318
+ text-align: center;
319
+ }
320
+
321
+ .pin-box h2 {
322
+ font-size: 1.1rem;
323
+ font-weight: 700;
324
+ margin-bottom: 6px;
325
+ }
326
+
327
+ .pin-box p {
328
+ font-size: 0.85rem;
329
+ color: var(--muted);
330
+ margin-bottom: 20px;
331
+ }
332
+
333
+ .pin-dots {
334
+ display: flex;
335
+ justify-content: center;
336
+ gap: 12px;
337
+ margin-bottom: 24px;
338
+ }
339
+
340
+ .pin-dot {
341
+ width: 14px;
342
+ height: 14px;
343
+ border-radius: 50%;
344
+ border: 2px solid var(--border);
345
+ background: transparent;
346
+ transition: background .15s, border-color .15s;
347
+ }
348
+
349
+ .pin-dot.filled {
350
+ background: var(--accent);
351
+ border-color: var(--accent);
352
+ }
353
+
354
+ .pin-dot.error {
355
+ background: #ef4444;
356
+ border-color: #ef4444;
357
+ }
358
+
359
+ .pin-keypad {
360
+ display: grid;
361
+ grid-template-columns: repeat(3, 1fr);
362
+ gap: 8px;
363
+ margin-bottom: 16px;
364
+ }
365
+
366
+ .pin-key {
367
+ padding: 14px;
368
+ border: none;
369
+ border-radius: 10px;
370
+ background: var(--surface);
371
+ font-size: 1.1rem;
372
+ font-weight: 500;
373
+ cursor: pointer;
374
+ transition: background .1s;
375
+ }
376
+
377
+ .pin-key:hover { background: #e5e7eb; }
378
+ .pin-key:active { background: #d1d5db; }
379
+
380
+ .pin-key.delete {
381
+ background: transparent;
382
+ color: var(--muted);
383
+ font-size: 0.9rem;
384
+ }
385
+
386
+ .pin-cancel {
387
+ font-size: 0.85rem;
388
+ color: var(--muted);
389
+ cursor: pointer;
390
+ border: none;
391
+ background: none;
392
+ padding: 8px;
393
+ }
394
+
395
+ .pin-cancel:hover { color: var(--text); }
396
+
397
+ .pin-error {
398
+ font-size: 0.82rem;
399
+ color: #ef4444;
400
+ min-height: 1.2em;
401
+ margin-bottom: 8px;
402
+ }
403
+
404
+ /* ── Admin table ── */
405
+ .admin-table {
406
+ width: 100%;
407
+ border-collapse: collapse;
408
+ font-size: 0.875rem;
409
+ }
410
+
411
+ .admin-table th {
412
+ text-align: left;
413
+ padding: 10px 12px;
414
+ border-bottom: 2px solid var(--border);
415
+ font-size: 0.75rem;
416
+ font-weight: 600;
417
+ text-transform: uppercase;
418
+ letter-spacing: .05em;
419
+ color: var(--muted);
420
+ }
421
+
422
+ .admin-table td {
423
+ padding: 10px 12px;
424
+ border-bottom: 1px solid var(--border);
425
+ vertical-align: middle;
426
+ }
427
+
428
+ .admin-table tr:hover td { background: var(--surface); }
429
+
430
+ /* ── Form ── */
431
+ .form-grid {
432
+ display: grid;
433
+ grid-template-columns: 1fr 1fr;
434
+ gap: 14px;
435
+ }
436
+
437
+ .form-group { display: flex; flex-direction: column; gap: 5px; }
438
+ .form-group.full { grid-column: 1 / -1; }
439
+
440
+ .form-group label {
441
+ font-size: 0.8rem;
442
+ font-weight: 600;
443
+ color: var(--muted);
444
+ text-transform: uppercase;
445
+ letter-spacing: .04em;
446
+ }
447
+
448
+ .form-group input,
449
+ .form-group select {
450
+ padding: 9px 12px;
451
+ border: 1.5px solid var(--border);
452
+ border-radius: 8px;
453
+ font-size: 0.9rem;
454
+ outline: none;
455
+ transition: border-color .15s;
456
+ }
457
+
458
+ .form-group input:focus,
459
+ .form-group select:focus {
460
+ border-color: var(--accent);
461
+ box-shadow: 0 0 0 3px rgba(37,99,235,.1);
462
+ }
463
+
464
+ /* ── Buttons ── */
465
+ .btn {
466
+ display: inline-flex;
467
+ align-items: center;
468
+ gap: 6px;
469
+ padding: 9px 18px;
470
+ border: none;
471
+ border-radius: 8px;
472
+ font-size: 0.875rem;
473
+ font-weight: 600;
474
+ cursor: pointer;
475
+ transition: background .15s, opacity .15s;
476
+ }
477
+
478
+ .btn-primary { background: var(--accent); color: #fff; }
479
+ .btn-primary:hover { background: var(--accent-h); }
480
+
481
+ .btn-ghost {
482
+ background: transparent;
483
+ color: var(--muted);
484
+ border: 1.5px solid var(--border);
485
+ }
486
+ .btn-ghost:hover { color: var(--text); border-color: #9ca3af; }
487
+
488
+ .btn-danger { background: #fee2e2; color: #b91c1c; }
489
+ .btn-danger:hover { background: #fecaca; }
490
+
491
+ .btn-sm { padding: 5px 12px; font-size: 0.8rem; }
492
+
493
+ /* ── Toggle switch ── */
494
+ .toggle {
495
+ position: relative;
496
+ display: inline-block;
497
+ width: 38px;
498
+ height: 22px;
499
+ }
500
+
501
+ .toggle input { opacity: 0; width: 0; height: 0; }
502
+
503
+ .toggle-slider {
504
+ position: absolute;
505
+ inset: 0;
506
+ border-radius: 999px;
507
+ background: #d1d5db;
508
+ cursor: pointer;
509
+ transition: background .2s;
510
+ }
511
+
512
+ .toggle-slider::before {
513
+ content: '';
514
+ position: absolute;
515
+ height: 16px;
516
+ width: 16px;
517
+ left: 3px;
518
+ bottom: 3px;
519
+ border-radius: 50%;
520
+ background: #fff;
521
+ transition: transform .2s;
522
+ box-shadow: 0 1px 3px rgba(0,0,0,.2);
523
+ }
524
+
525
+ .toggle input:checked + .toggle-slider { background: var(--accent); }
526
+ .toggle input:checked + .toggle-slider::before { transform: translateX(16px); }
527
+
528
+ /* ── Stats ── */
529
+ .stats-grid {
530
+ display: grid;
531
+ grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
532
+ gap: 12px;
533
+ }
534
+
535
+ .stat-card {
536
+ padding: 16px;
537
+ border: 1px solid var(--border);
538
+ border-radius: var(--radius);
539
+ background: var(--surface);
540
+ }
541
+
542
+ .stat-value {
543
+ font-size: 1.8rem;
544
+ font-weight: 700;
545
+ letter-spacing: -0.03em;
546
+ }
547
+
548
+ .stat-label {
549
+ font-size: 0.78rem;
550
+ color: var(--muted);
551
+ margin-top: 2px;
552
+ }
553
+
554
+ /* ── Card section ── */
555
+ .card {
556
+ background: #fff;
557
+ border: 1px solid var(--border);
558
+ border-radius: var(--radius);
559
+ padding: 24px;
560
+ margin-bottom: 20px;
561
+ }
562
+
563
+ .card-title {
564
+ font-size: 0.8rem;
565
+ font-weight: 600;
566
+ text-transform: uppercase;
567
+ letter-spacing: .06em;
568
+ color: var(--muted);
569
+ margin-bottom: 18px;
570
+ }
571
+
572
+ /* ── Feedback ── */
573
+ .feedback {
574
+ font-size: 0.85rem;
575
+ font-weight: 500;
576
+ min-height: 1.2em;
577
+ margin-top: 10px;
578
+ }
579
+ .feedback.ok { color: #15803d; }
580
+ .feedback.error { color: #b91c1c; }
581
+
582
+ /* ── No-results ── */
583
+ .no-results {
584
+ grid-column: 1 / -1;
585
+ text-align: center;
586
+ padding: 60px 0;
587
+ color: var(--muted);
588
+ font-size: 0.9rem;
589
+ }
590
+
591
+ /* ── Responsive ── */
592
+ @media (max-width: 640px) {
593
+ .form-grid { grid-template-columns: 1fr; }
594
+ .gotd-card { flex-direction: column; }
595
+ .gotd-thumb, .gotd-thumb-placeholder { width: 100%; height: 180px; }
596
+ .game-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
597
+ .header-inner { gap: 12px; }
598
+ }
599
+
600
+ .cat-badge.Adventure { background: #d1fae5; color: #065f46; }
601
+ .cat-badge.Classic { background: #fef3c7; color: #92400e; }
602
+ .cat-badge.Strategy { background: #e0e7ff; color: #3730a3; }