@nazuraki/styles 0.2.3 → 0.3.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 (42) hide show
  1. package/all.css +10 -0
  2. package/luminous-precision/base.css +24 -16
  3. package/luminous-precision/components/alert.css +10 -10
  4. package/luminous-precision/components/badge.css +6 -6
  5. package/luminous-precision/components/button.css +19 -19
  6. package/luminous-precision/components/card.css +3 -3
  7. package/luminous-precision/components/dialog.css +4 -4
  8. package/luminous-precision/components/form.css +26 -26
  9. package/luminous-precision/components/link.css +4 -4
  10. package/luminous-precision/components/progress.css +7 -7
  11. package/luminous-precision/components/table.css +5 -5
  12. package/luminous-precision/components/tabs.css +6 -6
  13. package/luminous-precision/design.md +13 -0
  14. package/luminous-precision/tokens.css +27 -10
  15. package/manifest.json +23 -0
  16. package/neon-butterfly/base.css +23 -10
  17. package/neon-butterfly/components/alert.css +10 -10
  18. package/neon-butterfly/components/badge.css +6 -6
  19. package/neon-butterfly/components/button.css +11 -11
  20. package/neon-butterfly/components/card.css +3 -3
  21. package/neon-butterfly/components/dialog.css +4 -4
  22. package/neon-butterfly/components/form.css +26 -26
  23. package/neon-butterfly/components/link.css +8 -8
  24. package/neon-butterfly/components/progress.css +7 -7
  25. package/neon-butterfly/components/table.css +5 -5
  26. package/neon-butterfly/components/tabs.css +6 -6
  27. package/neon-butterfly/design.md +12 -0
  28. package/neon-butterfly/tokens.css +29 -2
  29. package/package.json +9 -2
  30. package/summer-cloud/base.css +23 -13
  31. package/summer-cloud/components/alert.css +10 -10
  32. package/summer-cloud/components/badge.css +10 -10
  33. package/summer-cloud/components/button.css +22 -22
  34. package/summer-cloud/components/card.css +7 -7
  35. package/summer-cloud/components/dialog.css +4 -4
  36. package/summer-cloud/components/form.css +31 -31
  37. package/summer-cloud/components/link.css +16 -16
  38. package/summer-cloud/components/progress.css +8 -8
  39. package/summer-cloud/components/table.css +7 -7
  40. package/summer-cloud/components/tabs.css +7 -7
  41. package/summer-cloud/design.md +13 -0
  42. package/summer-cloud/tokens.css +27 -8
package/all.css ADDED
@@ -0,0 +1,10 @@
1
+ /* @nazuraki/styles — every theme in one import.
2
+ *
3
+ * Safe to load together: every rule in every theme is guarded by its
4
+ * data-nb-style attribute value, so nothing applies until an element opts in.
5
+ * Use this in apps that switch themes at runtime; single-theme apps should
6
+ * import just their theme's index.css.
7
+ */
8
+ @import "./neon-butterfly/index.css";
9
+ @import "./summer-cloud/index.css";
10
+ @import "./luminous-precision/index.css";
@@ -1,27 +1,40 @@
1
1
  /* luminous-precision — base styles
2
- * Global defaults. Requires tokens.css. Apps that need webfonts should
2
+ * Scoped defaults. Requires tokens.css. Apps that need webfonts should
3
3
  * include the Google Fonts <link>s for Sora (500, 600, 700) and
4
4
  * JetBrains Mono (400, 600, 700) or self-host; the token stacks fall back
5
5
  * to system families.
6
+ *
7
+ * The element carrying data-nb-style is the theme's canvas: it gets the
8
+ * background, text color, and body font — whether that is <html> for a page
9
+ * or a mount container for an embedded island. Page-only rules (body margin,
10
+ * viewport height) apply only when the attribute sits on <html>.
6
11
  */
7
- *,
8
- *::before,
9
- *::after {
12
+ :where([data-nb-style="luminous-precision"]) {
13
+ background-color: var(--nb-bg);
14
+ color: var(--nb-on-surface);
15
+ font-family: var(--nb-font-body);
16
+ font-weight: var(--nb-font-weight);
17
+ }
18
+
19
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *),
20
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *)::before,
21
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *)::after {
10
22
  box-sizing: border-box;
11
23
  }
12
24
 
13
- body {
25
+ :where(html[data-nb-style="luminous-precision"]) body {
14
26
  margin: 0;
15
27
  min-height: 100vh;
16
28
  background-color: var(--nb-bg);
17
29
  color: var(--nb-on-surface);
18
- font-family: var(--nb-font-mono);
30
+ font-family: var(--nb-font-body);
19
31
  font-weight: var(--nb-font-weight);
20
32
  }
21
33
 
22
34
  /* Opt-in page background: soft out-of-focus orchid/teal underlays over the
23
- * obsidian base — the "luminous underlay" treatment. Apply to <body>. */
24
- .nb-bg {
35
+ * obsidian base — the "luminous underlay" treatment. Apply to <body>, or to
36
+ * the attributed container itself. */
37
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-bg {
25
38
  background:
26
39
  radial-gradient(50rem 30rem at 12% -5%, rgba(198, 165, 255, 0.08), transparent 70%),
27
40
  radial-gradient(55rem 35rem at 90% 105%, rgba(0, 245, 255, 0.05), transparent 70%),
@@ -29,22 +42,17 @@ body {
29
42
  background-attachment: fixed;
30
43
  }
31
44
 
32
- h1,
33
- h2,
34
- h3,
35
- h4,
36
- h5,
37
- h6 {
45
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *):where(h1, h2, h3, h4, h5, h6) {
38
46
  font-family: var(--nb-font-display);
39
47
  font-weight: var(--nb-font-weight-medium);
40
48
  letter-spacing: -0.01em;
41
49
  }
42
50
 
43
- a {
51
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *):where(a) {
44
52
  color: var(--nb-primary);
45
53
  }
46
54
 
47
- ::selection {
55
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *)::selection {
48
56
  background: var(--nb-primary);
49
57
  color: var(--nb-bg);
50
58
  }
@@ -1,5 +1,5 @@
1
1
  /* luminous-precision — alert / callout */
2
- .nb-alert {
2
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-alert {
3
3
  padding: var(--nb-space-3) var(--nb-space-4);
4
4
  background: var(--nb-surface-glass);
5
5
  border: 1px solid var(--nb-border);
@@ -9,18 +9,18 @@
9
9
  color: var(--nb-on-surface);
10
10
  font-size: var(--nb-text-sm);
11
11
  }
12
- .nb-alert--info { border-left-color: var(--nb-info); }
13
- .nb-alert--success { border-left-color: var(--nb-success); }
14
- .nb-alert--warning { border-left-color: var(--nb-warning); }
15
- .nb-alert--danger { border-left-color: var(--nb-danger); }
16
- .nb-alert__title {
12
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-alert--info { border-left-color: var(--nb-info); }
13
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-alert--success { border-left-color: var(--nb-success); }
14
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-alert--warning { border-left-color: var(--nb-warning); }
15
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-alert--danger { border-left-color: var(--nb-danger); }
16
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-alert__title {
17
17
  display: block;
18
18
  margin-bottom: var(--nb-space-1);
19
19
  text-transform: uppercase;
20
20
  font-weight: var(--nb-font-weight-medium);
21
21
  letter-spacing: var(--nb-tracking-wide);
22
22
  }
23
- .nb-alert--info .nb-alert__title { color: var(--nb-info); }
24
- .nb-alert--success .nb-alert__title { color: var(--nb-success); }
25
- .nb-alert--warning .nb-alert__title { color: var(--nb-warning); }
26
- .nb-alert--danger .nb-alert__title { color: var(--nb-danger); }
23
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-alert--info .nb-alert__title { color: var(--nb-info); }
24
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-alert--success .nb-alert__title { color: var(--nb-success); }
25
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-alert--warning .nb-alert__title { color: var(--nb-warning); }
26
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-alert--danger .nb-alert__title { color: var(--nb-danger); }
@@ -1,6 +1,6 @@
1
1
  /* luminous-precision — badge: pill chip, 15% tint of its hue behind
2
2
  * full-saturation text */
3
- .nb-badge {
3
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-badge {
4
4
  display: inline-block;
5
5
  padding: 0.15rem var(--nb-space-2);
6
6
  background: rgba(255, 255, 255, 0.08);
@@ -12,8 +12,8 @@
12
12
  font-weight: var(--nb-font-weight-medium);
13
13
  letter-spacing: var(--nb-tracking-wide);
14
14
  }
15
- .nb-badge--primary { background: rgba(198, 165, 255, 0.15); color: var(--nb-primary); }
16
- .nb-badge--info { background: rgba(131, 183, 255, 0.15); color: var(--nb-info); }
17
- .nb-badge--success { background: rgba(71, 227, 78, 0.15); color: var(--nb-success); }
18
- .nb-badge--warning { background: rgba(255, 184, 108, 0.15); color: var(--nb-warning); }
19
- .nb-badge--danger { background: rgba(255, 77, 109, 0.15); color: var(--nb-danger); }
15
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-badge--primary { background: rgba(198, 165, 255, 0.15); color: var(--nb-primary); }
16
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-badge--info { background: rgba(131, 183, 255, 0.15); color: var(--nb-info); }
17
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-badge--success { background: rgba(71, 227, 78, 0.15); color: var(--nb-success); }
18
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-badge--warning { background: rgba(255, 184, 108, 0.15); color: var(--nb-warning); }
19
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-badge--danger { background: rgba(255, 77, 109, 0.15); color: var(--nb-danger); }
@@ -1,5 +1,5 @@
1
1
  /* luminous-precision — button */
2
- .nb-btn {
2
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-btn {
3
3
  display: inline-flex;
4
4
  align-items: center;
5
5
  gap: var(--nb-space-2);
@@ -19,55 +19,55 @@
19
19
  color var(--nb-transition),
20
20
  box-shadow var(--nb-transition);
21
21
  }
22
- .nb-btn:hover,
23
- .nb-btn:focus-visible {
22
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-btn:hover,
23
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-btn:focus-visible {
24
24
  border-color: var(--nb-primary-border);
25
25
  color: var(--nb-primary);
26
- animation: nb-pulse-glow 2s infinite;
26
+ animation: nb-lp-pulse-glow 2s infinite;
27
27
  outline: none;
28
28
  }
29
29
 
30
30
  /* primary: solid orchid fill, dark text, glow pulse on hover */
31
- .nb-btn--primary {
31
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-btn--primary {
32
32
  background: var(--nb-primary);
33
33
  border-color: var(--nb-primary);
34
34
  color: var(--nb-on-primary);
35
35
  }
36
- .nb-btn--primary:hover,
37
- .nb-btn--primary:focus-visible {
36
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-btn--primary:hover,
37
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-btn--primary:focus-visible {
38
38
  border-color: var(--nb-primary);
39
39
  color: var(--nb-on-primary);
40
40
  }
41
41
 
42
42
  /* accent: teal ghost — critical navigation paths */
43
- .nb-btn--accent {
43
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-btn--accent {
44
44
  border-color: var(--nb-accent);
45
45
  color: var(--nb-accent);
46
46
  }
47
- .nb-btn--accent:hover,
48
- .nb-btn--accent:focus-visible {
47
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-btn--accent:hover,
48
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-btn--accent:focus-visible {
49
49
  border-color: var(--nb-accent);
50
50
  color: var(--nb-accent);
51
- animation-name: nb-pulse-glow-accent;
51
+ animation-name: nb-lp-pulse-glow-accent;
52
52
  }
53
53
 
54
- .nb-btn--danger {
54
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-btn--danger {
55
55
  border-color: var(--nb-danger);
56
56
  color: var(--nb-danger);
57
57
  }
58
- .nb-btn--danger:hover,
59
- .nb-btn--danger:focus-visible {
58
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-btn--danger:hover,
59
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-btn--danger:focus-visible {
60
60
  border-color: var(--nb-danger);
61
61
  color: var(--nb-danger);
62
62
  }
63
63
 
64
- .nb-btn:disabled {
64
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-btn:disabled {
65
65
  opacity: 0.5;
66
66
  cursor: not-allowed;
67
67
  animation: none;
68
68
  }
69
69
 
70
- @keyframes nb-pulse-glow-accent {
70
+ @keyframes nb-lp-pulse-glow-accent {
71
71
  0%,
72
72
  100% {
73
73
  box-shadow: 0 0 5px rgba(0, 245, 255, 0.15);
@@ -78,11 +78,11 @@
78
78
  }
79
79
 
80
80
  @media (prefers-reduced-motion: reduce) {
81
- .nb-btn {
81
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-btn {
82
82
  transition: none;
83
83
  }
84
- .nb-btn:hover,
85
- .nb-btn:focus-visible {
84
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-btn:hover,
85
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-btn:focus-visible {
86
86
  animation: none;
87
87
  }
88
88
  }
@@ -1,5 +1,5 @@
1
1
  /* luminous-precision — card: glass pane with a lit top edge */
2
- .nb-card {
2
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-card {
3
3
  padding: var(--nb-space-4);
4
4
  background: var(--nb-surface-glass);
5
5
  border: 1px solid var(--nb-border);
@@ -8,5 +8,5 @@
8
8
  backdrop-filter: blur(var(--nb-blur));
9
9
  color: var(--nb-on-surface);
10
10
  }
11
- .nb-card > :first-child { margin-top: 0; }
12
- .nb-card > :last-child { margin-bottom: 0; }
11
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-card > :first-child { margin-top: 0; }
12
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-card > :last-child { margin-bottom: 0; }
@@ -1,5 +1,5 @@
1
1
  /* luminous-precision — dialog (native <dialog>) */
2
- .nb-dialog {
2
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-dialog {
3
3
  padding: var(--nb-space-4);
4
4
  max-width: 32rem;
5
5
  width: calc(100vw - 2rem);
@@ -11,11 +11,11 @@
11
11
  font-family: var(--nb-font-mono);
12
12
  box-shadow: 0 0 40px var(--nb-primary-glow);
13
13
  }
14
- .nb-dialog::backdrop {
14
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-dialog::backdrop {
15
15
  background: rgba(10, 12, 16, 0.6);
16
16
  backdrop-filter: blur(var(--nb-blur));
17
17
  }
18
- .nb-dialog__title {
18
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-dialog__title {
19
19
  margin: 0 0 var(--nb-space-3);
20
20
  color: var(--nb-primary);
21
21
  font-family: var(--nb-font-display);
@@ -23,7 +23,7 @@
23
23
  font-weight: var(--nb-font-weight-medium);
24
24
  letter-spacing: -0.01em;
25
25
  }
26
- .nb-dialog__actions {
26
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-dialog__actions {
27
27
  display: flex;
28
28
  justify-content: flex-end;
29
29
  gap: var(--nb-space-2);
@@ -1,9 +1,9 @@
1
1
  /* luminous-precision — form controls: input, textarea, select, checkbox,
2
2
  * radio, switch. Focus drops the resting border for an electric-teal line
3
3
  * with a soft outer glow. */
4
- .nb-input,
5
- .nb-select,
6
- .nb-textarea {
4
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-input,
5
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-select,
6
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-textarea {
7
7
  display: block;
8
8
  width: 100%;
9
9
  padding: var(--nb-space-2) var(--nb-space-3);
@@ -16,30 +16,30 @@
16
16
  font-size: var(--nb-text-sm);
17
17
  transition: border-color var(--nb-transition), box-shadow var(--nb-transition);
18
18
  }
19
- .nb-select {
19
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-select {
20
20
  appearance: none;
21
21
  padding-right: 2.25rem;
22
22
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23958e9b' stroke-width='1.5'/%3E%3C/svg%3E");
23
23
  background-repeat: no-repeat;
24
24
  background-position: right 0.75rem center;
25
25
  }
26
- .nb-input::placeholder,
27
- .nb-textarea::placeholder {
26
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-input::placeholder,
27
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-textarea::placeholder {
28
28
  color: var(--nb-faint);
29
29
  }
30
- .nb-input:focus,
31
- .nb-select:focus,
32
- .nb-textarea:focus {
30
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-input:focus,
31
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-select:focus,
32
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-textarea:focus {
33
33
  outline: none;
34
34
  border-color: var(--nb-accent);
35
35
  box-shadow: 0 0 8px var(--nb-accent-glow);
36
36
  }
37
- .nb-input[aria-invalid="true"],
38
- .nb-textarea[aria-invalid="true"] {
37
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-input[aria-invalid="true"],
38
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-textarea[aria-invalid="true"] {
39
39
  border-color: var(--nb-danger);
40
40
  }
41
41
 
42
- .nb-label {
42
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-label {
43
43
  display: block;
44
44
  margin-bottom: var(--nb-space-1);
45
45
  color: var(--nb-faint);
@@ -49,13 +49,13 @@
49
49
  letter-spacing: var(--nb-tracking-wide);
50
50
  }
51
51
 
52
- .nb-field {
52
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-field {
53
53
  margin-bottom: var(--nb-space-3);
54
54
  }
55
55
 
56
56
  /* checkbox & radio */
57
- .nb-checkbox,
58
- .nb-radio {
57
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-checkbox,
58
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-radio {
59
59
  appearance: none;
60
60
  width: 1.1rem;
61
61
  height: 1.1rem;
@@ -67,22 +67,22 @@
67
67
  cursor: pointer;
68
68
  transition: border-color var(--nb-transition), box-shadow var(--nb-transition);
69
69
  }
70
- .nb-radio {
70
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-radio {
71
71
  border-radius: 50%;
72
72
  }
73
- .nb-checkbox:checked,
74
- .nb-radio:checked {
73
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-checkbox:checked,
74
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-radio:checked {
75
75
  border-color: var(--nb-accent);
76
76
  box-shadow: inset 0 0 0 3px var(--nb-surface), inset 0 0 0 1rem var(--nb-accent),
77
77
  0 0 6px var(--nb-accent-glow);
78
78
  }
79
- .nb-checkbox:focus-visible,
80
- .nb-radio:focus-visible,
81
- .nb-switch:focus-visible {
79
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-checkbox:focus-visible,
80
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-radio:focus-visible,
81
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-switch:focus-visible {
82
82
  outline: none;
83
83
  border-color: var(--nb-primary-border);
84
84
  }
85
- .nb-choice {
85
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-choice {
86
86
  display: inline-flex;
87
87
  align-items: center;
88
88
  gap: var(--nb-space-2);
@@ -92,7 +92,7 @@
92
92
  }
93
93
 
94
94
  /* switch */
95
- .nb-switch {
95
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-switch {
96
96
  appearance: none;
97
97
  width: 2.4rem;
98
98
  height: 1.3rem;
@@ -105,7 +105,7 @@
105
105
  position: relative;
106
106
  transition: border-color var(--nb-transition);
107
107
  }
108
- .nb-switch::after {
108
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-switch::after {
109
109
  content: "";
110
110
  position: absolute;
111
111
  top: 2px;
@@ -116,10 +116,10 @@
116
116
  background: var(--nb-faint);
117
117
  transition: transform var(--nb-transition), background var(--nb-transition);
118
118
  }
119
- .nb-switch:checked {
119
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-switch:checked {
120
120
  border-color: var(--nb-accent);
121
121
  }
122
- .nb-switch:checked::after {
122
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-switch:checked::after {
123
123
  transform: translateX(1.1rem);
124
124
  background: var(--nb-accent);
125
125
  box-shadow: 0 0 6px var(--nb-accent-glow);
@@ -1,6 +1,6 @@
1
1
  /* luminous-precision — nav link: glass list row; hover shifts the indigo and
2
2
  * lights a 2px electric-teal bar on the left edge */
3
- .nb-link {
3
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-link {
4
4
  display: flex;
5
5
  align-items: baseline;
6
6
  gap: var(--nb-space-3);
@@ -21,7 +21,7 @@
21
21
  color var(--nb-transition),
22
22
  box-shadow var(--nb-transition);
23
23
  }
24
- .nb-link:hover {
24
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-link:hover {
25
25
  background: var(--nb-surface);
26
26
  color: var(--nb-accent);
27
27
  box-shadow:
@@ -29,7 +29,7 @@
29
29
  0 0 12px var(--nb-accent-glow);
30
30
  }
31
31
 
32
- @keyframes nb-pulse-glow {
32
+ @keyframes nb-lp-pulse-glow {
33
33
  0%,
34
34
  100% {
35
35
  box-shadow: 0 0 5px rgba(198, 165, 255, 0.15);
@@ -40,7 +40,7 @@
40
40
  }
41
41
 
42
42
  @media (prefers-reduced-motion: reduce) {
43
- .nb-link {
43
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-link {
44
44
  transition: none;
45
45
  }
46
46
  }
@@ -1,5 +1,5 @@
1
1
  /* luminous-precision — progress bar & spinner */
2
- .nb-progress {
2
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-progress {
3
3
  display: block;
4
4
  width: 100%;
5
5
  height: 0.5rem;
@@ -8,34 +8,34 @@
8
8
  border-radius: 1rem;
9
9
  overflow: hidden;
10
10
  }
11
- .nb-progress__bar {
11
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-progress__bar {
12
12
  height: 100%;
13
13
  background: var(--nb-primary);
14
14
  box-shadow: 0 0 8px var(--nb-primary-glow);
15
15
  border-radius: 1rem;
16
16
  transition: width var(--nb-transition);
17
17
  }
18
- .nb-progress__bar--accent {
18
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-progress__bar--accent {
19
19
  background: var(--nb-accent);
20
20
  box-shadow: 0 0 8px var(--nb-accent-glow);
21
21
  }
22
22
 
23
- .nb-spinner {
23
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-spinner {
24
24
  display: inline-block;
25
25
  width: 1.5rem;
26
26
  height: 1.5rem;
27
27
  border: 2px solid var(--nb-border);
28
28
  border-top-color: var(--nb-primary);
29
29
  border-radius: 50%;
30
- animation: nb-spin 0.8s linear infinite;
30
+ animation: nb-lp-spin 0.8s linear infinite;
31
31
  }
32
- @keyframes nb-spin {
32
+ @keyframes nb-lp-spin {
33
33
  to {
34
34
  transform: rotate(360deg);
35
35
  }
36
36
  }
37
37
  @media (prefers-reduced-motion: reduce) {
38
- .nb-spinner {
38
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-spinner {
39
39
  animation-duration: 2s;
40
40
  }
41
41
  }
@@ -1,11 +1,11 @@
1
1
  /* luminous-precision — table */
2
- .nb-table {
2
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-table {
3
3
  width: 100%;
4
4
  border-collapse: collapse;
5
5
  font-size: var(--nb-text-sm);
6
6
  color: var(--nb-on-surface);
7
7
  }
8
- .nb-table th {
8
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-table th {
9
9
  padding: var(--nb-space-2) var(--nb-space-3);
10
10
  border-bottom: 1px solid var(--nb-border-lit);
11
11
  color: var(--nb-faint);
@@ -15,14 +15,14 @@
15
15
  font-weight: var(--nb-font-weight-medium);
16
16
  letter-spacing: var(--nb-tracking-wide);
17
17
  }
18
- .nb-table td {
18
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-table td {
19
19
  padding: var(--nb-space-2) var(--nb-space-3);
20
20
  border-bottom: 1px solid var(--nb-border);
21
21
  }
22
- .nb-table tbody tr {
22
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-table tbody tr {
23
23
  transition: background var(--nb-transition), box-shadow var(--nb-transition);
24
24
  }
25
- .nb-table tbody tr:hover {
25
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-table tbody tr:hover {
26
26
  background: var(--nb-surface-glass);
27
27
  box-shadow: inset 2px 0 0 0 var(--nb-accent);
28
28
  }
@@ -1,10 +1,10 @@
1
1
  /* luminous-precision — tabs: active tab carries the electric-teal path */
2
- .nb-tabs {
2
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-tabs {
3
3
  display: flex;
4
4
  gap: var(--nb-space-2);
5
5
  border-bottom: 1px solid var(--nb-border);
6
6
  }
7
- .nb-tab {
7
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-tab {
8
8
  padding: var(--nb-space-2) var(--nb-space-3);
9
9
  margin-bottom: -1px;
10
10
  background: none;
@@ -19,15 +19,15 @@
19
19
  cursor: pointer;
20
20
  transition: color var(--nb-transition), border-color var(--nb-transition);
21
21
  }
22
- .nb-tab:hover {
22
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-tab:hover {
23
23
  color: var(--nb-on-surface);
24
24
  }
25
- .nb-tab--active,
26
- .nb-tab[aria-selected="true"] {
25
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-tab--active,
26
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-tab[aria-selected="true"] {
27
27
  color: var(--nb-accent);
28
28
  border-bottom-color: var(--nb-accent);
29
29
  text-shadow: 0 0 8px var(--nb-accent-glow);
30
30
  }
31
- .nb-tabpanel {
31
+ :where([data-nb-style="luminous-precision"], [data-nb-style="luminous-precision"] *).nb-tabpanel {
32
32
  padding: var(--nb-space-3) 0;
33
33
  }
@@ -74,3 +74,16 @@ Class prefix `nb-` (shared token/class contract with the other themes).
74
74
  the teal left bar.
75
75
  - **Progress** `.nb-progress`, **Spinner** `.nb-spinner` — glowing orchid
76
76
  indicators (`--accent` bar variant in teal).
77
+
78
+ ## Code syntax
79
+
80
+ Tokens `--nb-code-*`, part of the baseline contract. Orchid keywords, teal
81
+ types, info-blue functions, amber numbers, success-green strings, soft-rose
82
+ variables, dimmed-faint comments, faint meta — palette voices reused, never
83
+ new hues for decoration.
84
+
85
+ ## Scoping
86
+
87
+ Every rule is guarded by `data-nb-style="luminous-precision"` (self or
88
+ ancestor), wrapped in zero-specificity `:where()`. Set the attribute on
89
+ `<html>` for a page or on a container for an embedded island.
@@ -3,27 +3,33 @@
3
3
  * @import "@nazuraki/styles/luminous-precision/tokens";
4
4
  * or pull the whole theme with ./index.css.
5
5
  *
6
- * Token names mirror neon-butterfly's --nb-* contract so themes stay
7
- * swappable; names marked (extra) are additions this theme needs and that
8
- * neon-butterfly does not define.
6
+ * Nothing applies until an element carries data-nb-style="luminous-precision"
7
+ * set it on <html> for a page, or on any container for an embedded island.
8
+ * The :where() keeps specificity at zero, so any consumer rule overrides.
9
+ *
10
+ * Every theme declares the same baseline token set (styles/test enforces
11
+ * parity); names marked (extra) are additions beyond it that only this
12
+ * theme's own component CSS may rely on.
9
13
  */
10
- :root {
14
+ :where([data-nb-style="luminous-precision"]) {
15
+ color-scheme: dark;
16
+
11
17
  /* color */
12
18
  --nb-bg: #0a0c10;
13
19
  --nb-bg-blend: #111319;
14
20
  --nb-surface: #1a1d29;
15
- --nb-surface-sunken: #0c0e14; /* (extra) inset fields, log wells */
21
+ --nb-surface-sunken: #0c0e14; /* inset fields, log wells */
16
22
  --nb-surface-glass: rgba(26, 29, 41, 0.4);
17
23
  --nb-on-surface: #e2e2eb;
18
24
  --nb-faint: #958e9b;
19
25
  --nb-primary: #c6a5ff;
20
26
  --nb-primary-glow: rgba(198, 165, 255, 0.35);
21
27
  --nb-primary-border: rgba(198, 165, 255, 0.6);
22
- --nb-on-primary: #16101f; /* (extra) text on solid orchid fills */
28
+ --nb-on-primary: #16101f; /* text on solid orchid fills */
23
29
  --nb-accent: #00f5ff;
24
30
  --nb-accent-glow: rgba(0, 245, 255, 0.3);
25
31
  --nb-border: rgba(255, 255, 255, 0.08);
26
- --nb-border-lit: rgba(255, 255, 255, 0.2); /* (extra) lit top edge of glass panes */
32
+ --nb-border-lit: rgba(255, 255, 255, 0.2); /* lit top edge of glass panes */
27
33
 
28
34
  /* semantic color */
29
35
  --nb-info: #83b7ff;
@@ -31,18 +37,29 @@
31
37
  --nb-warning: #ffb86c;
32
38
  --nb-danger: #ff4d6d;
33
39
 
40
+ /* code syntax — orchid keywords, teal types, palette-derived accents */
41
+ --nb-code-keyword: #c6a5ff;
42
+ --nb-code-string: #47e34e;
43
+ --nb-code-number: #ffb86c;
44
+ --nb-code-comment: #837b8d;
45
+ --nb-code-function: #83b7ff;
46
+ --nb-code-variable: #ff7d95;
47
+ --nb-code-type: #00f5ff;
48
+ --nb-code-meta: #958e9b;
49
+
34
50
  /* typography */
35
- --nb-font-display: "Sora", ui-sans-serif, system-ui, sans-serif; /* (extra) headlines */
51
+ --nb-font-display: "Sora", ui-sans-serif, system-ui, sans-serif; /* headlines */
52
+ --nb-font-body: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; /* mono body is the design */
36
53
  --nb-font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
37
54
  --nb-font-weight: 400;
38
- --nb-font-weight-medium: 600; /* (extra) labels, interactive text */
55
+ --nb-font-weight-medium: 600; /* labels, interactive text */
39
56
  --nb-font-weight-bold: 700;
40
57
  --nb-text-sm: 14px;
41
58
  --nb-tracking-wide: 0.05em;
42
59
 
43
60
  /* shape & effects */
44
61
  --nb-radius: 0.5rem;
45
- --nb-radius-lg: 1rem; /* (extra) cards and large containers */
62
+ --nb-radius-lg: 1rem; /* cards and large containers */
46
63
  --nb-blur: 12px;
47
64
  --nb-transition: 0.3s;
48
65