@bsuite/theme 0.7.2 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsuite/theme",
3
- "version": "0.7.2",
3
+ "version": "0.9.0",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
6
  "publishConfig": {
@@ -113,6 +113,64 @@
113
113
  --role-success: var(--braden-aqua);
114
114
  --role-info: var(--braden-teal-deep);
115
115
 
116
+ /* ═══ INFORMATIONAL SCALE — categorical, NOT semantic ═══
117
+ Added 2026-08-03 by operator ruling: "informational hues might be handy
118
+ to stand out against the style colour palette."
119
+
120
+ Role tokens describe STATE. They cannot describe CATEGORY — which
121
+ pipeline stage, which user role, which product tile. Apps that needed a
122
+ category reached for raw Tailwind instead, which is how one role-badge
123
+ table came to use purple, indigo, blue, violet and sky as its only
124
+ distinguishing signal.
125
+
126
+ NUMBERED, NOT NAMED, deliberately. Call one of these "moss green" and
127
+ it will be used for success within a week. A number says what these
128
+ are: interchangeable slots carrying no meaning of their own.
129
+ NEVER use an --info-* for state. State has role tokens.
130
+
131
+ Derived, not picked by eye: Vienot-Brettel-Mollon dichromat simulation,
132
+ DeltaE in OKLab, scored as the WORST case across normal, deuteranope and
133
+ protanope vision. Two constraints — perceptual distance keeps them
134
+ DISTINGUISHABLE, a >=28 degree hue gap keeps them looking CATEGORICAL
135
+ rather than like a light/dark pair of one colour. Every one is also
136
+ held away from the brand roles, which is what "stand out against the
137
+ style palette" requires: an informational badge must not read as a
138
+ primary action or an error.
139
+ Reproduce with scripts/design-informational-hues.py
140
+
141
+ LIMIT: worst-case separation is ~0.06-0.07, against >=0.156 for the
142
+ semantic pairs. That is 10x better than the purple-vs-blue pairing this
143
+ system rejected (0.006), but it is NOT the semantic standard and cannot
144
+ be — 8 mutually-distinct categories that also avoid 6 reserved brand
145
+ colours is a harder problem than 6 roles. So: colour is never the sole
146
+ signifier for a category. Always pair with a label or an icon. Past 8
147
+ categories, stop adding hues and add a second dimension. */
148
+ --info-1: oklch(0.660 0.120 0.0);
149
+ --info-2: oklch(0.660 0.120 30.0);
150
+ --info-3: oklch(0.620 0.120 72.0);
151
+ --info-4: oklch(0.460 0.120 132.0);
152
+ --info-5: oklch(0.780 0.120 162.0);
153
+ --info-6: oklch(0.740 0.120 222.0);
154
+ --info-7: oklch(0.660 0.120 252.0);
155
+ --info-8: oklch(0.620 0.120 324.0);
156
+
157
+ /* ═══ STAGE RAMP — progression, one hue, ascending lightness ═══
158
+ For an ORDERED sequence (pipeline stages), not a category set. A ramp
159
+ encodes direction: "further along" is visible at a glance, and it
160
+ survives greyscale and both dichromacies because lightness carries it.
161
+ Arbitrary per-stage hues cannot do that — a reader has to LEARN that
162
+ sky comes after amber.
163
+
164
+ Progression only. OUTCOMES are state, not stage: a hired candidate is
165
+ --role-success, a rejected one --role-error, a withdrawn one muted.
166
+ Do not extend this ramp to cover them. */
167
+ --stage-1: oklch(0.860 0.090 249.0);
168
+ --stage-2: oklch(0.780 0.090 249.0);
169
+ --stage-3: oklch(0.700 0.090 249.0);
170
+ --stage-4: oklch(0.620 0.090 249.0);
171
+ --stage-5: oklch(0.540 0.090 249.0);
172
+ --stage-6: oklch(0.460 0.090 249.0);
173
+
116
174
  /* ============================================================
117
175
  LAYER 3 — AA-SAFE TEXT RENDERINGS OF THE SATURATED ROLES
118
176
  A saturated fill colour is not a legible text colour.
package/src/css/vars.css CHANGED
@@ -127,6 +127,77 @@
127
127
  --role-success: var(--neon-electric-teal); /* was green — 0.043 from red */
128
128
  --role-info: var(--neon-electric-cyan); /* oklch(0.769 0.132 191.7) */
129
129
 
130
+ /* ═══ TYPE ═══ Lifted from the D2C contract, which specified a font
131
+ stack this package never shipped. Apps were left to pick their own, so
132
+ the estate ran system-ui, Inter and JetBrains Mono simultaneously while
133
+ the contract asked for one family. Same shape of gap as the heading
134
+ ramp: written down, never implemented. */
135
+ --font-display: 'Geist Variable', Geist, system-ui, sans-serif;
136
+ --font-body: 'Geist Variable', Geist, system-ui, sans-serif;
137
+ --font-mono: 'Geist Mono Variable', 'Geist Mono', ui-monospace, monospace;
138
+ --track-display: -0.028em;
139
+ --track-heading: -0.018em;
140
+ --track-body: 0em;
141
+ --track-eyebrow: 0.09em;
142
+
143
+ /* ═══ INFORMATIONAL SCALE — categorical, NOT semantic ═══
144
+ Added 2026-08-03 by operator ruling: "informational hues might be handy
145
+ to stand out against the style colour palette."
146
+
147
+ Role tokens describe STATE. They cannot describe CATEGORY — which
148
+ pipeline stage, which user role, which product tile. Apps that needed a
149
+ category reached for raw Tailwind instead, which is how one role-badge
150
+ table came to use purple, indigo, blue, violet and sky as its only
151
+ distinguishing signal.
152
+
153
+ NUMBERED, NOT NAMED, deliberately. Call one of these "moss green" and
154
+ it will be used for success within a week. A number says what these
155
+ are: interchangeable slots carrying no meaning of their own.
156
+ NEVER use an --info-* for state. State has role tokens.
157
+
158
+ Derived, not picked by eye: Vienot-Brettel-Mollon dichromat simulation,
159
+ DeltaE in OKLab, scored as the WORST case across normal, deuteranope and
160
+ protanope vision. Two constraints — perceptual distance keeps them
161
+ DISTINGUISHABLE, a >=28 degree hue gap keeps them looking CATEGORICAL
162
+ rather than like a light/dark pair of one colour. Every one is also
163
+ held away from the brand roles, which is what "stand out against the
164
+ style palette" requires: an informational badge must not read as a
165
+ primary action or an error.
166
+ Reproduce with scripts/design-informational-hues.py
167
+
168
+ LIMIT: worst-case separation is ~0.06-0.07, against >=0.156 for the
169
+ semantic pairs. That is 10x better than the purple-vs-blue pairing this
170
+ system rejected (0.006), but it is NOT the semantic standard and cannot
171
+ be — 8 mutually-distinct categories that also avoid 6 reserved brand
172
+ colours is a harder problem than 6 roles. So: colour is never the sole
173
+ signifier for a category. Always pair with a label or an icon. Past 8
174
+ categories, stop adding hues and add a second dimension. */
175
+ --info-1: oklch(0.460 0.140 0.0);
176
+ --info-2: oklch(0.700 0.140 42.0);
177
+ --info-3: oklch(0.540 0.140 138.0);
178
+ --info-4: oklch(0.700 0.140 168.0);
179
+ --info-5: oklch(0.780 0.140 228.0);
180
+ --info-6: oklch(0.700 0.140 258.0);
181
+ --info-7: oklch(0.500 0.140 300.0);
182
+ --info-8: oklch(0.460 0.140 330.0);
183
+
184
+ /* ═══ STAGE RAMP — progression, one hue, ascending lightness ═══
185
+ For an ORDERED sequence (pipeline stages), not a category set. A ramp
186
+ encodes direction: "further along" is visible at a glance, and it
187
+ survives greyscale and both dichromacies because lightness carries it.
188
+ Arbitrary per-stage hues cannot do that — a reader has to LEARN that
189
+ sky comes after amber.
190
+
191
+ Progression only. OUTCOMES are state, not stage: a hired candidate is
192
+ --role-success, a rejected one --role-error, a withdrawn one muted.
193
+ Do not extend this ramp to cover them. */
194
+ --stage-1: oklch(0.860 0.130 262.9);
195
+ --stage-2: oklch(0.780 0.130 262.9);
196
+ --stage-3: oklch(0.700 0.130 262.9);
197
+ --stage-4: oklch(0.620 0.130 262.9);
198
+ --stage-5: oklch(0.540 0.130 262.9);
199
+ --stage-6: oklch(0.460 0.130 262.9);
200
+
130
201
  /* AA-safe text renderings of the saturated roles on light surfaces.
131
202
  A saturated fill colour is not a legible text colour; these are the
132
203
  text variants and are the ONLY correct token for coloured type. */
package/src/preset-v4.css CHANGED
@@ -102,6 +102,30 @@
102
102
  --color-warning-text: var(--role-warning-text);
103
103
  --color-success-text: var(--role-success-text);
104
104
 
105
+ /* Informational scale — CATEGORICAL, never state. `bg-info-3`, `text-info-5`.
106
+ Numbered because they are interchangeable slots with no meaning of their
107
+ own; naming one invites it to be used as a semantic. Pair every one with a
108
+ label or icon — their separation is deliberately below the semantic
109
+ standard and cannot carry meaning alone. See --info-* in vars.css. */
110
+ --color-info-1: var(--info-1);
111
+ --color-info-2: var(--info-2);
112
+ --color-info-3: var(--info-3);
113
+ --color-info-4: var(--info-4);
114
+ --color-info-5: var(--info-5);
115
+ --color-info-6: var(--info-6);
116
+ --color-info-7: var(--info-7);
117
+ --color-info-8: var(--info-8);
118
+
119
+ /* Stage ramp — ORDERED progression. `bg-stage-1` .. `bg-stage-6`, lightness
120
+ descending, so "further along" reads at a glance and survives greyscale.
121
+ Outcomes are NOT stages: hired is --role-success, rejected --role-error. */
122
+ --color-stage-1: var(--stage-1);
123
+ --color-stage-2: var(--stage-2);
124
+ --color-stage-3: var(--stage-3);
125
+ --color-stage-4: var(--stage-4);
126
+ --color-stage-5: var(--stage-5);
127
+ --color-stage-6: var(--stage-6);
128
+
105
129
  /* Per-app accent (Layer 5). Resolves through [data-app] on <body>,
106
130
  falling back to the shared accent when no app is declared. */
107
131
  --color-app-accent: var(--app-accent, var(--role-accent));
@@ -144,6 +168,17 @@
144
168
  --color-text-on-success: var(--text-on-success);
145
169
  --color-text-on-warning: var(--text-on-warning);
146
170
 
171
+ /* ============================================================
172
+ TYPE — the contract's stack, bridged to Tailwind's font-* utilities.
173
+ `font-sans` and `font-mono` are what components actually write, so
174
+ without this bridge the tokens exist and nothing uses them. Every D2C
175
+ app had been declaring its own --font-sans locally instead, which is how
176
+ the estate came to run system-ui, Inter and JetBrains Mono at once.
177
+ ============================================================ */
178
+ --font-sans: var(--font-body);
179
+ --font-display: var(--font-display);
180
+ --font-mono: var(--font-mono);
181
+
147
182
  /* ============================================================
148
183
  ANIMATIONS
149
184
  ============================================================ */