@kanzo-tech/theme 0.0.1-alpha

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 (44) hide show
  1. package/README.md +130 -0
  2. package/dist/index.d.ts +427 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +269 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/ink.d.ts +52 -0
  7. package/dist/ink.d.ts.map +1 -0
  8. package/dist/obligations.d.ts +45 -0
  9. package/dist/obligations.d.ts.map +1 -0
  10. package/dist/sections.d.ts +304 -0
  11. package/dist/sections.d.ts.map +1 -0
  12. package/package.json +43 -0
  13. package/theme-data.json +311 -0
  14. package/themes/acid.css +54 -0
  15. package/themes/bank-dark.css +64 -0
  16. package/themes/bank-private-dark.css +64 -0
  17. package/themes/bank-private.css +63 -0
  18. package/themes/bank.css +63 -0
  19. package/themes/catppuccin-latte-dark.css +64 -0
  20. package/themes/catppuccin-latte.css +63 -0
  21. package/themes/catppuccin-mocha-dark.css +64 -0
  22. package/themes/catppuccin-mocha.css +63 -0
  23. package/themes/cmyk.css +54 -0
  24. package/themes/coffee.css +54 -0
  25. package/themes/cyberpunk.css +54 -0
  26. package/themes/dim.css +54 -0
  27. package/themes/dracula-dark.css +64 -0
  28. package/themes/dracula.css +63 -0
  29. package/themes/forest.css +54 -0
  30. package/themes/kanzo-dark.css +73 -0
  31. package/themes/kanzo.css +70 -0
  32. package/themes/lemonade.css +54 -0
  33. package/themes/lofi.css +54 -0
  34. package/themes/luxury.css +54 -0
  35. package/themes/monochrome-dark.css +64 -0
  36. package/themes/monochrome.css +63 -0
  37. package/themes/night.css +54 -0
  38. package/themes/nord-dark.css +64 -0
  39. package/themes/nord.css +63 -0
  40. package/themes/sunset.css +54 -0
  41. package/themes/synthwave.css +54 -0
  42. package/themes/wireframe.css +54 -0
  43. package/themes.css +92 -0
  44. package/tokens.css +311 -0
package/tokens.css ADDED
@@ -0,0 +1,311 @@
1
+ /*
2
+ * @kanzo-tech/theme — the utility surface. HAND-WRITTEN, all of it.
3
+ *
4
+ * This file used to have two halves: a hand-written one and a generated one carrying a compiled
5
+ * palette document. **The generated half is gone**, and with it the thirteen-stage derivation that
6
+ * produced it. A theme is now `themes/<name>.css` — one flat block of about fifty-five
7
+ * declarations that a person writes, pastes, reviews and diffs. See
8
+ * `.planning/THEME-REFOUNDATION.md`.
9
+ *
10
+ * What is left here is the bridge: `@theme inline` is what makes `bg-primary` and
11
+ * `text-muted-foreground` resolve to a theme's tokens and follow it live. Plus the shape scale, the
12
+ * font stacks, two keyframes and the element-level base layer.
13
+ *
14
+ * ## Twenty-one carry a value; everything else uses one
15
+ *
16
+ * A theme authors twenty-one colours. Every other name in the vocabulary is a *use* of one of
17
+ * them, declared once, here. That is the rule from `a-role-earns-its-name-or-becomes-a-step`
18
+ * applied to the whole system rather than to the reference tier: a name is worth having when a
19
+ * theme would plausibly give it a different value, and a name that can only ever repeat another is
20
+ * a second spelling.
21
+ *
22
+ * Eight names were measured against that rule and lost. Across the sixteen hand-written blocks that
23
+ * authored them, `--card-foreground` and `--popover-foreground` were byte-identical to
24
+ * `--foreground`, and six of the eight sidebar tokens were byte-identical to the core token they
25
+ * shadow — ninety-six declarations writing a value that was already written. Nothing authors any of
26
+ * the eight today, in any of the twenty-nine. The NAMES stay, because Shark's recipes paste them
27
+ * verbatim and that clause is what keeps a Shark name alive. What stopped is authoring them per
28
+ * theme. `themes.test.ts` resolves each deleted name through this bridge in every shipped theme and
29
+ * fails if a fallback lands somewhere other than the token it replaced, so this is checked rather
30
+ * than remembered.
31
+ *
32
+ * ## Why they are bridged here and NOT declared in `:root`
33
+ *
34
+ * This is the trap, and it is worth the paragraph because nothing about it is a compile error.
35
+ *
36
+ * `:root { --sidebar-primary: var(--primary) }` looks equivalent and is not. A custom property
37
+ * inherits its **computed** value: `--sidebar-primary` resolves once, on `<html>`, against that
38
+ * element's `--primary`. A scoped preview — `<div data-theme="dracula">` — sets a new `--primary`
39
+ * on the div, but `--sidebar-primary` was already substituted on the ancestor and inherits that
40
+ * old value. The div renders Dracula's brand with Nord's sidebar, silently.
41
+ *
42
+ * `@theme inline` has no such problem: Tailwind inlines the value into the *utility*, so
43
+ * `bg-sidebar-primary` compiles to `background-color: var(--primary)` and the `var()` is resolved
44
+ * on the element that wears the class. Scoped themes work, and they work at any nesting depth.
45
+ *
46
+ * That is also why the whole colour vocabulary is bridged and none of it is re-declared: a theme
47
+ * block is self-contained by construction, which is the property that makes a preview a `div`.
48
+ *
49
+ * ## The status families keep Shark's asymmetry
50
+ *
51
+ * For NEUTRAL and BRAND, the base name is the fill and `-foreground` is the ink meant to sit on it.
52
+ * The STATUS families do not follow that rule, and this is inherited from Shark verbatim — do not
53
+ * "fix" it, it would fork us. There, `-foreground` is a *readable-on-the-page variant of the same
54
+ * hue*: error text, invalid rings, destructive menu items — never text on the fill. On-fill ink is
55
+ * a third token per family, `--*-content`, which is daisyUI's word for exactly this role.
56
+ */
57
+
58
+ @theme inline {
59
+ /* ── The twenty-one a theme authors ───────────────────────────────────────── */
60
+ --color-background: var(--background);
61
+ --color-foreground: var(--foreground);
62
+ --color-card: var(--card);
63
+ --color-muted: var(--muted);
64
+ --color-muted-foreground: var(--muted-foreground);
65
+ --color-primary: var(--primary);
66
+ --color-primary-foreground: var(--primary-foreground);
67
+ --color-secondary: var(--secondary);
68
+ --color-secondary-foreground: var(--secondary-foreground, var(--foreground));
69
+ --color-accent: var(--accent);
70
+ --color-accent-foreground: var(--accent-foreground, var(--foreground));
71
+ --color-destructive: var(--destructive);
72
+ --color-destructive-content: var(--destructive-content);
73
+ --color-info: var(--info);
74
+ --color-info-content: var(--info-content);
75
+ --color-success: var(--success);
76
+ --color-success-content: var(--success-content);
77
+ --color-warning: var(--warning);
78
+ --color-warning-content: var(--warning-content);
79
+ --color-border: var(--border);
80
+ --color-ring: var(--ring);
81
+
82
+ /* ── Authored today, pending a measured `color-mix` default ───────────────────
83
+ Each of these is NOT an alias in any shipped theme — measured — so none of them could be
84
+ dropped without moving a real value. Each is its own question later; the fallback is what a
85
+ theme that omits it gets. */
86
+ --color-popover: var(--popover, var(--card));
87
+ --color-popover-foreground: var(--foreground);
88
+ --color-card-foreground: var(--foreground);
89
+ --color-input: var(--input, var(--border));
90
+ --color-field: var(--field, var(--muted));
91
+ --color-faint: var(--faint, var(--muted-foreground));
92
+ --color-destructive-foreground: var(--destructive-foreground, var(--destructive));
93
+ --color-info-foreground: var(--info-foreground, var(--info));
94
+ --color-success-foreground: var(--success-foreground, var(--success));
95
+ --color-warning-foreground: var(--warning-foreground, var(--warning));
96
+
97
+ /* ── Sidebar: none authored, eight that only ever repeated ───────────────────
98
+ `--sidebar` was `--popover` in all sixteen hand-written themes and `--sidebar-foreground` was
99
+ `--muted-foreground` in all sixteen, so the fallbacks point there and the themes stopped
100
+ writing them. The chain for `--sidebar` runs on to `--card`, which is where `--popover` itself
101
+ defers. A theme that wants a sidebar of its own still says so; none of the twenty-nine does
102
+ today, and the thirteen imported from daisyUI never had a sidebar channel to carry. */
103
+ --color-sidebar: var(--sidebar, var(--popover, var(--card)));
104
+ --color-sidebar-foreground: var(--sidebar-foreground, var(--muted-foreground));
105
+ --color-sidebar-border: var(--border);
106
+ --color-sidebar-primary: var(--primary);
107
+ --color-sidebar-primary-foreground: var(--primary-foreground);
108
+ --color-sidebar-accent: var(--accent);
109
+ --color-sidebar-accent-foreground: var(--accent-foreground);
110
+ --color-sidebar-ring: var(--ring);
111
+
112
+ /* ── The categorical set ──────────────────────────────────────────────────────
113
+ A theme authors these or it does not; the eight it gets by saying nothing are DECLARED in the
114
+ `:root` block at the foot of this file rather than written as a fallback here, and the note
115
+ there says why this one default is a value where every other is an alias. */
116
+ --color-chart-1: var(--chart-1);
117
+ --color-chart-2: var(--chart-2);
118
+ --color-chart-3: var(--chart-3);
119
+ --color-chart-4: var(--chart-4);
120
+ --color-chart-5: var(--chart-5);
121
+ --color-chart-6: var(--chart-6);
122
+ --color-chart-7: var(--chart-7);
123
+ --color-chart-8: var(--chart-8);
124
+
125
+ /* ── Shape: three radius knobs where there was one ────────────────────────────
126
+ daisyUI's split, and it buys something the single knob could not express — a rounded selector
127
+ beside a square card. The size scale below is unchanged and still hangs off ONE knob, so every
128
+ existing `rounded-*` call site keeps its pixels; `--radius` now defaults to `--radius-field`,
129
+ which is the knob a button and an input answer to. Recipes migrate to the three role
130
+ utilities (`rounded-box` / `rounded-field` / `rounded-selector`) component by component.
131
+
132
+ Multiplicative, which is Shark's exact ratios: every step is a multiple of one knob, so the
133
+ scale holds its proportions at any setting and `0` collapses cleanly to square. An additive
134
+ `calc(--radius - Npx)` scale diverges off the default and clamps small corners to 0 — that was
135
+ the bug.
136
+
137
+ The size scale hangs off `--radius-field` DIRECTLY rather than off an intermediate `--radius`,
138
+ and that is not a tidy-up: an intermediate declared in `:root` inherits already substituted, so
139
+ a scoped `<div data-theme>` with a different field radius would never reach it. Same trap as the
140
+ colour bridge above, same fix — resolve in the utility, on the element. */
141
+ --radius-box: var(--radius-box, 0.75rem);
142
+ --radius-field: var(--radius-field, 0.5rem);
143
+ --radius-selector: var(--radius-selector, 0.25rem);
144
+
145
+ --radius-xs: calc(var(--radius-field, 0.5rem) * 0.25);
146
+ --radius-sm: calc(var(--radius-field, 0.5rem) * 0.5);
147
+ --radius-md: calc(var(--radius-field, 0.5rem) * 0.75);
148
+ --radius-lg: calc(var(--radius-field, 0.5rem) * 1);
149
+ --radius-xl: calc(var(--radius-field, 0.5rem) * 1.5);
150
+ --radius-2xl: calc(var(--radius-field, 0.5rem) * 2);
151
+ --radius-3xl: calc(var(--radius-field, 0.5rem) * 3);
152
+ --radius-4xl: calc(var(--radius-field, 0.5rem) * 4);
153
+
154
+ /* Fonts — a theme may carry them now, so a tenant ships a typeface with their colours. These
155
+ are the fallbacks, and the shape is Shark's. daisyUI has no font in its theme at all; keeping
156
+ `--font-heading` separate from `--font-sans` is the single most identity-carrying typographic
157
+ choice a white-label document can make. */
158
+ --font-sans: var(--font-sans, ui-sans-serif, system-ui, sans-serif);
159
+ --font-heading: var(--font-heading, ui-sans-serif, system-ui, sans-serif);
160
+ --font-mono: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
161
+
162
+ /* Height-based expand/collapse for Ark Collapsible / TreeView. Ark supplies `--height`
163
+ at runtime (tw-animate-css can't measure it), so we ship the `expand`/`collapse` pair
164
+ its components reference. These live in the TOKEN layer, not the bundled `styles.css`,
165
+ because Tailwind-native consumers (the playground, keasy) scan the DS source and emit
166
+ `animate-expand` / `animate-[collapse_…]` themselves — they import these tokens, not
167
+ the compiled sheet. Without the keyframes here the exit animation never runs, so Ark's
168
+ `unmountOnExit` never fires its `animationend` and collapsed branches stay mounted. */
169
+ --animate-expand: expand 200ms ease-out;
170
+ --animate-collapse: collapse 200ms ease-out;
171
+
172
+ /* The arrival of one streamed word — `MessageText` in `@kanzo-tech/ai`. Here for the reason the
173
+ pair above is here: a Tailwind-native consumer scans the source, emits `animate-arrive`
174
+ itself, and would otherwise get a utility with no keyframes behind it.
175
+
176
+ The numbers are Streamdown's, which is what AI Elements renders a streamed answer with:
177
+ 150ms and `ease`, not a longer curve — the cascade is what reads as writing, and a slow word
178
+ reads as a page loading. `both`, so a word scheduled behind the cascade holds at `opacity: 0`
179
+ until its delay elapses. */
180
+ --animate-arrive: arrive 150ms ease both;
181
+ }
182
+
183
+ @keyframes expand {
184
+ from { height: 0; }
185
+ to { height: var(--height); }
186
+ }
187
+ @keyframes collapse {
188
+ from { height: var(--height); }
189
+ to { height: 0; }
190
+ }
191
+ /* Opacity and nothing else, which is `sd-fadeIn` — Streamdown's default of three. Its other two
192
+ are `sd-blurIn` (a 4px blur out) and `sd-slideUp` (a 4px rise); neither is here, because one
193
+ arrival is the fundamental and the other two are taste with a compositing cost.
194
+
195
+ An earlier draft of this tinted the word and settled it to `inherit`. That was not taken from
196
+ anywhere: no reference colours a word by who wrote it, and the tint made the settle a second
197
+ event to get right. */
198
+ @keyframes arrive {
199
+ from { opacity: 0; }
200
+ to { opacity: 1; }
201
+ }
202
+
203
+ /* Element-level base defaults that the COMPONENTS depend on (Shark's canonical base
204
+ layer). These live in the token layer — not the bundled `styles.css` — because Shark's
205
+ primitives write bare `border` / `border-t` (no colour) and rely on this rule to paint
206
+ them with `--border`; without it, Tailwind v4 falls back to `currentColor`, so every
207
+ card/dialog/table border inherits the (dark) text colour instead. Tailwind-native
208
+ consumers (the playground, keasy) import these tokens, not the compiled sheet, so the
209
+ rule must ship here for their borders + focus outlines to resolve correctly.
210
+ Document/app-shell defaults (`html`, `body`) stay in `styles.css` — a library shouldn't
211
+ impose page background on a Tailwind-native consumer.
212
+
213
+ `border-width` reads the theme's `--stroke` rather than Tailwind's 1px, which is what makes
214
+ "this tenant draws a 2px hairline" a theme declaration instead of a fork. `--stroke` and not
215
+ `--border`, because `--border` is the line COLOUR here and the width in daisyUI — one of the two
216
+ had to move, and renaming ours would have forked every Shark recipe. */
217
+ @layer base {
218
+ *,
219
+ ::after,
220
+ ::before {
221
+ @apply border-border outline-ring/50;
222
+ border-width: 0;
223
+ border-style: solid;
224
+ }
225
+ ::selection {
226
+ @apply bg-primary/80 text-primary-foreground;
227
+ }
228
+ button:not(:disabled),
229
+ [role="button"]:not(:disabled) {
230
+ cursor: pointer;
231
+ }
232
+ }
233
+
234
+ :root {
235
+ /* ── The categorical set a theme gets by saying nothing ───────────────────────
236
+ Sixteen themes author their own; thirteen do not, because daisyUI has no such channel to
237
+ import, and their slots resolved to nothing.
238
+
239
+ **Declared here, not bridged, and it is the one fallback in this file that is a literal.**
240
+ Every other name above defers to another token, so it must resolve on the element that uses
241
+ it — hence `@theme inline`. These defer to nothing: they are values. That makes a plain `:root`
242
+ declaration correct where it would be a bug anywhere else, and it is the only shape that
243
+ works, because a chart does not read a utility. `categoricalColor` returns `var(--chart-N)`
244
+ and the chart pipeline resolves it against the live element, so a fallback written into the
245
+ bridge would reach `bg-chart-1` and never reach a mark. Declared here it inherits, a
246
+ `[data-theme]` block overrides it slot by slot on the element that carries it, and both paths
247
+ get the same answer.
248
+
249
+ Chosen by search under the bars a chart is actually read against, all of them re-run by
250
+ `categorical.test.ts` over the shipped files rather than trusted here:
251
+
252
+ · every slot inside OKLCH L 0.48–0.67, the INTERSECTION of the light band (0.43–0.77) and
253
+ the dark one — the only way one set is in band on `#ffffff` and on `#09002f`;
254
+ · ≥ 3:1 against **all twenty-nine** backgrounds, not against the two ends. The ends are not
255
+ the hard case: `dim` (#2a303c) and `cyberpunk` (#fff248) between them leave a window of
256
+ relative luminance 0.188–0.251, and a set validated only at the extremes failed on six
257
+ themes in the middle;
258
+ · worst adjacent pair 17.6 ΔE under protan/deutan simulation, 14.4 under tritan and 21.4 to
259
+ normal vision. The old per-document bar was 15;
260
+ · ≥ 8 ΔE from all fifty-two distinct status fills the twenty-nine publish, so a series does
261
+ not read as a state.
262
+
263
+ There is no deriving these from `--primary`: `--chart-6` takes twelve distinct values across
264
+ the sixteen authored sets. A set answers to *separation*, which is a property of the eight
265
+ together.
266
+
267
+ A theme that declines the channel outright still says so with `--chart-capacity: 0`, and these
268
+ colours simply go unread — `monochrome` is the one, and `monochrome-is-a-palette-not-a-look`
269
+ is the record. */
270
+ --chart-1: #aa5aee;
271
+ --chart-2: #dc356d;
272
+ --chart-3: #737fee;
273
+ --chart-4: #b36d2a;
274
+ --chart-5: #2d84bf;
275
+ --chart-6: #96822c;
276
+ --chart-7: #d036b6;
277
+ --chart-8: #6a8a2a;
278
+
279
+ /* The shape knobs with no theme applied. Plain values, never `var()` of one another — see the
280
+ inheritance note on the radius scale. `themes.css` re-points them per `data-radius`, which is
281
+ the user's preference layered over the theme's own declaration.
282
+
283
+ There is no `--radius` any more. It was one knob standing for three, and the size-named
284
+ utilities now answer to `--radius-field` — `rounded-lg` sits on a button far more often than
285
+ on a card. */
286
+ --stroke: 1px;
287
+ --depth: 0;
288
+ --size-field: 0.25rem;
289
+ --size-selector: 0.25rem;
290
+
291
+ /* ── The three type sizes below Tailwind's floor ──────────────────────────────
292
+ Not in Shark, and not in Tailwind either: its scale stops at `text-xs`, 12px. These are the
293
+ IDE tier — a code pane, a preferences label, a marker badge — and they exist because the
294
+ smallest thing Tailwind offers is too big for all three.
295
+
296
+ **They were deleted by `6c602df` and three components kept asking for them**, which is why
297
+ this comment is longer than the block. That commit's subject is colour and its scope was the
298
+ colour half of this file; the block went with it, and nothing failed — an undefined custom
299
+ property makes `font-size` invalid at computed-value time, so the declaration is dropped and
300
+ the element silently inherits. Measured on 2026-08-23: `Badge size="xs"` computed 16px inside
301
+ its own `h-4` box, and since the recipe carries `overflow-hidden` the text was clipped by
302
+ 3px — a 19px content in a 16px box, visible in `app-shell` and `job-studio` and in no test.
303
+ `theme-tokens.test.ts` is the guard that makes the next deletion fail out loud.
304
+
305
+ `CodeEditor` reads two of these with a literal fallback and so kept rendering — at 14px and
306
+ 12px rather than 13px and 11px. That is the same defect wearing a fallback, and it is the
307
+ reason a fallback is not the fix here. */
308
+ --kanzo-font-size-base: 0.8125rem; /* 13px — IDE base (below Tailwind text-xs) */
309
+ --kanzo-font-size-small: 0.6875rem; /* 11px */
310
+ --kanzo-font-size-xs: 0.625rem; /* 10px — `obligations.ts` grades this one */
311
+ }