@danieldeusing/design 0.1.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.
@@ -0,0 +1,554 @@
1
+ /*! danieldeusing-design v0.1.0 | MIT | https://github.com/danieldeusing/danieldeusing-design */
2
+ /* ===== reset.css ===== */
3
+ /*
4
+ * danieldeusing-design — minimal reset.
5
+ *
6
+ * Only loaded on the build-free path (index.css / the dist bundle / CDN), where
7
+ * there is no Tailwind Preflight to normalize the document. Tailwind v4 apps must
8
+ * NOT import this — they already get an equivalent reset from Preflight, and
9
+ * importing it twice would be redundant. Deliberately tiny: it normalizes the box
10
+ * model and strips default margins so the terminal layout is predictable, and
11
+ * stops short of a full normalize.css.
12
+ */
13
+
14
+ *,
15
+ *::before,
16
+ *::after {
17
+ box-sizing: border-box;
18
+ }
19
+
20
+ * {
21
+ margin: 0;
22
+ }
23
+
24
+ html {
25
+ -webkit-text-size-adjust: 100%;
26
+ text-size-adjust: 100%;
27
+ tab-size: 4;
28
+ }
29
+
30
+ body {
31
+ min-height: 100vh;
32
+ min-height: 100dvh;
33
+ line-height: 1.5;
34
+ }
35
+
36
+ img,
37
+ picture,
38
+ video,
39
+ canvas,
40
+ svg {
41
+ display: block;
42
+ max-width: 100%;
43
+ }
44
+
45
+ input,
46
+ button,
47
+ textarea,
48
+ select {
49
+ font: inherit;
50
+ color: inherit;
51
+ }
52
+
53
+ p,
54
+ h1,
55
+ h2,
56
+ h3,
57
+ h4,
58
+ h5,
59
+ h6 {
60
+ overflow-wrap: break-word;
61
+ }
62
+
63
+ ul,
64
+ ol {
65
+ list-style: none;
66
+ padding: 0;
67
+ }
68
+
69
+ a {
70
+ color: inherit;
71
+ text-decoration: none;
72
+ }
73
+
74
+ table {
75
+ border-collapse: collapse;
76
+ }
77
+
78
+ /* ===== tokens.css ===== */
79
+ /*
80
+ * danieldeusing-design — design tokens.
81
+ *
82
+ * The single source of truth for the "terminal" theme: CRT phosphor on
83
+ * JetBrains Mono, $-prompts, ASCII rules, scanline overlay. Four variants
84
+ * selected via html[data-theme]: warm (default), green, mono, paper.
85
+ * :root holds the warm defaults so the theme works with no attribute set.
86
+ *
87
+ * These are plain CSS custom properties — they work in any framework, any
88
+ * browser, with or without a build step. Load this file first; base.css and
89
+ * components.css resolve against the variables declared here.
90
+ */
91
+
92
+ :root {
93
+ --background: #f5efe2;
94
+ --foreground: #43352a;
95
+ --card: #efe7d4;
96
+ --card-foreground: #43352a;
97
+ --popover: #efe7d4;
98
+ --popover-foreground: #43352a;
99
+ --primary: #8a4516;
100
+ --primary-foreground: #f8f3e8;
101
+ --secondary: #ece3cf;
102
+ --secondary-foreground: #43352a;
103
+ --muted: #ece3cf;
104
+ --muted-foreground: #71614e;
105
+ --accent: #8a4516;
106
+ --accent-foreground: #f8f3e8;
107
+ --destructive: #a02c2c;
108
+ --border: #d9cdb6;
109
+ --input: #d9cdb6;
110
+ --ring: #8a4516;
111
+
112
+ --glow: rgba(160, 82, 45, 0.1);
113
+ --glow-soft: rgba(160, 82, 45, 0.05);
114
+ --scanline-opacity: 0.15;
115
+
116
+ --radius: 0rem;
117
+
118
+ --font-mono: "JetBrains Mono Variable", "JetBrains Mono", "Menlo", monospace;
119
+ }
120
+
121
+ /* CRT phosphor green */
122
+ html[data-theme="green"] {
123
+ --background: #020604;
124
+ --foreground: #4fdd7d;
125
+ --card: #04110a;
126
+ --card-foreground: #4fdd7d;
127
+ --popover: #04110a;
128
+ --popover-foreground: #4fdd7d;
129
+ --primary: #33ff66;
130
+ --primary-foreground: #02160a;
131
+ --secondary: #071509;
132
+ --secondary-foreground: #4fdd7d;
133
+ --muted: #071509;
134
+ --muted-foreground: #3da45e;
135
+ --accent: #33ff66;
136
+ --accent-foreground: #02160a;
137
+ --destructive: #ff5c5c;
138
+ --border: #1c4a2c;
139
+ --input: #1c4a2c;
140
+ --ring: #33ff66;
141
+ --glow: rgba(51, 255, 102, 0.35);
142
+ --glow-soft: rgba(51, 255, 102, 0.12);
143
+ --scanline-opacity: 0.5;
144
+ }
145
+
146
+ /* white-phosphor terminal */
147
+ html[data-theme="mono"] {
148
+ --background: #050505;
149
+ --foreground: #d4d4d4;
150
+ --card: #0d0d0d;
151
+ --card-foreground: #d4d4d4;
152
+ --popover: #0d0d0d;
153
+ --popover-foreground: #d4d4d4;
154
+ --primary: #ffffff;
155
+ --primary-foreground: #050505;
156
+ --secondary: #111111;
157
+ --secondary-foreground: #d4d4d4;
158
+ --muted: #111111;
159
+ --muted-foreground: #8a8a8a;
160
+ --accent: #ffffff;
161
+ --accent-foreground: #050505;
162
+ --destructive: #ff5c5c;
163
+ --border: #333333;
164
+ --input: #333333;
165
+ --ring: #ffffff;
166
+ --glow: rgba(255, 255, 255, 0.25);
167
+ --glow-soft: rgba(255, 255, 255, 0.08);
168
+ --scanline-opacity: 0.45;
169
+ }
170
+
171
+ /* black-on-white terminal (e-ink / printout) */
172
+ html[data-theme="paper"] {
173
+ --background: #fafafa;
174
+ --foreground: #1f1f1f;
175
+ --card: #f1f1f1;
176
+ --card-foreground: #1f1f1f;
177
+ --popover: #f1f1f1;
178
+ --popover-foreground: #1f1f1f;
179
+ --primary: #000000;
180
+ --primary-foreground: #fafafa;
181
+ --secondary: #efefef;
182
+ --secondary-foreground: #1f1f1f;
183
+ --muted: #efefef;
184
+ --muted-foreground: #595959;
185
+ --accent: #000000;
186
+ --accent-foreground: #fafafa;
187
+ --destructive: #b3261e;
188
+ --border: #d4d4d4;
189
+ --input: #d4d4d4;
190
+ --ring: #000000;
191
+ --glow: rgba(0, 0, 0, 0.06);
192
+ --glow-soft: rgba(0, 0, 0, 0.04);
193
+ --scanline-opacity: 0.12;
194
+ }
195
+
196
+ /* ===== base.css ===== */
197
+ /*
198
+ * danieldeusing-design — base layer.
199
+ *
200
+ * The document-level look of the terminal theme: monospace body, CRT scanline
201
+ * overlay, phosphor selection, themed default border colour. Resolves against
202
+ * tokens.css (load that first). Plain CSS — no Tailwind required.
203
+ */
204
+
205
+ html {
206
+ scroll-behavior: smooth;
207
+ }
208
+
209
+ /* Default any element's border to the themed colour, so a bare `border-width`
210
+ (or a Tailwind `border` utility) paints in the theme border rather than the
211
+ element's currentColor. Mirrors the canonical `* { @apply border-border }`. */
212
+ *,
213
+ *::before,
214
+ *::after {
215
+ border-color: var(--border);
216
+ }
217
+
218
+ /* Visible, on-theme focus ring for keyboard navigation. */
219
+ :focus-visible {
220
+ outline: 2px solid var(--ring);
221
+ outline-offset: 2px;
222
+ }
223
+
224
+ body {
225
+ background: var(--background);
226
+ color: var(--foreground);
227
+ font-family: var(--font-mono);
228
+ font-size: 0.75rem;
229
+ line-height: 1.5;
230
+ overflow-x: hidden;
231
+ -webkit-font-smoothing: antialiased;
232
+ -moz-osx-font-smoothing: grayscale;
233
+ }
234
+
235
+ /* Tailwind v4's reset drops the default button cursor — restore it for all
236
+ interactive controls (buttons, summaries, role=button). */
237
+ button:not(:disabled),
238
+ summary,
239
+ [role="button"] {
240
+ cursor: pointer;
241
+ }
242
+
243
+ /* CRT scanlines: a fixed, non-interactive overlay above the page. Intensity is
244
+ per-theme via --scanline-opacity. */
245
+ body::after {
246
+ content: "";
247
+ position: fixed;
248
+ inset: 0;
249
+ z-index: 40;
250
+ pointer-events: none;
251
+ background: repeating-linear-gradient(
252
+ 0deg,
253
+ rgba(0, 0, 0, 0.25) 0px,
254
+ rgba(0, 0, 0, 0.25) 1px,
255
+ transparent 1px,
256
+ transparent 3px
257
+ );
258
+ opacity: var(--scanline-opacity);
259
+ }
260
+
261
+ ::selection {
262
+ background: var(--primary);
263
+ color: var(--primary-foreground);
264
+ }
265
+
266
+ /* ===== components.css ===== */
267
+ /*
268
+ * danieldeusing-design — component layer.
269
+ *
270
+ * Reusable, framework-agnostic primitives in plain CSS (no Tailwind @apply), so
271
+ * they render identically in an Astro/React/Angular app, a Tauri webview, or a
272
+ * single static HTML file. Every value resolves against tokens.css.
273
+ */
274
+
275
+ /* ─────────────────────────────────────────────────────────────────────────
276
+ Phosphor glow — for bright, "lit" elements (brand mark, active items).
277
+ ───────────────────────────────────────────────────────────────────────── */
278
+ .glow {
279
+ color: var(--primary);
280
+ text-shadow: 0 0 8px var(--glow);
281
+ }
282
+ .glow-lg {
283
+ color: var(--primary);
284
+ text-shadow: 0 0 12px var(--glow);
285
+ }
286
+
287
+ /* ─────────────────────────────────────────────────────────────────────────
288
+ Shell affordances — `$ command` section headers and `# comment` lines.
289
+ ───────────────────────────────────────────────────────────────────────── */
290
+ .prompt {
291
+ font-size: 0.75rem;
292
+ font-weight: 700;
293
+ color: var(--muted-foreground);
294
+ }
295
+ .prompt::before {
296
+ content: "$ ";
297
+ color: var(--primary);
298
+ }
299
+
300
+ .comment::before {
301
+ content: "# ";
302
+ color: var(--border);
303
+ }
304
+
305
+ /* Blinking block cursor — pair with a brand mark or end-of-line. */
306
+ .cursor-block {
307
+ display: inline-block;
308
+ width: 0.55em;
309
+ height: 1em;
310
+ margin-left: 8px;
311
+ background: var(--primary);
312
+ vertical-align: baseline;
313
+ transform: translateY(0.12em);
314
+ animation: ddd-blink 1.1s step-end infinite;
315
+ }
316
+ @keyframes ddd-blink {
317
+ 50% {
318
+ opacity: 0;
319
+ }
320
+ }
321
+
322
+ /* ─────────────────────────────────────────────────────────────────────────
323
+ Primary CTA — `> label` with a phosphor glow that lifts on hover.
324
+ ───────────────────────────────────────────────────────────────────────── */
325
+ .btn-terminal {
326
+ display: inline-block;
327
+ background: var(--primary);
328
+ color: var(--primary-foreground);
329
+ font-weight: 700;
330
+ padding: 12px 24px;
331
+ box-shadow: 0 0 16px var(--glow);
332
+ transition:
333
+ box-shadow 0.15s ease,
334
+ transform 0.15s ease;
335
+ }
336
+ .btn-terminal::before {
337
+ content: "> ";
338
+ }
339
+ .btn-terminal:hover {
340
+ box-shadow: 0 0 28px var(--glow);
341
+ transform: translateY(-2px);
342
+ }
343
+
344
+ /* Quiet, underlined link that warms to the primary colour on hover. */
345
+ .link-quiet {
346
+ color: var(--muted-foreground);
347
+ text-decoration: underline;
348
+ text-underline-offset: 4px;
349
+ transition: color 0.15s ease;
350
+ }
351
+ .link-quiet:hover {
352
+ color: var(--primary);
353
+ }
354
+
355
+ /* ASCII horizontal rule — a clipped, full-width row of box-drawing dashes that
356
+ reads like a terminal separator. Use on an <hr> or <div>; the dashes are a
357
+ decorative ::before clipped to the element width. */
358
+ .ascii-rule {
359
+ margin: 1rem 0;
360
+ border: 0;
361
+ color: var(--border);
362
+ line-height: 1;
363
+ white-space: nowrap;
364
+ overflow: hidden;
365
+ user-select: none;
366
+ }
367
+ .ascii-rule::before {
368
+ content: "────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────";
369
+ }
370
+
371
+ /* ─────────────────────────────────────────────────────────────────────────
372
+ Card — bordered surface that warms its border and glows softly on hover.
373
+ ───────────────────────────────────────────────────────────────────────── */
374
+ .card-terminal {
375
+ background: var(--card);
376
+ border: 1px solid var(--border);
377
+ transition:
378
+ border-color 0.15s ease,
379
+ box-shadow 0.15s ease;
380
+ }
381
+ .card-terminal:hover {
382
+ border-color: var(--primary);
383
+ box-shadow: 0 0 20px var(--glow-soft);
384
+ }
385
+
386
+ /* ─────────────────────────────────────────────────────────────────────────
387
+ Dropdown — a <details class="dropdown"> with a <summary> trigger and a
388
+ floating panel. Pairs with runtime/dropdown.js (close-others, click-away,
389
+ Escape). The panel opens UPWARD by default (for status-bar / footer menus);
390
+ add .dropdown-panel--down to open below the trigger.
391
+ ───────────────────────────────────────────────────────────────────────── */
392
+ .dropdown {
393
+ position: relative;
394
+ }
395
+ .dropdown > summary {
396
+ display: inline-flex;
397
+ align-items: center;
398
+ gap: 6px;
399
+ cursor: pointer;
400
+ user-select: none;
401
+ list-style: none;
402
+ color: var(--muted-foreground);
403
+ transition: color 0.15s ease;
404
+ }
405
+ .dropdown > summary::-webkit-details-marker {
406
+ display: none;
407
+ }
408
+ .dropdown > summary:hover,
409
+ .dropdown[open] > summary {
410
+ color: var(--primary);
411
+ }
412
+ .dropdown-panel {
413
+ position: absolute;
414
+ right: 0;
415
+ bottom: calc(100% + 12px);
416
+ z-index: 50;
417
+ min-width: 128px;
418
+ margin: 0;
419
+ padding: 4px 0;
420
+ list-style: none;
421
+ background: var(--card);
422
+ border: 1px solid var(--border);
423
+ border-radius: 0;
424
+ box-shadow: 0 0 20px var(--glow-soft);
425
+ }
426
+ /* open below the trigger instead of above */
427
+ .dropdown-panel--down {
428
+ top: calc(100% + 8px);
429
+ bottom: auto;
430
+ left: 0;
431
+ right: auto;
432
+ }
433
+ .dropdown-item {
434
+ display: flex;
435
+ align-items: center;
436
+ gap: 8px;
437
+ width: 100%;
438
+ padding: 5px 14px;
439
+ text-align: left;
440
+ font: inherit;
441
+ line-height: 1.5;
442
+ background: none;
443
+ border: 0;
444
+ color: var(--muted-foreground);
445
+ cursor: pointer;
446
+ white-space: nowrap;
447
+ transition: color 0.15s ease;
448
+ }
449
+ .dropdown-item:hover {
450
+ color: var(--primary);
451
+ background: var(--muted);
452
+ }
453
+ .dropdown-item[aria-current="true"],
454
+ html:not([data-theme]) .dropdown-item[data-theme-value="warm"],
455
+ html[data-theme="green"] .dropdown-item[data-theme-value="green"],
456
+ html[data-theme="mono"] .dropdown-item[data-theme-value="mono"],
457
+ html[data-theme="paper"] .dropdown-item[data-theme-value="paper"],
458
+ html[data-theme="warm"] .dropdown-item[data-theme-value="warm"] {
459
+ color: var(--primary);
460
+ text-shadow: 0 0 8px var(--glow);
461
+ }
462
+
463
+ /* ─────────────────────────────────────────────────────────────────────────
464
+ ELI5 — an "explain like I'm 5" callout box (first-time-term explainers).
465
+ ───────────────────────────────────────────────────────────────────────── */
466
+ .eli5 {
467
+ margin: 1.25em 0;
468
+ padding: 0.7em 1em;
469
+ color: var(--foreground);
470
+ background: color-mix(in srgb, var(--primary) 7%, var(--card));
471
+ border: 1px solid var(--border);
472
+ border-left: 3px solid var(--primary);
473
+ border-radius: var(--radius);
474
+ font-size: 0.92em;
475
+ line-height: 1.6;
476
+ }
477
+ .eli5::before {
478
+ content: "ELI5";
479
+ display: inline-flex;
480
+ align-items: center;
481
+ justify-content: center;
482
+ margin-right: 0.6em;
483
+ vertical-align: 0.08em;
484
+ font-family: var(--font-mono);
485
+ font-size: 0.72em;
486
+ font-weight: 700;
487
+ line-height: 1;
488
+ letter-spacing: 0.04em;
489
+ padding: 0.34em 0.6em;
490
+ border-radius: 5px;
491
+ background: #b42318;
492
+ color: #fff;
493
+ }
494
+ .eli5-term {
495
+ font-weight: 700;
496
+ color: var(--primary);
497
+ }
498
+
499
+ /* ─────────────────────────────────────────────────────────────────────────
500
+ Animation kill-switch — add html.anim-off (e.g. from a footer "animations
501
+ off" toggle) to stop ALL motion regardless of the OS reduced-motion setting.
502
+ runtime/terminal.js also bails when this class is present, so content stays
503
+ visible. Complements the prefers-reduced-motion handling below.
504
+ ───────────────────────────────────────────────────────────────────────── */
505
+ html.anim-off *,
506
+ html.anim-off *::before,
507
+ html.anim-off *::after {
508
+ animation: none !important;
509
+ transition: none !important;
510
+ }
511
+ html.anim-off .cursor-block {
512
+ opacity: 1;
513
+ }
514
+
515
+ /* ─────────────────────────────────────────────────────────────────────────
516
+ Terminal session animation — `$ command` prompts type out, then their
517
+ section's content reveals like command output. Pairs with
518
+ runtime/terminal.js, which adds html.term-anim pre-paint. With JS disabled
519
+ or prefers-reduced-motion, the gate is never added and nothing is hidden, so
520
+ all content is visible by default (progressive enhancement).
521
+
522
+ Markup: a section gets [data-term]; its prompt uses .prompt; each chunk of
523
+ output gets [data-term-out].
524
+ ───────────────────────────────────────────────────────────────────────── */
525
+ @media (prefers-reduced-motion: no-preference) {
526
+ /* pending prompt: fully invisible (incl. the `$ ` prefix), line box reserved */
527
+ html.term-anim [data-term] .prompt:not(.term-live),
528
+ html.term-anim [data-term] .prompt:not(.term-live)::before {
529
+ color: transparent;
530
+ }
531
+ /* pending output: keep layout (no CLS), no interaction until revealed */
532
+ html.term-anim [data-term] [data-term-out]:not(.term-show) {
533
+ visibility: hidden;
534
+ }
535
+ /* phosphor warm-up flicker as output appears */
536
+ html.term-anim [data-term] [data-term-out].term-show {
537
+ animation: ddd-term-output 0.2s steps(3, end) both;
538
+ }
539
+ @keyframes ddd-term-output {
540
+ from {
541
+ opacity: 0;
542
+ }
543
+ }
544
+ /* caret at the typing edge (created by runtime/terminal.js) */
545
+ .term-caret {
546
+ display: inline-block;
547
+ width: 0.55em;
548
+ height: 1em;
549
+ margin-left: 2px;
550
+ background: var(--primary);
551
+ vertical-align: baseline;
552
+ transform: translateY(0.12em);
553
+ }
554
+ }
@@ -0,0 +1,2 @@
1
+ /*! danieldeusing-design v0.1.0 | MIT | https://github.com/danieldeusing/danieldeusing-design */
2
+ *,*::before,*::after{box-sizing: border-box}*{margin: 0}html{-webkit-text-size-adjust: 100%;text-size-adjust: 100%;tab-size: 4}body{min-height: 100vh;min-height: 100dvh;line-height: 1.5}img,picture,video,canvas,svg{display: block;max-width: 100%}input,button,textarea,select{font: inherit;color: inherit}p,h1,h2,h3,h4,h5,h6{overflow-wrap: break-word}ul,ol{list-style: none;padding: 0}a{color: inherit;text-decoration: none}table{border-collapse: collapse}:root{--background: #f5efe2;--foreground: #43352a;--card: #efe7d4;--card-foreground: #43352a;--popover: #efe7d4;--popover-foreground: #43352a;--primary: #8a4516;--primary-foreground: #f8f3e8;--secondary: #ece3cf;--secondary-foreground: #43352a;--muted: #ece3cf;--muted-foreground: #71614e;--accent: #8a4516;--accent-foreground: #f8f3e8;--destructive: #a02c2c;--border: #d9cdb6;--input: #d9cdb6;--ring: #8a4516;--glow: rgba(160,82,45,0.1);--glow-soft: rgba(160,82,45,0.05);--scanline-opacity: 0.15;--radius: 0rem;--font-mono: "JetBrains Mono Variable","JetBrains Mono","Menlo",monospace}html[data-theme="green"]{--background: #020604;--foreground: #4fdd7d;--card: #04110a;--card-foreground: #4fdd7d;--popover: #04110a;--popover-foreground: #4fdd7d;--primary: #33ff66;--primary-foreground: #02160a;--secondary: #071509;--secondary-foreground: #4fdd7d;--muted: #071509;--muted-foreground: #3da45e;--accent: #33ff66;--accent-foreground: #02160a;--destructive: #ff5c5c;--border: #1c4a2c;--input: #1c4a2c;--ring: #33ff66;--glow: rgba(51,255,102,0.35);--glow-soft: rgba(51,255,102,0.12);--scanline-opacity: 0.5}html[data-theme="mono"]{--background: #050505;--foreground: #d4d4d4;--card: #0d0d0d;--card-foreground: #d4d4d4;--popover: #0d0d0d;--popover-foreground: #d4d4d4;--primary: #ffffff;--primary-foreground: #050505;--secondary: #111111;--secondary-foreground: #d4d4d4;--muted: #111111;--muted-foreground: #8a8a8a;--accent: #ffffff;--accent-foreground: #050505;--destructive: #ff5c5c;--border: #333333;--input: #333333;--ring: #ffffff;--glow: rgba(255,255,255,0.25);--glow-soft: rgba(255,255,255,0.08);--scanline-opacity: 0.45}html[data-theme="paper"]{--background: #fafafa;--foreground: #1f1f1f;--card: #f1f1f1;--card-foreground: #1f1f1f;--popover: #f1f1f1;--popover-foreground: #1f1f1f;--primary: #000000;--primary-foreground: #fafafa;--secondary: #efefef;--secondary-foreground: #1f1f1f;--muted: #efefef;--muted-foreground: #595959;--accent: #000000;--accent-foreground: #fafafa;--destructive: #b3261e;--border: #d4d4d4;--input: #d4d4d4;--ring: #000000;--glow: rgba(0,0,0,0.06);--glow-soft: rgba(0,0,0,0.04);--scanline-opacity: 0.12}html{scroll-behavior: smooth}*,*::before,*::after{border-color: var(--border)}:focus-visible{outline: 2px solid var(--ring);outline-offset: 2px}body{background: var(--background);color: var(--foreground);font-family: var(--font-mono);font-size: 0.75rem;line-height: 1.5;overflow-x: hidden;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale}button:not(:disabled),summary,[role="button"]{cursor: pointer}body::after{content: "";position: fixed;inset: 0;z-index: 40;pointer-events: none;background: repeating-linear-gradient( 0deg,rgba(0,0,0,0.25) 0px,rgba(0,0,0,0.25) 1px,transparent 1px,transparent 3px );opacity: var(--scanline-opacity)}::selection{background: var(--primary);color: var(--primary-foreground)}.glow{color: var(--primary);text-shadow: 0 0 8px var(--glow)}.glow-lg{color: var(--primary);text-shadow: 0 0 12px var(--glow)}.prompt{font-size: 0.75rem;font-weight: 700;color: var(--muted-foreground)}.prompt::before{content: "$ ";color: var(--primary)}.comment::before{content: "# ";color: var(--border)}.cursor-block{display: inline-block;width: 0.55em;height: 1em;margin-left: 8px;background: var(--primary);vertical-align: baseline;transform: translateY(0.12em);animation: ddd-blink 1.1s step-end infinite}@keyframes ddd-blink{50%{opacity: 0}}.btn-terminal{display: inline-block;background: var(--primary);color: var(--primary-foreground);font-weight: 700;padding: 12px 24px;box-shadow: 0 0 16px var(--glow);transition: box-shadow 0.15s ease,transform 0.15s ease}.btn-terminal::before{content: "> "}.btn-terminal:hover{box-shadow: 0 0 28px var(--glow);transform: translateY(-2px)}.link-quiet{color: var(--muted-foreground);text-decoration: underline;text-underline-offset: 4px;transition: color 0.15s ease}.link-quiet:hover{color: var(--primary)}.ascii-rule{margin: 1rem 0;border: 0;color: var(--border);line-height: 1;white-space: nowrap;overflow: hidden;user-select: none}.ascii-rule::before{content: "────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────"}.card-terminal{background: var(--card);border: 1px solid var(--border);transition: border-color 0.15s ease,box-shadow 0.15s ease}.card-terminal:hover{border-color: var(--primary);box-shadow: 0 0 20px var(--glow-soft)}.dropdown{position: relative}.dropdown>summary{display: inline-flex;align-items: center;gap: 6px;cursor: pointer;user-select: none;list-style: none;color: var(--muted-foreground);transition: color 0.15s ease}.dropdown>summary::-webkit-details-marker{display: none}.dropdown>summary:hover,.dropdown[open]>summary{color: var(--primary)}.dropdown-panel{position: absolute;right: 0;bottom: calc(100% + 12px);z-index: 50;min-width: 128px;margin: 0;padding: 4px 0;list-style: none;background: var(--card);border: 1px solid var(--border);border-radius: 0;box-shadow: 0 0 20px var(--glow-soft)}.dropdown-panel--down{top: calc(100% + 8px);bottom: auto;left: 0;right: auto}.dropdown-item{display: flex;align-items: center;gap: 8px;width: 100%;padding: 5px 14px;text-align: left;font: inherit;line-height: 1.5;background: none;border: 0;color: var(--muted-foreground);cursor: pointer;white-space: nowrap;transition: color 0.15s ease}.dropdown-item:hover{color: var(--primary);background: var(--muted)}.dropdown-item[aria-current="true"],html:not([data-theme]) .dropdown-item[data-theme-value="warm"],html[data-theme="green"] .dropdown-item[data-theme-value="green"],html[data-theme="mono"] .dropdown-item[data-theme-value="mono"],html[data-theme="paper"] .dropdown-item[data-theme-value="paper"],html[data-theme="warm"] .dropdown-item[data-theme-value="warm"]{color: var(--primary);text-shadow: 0 0 8px var(--glow)}.eli5{margin: 1.25em 0;padding: 0.7em 1em;color: var(--foreground);background: color-mix(in srgb,var(--primary) 7%,var(--card));border: 1px solid var(--border);border-left: 3px solid var(--primary);border-radius: var(--radius);font-size: 0.92em;line-height: 1.6}.eli5::before{content: "ELI5";display: inline-flex;align-items: center;justify-content: center;margin-right: 0.6em;vertical-align: 0.08em;font-family: var(--font-mono);font-size: 0.72em;font-weight: 700;line-height: 1;letter-spacing: 0.04em;padding: 0.34em 0.6em;border-radius: 5px;background: #b42318;color: #fff}.eli5-term{font-weight: 700;color: var(--primary)}html.anim-off *,html.anim-off *::before,html.anim-off *::after{animation: none !important;transition: none !important}html.anim-off .cursor-block{opacity: 1}@media (prefers-reduced-motion: no-preference){html.term-anim [data-term] .prompt:not(.term-live),html.term-anim [data-term] .prompt:not(.term-live)::before{color: transparent}html.term-anim [data-term] [data-term-out]:not(.term-show){visibility: hidden}html.term-anim [data-term] [data-term-out].term-show{animation: ddd-term-output 0.2s steps(3,end) both}@keyframes ddd-term-output{from{opacity: 0}}.term-caret{display: inline-block;width: 0.55em;height: 1em;margin-left: 2px;background: var(--primary);vertical-align: baseline;transform: translateY(0.12em)}}
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@danieldeusing/design",
3
+ "version": "0.1.0",
4
+ "description": "The danieldeusing terminal design system — framework-agnostic CSS tokens, components, and a vanilla-JS runtime for the CRT/JetBrains-Mono look used across danieldeusing.de, seedr, and briefs.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Daniel Deusing",
8
+ "homepage": "https://github.com/danieldeusing/danieldeusing-design#readme",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/danieldeusing/danieldeusing-design.git"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/danieldeusing/danieldeusing-design/issues"
15
+ },
16
+ "keywords": [
17
+ "design-system",
18
+ "design-tokens",
19
+ "css",
20
+ "tailwindcss",
21
+ "tailwind-v4",
22
+ "terminal",
23
+ "crt",
24
+ "theme",
25
+ "danieldeusing"
26
+ ],
27
+ "main": "./src/index.css",
28
+ "style": "./src/index.css",
29
+ "exports": {
30
+ ".": "./src/index.css",
31
+ "./tailwind.css": "./src/tailwind.css",
32
+ "./index.css": "./src/index.css",
33
+ "./reset.css": "./src/reset.css",
34
+ "./fonts.css": "./src/fonts.css",
35
+ "./tokens.css": "./src/tokens.css",
36
+ "./base.css": "./src/base.css",
37
+ "./components.css": "./src/components.css",
38
+ "./tokens.json": "./tokens/tokens.json",
39
+ "./runtime": "./runtime/index.js",
40
+ "./runtime/*": "./runtime/*.js",
41
+ "./dist/*": "./dist/*",
42
+ "./package.json": "./package.json"
43
+ },
44
+ "files": [
45
+ "src",
46
+ "runtime",
47
+ "dist",
48
+ "tokens",
49
+ "README.md",
50
+ "LICENSE"
51
+ ],
52
+ "sideEffects": [
53
+ "*.css"
54
+ ],
55
+ "scripts": {
56
+ "build": "node scripts/build.mjs",
57
+ "prepublishOnly": "node scripts/build.mjs"
58
+ },
59
+ "engines": {
60
+ "node": ">=18"
61
+ },
62
+ "publishConfig": {
63
+ "access": "public"
64
+ }
65
+ }
@@ -0,0 +1,44 @@
1
+ /*
2
+ * danieldeusing-design — dropdown controller.
3
+ *
4
+ * Behaviour for <details class="dropdown"> menus styled by components.css:
5
+ * opening one closes the others, a click outside closes all, and Escape closes
6
+ * all. Native <details> already handles open/close and keyboard focus, so this
7
+ * is purely the "only one open, dismiss on outside interaction" layer.
8
+ */
9
+
10
+ /**
11
+ * @param {ParentNode} [root=document] Where to look for `details.dropdown`.
12
+ * @returns {(except?: HTMLDetailsElement) => void} A closeAll() you can call
13
+ * manually (e.g. after a menu item triggers navigation).
14
+ */
15
+ export function initDropdowns(root = document) {
16
+ const dropdowns = /** @type {HTMLDetailsElement[]} */ (
17
+ Array.from(root.querySelectorAll("details.dropdown"))
18
+ );
19
+
20
+ const closeAll = (except) => {
21
+ dropdowns.forEach((dropdown) => {
22
+ if (dropdown !== except) dropdown.removeAttribute("open");
23
+ });
24
+ };
25
+
26
+ dropdowns.forEach((dropdown) => {
27
+ dropdown.addEventListener("toggle", () => {
28
+ if (dropdown.open) closeAll(dropdown);
29
+ });
30
+ });
31
+
32
+ document.addEventListener("click", (event) => {
33
+ const target = event.target;
34
+ if (!(target instanceof Node) || !dropdowns.some((dropdown) => dropdown.contains(target))) {
35
+ closeAll();
36
+ }
37
+ });
38
+
39
+ document.addEventListener("keydown", (event) => {
40
+ if (event.key === "Escape") closeAll();
41
+ });
42
+
43
+ return closeAll;
44
+ }
@@ -0,0 +1,16 @@
1
+ /*
2
+ * danieldeusing-design — runtime barrel.
3
+ *
4
+ * Optional, dependency-free vanilla-JS enhancements for the terminal theme.
5
+ * Tree-shakeable: import only what you need, e.g.
6
+ *
7
+ * import { applyStoredTheme, initThemeSwitcher } from "@danieldeusing/design/runtime";
8
+ *
9
+ * The CSS works on its own; this layer adds theme switching, the resolution
10
+ * zoom, dropdown behaviour, and the terminal typing animation.
11
+ */
12
+
13
+ export * from "./theme.js";
14
+ export * from "./zoom.js";
15
+ export * from "./dropdown.js";
16
+ export * from "./terminal.js";