pkg/darkmatter/assets/darkmatter.css 11.8 K raw
1
/* Darkmatter — canonical CSS for Andromeda apps.
2
 * Source of truth for reset, tokens, and shared components.
3
 * Docs: /darkmatter
4
 */
5
6
@font-face {
7
  font-family: "Commit Mono";
8
  src: url("/assets/fonts/CommitMono-400-Regular.otf") format("opentype");
9
  font-weight: 400;
10
  font-style: normal;
11
  font-display: swap;
12
}
13
14
@font-face {
15
  font-family: "Commit Mono";
16
  src: url("/assets/fonts/CommitMono-700-Regular.otf") format("opentype");
17
  font-weight: 700;
18
  font-style: normal;
19
  font-display: swap;
20
}
21
22
/* ── Reset + webkit hardening ─────────────────────────────────────── */
23
24
*,
25
*::before,
26
*::after {
27
  padding: 0;
28
  margin: 0;
29
  box-sizing: border-box;
30
  font-family: "Commit Mono", monospace, sans-serif;
31
  -webkit-tap-highlight-color: transparent;
32
}
33
34
* {
35
  scrollbar-width: none;
36
  -ms-overflow-style: none;
37
}
38
39
html {
40
  background: #121113;
41
  color: #ffffff;
42
  font-size: 14px;
43
  line-height: 1.6;
44
  -webkit-text-size-adjust: 100%;
45
  text-size-adjust: 100%;
46
}
47
48
html::-webkit-scrollbar {
49
  display: none;
50
}
51
52
body {
53
  display: flex;
54
  flex-direction: column;
55
  justify-content: start;
56
  align-items: start;
57
  gap: 1.5rem;
58
  min-height: 100vh;
59
  max-width: 700px;
60
  margin: auto;
61
  padding: 0 1rem 4rem;
62
}
63
64
@media (max-width: 480px) {
65
  body {
66
    padding: 1rem;
67
    gap: 1rem;
68
  }
69
}
70
71
/* ── Links ────────────────────────────────────────────────────────── */
72
73
a {
74
  color: #ffffff;
75
  text-decoration: none;
76
  touch-action: manipulation;
77
}
78
79
a:hover {
80
  opacity: 0.7;
81
}
82
83
/* ── Header / nav ─────────────────────────────────────────────────── */
84
85
.header {
86
  display: flex;
87
  flex-direction: column;
88
  gap: 0.5rem;
89
  width: 100%;
90
  margin-top: 2rem;
91
  border-bottom: 1px solid #333;
92
  padding-bottom: 1rem;
93
}
94
95
.logo {
96
  font-size: 28px;
97
  font-weight: 700;
98
  text-decoration: none;
99
  text-transform: uppercase;
100
}
101
102
.links {
103
  display: flex;
104
  align-items: center;
105
  gap: 0.75rem;
106
  font-size: 12px;
107
}
108
109
/* ── Main ─────────────────────────────────────────────────────────── */
110
111
main {
112
  width: 100%;
113
  display: flex;
114
  flex-direction: column;
115
  gap: 1rem;
116
}
117
118
/* ── Forms ────────────────────────────────────────────────────────── */
119
120
.form {
121
  display: flex;
122
  flex-direction: column;
123
  gap: 0.5rem;
124
  width: 100%;
125
}
126
127
.form-row {
128
  display: flex;
129
  gap: 0.5rem;
130
  width: 100%;
131
}
132
133
.form-row .form-field {
134
  flex: 1;
135
}
136
137
.form-field {
138
  display: flex;
139
  flex-direction: column;
140
  gap: 0.25rem;
141
}
142
143
.form-actions {
144
  display: flex;
145
  gap: 0.5rem;
146
}
147
148
@media (max-width: 480px) {
149
  .form-row {
150
    flex-direction: column;
151
  }
152
}
153
154
label {
155
  font-size: 12px;
156
  opacity: 0.7;
157
}
158
159
input,
160
textarea,
161
select {
162
  background: #121113;
163
  color: #ffffff;
164
  border: 1px solid #ffffff;
165
  padding: 0.4rem 0.75rem;
166
  font-size: 16px; /* 16px prevents iOS focus zoom */
167
  width: 100%;
168
  border-radius: 0;
169
  -webkit-appearance: none;
170
  appearance: none;
171
  outline: none;
172
}
173
174
input:focus,
175
textarea:focus,
176
select:focus {
177
  outline: none;
178
}
179
180
textarea {
181
  min-height: 400px;
182
  resize: vertical;
183
}
184
185
select {
186
  background-image: none;
187
  padding-right: 0.75rem;
188
}
189
190
input[type="file"] {
191
  cursor: pointer;
192
  font-size: 14px;
193
}
194
195
input[type="file"]::-webkit-file-upload-button,
196
input[type="file"]::file-selector-button {
197
  background: #121113;
198
  color: #ffffff;
199
  border: 1px solid #555;
200
  padding: 0.25rem 0.5rem;
201
  cursor: pointer;
202
  font-family: "Commit Mono", monospace;
203
  font-size: 12px;
204
  margin-right: 0.5rem;
205
  border-radius: 0;
206
}
207
208
input[type="search"]::-webkit-search-decoration,
209
input[type="search"]::-webkit-search-cancel-button,
210
input[type="search"]::-webkit-search-results-button,
211
input[type="search"]::-webkit-search-results-decoration {
212
  -webkit-appearance: none;
213
}
214
215
input[type="checkbox"],
216
input[type="radio"] {
217
  -webkit-appearance: none;
218
  appearance: none;
219
  width: 16px;
220
  height: 16px;
221
  background: transparent;
222
  border: 1px solid #ffffff;
223
  border-radius: 0;
224
  padding: 0;
225
  cursor: pointer;
226
  position: relative;
227
  flex-shrink: 0;
228
  touch-action: manipulation;
229
}
230
231
input[type="radio"] {
232
  border-radius: 50%;
233
}
234
235
input[type="checkbox"]:checked::after {
236
  content: '✔︎';
237
  position: absolute;
238
  top: 50%;
239
  left: 50%;
240
  transform: translate(-50%, -50%);
241
  font-size: 12px;
242
  color: #ffffff;
243
  line-height: 1;
244
}
245
246
input[type="radio"]:checked::after {
247
  content: '';
248
  position: absolute;
249
  top: 50%;
250
  left: 50%;
251
  width: 8px;
252
  height: 8px;
253
  border-radius: 50%;
254
  background: #ffffff;
255
  transform: translate(-50%, -50%);
256
}
257
258
.checkbox-field {
259
  justify-content: flex-end;
260
}
261
262
.checkbox-field label {
263
  display: flex;
264
  align-items: center;
265
  gap: 0.5rem;
266
  font-size: 14px;
267
  opacity: 1;
268
  cursor: pointer;
269
}
270
271
/* Switch */
272
273
.switch-row {
274
  display: flex;
275
  align-items: center;
276
  gap: 0.5rem;
277
}
278
279
.switch-label {
280
  font-size: 14px;
281
}
282
283
.switch {
284
  position: relative;
285
  display: inline-block;
286
  width: 36px;
287
  height: 20px;
288
  flex-shrink: 0;
289
}
290
291
.switch input {
292
  opacity: 0;
293
  width: 0;
294
  height: 0;
295
}
296
297
.switch-slider {
298
  position: absolute;
299
  cursor: pointer;
300
  top: 0;
301
  left: 0;
302
  right: 0;
303
  bottom: 0;
304
  background: #333;
305
  border-radius: 20px;
306
  transition: background 0.2s;
307
}
308
309
.switch-slider::before {
310
  content: "";
311
  position: absolute;
312
  height: 14px;
313
  width: 14px;
314
  left: 3px;
315
  bottom: 3px;
316
  background: #888;
317
  border-radius: 50%;
318
  transition: transform 0.2s, background 0.2s;
319
}
320
321
.switch input:checked + .switch-slider {
322
  background: #555;
323
}
324
325
.switch input:checked + .switch-slider::before {
326
  transform: translateX(16px);
327
  background: #ffffff;
328
}
329
330
/* ── Buttons ──────────────────────────────────────────────────────── */
331
332
button,
333
.btn {
334
  background: #121113;
335
  color: #ffffff;
336
  padding: 0.2rem 0.75rem;
337
  border: 1px solid #ffffff;
338
  cursor: pointer;
339
  width: fit-content;
340
  font-size: 14px;
341
  line-height: 1.4;
342
  border-radius: 0;
343
  -webkit-appearance: none;
344
  appearance: none;
345
  text-decoration: none;
346
  display: inline-block;
347
  touch-action: manipulation;
348
}
349
350
button:hover,
351
.btn:hover {
352
  opacity: 0.7;
353
}
354
355
button.loading {
356
  cursor: wait;
357
}
358
359
.link-button {
360
  background: none;
361
  border: none;
362
  color: #ffffff;
363
  cursor: pointer;
364
  font-size: 12px;
365
  padding: 0;
366
  font-family: inherit;
367
  -webkit-appearance: none;
368
  appearance: none;
369
}
370
371
.link-button:hover {
372
  opacity: 0.7;
373
}
374
375
.link-button.danger {
376
  opacity: 0.5;
377
}
378
379
.link-button.danger:hover {
380
  opacity: 0.3;
381
}
382
383
.inline-form {
384
  display: inline;
385
  margin: 0;
386
  padding: 0;
387
}
388
389
/* ── Feedback ─────────────────────────────────────────────────────── */
390
391
.error {
392
  color: #ffffff;
393
  border-left: 2px solid #ffffff;
394
  padding-left: 0.5rem;
395
  font-size: 13px;
396
  opacity: 0.8;
397
}
398
399
.success {
400
  color: #ffffff;
401
  border-left: 2px solid #555;
402
  padding-left: 0.5rem;
403
  font-size: 13px;
404
  opacity: 0.7;
405
}
406
407
.empty {
408
  opacity: 0.5;
409
  font-size: 12px;
410
}
411
412
/* ── Item list (generic stacked list pattern) ────────────────────── */
413
414
.item-list {
415
  display: flex;
416
  flex-direction: column;
417
  width: 100%;
418
}
419
420
.item {
421
  display: flex;
422
  flex-direction: column;
423
  gap: 0.25rem;
424
  padding: 0.75rem 0;
425
  border-bottom: 1px solid #333;
426
  min-width: 0;
427
}
428
429
.item:hover {
430
  opacity: 0.7;
431
}
432
433
.item-title {
434
  display: grid;
435
  grid-template-columns: auto minmax(0, 1fr);
436
  align-items: center;
437
  gap: 0.4rem;
438
  min-width: 0;
439
  max-width: 100%;
440
  font-size: 16px;
441
  overflow-wrap: anywhere;
442
}
443
444
.item-meta {
445
  max-width: 100%;
446
  font-size: 12px;
447
  opacity: 0.5;
448
  overflow-wrap: anywhere;
449
  word-break: break-word;
450
}
451
452
.favicon {
453
  flex-shrink: 0;
454
}
455
456
/* ── Admin list (horizontal row w/ actions) ──────────────────────── */
457
458
.admin-list {
459
  display: flex;
460
  flex-direction: column;
461
  width: 100%;
462
}
463
464
.admin-list-item {
465
  display: flex;
466
  justify-content: space-between;
467
  align-items: center;
468
  padding: 8px 0;
469
  border-bottom: 1px solid #333;
470
  gap: 1rem;
471
  min-width: 0;
472
}
473
474
.admin-list-info {
475
  display: flex;
476
  flex: 1;
477
  flex-direction: column;
478
  gap: 0.2rem;
479
  min-width: 0;
480
}
481
482
.admin-list-title {
483
  display: grid;
484
  grid-template-columns: auto minmax(0, 1fr);
485
  align-items: center;
486
  gap: 0.4rem;
487
  min-width: 0;
488
  max-width: 100%;
489
  font-size: 15px;
490
  white-space: normal;
491
  overflow: visible;
492
  text-overflow: clip;
493
  overflow-wrap: anywhere;
494
}
495
496
.admin-list-meta {
497
  display: flex;
498
  gap: 0.75rem;
499
  align-items: center;
500
}
501
502
.admin-list-date {
503
  font-size: 11px;
504
  opacity: 0.4;
505
}
506
507
.admin-list-actions {
508
  display: flex;
509
  gap: 1rem;
510
  font-size: 12px;
511
  flex-shrink: 0;
512
  flex-wrap: wrap;
513
}
514
515
.admin-toolbar {
516
  display: flex;
517
  justify-content: space-between;
518
  align-items: center;
519
  width: 100%;
520
}
521
522
.admin-toolbar h2 {
523
  font-size: 18px;
524
  font-weight: 700;
525
}
526
527
@media (max-width: 480px) {
528
  .admin-list-item {
529
    flex-direction: column;
530
    align-items: flex-start;
531
    gap: 0.5rem;
532
  }
533
}
534
535
/* ── Tags / badges ───────────────────────────────────────────────── */
536
537
.tag {
538
  font-size: 11px;
539
  opacity: 0.5;
540
  background: #1e1c1f;
541
  padding: 1px 6px;
542
  border: 1px solid #333;
543
}
544
545
.status-badge {
546
  font-size: 11px;
547
  padding: 1px 6px;
548
  border: 1px solid #333;
549
}
550
551
.status-published {
552
  opacity: 1;
553
  border-color: #555;
554
}
555
556
.status-draft {
557
  opacity: 0.4;
558
}
559
560
/* ── Tables ──────────────────────────────────────────────────────── */
561
562
table {
563
  width: 100%;
564
  border-collapse: collapse;
565
}
566
567
th {
568
  opacity: 0.5;
569
  font-weight: 400;
570
  font-size: 12px;
571
  text-transform: uppercase;
572
  text-align: left;
573
  padding: 6px;
574
  border-bottom: 1px solid #333;
575
}
576
577
td {
578
  padding: 6px;
579
  border-bottom: 1px solid #333;
580
}
581
582
/* ── Spinner (braille) ────────────────────────────────────────────── */
583
584
.spinner {
585
  margin-left: 0.6rem;
586
}
587
588
.spinner::after {
589
  content: "⠋";
590
  display: inline-block;
591
  animation: braille-spin 0.8s steps(10) infinite;
592
}
593
594
@keyframes braille-spin {
595
  0%   { content: "⠋"; }
596
  10%  { content: "⠙"; }
597
  20%  { content: "⠹"; }
598
  30%  { content: "⠸"; }
599
  40%  { content: "⠼"; }
600
  50%  { content: "⠴"; }
601
  60%  { content: "⠦"; }
602
  70%  { content: "⠧"; }
603
  80%  { content: "⠇"; }
604
  90%  { content: "⠏"; }
605
}
606
607
/* ── Inline code ─────────────────────────────────────────────────── */
608
609
code {
610
  background: #1e1c1f;
611
  padding: 2px 4px;
612
  font-size: 13px;
613
}
614
615
pre {
616
  background: #1e1c1f;
617
  padding: 12px;
618
  overflow-x: auto;
619
  border: 1px solid #333;
620
  -webkit-overflow-scrolling: touch;
621
}
622
623
pre code {
624
  background: none;
625
  padding: 0;
626
}
627
628
/* ── Footer ──────────────────────────────────────────────────────── */
629
630
.footer {
631
  width: 100%;
632
  border-top: 1px solid #333;
633
  padding-top: 1rem;
634
  margin-top: auto;
635
  display: flex;
636
  justify-content: center;
637
}
638
639
/* ── Utility ─────────────────────────────────────────────────────── */
640
641
.hidden {
642
  display: none;
643
}
644
645
.scroll-x {
646
  overflow-x: auto;
647
  -webkit-overflow-scrolling: touch;
648
}