@rackbops/styles 0.1.10 → 0.2.3

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 (34) hide show
  1. package/amber-ember/components/button.css +3 -1
  2. package/amber-ember/components/tabs.css +5 -1
  3. package/amber-hearth/components/button.css +3 -1
  4. package/amber-hearth/components/tabs.css +5 -1
  5. package/arcane-obsidian/components/button.css +3 -1
  6. package/arcane-obsidian/components/tabs.css +5 -1
  7. package/arcane-obsidian/components/tabstrip.css +5 -1
  8. package/arcane-parchment/components/button.css +3 -1
  9. package/arcane-parchment/components/tabs.css +5 -1
  10. package/arcane-parchment/components/tabstrip.css +5 -1
  11. package/concrete-signal/components/button.css +13 -2
  12. package/concrete-signal/components/tabs.css +5 -1
  13. package/concrete-signal/design.md +7 -2
  14. package/concrete-signal-light/components/button.css +13 -2
  15. package/concrete-signal-light/components/tabs.css +5 -1
  16. package/concrete-signal-light/design.md +3 -1
  17. package/contract.json +9 -1
  18. package/luminous-precision/base.css +19 -1
  19. package/luminous-precision/components/tabs.css +5 -1
  20. package/luminous-precision/design.md +3 -1
  21. package/mono-field/components/tabs.css +5 -1
  22. package/mono-field/design.md +3 -1
  23. package/neon-butterfly/base.css +27 -4
  24. package/neon-butterfly/components/tabs.css +5 -1
  25. package/neon-butterfly/design.md +3 -0
  26. package/package.json +1 -1
  27. package/rackbops-noir/components/tabs.css +5 -1
  28. package/rackbops-studio/components/tabs.css +5 -1
  29. package/summer-cloud/base.css +19 -1
  30. package/summer-cloud/components/badge.css +7 -3
  31. package/summer-cloud/components/button.css +4 -4
  32. package/summer-cloud/components/form.css +1 -1
  33. package/summer-cloud/components/tabs.css +5 -1
  34. package/summer-cloud/design.md +10 -3
@@ -40,8 +40,10 @@
40
40
  }
41
41
  :where([data-rb-style="amber-ember"], [data-rb-style="amber-ember"] *).rb-btn:not(:disabled):hover,
42
42
  :where([data-rb-style="amber-ember"], [data-rb-style="amber-ember"] *).rb-btn:focus-visible {
43
+ /* Hover firms the border; focus additionally keeps the base accent outline
44
+ (base.css) -- "Focus is the accent" -- so keyboard focus reads distinctly
45
+ and accent-based, not just a neutral border shift. */
43
46
  border-color: var(--rb-border-strong);
44
- outline: none;
45
47
  }
46
48
  :where([data-rb-style="amber-ember"], [data-rb-style="amber-ember"] *).rb-btn--primary {
47
49
  background: var(--rb-accent);
@@ -19,9 +19,13 @@
19
19
  cursor: pointer;
20
20
  transition: color var(--rb-transition);
21
21
  }
22
- :where([data-rb-style="amber-ember"], [data-rb-style="amber-ember"] *).rb-tab:hover {
22
+ :where([data-rb-style="amber-ember"], [data-rb-style="amber-ember"] *).rb-tab:not(:disabled):hover {
23
23
  color: var(--rb-text);
24
24
  }
25
+ :where([data-rb-style="amber-ember"], [data-rb-style="amber-ember"] *).rb-tab:disabled {
26
+ opacity: 0.5;
27
+ cursor: not-allowed;
28
+ }
25
29
  :where([data-rb-style="amber-ember"], [data-rb-style="amber-ember"] *).rb-tab.rb-tab--active,
26
30
  :where([data-rb-style="amber-ember"], [data-rb-style="amber-ember"] *).rb-tab[aria-selected="true"] {
27
31
  color: var(--rb-accent);
@@ -40,8 +40,10 @@
40
40
  }
41
41
  :where([data-rb-style="amber-hearth"], [data-rb-style="amber-hearth"] *).rb-btn:not(:disabled):hover,
42
42
  :where([data-rb-style="amber-hearth"], [data-rb-style="amber-hearth"] *).rb-btn:focus-visible {
43
+ /* Hover firms the border; focus additionally keeps the base accent outline
44
+ (base.css) -- "Focus is the accent" -- so keyboard focus reads distinctly
45
+ and accent-based, not just a neutral border shift. */
43
46
  border-color: var(--rb-border-strong);
44
- outline: none;
45
47
  }
46
48
  :where([data-rb-style="amber-hearth"], [data-rb-style="amber-hearth"] *).rb-btn--primary {
47
49
  background: var(--rb-accent);
@@ -19,9 +19,13 @@
19
19
  cursor: pointer;
20
20
  transition: color var(--rb-transition);
21
21
  }
22
- :where([data-rb-style="amber-hearth"], [data-rb-style="amber-hearth"] *).rb-tab:hover {
22
+ :where([data-rb-style="amber-hearth"], [data-rb-style="amber-hearth"] *).rb-tab:not(:disabled):hover {
23
23
  color: var(--rb-text);
24
24
  }
25
+ :where([data-rb-style="amber-hearth"], [data-rb-style="amber-hearth"] *).rb-tab:disabled {
26
+ opacity: 0.5;
27
+ cursor: not-allowed;
28
+ }
25
29
  :where([data-rb-style="amber-hearth"], [data-rb-style="amber-hearth"] *).rb-tab.rb-tab--active,
26
30
  :where([data-rb-style="amber-hearth"], [data-rb-style="amber-hearth"] *).rb-tab[aria-selected="true"] {
27
31
  color: var(--rb-accent);
@@ -38,8 +38,10 @@
38
38
  }
39
39
  :where([data-rb-style="arcane-obsidian"], [data-rb-style="arcane-obsidian"] *).rb-btn:not(:disabled):hover,
40
40
  :where([data-rb-style="arcane-obsidian"], [data-rb-style="arcane-obsidian"] *).rb-btn:focus-visible {
41
+ /* Keep the base :focus-visible accent outline (base.css) as the focus
42
+ indicator -- "interactive elements take a 2px accent outline" (design.md);
43
+ hover shares the accent border but not the outline (it isn't focus). */
41
44
  border-color: var(--rb-accent);
42
- outline: none;
43
45
  }
44
46
  :where([data-rb-style="arcane-obsidian"], [data-rb-style="arcane-obsidian"] *).rb-btn--primary {
45
47
  background: var(--rb-accent);
@@ -18,9 +18,13 @@
18
18
  cursor: pointer;
19
19
  transition: color var(--rb-transition);
20
20
  }
21
- :where([data-rb-style="arcane-obsidian"], [data-rb-style="arcane-obsidian"] *).rb-tab:hover {
21
+ :where([data-rb-style="arcane-obsidian"], [data-rb-style="arcane-obsidian"] *).rb-tab:not(:disabled):hover {
22
22
  color: var(--rb-text);
23
23
  }
24
+ :where([data-rb-style="arcane-obsidian"], [data-rb-style="arcane-obsidian"] *).rb-tab:disabled {
25
+ opacity: 0.5;
26
+ cursor: not-allowed;
27
+ }
24
28
  :where([data-rb-style="arcane-obsidian"], [data-rb-style="arcane-obsidian"] *).rb-tab.rb-tab--active,
25
29
  :where([data-rb-style="arcane-obsidian"], [data-rb-style="arcane-obsidian"] *).rb-tab[aria-selected="true"] {
26
30
  color: var(--rb-accent);
@@ -19,9 +19,13 @@
19
19
  cursor: pointer;
20
20
  transition: border-color var(--rb-transition);
21
21
  }
22
- :where([data-rb-style="arcane-obsidian"], [data-rb-style="arcane-obsidian"] *).rb-tabstrip__tab:hover {
22
+ :where([data-rb-style="arcane-obsidian"], [data-rb-style="arcane-obsidian"] *).rb-tabstrip__tab:not(:disabled):hover {
23
23
  border-color: var(--rb-accent);
24
24
  }
25
+ :where([data-rb-style="arcane-obsidian"], [data-rb-style="arcane-obsidian"] *).rb-tabstrip__tab:disabled {
26
+ opacity: 0.5;
27
+ cursor: not-allowed;
28
+ }
25
29
  :where([data-rb-style="arcane-obsidian"], [data-rb-style="arcane-obsidian"] *).rb-tabstrip__tab.rb-tabstrip__tab--active {
26
30
  color: var(--rb-accent);
27
31
  border-color: color-mix(in srgb, var(--rb-accent) 40%, var(--rb-border));
@@ -38,8 +38,10 @@
38
38
  }
39
39
  :where([data-rb-style="arcane-parchment"], [data-rb-style="arcane-parchment"] *).rb-btn:not(:disabled):hover,
40
40
  :where([data-rb-style="arcane-parchment"], [data-rb-style="arcane-parchment"] *).rb-btn:focus-visible {
41
+ /* Keep the base :focus-visible accent outline (base.css) as the focus
42
+ indicator -- "interactive elements take a 2px accent outline" (design.md);
43
+ hover shares the accent border but not the outline (it isn't focus). */
41
44
  border-color: var(--rb-accent);
42
- outline: none;
43
45
  }
44
46
  :where([data-rb-style="arcane-parchment"], [data-rb-style="arcane-parchment"] *).rb-btn--primary {
45
47
  background: var(--rb-accent);
@@ -18,9 +18,13 @@
18
18
  cursor: pointer;
19
19
  transition: color var(--rb-transition);
20
20
  }
21
- :where([data-rb-style="arcane-parchment"], [data-rb-style="arcane-parchment"] *).rb-tab:hover {
21
+ :where([data-rb-style="arcane-parchment"], [data-rb-style="arcane-parchment"] *).rb-tab:not(:disabled):hover {
22
22
  color: var(--rb-text);
23
23
  }
24
+ :where([data-rb-style="arcane-parchment"], [data-rb-style="arcane-parchment"] *).rb-tab:disabled {
25
+ opacity: 0.5;
26
+ cursor: not-allowed;
27
+ }
24
28
  :where([data-rb-style="arcane-parchment"], [data-rb-style="arcane-parchment"] *).rb-tab.rb-tab--active,
25
29
  :where([data-rb-style="arcane-parchment"], [data-rb-style="arcane-parchment"] *).rb-tab[aria-selected="true"] {
26
30
  color: var(--rb-accent);
@@ -19,9 +19,13 @@
19
19
  cursor: pointer;
20
20
  transition: border-color var(--rb-transition);
21
21
  }
22
- :where([data-rb-style="arcane-parchment"], [data-rb-style="arcane-parchment"] *).rb-tabstrip__tab:hover {
22
+ :where([data-rb-style="arcane-parchment"], [data-rb-style="arcane-parchment"] *).rb-tabstrip__tab:not(:disabled):hover {
23
23
  border-color: var(--rb-accent);
24
24
  }
25
+ :where([data-rb-style="arcane-parchment"], [data-rb-style="arcane-parchment"] *).rb-tabstrip__tab:disabled {
26
+ opacity: 0.5;
27
+ cursor: not-allowed;
28
+ }
25
29
  :where([data-rb-style="arcane-parchment"], [data-rb-style="arcane-parchment"] *).rb-tabstrip__tab.rb-tabstrip__tab--active {
26
30
  color: var(--rb-accent);
27
31
  border-color: color-mix(in srgb, var(--rb-accent) 40%, var(--rb-border));
@@ -42,9 +42,11 @@
42
42
  }
43
43
  :where([data-rb-style="concrete-signal"], [data-rb-style="concrete-signal"] *).rb-btn:not(:disabled):hover,
44
44
  :where([data-rb-style="concrete-signal"], [data-rb-style="concrete-signal"] *).rb-btn:focus-visible {
45
+ /* Hover and focus both firm the border/text to accent; focus additionally
46
+ keeps the base hard accent outline (base.css) -- hard-edged, no wash or
47
+ glow -- so keyboard focus stays distinct from a pointer hover. */
45
48
  border-color: var(--rb-accent);
46
49
  color: var(--rb-accent);
47
- outline: none;
48
50
  }
49
51
  :where([data-rb-style="concrete-signal"], [data-rb-style="concrete-signal"] *).rb-btn--primary {
50
52
  background: var(--rb-accent);
@@ -56,7 +58,6 @@
56
58
  box-shadow var(--rb-transition);
57
59
  }
58
60
  :where([data-rb-style="concrete-signal"], [data-rb-style="concrete-signal"] *).rb-btn--primary:not(:disabled):hover,
59
- :where([data-rb-style="concrete-signal"], [data-rb-style="concrete-signal"] *).rb-btn--primary:focus-visible,
60
61
  :where([data-rb-style="concrete-signal"], [data-rb-style="concrete-signal"] *).rb-btn--primary:active {
61
62
  border-color: var(--rb-accent);
62
63
  color: var(--rb-accent-fg);
@@ -64,6 +65,16 @@
64
65
  transform: translate(2px, 2px);
65
66
  box-shadow: none;
66
67
  }
68
+ /* Focus: a 1->2px border-weight change is invisible on the accent fill
69
+ (border == fill), so focus is a hard 2px accent outline offset from the
70
+ button -- hard-edged, not a soft wash ring or glow -- distinct from the
71
+ hover/active press. Text stays --accent-fg so it doesn't inherit the default
72
+ .rb-btn:focus-visible accent color against the accent fill. */
73
+ :where([data-rb-style="concrete-signal"], [data-rb-style="concrete-signal"] *).rb-btn--primary:focus-visible {
74
+ color: var(--rb-accent-fg);
75
+ outline: 2px solid var(--rb-accent);
76
+ outline-offset: 2px;
77
+ }
67
78
  :where([data-rb-style="concrete-signal"], [data-rb-style="concrete-signal"] *).rb-btn--accent {
68
79
  background: var(--rb-accent-wash);
69
80
  border-color: var(--rb-accent);
@@ -21,9 +21,13 @@
21
21
  cursor: pointer;
22
22
  transition: color var(--rb-transition);
23
23
  }
24
- :where([data-rb-style="concrete-signal"], [data-rb-style="concrete-signal"] *).rb-tab:hover {
24
+ :where([data-rb-style="concrete-signal"], [data-rb-style="concrete-signal"] *).rb-tab:not(:disabled):hover {
25
25
  color: var(--rb-text);
26
26
  }
27
+ :where([data-rb-style="concrete-signal"], [data-rb-style="concrete-signal"] *).rb-tab:disabled {
28
+ opacity: 0.5;
29
+ cursor: not-allowed;
30
+ }
27
31
  :where([data-rb-style="concrete-signal"], [data-rb-style="concrete-signal"] *).rb-tab.rb-tab--active,
28
32
  :where([data-rb-style="concrete-signal"], [data-rb-style="concrete-signal"] *).rb-tab[aria-selected="true"] {
29
33
  color: var(--rb-accent);
@@ -67,8 +67,13 @@ gradient has no soft midpoint.
67
67
  `--rb-shadow-lg` (`4px 4px 0`) for dialogs and raised cards. `--rb-blur` is
68
68
  `0px` — this theme never applies `backdrop-filter` or any soft blur.
69
69
  Dialog backdrops are a flat `rgba(0,0,0,.6)` scrim.
70
- Focus is a hard border-weight change (1px to 2px solid accent), never a
71
- soft wash ring or glow.
70
+ Focus is a hard border-weight change (1px to 2px solid accent) on form
71
+ controls, never a soft wash ring or glow. Buttons instead keep the theme's
72
+ base hard 2px accent outline offset from the button (also hard-edged, no wash
73
+ or glow), so keyboard focus reads distinctly from a pointer hover; the
74
+ accent-fill `--primary` in particular relies on it, since a border-weight
75
+ change is invisible against its own fill, and it stays distinct from the
76
+ press translate.
72
77
  - Primary buttons carry the theme's signature interaction: the offset shadow
73
78
  disappears and the button translates by the shadow's own offset on
74
79
  hover/active (`transform: translate(2px, 2px); box-shadow: none;`) — the
@@ -42,9 +42,11 @@
42
42
  }
43
43
  :where([data-rb-style="concrete-signal-light"], [data-rb-style="concrete-signal-light"] *).rb-btn:not(:disabled):hover,
44
44
  :where([data-rb-style="concrete-signal-light"], [data-rb-style="concrete-signal-light"] *).rb-btn:focus-visible {
45
+ /* Hover and focus both firm the border/text to accent; focus additionally
46
+ keeps the base hard accent outline (base.css) -- hard-edged, no wash or
47
+ glow -- so keyboard focus stays distinct from a pointer hover. */
45
48
  border-color: var(--rb-accent);
46
49
  color: var(--rb-accent);
47
- outline: none;
48
50
  }
49
51
  :where([data-rb-style="concrete-signal-light"], [data-rb-style="concrete-signal-light"] *).rb-btn--primary {
50
52
  background: var(--rb-accent);
@@ -56,7 +58,6 @@
56
58
  box-shadow var(--rb-transition);
57
59
  }
58
60
  :where([data-rb-style="concrete-signal-light"], [data-rb-style="concrete-signal-light"] *).rb-btn--primary:not(:disabled):hover,
59
- :where([data-rb-style="concrete-signal-light"], [data-rb-style="concrete-signal-light"] *).rb-btn--primary:focus-visible,
60
61
  :where([data-rb-style="concrete-signal-light"], [data-rb-style="concrete-signal-light"] *).rb-btn--primary:active {
61
62
  border-color: var(--rb-accent);
62
63
  color: var(--rb-accent-fg);
@@ -64,6 +65,16 @@
64
65
  transform: translate(2px, 2px);
65
66
  box-shadow: none;
66
67
  }
68
+ /* Focus: a 1->2px border-weight change is invisible on the accent fill
69
+ (border == fill), so focus is a hard 2px accent outline offset from the
70
+ button -- hard-edged, not a soft wash ring or glow -- distinct from the
71
+ hover/active press. Text stays --accent-fg so it doesn't inherit the default
72
+ .rb-btn:focus-visible accent color against the accent fill. */
73
+ :where([data-rb-style="concrete-signal-light"], [data-rb-style="concrete-signal-light"] *).rb-btn--primary:focus-visible {
74
+ color: var(--rb-accent-fg);
75
+ outline: 2px solid var(--rb-accent);
76
+ outline-offset: 2px;
77
+ }
67
78
  :where([data-rb-style="concrete-signal-light"], [data-rb-style="concrete-signal-light"] *).rb-btn--accent {
68
79
  background: var(--rb-accent-wash);
69
80
  border-color: var(--rb-accent);
@@ -21,9 +21,13 @@
21
21
  cursor: pointer;
22
22
  transition: color var(--rb-transition);
23
23
  }
24
- :where([data-rb-style="concrete-signal-light"], [data-rb-style="concrete-signal-light"] *).rb-tab:hover {
24
+ :where([data-rb-style="concrete-signal-light"], [data-rb-style="concrete-signal-light"] *).rb-tab:not(:disabled):hover {
25
25
  color: var(--rb-text);
26
26
  }
27
+ :where([data-rb-style="concrete-signal-light"], [data-rb-style="concrete-signal-light"] *).rb-tab:disabled {
28
+ opacity: 0.5;
29
+ cursor: not-allowed;
30
+ }
27
31
  :where([data-rb-style="concrete-signal-light"], [data-rb-style="concrete-signal-light"] *).rb-tab.rb-tab--active,
28
32
  :where([data-rb-style="concrete-signal-light"], [data-rb-style="concrete-signal-light"] *).rb-tab[aria-selected="true"] {
29
33
  color: var(--rb-accent);
@@ -53,7 +53,9 @@ tables.
53
53
  Identical to concrete-signal — see its `design.md` for per-component notes;
54
54
  behaviour is the same, only the palette differs. Zero radius everywhere
55
55
  (save the near-square `--rb-radius-pill` used by badges), hard offset
56
- shadows instead of blur, a hard border-weight focus change, the theme's one
56
+ shadows instead of blur, a hard border-weight focus change on form controls
57
+ (buttons keep an offset accent outline instead, per concrete-signal's
58
+ `design.md`), the theme's one
57
59
  rationed gradient on the active-tab underline only, and `0.1s` snap
58
60
  transitions.
59
61
 
package/contract.json CHANGED
@@ -52,7 +52,7 @@
52
52
  "dialog": {
53
53
  "react": "Dialog",
54
54
  "classes": ["rb-dialog", "rb-dialog__title", "rb-dialog__actions", "rb-dialog__body"],
55
- "notes": "native <dialog>, open/onClose/actions; __body is a documented no-op in four themes (section 5.3)"
55
+ "notes": "native <dialog>; required open + onClose (onClose keeps the parent in sync after a native Escape close, so it must set open=false to reopen); optional actions; __body is a documented no-op in four themes (section 5.3)"
56
56
  },
57
57
  "tabs": {
58
58
  "react": "Tabs",
@@ -154,5 +154,13 @@
154
154
  { "theme": "concrete-signal", "reason": "flat scrim by design, no blur/glass anywhere in this theme", "permanent": true },
155
155
  { "theme": "concrete-signal-light", "reason": "flat scrim by design, no blur/glass anywhere in this theme", "permanent": true }
156
156
  ]
157
+ },
158
+ "permittedLiterals": {
159
+ "//": "Hex colours permitted outside color-mix (STANDARD.md 4.2, issue #94): documented per-theme literals no token expresses -- hand-tuned AA inks on a semantic fill (summer-cloud) and the rack panels' fixed-dark local palette (rackbops pair). Each is named in that theme's design.md. Data-URI SVG chevron strokes are %23-encoded and so never match the hex scan.",
160
+ "summer-cloud/alert.css": ["#1a7a1a", "#594400", "#93000a"],
161
+ "summer-cloud/badge.css": ["#004261", "#0a2e0a", "#241a00", "#4a0000"],
162
+ "summer-cloud/button.css": ["#4a0000"],
163
+ "rackbops-noir/rack.css": ["#0a121a", "#e7eef4", "#7d90a2", "#1e2b37"],
164
+ "rackbops-studio/rack.css": ["#101a24", "#e7eef4", "#7d90a2", "#26333f"]
157
165
  }
158
166
  }
@@ -35,11 +35,29 @@
35
35
  * obsidian base — the "luminous underlay" treatment. Apply to <body>, or to
36
36
  * the attributed container itself. */
37
37
  :where([data-rb-style="luminous-precision"], [data-rb-style="luminous-precision"] *).rb-bg {
38
+ position: relative;
39
+ isolation: isolate;
40
+ background: var(--rb-bg);
41
+ }
42
+
43
+ /* The radial underlays ride a viewport-fixed ::before rather than
44
+ * background-attachment: fixed, which iOS Safari silently ignores — there it
45
+ * would scroll with the page and leave the backdrop-filter cards compositing
46
+ * over a moving ground. A position: fixed pseudo pins to the viewport (or the
47
+ * nearest transformed/filtered ancestor, if any). z-index: -1 keeps it behind
48
+ * the container's own content; isolation: isolate contains it so it never
49
+ * slips under siblings. Apply .rb-bg to the page root — on a sub-viewport
50
+ * container the underlay still fills the viewport, not the element's box. */
51
+ :where([data-rb-style="luminous-precision"], [data-rb-style="luminous-precision"] *).rb-bg::before {
52
+ content: "";
53
+ position: fixed;
54
+ inset: 0;
55
+ z-index: -1;
38
56
  background:
39
57
  radial-gradient(50rem 30rem at 12% -5%, rgba(198, 165, 255, 0.08), transparent 70%),
40
58
  radial-gradient(55rem 35rem at 90% 105%, rgba(0, 245, 255, 0.05), transparent 70%),
41
59
  var(--rb-bg);
42
- background-attachment: fixed;
60
+ pointer-events: none;
43
61
  }
44
62
 
45
63
  :where([data-rb-style="luminous-precision"], [data-rb-style="luminous-precision"] *):where(h1, h2, h3, h4, h5, h6) {
@@ -19,9 +19,13 @@
19
19
  cursor: pointer;
20
20
  transition: color var(--rb-transition), border-color var(--rb-transition);
21
21
  }
22
- :where([data-rb-style="luminous-precision"], [data-rb-style="luminous-precision"] *).rb-tab:hover {
22
+ :where([data-rb-style="luminous-precision"], [data-rb-style="luminous-precision"] *).rb-tab:not(:disabled):hover {
23
23
  color: var(--rb-text);
24
24
  }
25
+ :where([data-rb-style="luminous-precision"], [data-rb-style="luminous-precision"] *).rb-tab:disabled {
26
+ opacity: 0.5;
27
+ cursor: not-allowed;
28
+ }
25
29
  :where([data-rb-style="luminous-precision"], [data-rb-style="luminous-precision"] *).rb-tab--active,
26
30
  :where([data-rb-style="luminous-precision"], [data-rb-style="luminous-precision"] *).rb-tab[aria-selected="true"] {
27
31
  color: var(--rb-accent-2);
@@ -105,7 +105,9 @@ Class prefix `rb-` (shared token/class contract with the other themes).
105
105
  square icon-only hit target (>=2rem), paired with `.rb-btn`.
106
106
  - **Form** `.rb-input`, `.rb-textarea`, `.rb-select`, `.rb-label`,
107
107
  `.rb-field`, `.rb-checkbox`, `.rb-radio`, `.rb-switch`, `.rb-choice` —
108
- checked/focus states glow teal.
108
+ checked/focus states glow teal. The `.rb-select` arrow is an inline data-URI
109
+ SVG, so its stroke is a literal (`#958e9b`, matching `--rb-text-faint`) — an
110
+ inline SVG can't reference a custom property.
109
111
  - **Badge** `.rb-badge` — pill chip: 15% tint of its hue behind
110
112
  full-saturation text (+ semantic modifiers).
111
113
  - **Alert** `.rb-alert` — glass, 3px left bar carries the semantic color.
@@ -19,9 +19,13 @@
19
19
  cursor: pointer;
20
20
  transition: color var(--rb-transition);
21
21
  }
22
- :where([data-rb-style="mono-field"], [data-rb-style="mono-field"] *).rb-tab:hover {
22
+ :where([data-rb-style="mono-field"], [data-rb-style="mono-field"] *).rb-tab:not(:disabled):hover {
23
23
  color: var(--rb-text);
24
24
  }
25
+ :where([data-rb-style="mono-field"], [data-rb-style="mono-field"] *).rb-tab:disabled {
26
+ opacity: 0.5;
27
+ cursor: not-allowed;
28
+ }
25
29
  :where([data-rb-style="mono-field"], [data-rb-style="mono-field"] *).rb-tab.rb-tab--active,
26
30
  :where([data-rb-style="mono-field"], [data-rb-style="mono-field"] *).rb-tab[aria-selected="true"] {
27
31
  color: var(--rb-accent);
@@ -109,7 +109,9 @@ extras.
109
109
  - **Form** `.rb-input` / `.rb-textarea` / `.rb-select` / `.rb-label` /
110
110
  `.rb-field` / `.rb-choice` / `.rb-checkbox` / `.rb-radio` / `.rb-switch` —
111
111
  sunken fields; focus swaps to the accent border plus a barely-there wash
112
- ring; labels are normal case, weight 500.
112
+ ring; labels are normal case, weight 500. The `.rb-select` arrow's data-URI
113
+ SVG hardcodes its stroke (`#5a5a5a`, matching `--rb-text-soft`), since an
114
+ inline SVG can't take a custom property.
113
115
  - **Badge** `.rb-badge` — pill, normal case (unusual for a badge, but matches
114
116
  this theme's no-shouting rule), weight 500, a 12%-alpha tint of its hue
115
117
  behind full-strength (but desaturated) text.
@@ -31,12 +31,35 @@
31
31
  }
32
32
 
33
33
  /* Opt-in page background: the butterfly circuit artwork blended into the navy.
34
- * Matches the switchboard landing page. Apply to <body>, or to the attributed
35
- * container itself. */
34
+ * Matches the switchboard landing page. Apply .rb-bg to <body> or the page
35
+ * root; on a sub-viewport container the underlay still fills the viewport (see
36
+ * the ::before note below). */
36
37
  :where([data-rb-style="neon-butterfly"], [data-rb-style="neon-butterfly"] *).rb-bg {
37
- background: var(--rb-bg) url("./assets/butterfly-circuit.png") center / cover fixed;
38
- background-blend-mode: luminosity;
38
+ position: relative;
39
+ isolation: isolate;
40
+ background: var(--rb-bg-blend);
41
+ }
42
+
43
+ /* The artwork rides a viewport-fixed ::before rather than the `fixed` keyword
44
+ * of the background shorthand (i.e. background-attachment: fixed), which iOS
45
+ * Safari silently ignores — there it would scroll with the page and leave the
46
+ * backdrop-filter glass surfaces compositing over a moving ground. A
47
+ * position: fixed pseudo pins to the viewport (or the nearest
48
+ * transformed/filtered ancestor, if any); z-index: -1 keeps it behind the
49
+ * container's own content; isolation: isolate contains it so it never slips
50
+ * under siblings. The luminosity blend of the artwork over --rb-bg-blend is
51
+ * preserved on the pseudo. */
52
+ :where([data-rb-style="neon-butterfly"], [data-rb-style="neon-butterfly"] *).rb-bg::before {
53
+ content: "";
54
+ position: fixed;
55
+ inset: 0;
56
+ z-index: -1;
39
57
  background-color: var(--rb-bg-blend);
58
+ background-image: url("./assets/butterfly-circuit.png");
59
+ background-position: center;
60
+ background-size: cover;
61
+ background-blend-mode: luminosity;
62
+ pointer-events: none;
40
63
  }
41
64
 
42
65
  :where([data-rb-style="neon-butterfly"], [data-rb-style="neon-butterfly"] *):where(h1, h2, h3, h4, h5, h6) {
@@ -19,9 +19,13 @@
19
19
  cursor: pointer;
20
20
  transition: color var(--rb-transition), border-color var(--rb-transition);
21
21
  }
22
- :where([data-rb-style="neon-butterfly"], [data-rb-style="neon-butterfly"] *).rb-tab:hover {
22
+ :where([data-rb-style="neon-butterfly"], [data-rb-style="neon-butterfly"] *).rb-tab:not(:disabled):hover {
23
23
  color: var(--rb-text);
24
24
  }
25
+ :where([data-rb-style="neon-butterfly"], [data-rb-style="neon-butterfly"] *).rb-tab:disabled {
26
+ opacity: 0.5;
27
+ cursor: not-allowed;
28
+ }
25
29
  :where([data-rb-style="neon-butterfly"], [data-rb-style="neon-butterfly"] *).rb-tab--active,
26
30
  :where([data-rb-style="neon-butterfly"], [data-rb-style="neon-butterfly"] *).rb-tab[aria-selected="true"] {
27
31
  color: var(--rb-accent);
@@ -94,6 +94,9 @@ Class prefix `rb-`. Variants use BEM-ish modifiers (`rb-btn--accent`).
94
94
  square icon-only hit target (>=2rem), paired with `.rb-btn`.
95
95
  - **Form** `.rb-input`, `.rb-textarea`, `.rb-select`, `.rb-label`, `.rb-field`,
96
96
  `.rb-checkbox`, `.rb-radio`, `.rb-switch`, `.rb-choice` — checked states glow lime.
97
+ The `.rb-select` arrow is an inline data-URI SVG whose stroke is a literal
98
+ (`#958da1`, matching `--rb-text-faint`) — an inline SVG can't reference a
99
+ custom property.
97
100
  - **Badge** `.rb-badge` + semantic modifiers.
98
101
  - **Alert** `.rb-alert` — left accent bar carries the semantic color.
99
102
  - **Dialog** `.rb-dialog` — native `<dialog>`, lilac border + glow, blurred backdrop.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rackbops/styles",
3
- "version": "0.1.10",
3
+ "version": "0.2.3",
4
4
  "description": "Rackbops design-system styles: tokens, base styles, and component classes per theme.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -18,9 +18,13 @@
18
18
  cursor: pointer;
19
19
  transition: color var(--rb-transition);
20
20
  }
21
- :where([data-rb-style="rackbops-noir"], [data-rb-style="rackbops-noir"] *).rb-tab:hover {
21
+ :where([data-rb-style="rackbops-noir"], [data-rb-style="rackbops-noir"] *).rb-tab:not(:disabled):hover {
22
22
  color: var(--rb-text);
23
23
  }
24
+ :where([data-rb-style="rackbops-noir"], [data-rb-style="rackbops-noir"] *).rb-tab:disabled {
25
+ opacity: 0.5;
26
+ cursor: not-allowed;
27
+ }
24
28
  :where([data-rb-style="rackbops-noir"], [data-rb-style="rackbops-noir"] *).rb-tab.rb-tab--active,
25
29
  :where([data-rb-style="rackbops-noir"], [data-rb-style="rackbops-noir"] *).rb-tab[aria-selected="true"] {
26
30
  color: var(--rb-text);
@@ -18,9 +18,13 @@
18
18
  cursor: pointer;
19
19
  transition: color var(--rb-transition);
20
20
  }
21
- :where([data-rb-style="rackbops-studio"], [data-rb-style="rackbops-studio"] *).rb-tab:hover {
21
+ :where([data-rb-style="rackbops-studio"], [data-rb-style="rackbops-studio"] *).rb-tab:not(:disabled):hover {
22
22
  color: var(--rb-text);
23
23
  }
24
+ :where([data-rb-style="rackbops-studio"], [data-rb-style="rackbops-studio"] *).rb-tab:disabled {
25
+ opacity: 0.5;
26
+ cursor: not-allowed;
27
+ }
24
28
  :where([data-rb-style="rackbops-studio"], [data-rb-style="rackbops-studio"] *).rb-tab.rb-tab--active,
25
29
  :where([data-rb-style="rackbops-studio"], [data-rb-style="rackbops-studio"] *).rb-tab[aria-selected="true"] {
26
30
  color: var(--rb-text);
@@ -37,8 +37,26 @@
37
37
  * the gradient is the signature — the theme reads as "airy" only against it.
38
38
  * Apply to <body>, or to the attributed container itself. */
39
39
  :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *).rb-bg {
40
+ position: relative;
41
+ isolation: isolate;
42
+ background: var(--rb-bg);
43
+ }
44
+
45
+ /* The gradient rides a viewport-fixed ::before underlay rather than
46
+ * background-attachment: fixed, which iOS Safari silently ignores — there it
47
+ * would scroll with the page and leave the backdrop-filter cards compositing
48
+ * over a moving ground. A position: fixed pseudo pins to the viewport (or the
49
+ * nearest transformed/filtered ancestor, if any). z-index: -1 keeps it behind
50
+ * the container's own content; isolation: isolate contains it so it never
51
+ * slips under siblings. Apply .rb-bg to the page root — on a sub-viewport
52
+ * container the underlay still fills the viewport, not the element's box. */
53
+ :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *).rb-bg::before {
54
+ content: "";
55
+ position: fixed;
56
+ inset: 0;
57
+ z-index: -1;
40
58
  background: linear-gradient(135deg, var(--rb-sky-start) 0%, var(--rb-sky-end) 100%);
41
- background-attachment: fixed;
59
+ pointer-events: none;
42
60
  }
43
61
 
44
62
  :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *):where(h1, h2, h3, h4, h5, h6) {
@@ -15,7 +15,7 @@
15
15
  letter-spacing: var(--rb-label-tracking);
16
16
  box-shadow: 0 1px 2px rgba(93, 43, 255, 0.06);
17
17
  }
18
- :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *).rb-badge--primary { background: var(--rb-accent); border-color: transparent; color: #fff; }
18
+ :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *).rb-badge--primary { background: var(--rb-accent); border-color: transparent; color: var(--rb-accent-fg); }
19
19
  :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *).rb-badge--info { background: var(--rb-info); border-color: transparent; color: #004261; }
20
20
  :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *).rb-badge--success { background: var(--rb-success); border-color: transparent; color: #0a2e0a; }
21
21
  :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *).rb-badge--warning { background: var(--rb-warning); border-color: transparent; color: #241a00; }
@@ -38,12 +38,16 @@
38
38
  transition: background var(--rb-transition), color var(--rb-transition),
39
39
  border-color var(--rb-transition);
40
40
  }
41
- :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *).rb-chip:hover {
41
+ :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *).rb-chip:not(:disabled):hover {
42
42
  background: var(--rb-sky-tint);
43
43
  }
44
+ :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *).rb-chip:disabled {
45
+ opacity: 0.5;
46
+ cursor: not-allowed;
47
+ }
44
48
  :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *).rb-chip--selected,
45
49
  :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *).rb-chip[aria-pressed="true"] {
46
50
  background: var(--rb-accent-bright);
47
51
  border-color: transparent;
48
- color: #fff;
52
+ color: var(--rb-accent-fg);
49
53
  }
@@ -56,18 +56,18 @@
56
56
  :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *).rb-btn--primary {
57
57
  background: var(--rb-accent);
58
58
  border-color: transparent;
59
- color: #fff;
59
+ color: var(--rb-accent-fg);
60
60
  font-weight: var(--rb-font-weight-bold);
61
61
  box-shadow: var(--rb-shadow-raised);
62
62
  }
63
63
  :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *).rb-btn--primary:not(:disabled):hover {
64
64
  background: var(--rb-accent-bright);
65
- color: #fff;
65
+ color: var(--rb-accent-fg);
66
66
  box-shadow: var(--rb-shadow-raised-hover);
67
67
  }
68
68
  :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *).rb-btn--primary:focus-visible {
69
69
  background: var(--rb-accent-bright);
70
- color: #fff;
70
+ color: var(--rb-accent-fg);
71
71
  box-shadow: var(--rb-shadow-raised-hover), 0 0 0 4px var(--rb-accent-glow);
72
72
  }
73
73
 
@@ -96,7 +96,7 @@
96
96
  :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *).rb-btn--danger {
97
97
  background: var(--rb-danger-deep);
98
98
  border-color: transparent;
99
- color: #fff;
99
+ color: var(--rb-accent-fg);
100
100
  font-weight: var(--rb-font-weight-bold);
101
101
  box-shadow: 0 4px 14px rgba(204, 31, 31, 0.39);
102
102
  }
@@ -127,7 +127,7 @@
127
127
  width: calc(1.75rem - 6px);
128
128
  height: calc(1.75rem - 6px);
129
129
  border-radius: 50%;
130
- background: #fff;
130
+ background: var(--rb-surface);
131
131
  box-shadow: 0 2px 6px rgba(93, 43, 255, 0.2);
132
132
  transition: transform var(--rb-transition) var(--rb-ease-bounce);
133
133
  }
@@ -19,10 +19,14 @@
19
19
  transition: color var(--rb-transition), background var(--rb-transition),
20
20
  border-color var(--rb-transition);
21
21
  }
22
- :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *).rb-tab:hover {
22
+ :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *).rb-tab:not(:disabled):hover {
23
23
  background: var(--rb-sky-tint);
24
24
  color: var(--rb-accent);
25
25
  }
26
+ :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *).rb-tab:disabled {
27
+ opacity: 0.5;
28
+ cursor: not-allowed;
29
+ }
26
30
  :where([data-rb-style="summer-cloud"], [data-rb-style="summer-cloud"] *).rb-tab:focus-visible {
27
31
  outline: none;
28
32
  box-shadow: 0 0 0 4px var(--rb-accent-2-glow);
@@ -40,7 +40,7 @@ here; that is intended, not a bug.
40
40
 
41
41
  | Role | Value | Usage |
42
42
  | --- | --- | --- |
43
- | Background | `#f6fafe` | Flat page ground; the `.rb-bg` sky gradient runs `--rb-sky-start` `#f0f4f8` → `--rb-sky-end` `#c9e6ff` at 135°, `fixed` |
43
+ | Background | `#f6fafe` | Flat page ground; the `.rb-bg` sky gradient runs `--rb-sky-start` `#f0f4f8` → `--rb-sky-end` `#c9e6ff` at 135°, pinned to the viewport by a `position: fixed` `::before` underlay (not `background-attachment: fixed`, which iOS Safari ignores) |
44
44
  | Surface | `#ffffff` | Dialogs and fully opaque panels |
45
45
  | Surface sunken | `#f0f4f8` | Inset form fields |
46
46
  | Surface glass | `rgba(255,255,255,0.6)` + 12px blur | Cards, alerts (Level 1) |
@@ -129,8 +129,15 @@ theme-agnostic). Variants use BEM-ish modifiers (`rb-btn--primary`).
129
129
  - **Form** `.rb-input`, `.rb-textarea`, `.rb-select`, `.rb-label`, `.rb-field`,
130
130
  `.rb-checkbox`, `.rb-radio`, `.rb-switch`, `.rb-choice` — sunken fields, no
131
131
  resting border, sky-blue ring on focus. The switch is the oversized
132
- "cloud-toggle": squishy, and green when live.
133
- - **Badge** `.rb-badge` + semantic modifiers solid pills, mono uppercase.
132
+ "cloud-toggle": squishy, and green when live. The `.rb-select` arrow is an
133
+ inline data-URI SVG, so its stroke is a literal (`#484457`, matching
134
+ `--rb-text-faint`); an inline SVG can't reference a custom property.
135
+ - **Badge** `.rb-badge` + semantic modifiers — solid pills, mono uppercase. The
136
+ dark ink on each semantic fill (`#004261`/`#0a2e0a`/`#241a00`/`#4a0000`), and
137
+ the alert titles (`#1a7a1a`/`#594400`/`#93000a`), are hand-tuned per-theme
138
+ literals chosen to read AA on that specific fill — a separate decision from
139
+ the fill's semantic token, so they don't track `--rb-success`/`--rb-danger`/
140
+ etc. (a permitted literal, STANDARD.md §4.2; allowlisted in `contract.json`).
134
141
  **Chip** `.rb-chip` — outlined filter chip; `--selected` fills violet (a
135
142
  summer-cloud extra, beyond the shared component set).
136
143
  - **Alert** `.rb-alert` — glass card with a 4px semantic left rule.