@tenphi/glaze 0.0.0-snapshot.78261ef → 0.0.0-snapshot.7b8c12f

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/dist/index.d.cts CHANGED
@@ -1,48 +1,113 @@
1
1
  //#region src/contrast-solver.d.ts
2
- /**
3
- * OKHSL Contrast Solver
4
- *
5
- * Finds the closest OKHSL lightness that satisfies a WCAG 2 contrast target
6
- * against a base color. Used by glaze when resolving dependent colors
7
- * with `contrast`.
8
- */
9
2
  type LinearRgb = [number, number, number];
10
3
  type ContrastPreset = 'AA' | 'AAA' | 'AA-large' | 'AAA-large';
11
4
  type MinContrast$1 = number | ContrastPreset;
12
- interface FindLightnessForContrastOptions {
5
+ /**
6
+ * Named APCA Lc floor presets (APCA Bronze Simple Mode conformance levels),
7
+ * independent of role. Use them anywhere an APCA target is accepted.
8
+ *
9
+ * | Preset | Lc | Use case |
10
+ * | ------------- | --- | ---------------------------------------------------- |
11
+ * | `'preferred'` | 90 | Preferred body / column text |
12
+ * | `'body'` | 75 | Minimum body / column text |
13
+ * | `'content'` | 60 | Readable non-body content (~WCAG AA 4.5:1) |
14
+ * | `'large'` | 45 | Large/bold headlines; fine icons/outlines (~3:1) |
15
+ * | `'non-text'` | 30 | Solid icons/controls; placeholder/disabled text |
16
+ * | `'min'` | 15 | Dividers/decorative; APCA "point of invisibility" |
17
+ */
18
+ type ApcaPreset = 'preferred' | 'body' | 'content' | 'large' | 'non-text' | 'min';
19
+ declare const APCA_PRESETS: Record<ApcaPreset, number>;
20
+ /**
21
+ * APCA-W3 "Enhanced Level" delta added to a bare APCA target in high-contrast
22
+ * mode when no explicit HC value is provided (analogous to WCAG AAA over AA).
23
+ * Only applied when neither the outer `contrast` pair nor the inner `apca`
24
+ * pair carries an explicit HC entry.
25
+ */
26
+ declare const APCA_HC_ENHANCEMENT = 15;
27
+ /** Upper bound for an APCA Lc target after HC enhancement. */
28
+ declare const APCA_MAX_LC = 106;
29
+ /**
30
+ * Resolve an APCA target — a raw Lc number (kept as-is) or an `ApcaPreset`
31
+ * keyword mapped to its Lc value. The magnitude is forced non-negative.
32
+ */
33
+ declare function resolveApcaTarget(value: number | ApcaPreset): number;
34
+ /** Metric + numeric target after resolving a `ContrastSpec` for a mode. */
35
+ interface ResolvedContrast {
36
+ metric: 'wcag' | 'apca';
37
+ /** WCAG ratio (>= 1) or APCA Lc magnitude (0–106). */
38
+ target: number;
39
+ /**
40
+ * APCA argument order: which side the resolved (candidate) color plays
41
+ * against the base. `'fg'` (default) → `apcaContrast(yCandidate, yBase)`;
42
+ * `'bg'` → `apcaContrast(yBase, yCandidate)`. Always `'fg'` for WCAG
43
+ * (symmetric, ignored).
44
+ */
45
+ polarity?: 'fg' | 'bg';
46
+ }
47
+ declare function resolveMinContrast(value: MinContrast$1): number;
48
+ /**
49
+ * Resolve a `ContrastSpec` (already selected from any outer HC pair) for a
50
+ * given mode into `{ metric, target }`. Handles the inner metric HC pair and
51
+ * preset resolution. `polarity` is passed through to the result for the APCA
52
+ * branch (it controls argument order in the solver); WCAG ignores it.
53
+ *
54
+ * `outerExplicitHC` indicates whether the caller selected this `spec` from an
55
+ * explicit high-contrast entry of the outer `contrast` pair. Together with the
56
+ * inner metric pair, it decides whether the HC auto-enhancement fires:
57
+ * - APCA: +15 Lc "Enhanced Level" boost when neither level is explicit.
58
+ * - WCAG: AA → AAA / AA-large → AAA-large promotion (SC 1.4.3 → 1.4.6) when
59
+ * neither level is explicit. AAA-family presets and bare numbers are left
60
+ * unchanged (AAA is the top WCAG tier).
61
+ * Defaults to `false` (correct for direct callers, which pass a single
62
+ * selected spec rather than an outer pair).
63
+ */
64
+ declare function resolveContrastForMode(spec: ContrastSpec, isHighContrast: boolean, polarity?: 'fg' | 'bg', outerExplicitHC?: boolean): ResolvedContrast;
65
+ /**
66
+ * APCA lightness contrast (Lc), signed: positive for dark text on light bg,
67
+ * negative for light text on dark bg. Inputs are screen luminances (0–1).
68
+ */
69
+ declare function apcaContrast(yText: number, yBg: number): number;
70
+ interface FindToneForContrastOptions {
13
71
  /** Hue of the candidate color (0–360). */
14
72
  hue: number;
15
73
  /** Saturation of the candidate color (0–1). */
16
74
  saturation: number;
17
- /** Preferred lightness of the candidate (0–1). */
18
- preferredLightness: number;
19
- /** Base/reference color as linear sRGB (channels may be outside 0–1 before clamp). */
20
- baseLinearRgb: [number, number, number];
21
- /** WCAG contrast ratio target floor. */
22
- contrast: MinContrast$1;
23
- /** Search bounds for lightness. Default: [0, 1]. */
24
- lightnessRange?: [number, number];
75
+ /** Preferred tone of the candidate (0–1). */
76
+ preferredTone: number;
77
+ /** Base/reference color as linear sRGB. */
78
+ baseLinearRgb: LinearRgb;
79
+ /** Resolved contrast floor (metric + target). */
80
+ contrast: ResolvedContrast;
81
+ /** Search bounds for tone. Default: [0, 1]. */
82
+ toneRange?: [number, number];
25
83
  /** Convergence threshold. Default: 1e-4. */
26
84
  epsilon?: number;
27
- /** Maximum binary-search iterations per branch. Default: 14. */
85
+ /** Maximum binary-search iterations per branch. Default: 18. */
28
86
  maxIterations?: number;
87
+ /** Preferred search direction before auto-flip is considered. */
88
+ initialDirection?: 'lighter' | 'darker';
89
+ /** Auto-flip tone direction when contrast can't be met. Default: false. */
90
+ flip?: boolean;
91
+ /** Use the hue-independent "safe" chroma boundary. Default: false. */
92
+ pastel?: boolean;
29
93
  }
30
- interface FindLightnessForContrastResult {
31
- /** Chosen lightness in 0–1. */
32
- lightness: number;
33
- /** Achieved WCAG contrast ratio. */
94
+ interface FindToneForContrastResult {
95
+ /** Chosen tone in 0–1. */
96
+ tone: number;
97
+ /** Achieved score (WCAG ratio or APCA Lc magnitude). */
34
98
  contrast: number;
35
99
  /** Whether the target was reached. */
36
100
  met: boolean;
37
101
  /** Which branch was selected. */
38
102
  branch: 'lighter' | 'darker' | 'preferred';
103
+ /** Whether the result auto-flipped to the opposite direction. */
104
+ flipped?: boolean;
39
105
  }
40
- declare function resolveMinContrast(value: MinContrast$1): number;
41
106
  /**
42
- * Find the OKHSL lightness that satisfies a WCAG 2 contrast target
43
- * against a base color, staying as close to `preferredLightness` as possible.
107
+ * Find the tone that satisfies a contrast floor against a base color,
108
+ * staying as close to `preferredTone` as possible.
44
109
  */
45
- declare function findLightnessForContrast(options: FindLightnessForContrastOptions): FindLightnessForContrastResult;
110
+ declare function findToneForContrast(options: FindToneForContrastOptions): FindToneForContrastResult;
46
111
  interface FindValueForMixContrastOptions {
47
112
  /** Preferred mix parameter (0–1). */
48
113
  preferredValue: number;
@@ -50,42 +115,84 @@ interface FindValueForMixContrastOptions {
50
115
  baseLinearRgb: LinearRgb;
51
116
  /** Target color as linear sRGB. */
52
117
  targetLinearRgb: LinearRgb;
53
- /** WCAG contrast target. */
54
- contrast: MinContrast$1;
55
- /**
56
- * Compute the luminance of the mixed color at parameter t.
57
- * For opaque: luminance of OKHSL-interpolated color.
58
- * For transparent: luminance of alpha-composited color over base.
59
- */
118
+ /** Resolved contrast floor (metric + target). */
119
+ contrast: ResolvedContrast;
120
+ /** Compute the luminance of the mixed color at parameter t. */
60
121
  luminanceAtValue: (t: number) => number;
61
122
  /** Convergence threshold. Default: 1e-4. */
62
123
  epsilon?: number;
63
124
  /** Maximum binary-search iterations per branch. Default: 20. */
64
125
  maxIterations?: number;
126
+ /** Auto-flip mix direction when contrast can't be met. Default: false. */
127
+ flip?: boolean;
65
128
  }
66
129
  interface FindValueForMixContrastResult {
67
- /** Chosen mix parameter (0–1). */
68
130
  value: number;
69
- /** Achieved WCAG contrast ratio. */
70
131
  contrast: number;
71
- /** Whether the target was reached. */
72
132
  met: boolean;
133
+ flipped?: boolean;
73
134
  }
74
135
  /**
75
- * Find the mix parameter (ratio or opacity) that satisfies a WCAG 2 contrast
76
- * target against a base color, staying as close to `preferredValue` as possible.
136
+ * Find the mix parameter (ratio or opacity) that satisfies a contrast floor
137
+ * against a base color, staying as close to `preferredValue` as possible.
77
138
  */
78
139
  declare function findValueForMixContrast(options: FindValueForMixContrastOptions): FindValueForMixContrastResult;
79
140
  //#endregion
80
141
  //#region src/types.d.ts
81
142
  /** A value or [normal, high-contrast] pair. */
82
143
  type HCPair<T> = T | [T, T];
144
+ /** Bare WCAG contrast target: a ratio number or a named preset. */
83
145
  type MinContrast = number | ContrastPreset;
146
+ /**
147
+ * A contrast floor with a pluggable metric.
148
+ *
149
+ * - `number` / `ContrastPreset`: a WCAG ratio (bare form).
150
+ * - `{ wcag }`: WCAG ratio or preset, optionally an HC pair.
151
+ * - `{ apca }`: APCA Lc target (absolute value or preset), optionally an HC pair.
152
+ *
153
+ * The `[normal, highContrast]` pair may live at the outer level
154
+ * (`[4.5, 7]`, `[{ wcag: 4.5 }, { wcag: 7 }]`) or inside the metric
155
+ * (`{ wcag: [4.5, 7] }`, `{ apca: [45, 60] }`, `{ apca: ['content', 'body'] }`).
156
+ */
157
+ type ContrastSpec = number | ContrastPreset | {
158
+ wcag: HCPair<number | ContrastPreset>;
159
+ } | {
160
+ apca: HCPair<number | ApcaPreset>;
161
+ };
162
+ /**
163
+ * The semantic role a color plays against its base, used to fix APCA contrast
164
+ * polarity (which side is the foreground vs the background). WCAG is
165
+ * symmetric, so role never changes WCAG results.
166
+ */
167
+ type Role = 'text' | 'surface' | 'border';
168
+ /**
169
+ * Any string accepted as a `role`. Canonical values plus aliases normalized by
170
+ * `normalizeRole` (see `roles.ts`): `surface` (bg/background/fill/canvas/
171
+ * paper/layer), `text` (fg/foreground/content/ink/label/stroke), `border`
172
+ * (divider/outline/separator/hairline/rule).
173
+ */
174
+ type RoleInput = Role | 'bg' | 'background' | 'fill' | 'canvas' | 'paper' | 'layer' | 'fg' | 'foreground' | 'content' | 'ink' | 'label' | 'stroke' | 'divider' | 'outline' | 'separator' | 'hairline' | 'rule';
84
175
  type AdaptationMode = 'auto' | 'fixed' | 'static';
85
176
  /** A signed relative offset string, e.g. '+20' or '-15.5'. */
86
177
  type RelativeValue = `+${number}` | `-${number}`;
178
+ /**
179
+ * Force a color to a tone extreme:
180
+ * - `'max'`: the highest tone in the active scheme range/window.
181
+ * - `'min'`: the lowest tone.
182
+ *
183
+ * Under `mode: 'auto'` the extreme inverts in the dark scheme (so `'max'`
184
+ * tracks the inversion and becomes the darkest tone). No `base` required.
185
+ */
186
+ type ExtremeValue = 'max' | 'min';
187
+ /**
188
+ * A tone value as authored on a color.
189
+ * - Number: absolute tone (0–100).
190
+ * - `'+N'` / `'-N'`: relative to the base's tone (requires `base`).
191
+ * - `'max'` / `'min'`: forced to the scheme's tone extreme (no base needed).
192
+ */
193
+ type ToneValue = number | RelativeValue | ExtremeValue;
87
194
  /** Color format for output. */
88
- type GlazeColorFormat = 'okhsl' | 'rgb' | 'hsl' | 'oklch';
195
+ type GlazeColorFormat = 'okhsl' | 'okhst' | 'rgb' | 'hsl' | 'oklch';
89
196
  /**
90
197
  * Controls which scheme variants are generated in the export.
91
198
  * Light is always included (it's the default).
@@ -104,13 +211,35 @@ interface OkhslColor {
104
211
  s: number;
105
212
  l: number;
106
213
  }
214
+ /**
215
+ * Direct OKHST color input — OKHSL with the lightness axis replaced by the
216
+ * contrast-uniform tone axis. `h`: 0–360, `s`: 0–1, `t`: 0–1 (tone).
217
+ */
218
+ interface OkhstColor {
219
+ h: number;
220
+ s: number;
221
+ t: number;
222
+ }
223
+ /** sRGB components in 0–255 (value-shorthand object form). */
224
+ interface RgbColor {
225
+ r: number;
226
+ g: number;
227
+ b: number;
228
+ }
229
+ /** OKLCh components matching CSS `oklch(L C H)` (L/C: 0–1, H: degrees). */
230
+ interface OklchColor {
231
+ l: number;
232
+ c: number;
233
+ h: number;
234
+ }
107
235
  interface RegularColorDef {
108
236
  /**
109
- * Lightness value (0–100).
110
- * - Number: absolute lightness.
111
- * - String ('+N' / '-N'): relative to base color's lightness (requires `base`).
237
+ * Tone value (0–100, contrast-uniform — see `docs/okhst.md`).
238
+ * - Number: absolute tone.
239
+ * - String ('+N' / '-N'): relative to base color's tone (requires `base`).
240
+ * - `'max'` / `'min'`: force to the scheme's tone extreme (no base needed).
112
241
  */
113
- lightness?: HCPair<number | RelativeValue>;
242
+ tone?: HCPair<ToneValue>;
114
243
  /** Saturation factor applied to the seed saturation (0–1, default: 1). */
115
244
  saturation?: number;
116
245
  /**
@@ -121,18 +250,51 @@ interface RegularColorDef {
121
250
  hue?: number | RelativeValue;
122
251
  /** Name of another color in the same theme (dependent color). */
123
252
  base?: string;
124
- /** WCAG contrast ratio floor against the base color. */
125
- contrast?: HCPair<MinContrast>;
253
+ /**
254
+ * Contrast floor against the base color. A bare number/preset is WCAG;
255
+ * use `{ wcag }` / `{ apca }` to pick the metric. Accepts an HC pair.
256
+ */
257
+ contrast?: HCPair<ContrastSpec>;
126
258
  /** Adaptation mode. Default: 'auto'. */
127
259
  mode?: AdaptationMode;
260
+ /**
261
+ * Whether to flip out-of-bounds results to the opposite side instead of
262
+ * clamping to the extreme. Affects both:
263
+ * - relative `tone`: when `base ± delta` exceeds `[0, 100]`, mirror the
264
+ * delta to the other side of the base. If the mirrored target is also
265
+ * out of range, keep the original delta and clamp on the authored side.
266
+ * - `contrast`: when the requested direction can't meet the floor, try the
267
+ * opposite side (same as the global `autoFlip`).
268
+ *
269
+ * Defaults to the global `autoFlip` config (default `true`). Set `false`
270
+ * to clamp instead.
271
+ */
272
+ autoFlip?: boolean;
128
273
  /**
129
274
  * Fixed opacity (0–1).
130
275
  * Output includes alpha in the CSS value.
131
276
  * Does not affect contrast resolution — a semi-transparent color
132
- * has no fixed perceived lightness, so `contrast` and `opacity`
277
+ * has no fixed perceived tone, so `contrast` and `opacity`
133
278
  * should not be combined (a console.warn is emitted).
134
279
  */
135
280
  opacity?: number;
281
+ /**
282
+ * Per-color override for the hue-independent "safe" chroma limit used in
283
+ * OKHSL↔sRGB conversions (luminance, contrast solving, output formatting).
284
+ * Falls through to the per-theme / per-token `pastel` override when omitted.
285
+ * @see GlazeConfigOverride.pastel
286
+ */
287
+ pastel?: boolean;
288
+ /**
289
+ * Semantic role against `base`: how this color is used. Fixes APCA contrast
290
+ * polarity (the argument order in `apcaContrast`). WCAG is symmetric so it
291
+ * never affects WCAG results.
292
+ *
293
+ * Resolution: explicit `role` wins; else inferred from the color name when
294
+ * `inferRole` is enabled (default); else the opposite of the base's role;
295
+ * else defaults to `'text'` (foreground).
296
+ */
297
+ role?: RoleInput;
136
298
  /**
137
299
  * Whether this color is inherited by child themes created via `extend()`.
138
300
  * Default: true. Set to false to make this color local to the current theme.
@@ -161,12 +323,6 @@ interface ShadowTuning {
161
323
  * 0 = pure fg hue, 1 = pure bg hue. Default: 0.2.
162
324
  */
163
325
  bgHueBlend?: number;
164
- /**
165
- * Power curve for dark-scheme shadow alpha (0-1). Default: 0.4.
166
- * Lower values compress low/mid-intensity shadows more aggressively.
167
- * 1.0 = no dampening (identity).
168
- */
169
- darkShadowCurve?: number;
170
326
  }
171
327
  interface ShadowColorDef {
172
328
  type: 'shadow';
@@ -188,6 +344,13 @@ interface ShadowColorDef {
188
344
  intensity: HCPair<number>;
189
345
  /** Override default tuning. Merged field-by-field with global `shadowTuning`. */
190
346
  tuning?: ShadowTuning;
347
+ /**
348
+ * Per-color override for the hue-independent "safe" chroma limit used in
349
+ * OKHSL↔sRGB conversions (luminance, contrast solving, output formatting).
350
+ * Falls through to the per-theme / per-token `pastel` override when omitted.
351
+ * @see GlazeConfigOverride.pastel
352
+ */
353
+ pastel?: boolean;
191
354
  /**
192
355
  * Whether this color is inherited by child themes created via `extend()`.
193
356
  * Default: true. Set to false to make this color local to the current theme.
@@ -221,12 +384,26 @@ interface MixColorDef {
221
384
  */
222
385
  space?: 'okhsl' | 'srgb';
223
386
  /**
224
- * Minimum WCAG contrast between the base and the resulting color.
387
+ * Minimum contrast between the base and the resulting color.
225
388
  * In 'opaque' mode, adjusts the mix ratio to meet contrast.
226
389
  * In 'transparent' mode, adjusts opacity to meet contrast against the composite.
227
- * Supports [normal, highContrast] pair.
390
+ * A bare number/preset is WCAG; use `{ wcag }` / `{ apca }` to pick the
391
+ * metric. Supports [normal, highContrast] pair.
228
392
  */
229
- contrast?: HCPair<MinContrast>;
393
+ contrast?: HCPair<ContrastSpec>;
394
+ /**
395
+ * Per-color override for the hue-independent "safe" chroma limit used in
396
+ * OKHSL↔sRGB conversions (luminance, contrast solving, output formatting).
397
+ * Falls through to the per-theme / per-token `pastel` override when omitted.
398
+ * @see GlazeConfigOverride.pastel
399
+ */
400
+ pastel?: boolean;
401
+ /**
402
+ * Semantic role of the mixed result against `base`. Same semantics as
403
+ * `RegularColorDef.role` (fixes APCA polarity). Resolution and defaults
404
+ * are identical.
405
+ */
406
+ role?: RoleInput;
230
407
  /**
231
408
  * Whether this color is inherited by child themes created via `extend()`.
232
409
  * Default: true. Set to false to make this color local to the current theme.
@@ -235,16 +412,28 @@ interface MixColorDef {
235
412
  }
236
413
  type ColorDef = RegularColorDef | ShadowColorDef | MixColorDef;
237
414
  type ColorMap = Record<string, ColorDef>;
238
- /** Resolved color for a single scheme variant. */
415
+ /**
416
+ * Resolved color for a single scheme variant.
417
+ *
418
+ * Stored in OKHST: `h` / `s` are OKHSL hue/saturation, `t` is the canonical
419
+ * contrast-uniform tone (0–1, reference eps). Convert to OKHSL lightness via
420
+ * `variantToOkhsl` at the rendering / luminance edges.
421
+ */
239
422
  interface ResolvedColorVariant {
240
423
  /** OKHSL hue (0–360). */
241
424
  h: number;
242
425
  /** OKHSL saturation (0–1). */
243
426
  s: number;
244
- /** OKHSL lightness (0–1). */
245
- l: number;
427
+ /** Canonical tone (0–1, reference eps). */
428
+ t: number;
246
429
  /** Opacity (0–1). Default: 1. */
247
430
  alpha: number;
431
+ /**
432
+ * Effective `pastel` flag used while resolving this variant (author def or
433
+ * config fallback). Carried on the variant so output formatting matches the
434
+ * gamut mapping applied during resolution.
435
+ */
436
+ pastel?: boolean;
248
437
  }
249
438
  /** Fully resolved color across all scheme variants. */
250
439
  interface ResolvedColor {
@@ -256,21 +445,32 @@ interface ResolvedColor {
256
445
  /** Adaptation mode. Present only for regular colors, omitted for shadows. */
257
446
  mode?: AdaptationMode;
258
447
  }
448
+ /**
449
+ * A scheme tone window.
450
+ * - `[lo, hi]`: OKHSL-lightness endpoints (0–100) the authored tone is
451
+ * remapped into, using the reference eps `0.05`. The common form.
452
+ * - `{ lo, hi, eps }`: same, with an explicit render curvature `eps`
453
+ * (advanced — most palettes never need this).
454
+ * - `false`: disable clamping (full range `[0, 100]` at the reference eps).
455
+ * This removes the *boundaries*, not the tone curve.
456
+ */
457
+ type ToneWindow = false | [number, number] | {
458
+ lo: number;
459
+ hi: number;
460
+ eps: number;
461
+ };
259
462
  interface GlazeConfig {
260
- /** Light scheme lightness window [lo, hi]. Default: [10, 100]. */
261
- lightLightness?: [number, number];
262
- /** Dark scheme lightness window [lo, hi]. Default: [15, 95]. */
263
- darkLightness?: [number, number];
463
+ /** Light scheme tone window — `[lo, hi]` (default `[10, 100]`), `{ lo, hi, eps }` for advanced eps tuning, or `false` to disable clamping. */
464
+ lightTone?: ToneWindow;
465
+ /** Dark scheme tone window — `[lo, hi]` (default `[15, 95]`), `{ lo, hi, eps }`, or `false` to disable clamping. */
466
+ darkTone?: ToneWindow;
264
467
  /** Saturation reduction factor for dark scheme (0–1). Default: 0.1. */
265
468
  darkDesaturation?: number;
266
469
  /**
267
- * Möbius beta for dark auto-inversion (0–1).
268
- * Lower values expand subtle near-white distinctions in dark mode.
269
- * Set to 1 for linear (legacy) behavior. Default: 0.5.
270
- * Accepts [normal, highContrast] pair for separate HC tuning.
470
+ * State alias names for Tasty token export. Default to media-query states
471
+ * (`'@media(prefers-color-scheme: dark)'` / `'@media(prefers-contrast: more)'`)
472
+ * so tokens react to the OS preference without registering custom states.
271
473
  */
272
- darkCurve?: HCPair<number>;
273
- /** State alias names for token export. */
274
474
  states?: {
275
475
  dark?: string;
276
476
  highContrast?: string;
@@ -279,44 +479,319 @@ interface GlazeConfig {
279
479
  modes?: GlazeOutputModes;
280
480
  /** Default tuning for all shadow colors. Per-color tuning merges field-by-field. */
281
481
  shadowTuning?: ShadowTuning;
482
+ /**
483
+ * Automatically flip tone direction when contrast can't be met.
484
+ *
485
+ * When enabled (default `true`), the solver searches the requested
486
+ * tone direction first. If that direction can't reach the target,
487
+ * it tries the opposite direction and uses it when it passes. If neither
488
+ * side passes, the tone is pinned to the requested-direction
489
+ * extreme and a warning is emitted.
490
+ *
491
+ * Set to `false` for strict "no flip" behavior. The opposite
492
+ * direction is never considered: if the requested direction can't
493
+ * meet the target, the tone is pinned to its extreme (never
494
+ * falls back to the originally requested tone).
495
+ */
496
+ autoFlip?: boolean;
497
+ /**
498
+ * If true (default), infer a color's `role` from its name when no explicit
499
+ * `role` is set. Set to `false` to opt out of name-based inference (the
500
+ * base-opposite and default-foreground fallbacks still apply).
501
+ * @default true
502
+ */
503
+ inferRole?: boolean;
282
504
  }
283
505
  interface GlazeConfigResolved {
284
- lightLightness: [number, number];
285
- darkLightness: [number, number];
506
+ lightTone: ToneWindow;
507
+ darkTone: ToneWindow;
286
508
  darkDesaturation: number;
287
- darkCurve: HCPair<number>;
288
509
  states: {
289
510
  dark: string;
290
511
  highContrast: string;
291
512
  };
292
513
  modes: Required<GlazeOutputModes>;
293
514
  shadowTuning?: ShadowTuning;
515
+ autoFlip: boolean;
516
+ /**
517
+ * Instance-level pastel default (`def.pastel ?? config.pastel`).
518
+ * Not set via `glaze.configure()` — only via per-theme / per-token
519
+ * `GlazeConfigOverride` (default `false`).
520
+ */
521
+ pastel: boolean;
522
+ inferRole: boolean;
294
523
  }
524
+ /**
525
+ * Per-instance config override for `glaze.color()` and `glaze()` themes.
526
+ * Fields that are set take priority over the live global config. Fields
527
+ * that are omitted fall through to the live global at resolve time
528
+ * (`pastel` is instance-only and defaults to `false` when omitted).
529
+ *
530
+ * `false` for a tone window disables clamping (full range at reference eps).
531
+ */
532
+ interface GlazeConfigOverride {
533
+ /** Light scheme tone window, or `false` to disable clamping. */
534
+ lightTone?: ToneWindow;
535
+ /** Dark scheme tone window, or `false` to disable clamping. */
536
+ darkTone?: ToneWindow;
537
+ /** Saturation reduction factor for dark scheme (0–1). */
538
+ darkDesaturation?: number;
539
+ /** Whether to auto-flip tone when contrast can't be met. */
540
+ autoFlip?: boolean;
541
+ /**
542
+ * Instance-level pastel default for colors that omit per-color `pastel`.
543
+ * Not available on `glaze.configure()` — set here or per-color.
544
+ * @default false
545
+ */
546
+ pastel?: boolean;
547
+ /**
548
+ * If true, infer a color's `role` from its name when no explicit `role` is
549
+ * set. Falls through to the live global at resolve time when omitted.
550
+ */
551
+ inferRole?: boolean;
552
+ /**
553
+ * Shadow tuning defaults. Only meaningful for themes; harmless on
554
+ * standalone color tokens.
555
+ */
556
+ shadowTuning?: ShadowTuning;
557
+ }
558
+ /**
559
+ * Current authoring-export schema version. Bump when the export shape
560
+ * changes in a non-compatible way. Written on every `.export()` snapshot.
561
+ */
562
+ declare const GLAZE_EXPORT_VERSION: 1;
563
+ /** Literal type of {@link GLAZE_EXPORT_VERSION}. */
564
+ type GlazeExportVersion = typeof GLAZE_EXPORT_VERSION;
565
+ /** Discriminator for authoring export snapshots. */
566
+ type GlazeExportKind = 'theme' | 'color' | 'palette';
295
567
  /** Serialized theme configuration (no resolved values). */
296
568
  interface GlazeThemeExport {
569
+ /** Snapshot kind. Always written by `theme.export()`; optional on legacy hand-written configs. */
570
+ kind?: 'theme';
571
+ /** Schema version. Always written by `theme.export()`; optional on legacy configs. */
572
+ version?: number;
297
573
  hue: number;
298
574
  saturation: number;
299
575
  colors: ColorMap;
576
+ /**
577
+ * Effective config freeze from `.export()` —
578
+ * `getConfig() ∪ instance local ∪ exportArg`. May be sparse on legacy
579
+ * snapshots (omitted fields fall through to the live global at restore).
580
+ */
581
+ config?: GlazeConfigOverride;
300
582
  }
301
583
  /** Input for `glaze.shadow()` standalone factory. */
302
584
  interface GlazeShadowInput {
303
- /** Background color — hex string or OKHSL { h, s (0-1), l (0-1) }. */
304
- bg: HexColor | OkhslColor;
305
- /** Foreground color for tinting + intensity modulation. */
306
- fg?: HexColor | OkhslColor;
585
+ /**
586
+ * Background color — accepts any `GlazeColorValue` form: hex
587
+ * (`#rgb` / `#rrggbb` / `#rrggbbaa`), `rgb()` / `hsl()` / `okhsl()`
588
+ * / `oklch()` strings, or literal objects (`{ r, g, b }`, `{ h, s, l }`,
589
+ * `{ l, c, h }`). Alpha components are dropped with a warning.
590
+ */
591
+ bg: GlazeColorValue;
592
+ /**
593
+ * Foreground color for tinting + intensity modulation. Accepts the
594
+ * same forms as `bg`.
595
+ */
596
+ fg?: GlazeColorValue;
307
597
  /** Intensity 0-100. */
308
598
  intensity: number;
309
599
  tuning?: ShadowTuning;
310
- /** Whether to apply dark-scheme dampening. Default: false. */
311
- dark?: boolean;
312
600
  }
313
- /** Input for `glaze.color()` standalone factory. */
601
+ /** Input for the structured `glaze.color()` overload. */
314
602
  interface GlazeColorInput {
315
603
  hue: number;
316
604
  saturation: number;
317
- lightness: HCPair<number>;
605
+ tone: HCPair<number | ExtremeValue>;
606
+ saturationFactor?: number;
607
+ mode?: AdaptationMode;
608
+ /** Flip out-of-bounds results instead of clamping. Default: global `autoFlip`. */
609
+ autoFlip?: boolean;
610
+ /**
611
+ * Fixed opacity (0–1). Output includes alpha in the CSS value.
612
+ * Combining with `contrast` is not recommended (perceived tone
613
+ * becomes unpredictable) — a `console.warn` is emitted in that case.
614
+ */
615
+ opacity?: number;
616
+ /**
617
+ * Optional dependency on another color. Same semantics as
618
+ * `GlazeColorOverrides.base` — `contrast` and relative `tone`
619
+ * anchor to the base per scheme.
620
+ */
621
+ base?: GlazeColorToken | GlazeColorValue;
622
+ /**
623
+ * Contrast floor against `base`. Requires `base` to be set. A bare
624
+ * number/preset is WCAG; use `{ wcag }` / `{ apca }` to pick the metric.
625
+ */
626
+ contrast?: HCPair<ContrastSpec>;
627
+ /**
628
+ * Optional human-readable name for the token. Used in error and
629
+ * warning messages (otherwise an internal name like `"value"` is
630
+ * used). Does not affect output keys.
631
+ */
632
+ name?: string;
633
+ /**
634
+ * Per-color override for the hue-independent "safe" chroma limit used in
635
+ * OKHSL↔sRGB conversions (luminance, contrast solving, output formatting).
636
+ * Falls through to the per-theme / per-token `pastel` override when omitted.
637
+ * @see GlazeConfigOverride.pastel
638
+ */
639
+ pastel?: boolean;
640
+ /**
641
+ * Semantic role against `base` / the literal seed: how this token is used.
642
+ * Fixes APCA contrast polarity. Same resolution chain as
643
+ * `RegularColorDef.role` (explicit → name inference → opposite of base →
644
+ * `'text'`). For standalone tokens the name is internal, so set `role`
645
+ * explicitly or rely on the base-opposite / foreground default.
646
+ */
647
+ role?: RoleInput;
648
+ }
649
+ /**
650
+ * Any single-color input form accepted by the value-shorthand
651
+ * overload of `glaze.color()`.
652
+ *
653
+ * Strings cover hex (`#rgb` / `#rrggbb` / `#rrggbbaa`, alpha dropped
654
+ * with a warning) and the four CSS color functions Glaze itself emits:
655
+ * `rgb()`, `hsl()`, `okhsl()`, `oklch()` (alpha components also dropped
656
+ * with a warning).
657
+ *
658
+ * Literal object forms:
659
+ * - `{ h, s, l }` — OKHSL (h: 0–360, s/l: 0–1). Passing 0–100 for `s`/`l`
660
+ * throws with a hint to use the structured form.
661
+ * - `{ h, s, t }` — OKHST (h: 0–360, s/t: 0–1). Tone in 0–1.
662
+ * - `{ r, g, b }` — sRGB 0–255.
663
+ * - `{ l, c, h }` — OKLCh (L/C: 0–1, H: degrees), same as `oklch()` strings.
664
+ */
665
+ type GlazeColorValue = string | OkhslColor | OkhstColor | RgbColor | OklchColor;
666
+ /** Color overrides for the `from` and value-shorthand inputs. */
667
+ interface GlazeColorOverrides {
668
+ /**
669
+ * Override hue. Number is absolute (0–360); `'+N'`/`'-N'` is relative
670
+ * to the extracted (or overridden) seed hue — same semantics as
671
+ * `RegularColorDef.hue`.
672
+ */
673
+ hue?: number | RelativeValue;
674
+ /** Override seed saturation (0–100). Default: extracted from value. */
675
+ saturation?: number;
676
+ /**
677
+ * Override tone. Number is absolute (0–100, contrast-uniform); `'+N'`/`'-N'`
678
+ * is relative to the literal seed (the value passed to `glaze.color()`);
679
+ * `'max'` / `'min'` force to the scheme's tone extreme.
680
+ * Supports HCPair for high-contrast.
681
+ */
682
+ tone?: HCPair<ToneValue>;
683
+ /** Saturation multiplier on the seed (0–1). Default: 1. */
318
684
  saturationFactor?: number;
685
+ /**
686
+ * Adaptation mode. Defaults to `'auto'` for every input form, so
687
+ * colors automatically adapt between light and dark like an ordinary
688
+ * theme color. Value-shorthand inputs (strings and literal objects)
689
+ * preserve light tone via a local `lightTone: false` default; other
690
+ * omitted config fields fall through to the live global at resolve
691
+ * time. Structured `{ hue, saturation, tone }` form also falls
692
+ * through for both tone windows unless overridden.
693
+ *
694
+ * Pass `'fixed'` explicitly to opt back into the linear, non-
695
+ * inverting mapping; pass `'static'` to pin the same tone
696
+ * across every variant.
697
+ */
319
698
  mode?: AdaptationMode;
699
+ /**
700
+ * Flip out-of-bounds results (relative `tone` overshoot / unmet
701
+ * `contrast`) to the opposite side instead of clamping. Defaults to
702
+ * the global `autoFlip`.
703
+ */
704
+ autoFlip?: boolean;
705
+ /**
706
+ * Contrast floor. By default solved against the literal seed
707
+ * (the value itself); when `base` is set, solved against the base's
708
+ * resolved variant per scheme. Same shape as `RegularColorDef.contrast`
709
+ * (bare number/preset = WCAG; `{ wcag }` / `{ apca }` to pick the metric).
710
+ */
711
+ contrast?: HCPair<ContrastSpec>;
712
+ /**
713
+ * Optional dependency on another color. Accepts either a
714
+ * `GlazeColorToken` (returned by another `glaze.color()`) or a raw
715
+ * `GlazeColorValue` (hex / CSS strings / `{ r, g, b }` / `{ h, s, l }` / …),
716
+ * which is automatically wrapped in `glaze.color(value)`.
717
+ *
718
+ * When set:
719
+ * - `contrast` is solved against the base's resolved variant
720
+ * per-scheme (light / dark / lightContrast / darkContrast).
721
+ * - Relative `tone: '+N'` / `'-N'` is anchored to the base's
722
+ * tone per-scheme (matches theme behavior for dependent colors).
723
+ * - Relative `hue: '+N'` / `'-N'` still anchors to the seed (the
724
+ * value passed to `glaze.color()`), not the base.
725
+ * - When the base was created via the structured form (with explicit
726
+ * `hue`/`saturation`/`tone`), it is resolved at full range
727
+ * (`lightTone: false`) for the linking math — ensuring the
728
+ * contrast/tone anchor matches the input tone, not the
729
+ * windowed output. The base's own `.resolve()` output is unaffected.
730
+ *
731
+ * The base token's `.resolve()` is called lazily on first resolve and
732
+ * its result is captured by reference; later mutations to the base's
733
+ * defining call don't apply (matches existing token snapshot semantics).
734
+ */
735
+ base?: GlazeColorToken | GlazeColorValue;
736
+ /**
737
+ * Fixed opacity (0–1). Output includes alpha in the CSS value.
738
+ * Combining with `contrast` is not recommended (perceived tone
739
+ * becomes unpredictable) — a `console.warn` is emitted in that case.
740
+ */
741
+ opacity?: number;
742
+ /**
743
+ * Optional human-readable name for the token. Used in error and
744
+ * warning messages (otherwise an internal name like `"value"` is
745
+ * used). Does not affect output keys.
746
+ */
747
+ name?: string;
748
+ /**
749
+ * Per-color override for the hue-independent "safe" chroma limit used in
750
+ * OKHSL↔sRGB conversions (luminance, contrast solving, output formatting).
751
+ * Falls through to the per-theme / per-token `pastel` override when omitted.
752
+ * @see GlazeConfigOverride.pastel
753
+ */
754
+ pastel?: boolean;
755
+ /**
756
+ * Semantic role against `base` / the literal seed: how this token is used.
757
+ * Fixes APCA contrast polarity. Same resolution chain as
758
+ * `RegularColorDef.role`.
759
+ */
760
+ role?: RoleInput;
761
+ }
762
+ /**
763
+ * Object input for `glaze.color()` that carries a raw color value plus
764
+ * optional color overrides in the same object.
765
+ *
766
+ * ```ts
767
+ * glaze.color({ from: '#1a1a2e', base: bg, contrast: 'AA' })
768
+ * glaze.color({ from: { r: 38, g: 252, b: 178 }, tone: '+10' })
769
+ * ```
770
+ */
771
+ interface GlazeFromInput extends GlazeColorOverrides {
772
+ /** The source color value. Accepts the same forms as a bare `GlazeColorValue`. */
773
+ from: GlazeColorValue;
774
+ }
775
+ /** Options for `GlazeColorToken.css()`. */
776
+ interface GlazeColorCssOptions {
777
+ /**
778
+ * Custom property base name (without leading `--`). Required.
779
+ * Becomes the variable identifier in the output, e.g.
780
+ * `name: 'brand'` → `--brand-color: …`.
781
+ */
782
+ name: string;
783
+ /** Output color format. Default: 'oklch'. */
784
+ format?: GlazeColorFormat;
785
+ /**
786
+ * Suffix appended to the name. Default: '-color' (matches
787
+ * `theme.css` default).
788
+ */
789
+ suffix?: string;
790
+ /**
791
+ * Emit hue as a separate custom property, referenced via `var()`.
792
+ * Requires `format: 'oklch'` and a pastel token. oklch + all-pastel only.
793
+ */
794
+ splitHue?: boolean;
320
795
  }
321
796
  /** Return type for `glaze.color()`. */
322
797
  interface GlazeColorToken {
@@ -326,18 +801,128 @@ interface GlazeColorToken {
326
801
  token(options?: GlazeTokenOptions): Record<string, string>;
327
802
  /**
328
803
  * Export as a tasty style-to-state binding (no color name key).
329
- * Uses `#name` keys and state aliases (`''`, `@dark`, etc.).
330
- * @see https://cube-ui-kit.vercel.app/?path=/docs/tasty-documentation--docs
804
+ * Uses `#name` keys and state aliases (`''`, `'@media(prefers-color-scheme: dark)'`, etc.).
805
+ * @see https://tasty.style/docs
331
806
  */
332
807
  tasty(options?: GlazeTokenOptions): Record<string, string>;
333
808
  /** Export as a flat JSON map (no color name key). */
334
809
  json(options?: GlazeJsonOptions): Record<string, string>;
810
+ /** Export as CSS custom property declarations grouped by scheme variant. */
811
+ css(options: GlazeColorCssOptions): GlazeCssResult;
812
+ /**
813
+ * Export as W3C DTCG color tokens (one per scheme variant, no color name
814
+ * key). Each entry is a full `{ $type: 'color', $value }` token.
815
+ * @see https://www.designtokens.org/
816
+ */
817
+ dtcg(options?: GlazeDtcgOptions): GlazeColorDtcgResult;
818
+ /**
819
+ * Export as a single W3C DTCG Resolver-Module document for this color,
820
+ * keyed by `name` across all scheme variants. `name` is required.
821
+ * @see https://www.designtokens.org/
822
+ */
823
+ dtcgResolver(options: GlazeColorDtcgResolverOptions): GlazeDtcgResolverDocument;
824
+ /**
825
+ * Export as a Tailwind CSS v4 `@theme` block (light baseline) plus dark /
826
+ * high-contrast overrides. Returns a single ready-to-paste CSS string.
827
+ * `name` is required (forms `--color-<name>`).
828
+ * @see https://tailwindcss.com/docs/theme
829
+ */
830
+ tailwind(options: GlazeColorTailwindOptions): string;
831
+ /**
832
+ * Serialize the token as a JSON-safe object. Captures the original
833
+ * input value, overrides, and config so it can be rehydrated via
834
+ * `glaze.colorFrom(...)`. `base` is recursively serialized.
835
+ * Optional `override` is merged over the instance local at export time.
836
+ */
837
+ export(override?: GlazeConfigOverride): GlazeColorTokenExport;
838
+ }
839
+ /**
840
+ * JSON-safe serialization of a `glaze.color()` token. Pass to
841
+ * `glaze.colorFrom(...)` to rehydrate.
842
+ */
843
+ interface GlazeColorTokenExport {
844
+ /** Snapshot kind. Always written by `token.export()`; optional on legacy snapshots. */
845
+ kind?: 'color';
846
+ /** Schema version. Always written by `token.export()`; optional on legacy snapshots. */
847
+ version?: number;
848
+ /**
849
+ * Discriminator for the source overload that created the token.
850
+ * - `'value'`: created via `glaze.color(value)` or `glaze.color({ from, ...overrides })`.
851
+ * - `'structured'`: created via `glaze.color({ hue, saturation, ... })`.
852
+ */
853
+ form: 'value' | 'structured';
854
+ /** Original input. For `form: 'value'` this is the raw `GlazeColorValue`; for `form: 'structured'` this is the structured input. */
855
+ input: GlazeColorValue | GlazeColorInputExport;
856
+ /**
857
+ * Overrides recorded at creation time. `base` is recursively
858
+ * serialized. Only present for `form: 'value'`.
859
+ */
860
+ overrides?: GlazeColorOverridesExport;
861
+ /**
862
+ * Effective config freeze from `.export()` — `getConfig() ∪ local ∪
863
+ * exportArg` at call time. Used by `glaze.colorFrom()` to pin
864
+ * deterministic behavior across later `configure()` calls.
865
+ */
866
+ config?: GlazeConfigOverride;
867
+ }
868
+ /**
869
+ * JSON-safe serialization of a `glaze.palette()` composition.
870
+ * Pass to `glaze.paletteFrom(...)` to rehydrate.
871
+ */
872
+ interface GlazePaletteExport {
873
+ /** Snapshot kind. Always written by `palette.export()`. */
874
+ kind?: 'palette';
875
+ /** Schema version. Always written by `palette.export()`. */
876
+ version?: number;
877
+ /** Per-theme authoring snapshots keyed by theme name. */
878
+ themes: Record<string, GlazeThemeExport>;
879
+ /** Primary theme name, if set on the palette. */
880
+ primary?: string;
881
+ }
882
+ /**
883
+ * Serializable shape of a structured `glaze.color({...})` input.
884
+ * Differs from `GlazeColorInput` only in that `base` is replaced by an
885
+ * `export` instead of a token reference.
886
+ */
887
+ interface GlazeColorInputExport {
888
+ hue: number;
889
+ saturation: number;
890
+ tone: HCPair<number | ExtremeValue>;
891
+ saturationFactor?: number;
892
+ mode?: AdaptationMode;
893
+ autoFlip?: boolean;
894
+ opacity?: number;
895
+ base?: GlazeColorTokenExport | GlazeColorValue;
896
+ contrast?: HCPair<ContrastSpec>;
897
+ name?: string;
898
+ pastel?: boolean;
899
+ role?: RoleInput;
900
+ }
901
+ /**
902
+ * Serializable shape of `GlazeColorOverrides`. `base` is replaced by
903
+ * its export (or left as a `GlazeColorValue` if it was originally a value).
904
+ */
905
+ interface GlazeColorOverridesExport {
906
+ hue?: number | RelativeValue;
907
+ saturation?: number;
908
+ tone?: HCPair<ToneValue>;
909
+ saturationFactor?: number;
910
+ mode?: AdaptationMode;
911
+ autoFlip?: boolean;
912
+ contrast?: HCPair<ContrastSpec>;
913
+ base?: GlazeColorTokenExport | GlazeColorValue;
914
+ opacity?: number;
915
+ name?: string;
916
+ pastel?: boolean;
917
+ role?: RoleInput;
335
918
  }
336
919
  interface GlazeTheme {
337
920
  /** The hue seed (0–360). */
338
921
  readonly hue: number;
339
922
  /** The saturation seed (0–100). */
340
923
  readonly saturation: number;
924
+ /** The effective config for this theme. */
925
+ getConfig(): GlazeConfigResolved;
341
926
  /** Add/replace colors (additive merge with existing definitions). */
342
927
  colors(defs: ColorMap): void;
343
928
  /** Get a color definition by name. */
@@ -353,7 +938,7 @@ interface GlazeTheme {
353
938
  /** Clear all color definitions. */
354
939
  reset(): void;
355
940
  /** Export the theme configuration as a JSON-safe object. */
356
- export(): GlazeThemeExport;
941
+ export(override?: GlazeConfigOverride): GlazeThemeExport;
357
942
  /** Create a child theme inheriting all color definitions. */
358
943
  extend(options: GlazeExtendOptions): GlazeTheme;
359
944
  /** Resolve all colors and return the result map. */
@@ -369,20 +954,43 @@ interface GlazeTheme {
369
954
  tokens(options?: GlazeJsonOptions): Record<string, Record<string, string>>;
370
955
  /**
371
956
  * Export as tasty style-to-state bindings.
372
- * Uses `#name` color token keys and state aliases (`''`, `@dark`, etc.).
957
+ * Uses `#name` color token keys and state aliases (`''`, `'@media(prefers-color-scheme: dark)'`, etc.).
373
958
  * Spread into component styles or register as a recipe via `configure({ recipes })`.
374
- * @see https://cube-ui-kit.vercel.app/?path=/docs/tasty-documentation--docs
959
+ * @see https://tasty.style/docs
375
960
  */
376
961
  tasty(options?: GlazeTokenOptions): Record<string, Record<string, string>>;
377
962
  /** Export as plain JSON. */
378
963
  json(options?: GlazeJsonOptions): Record<string, Record<string, string>>;
379
964
  /** Export as CSS custom property declarations. */
380
965
  css(options?: GlazeCssOptions): GlazeCssResult;
966
+ /**
967
+ * Export as W3C Design Tokens Format Module (2025.10) documents, one per
968
+ * scheme variant. Consumable by Figma, Tokens Studio, Style Dictionary,
969
+ * Terrazzo, and any DTCG-compatible tool.
970
+ * @see https://www.designtokens.org/
971
+ */
972
+ dtcg(options?: GlazeDtcgOptions): GlazeDtcgResult;
973
+ /**
974
+ * Export as a single W3C DTCG Resolver-Module document describing every
975
+ * scheme variant as one `sets` entry plus a single `scheme` modifier with a
976
+ * context per variant. Consumable by resolver tools such as Dispersa.
977
+ * @see https://www.designtokens.org/
978
+ */
979
+ dtcgResolver(options?: GlazeDtcgResolverOptions): GlazeDtcgResolverDocument;
980
+ /**
981
+ * Export as a Tailwind CSS v4 `@theme` block (light baseline) plus dark /
982
+ * high-contrast overrides under configurable selectors. Returns a single
983
+ * ready-to-paste CSS string.
984
+ * @see https://tailwindcss.com/docs/theme
985
+ */
986
+ tailwind(options?: GlazeTailwindOptions): string;
381
987
  }
382
988
  interface GlazeExtendOptions {
383
989
  hue?: number;
384
990
  saturation?: number;
385
991
  colors?: ColorMap;
992
+ /** Config override for the child theme. Merged with the parent's override. */
993
+ config?: GlazeConfigOverride;
386
994
  }
387
995
  interface GlazeTokenOptions {
388
996
  /** Prefix mode. `true` uses "<themeName>-", or provide a custom map. */
@@ -394,20 +1002,40 @@ interface GlazeTokenOptions {
394
1002
  };
395
1003
  /** Override which scheme variants to include. */
396
1004
  modes?: GlazeOutputModes;
397
- /** Output color format. Default: 'okhsl'. */
1005
+ /** Output color format. Default: 'oklch'. */
398
1006
  format?: GlazeColorFormat;
1007
+ /**
1008
+ * Emit hue as a separate custom property, referenced via `var()`.
1009
+ * Requires `format: 'oklch'` and every color to be pastel.
1010
+ */
1011
+ splitHue?: boolean;
1012
+ /**
1013
+ * Base name for the theme-level hue var (`--{name}-hue`). Default: `'theme'`.
1014
+ * Palette export auto-derives this from the theme name.
1015
+ */
1016
+ name?: string;
399
1017
  }
400
1018
  interface GlazeJsonOptions {
401
1019
  /** Override which scheme variants to include. */
402
1020
  modes?: GlazeOutputModes;
403
- /** Output color format. Default: 'okhsl'. */
1021
+ /** Output color format. Default: 'oklch'. */
404
1022
  format?: GlazeColorFormat;
405
1023
  }
406
1024
  interface GlazeCssOptions {
407
- /** Output color format. Default: 'rgb'. */
1025
+ /** Output color format. Default: 'oklch'. */
408
1026
  format?: GlazeColorFormat;
409
1027
  /** Suffix appended to each CSS custom property name. Default: '-color'. */
410
1028
  suffix?: string;
1029
+ /**
1030
+ * Emit hue as a separate custom property, referenced via `var()`.
1031
+ * Requires `format: 'oklch'` and every color to be pastel.
1032
+ */
1033
+ splitHue?: boolean;
1034
+ /**
1035
+ * Base name for the theme-level hue var (`--{name}-hue`). Default: `'theme'`.
1036
+ * Palette export auto-derives this from the theme name.
1037
+ */
1038
+ name?: string;
411
1039
  }
412
1040
  /** CSS custom property declarations grouped by scheme variant. */
413
1041
  interface GlazeCssResult {
@@ -416,6 +1044,182 @@ interface GlazeCssResult {
416
1044
  lightContrast: string;
417
1045
  darkContrast: string;
418
1046
  }
1047
+ /**
1048
+ * Color space used for DTCG `$value` color objects.
1049
+ * @see https://www.designtokens.org/
1050
+ */
1051
+ type DtcgColorSpace = 'srgb' | 'oklch';
1052
+ /**
1053
+ * A DTCG color `$value` in the sRGB color space: gamma sRGB components in
1054
+ * 0–1 plus a 6-digit `hex` hint. Universally understood by Figma, Tokens
1055
+ * Studio, Style Dictionary, and every DTCG reader.
1056
+ */
1057
+ interface DtcgSrgbColorValue {
1058
+ colorSpace: 'srgb';
1059
+ components: [number, number, number];
1060
+ hex: HexColor;
1061
+ /** Opacity 0–1. Omitted when fully opaque (alpha = 1). */
1062
+ alpha?: number;
1063
+ }
1064
+ /**
1065
+ * A DTCG color `$value` in the OKLCH color space: `[L, C, H]` components
1066
+ * (L/C: 0–1, H: degrees). Wide-gamut and Glaze-native; no `hex` is emitted.
1067
+ */
1068
+ interface DtcgOklchColorValue {
1069
+ colorSpace: 'oklch';
1070
+ components: [number, number, number];
1071
+ /** Opacity 0–1. Omitted when fully opaque (alpha = 1). */
1072
+ alpha?: number;
1073
+ }
1074
+ /** A DTCG `$value` for a color token, in either supported color space. */
1075
+ type DtcgColorValue = DtcgSrgbColorValue | DtcgOklchColorValue;
1076
+ /**
1077
+ * A single W3C DTCG color token: `{ $type: 'color', $value }`.
1078
+ * `$description` is optional and not populated by Glaze today.
1079
+ */
1080
+ interface DtcgColorToken {
1081
+ $type: 'color';
1082
+ $value: DtcgColorValue;
1083
+ $description?: string;
1084
+ }
1085
+ /**
1086
+ * A W3C Design Tokens Format Module (2025.10) token tree for one scheme.
1087
+ * Glaze emits one document per scheme variant — the most tool-compatible
1088
+ * convention (one file per Style Dictionary theme / Tokens Studio set /
1089
+ * Figma variable mode).
1090
+ */
1091
+ type DtcgDocument = Record<string, DtcgColorToken>;
1092
+ /** DTCG token documents grouped by scheme variant. Light is always present. */
1093
+ interface GlazeDtcgResult {
1094
+ light: DtcgDocument;
1095
+ dark?: DtcgDocument;
1096
+ lightContrast?: DtcgDocument;
1097
+ darkContrast?: DtcgDocument;
1098
+ }
1099
+ /** A single DTCG color token grouped by scheme variant (standalone tokens). */
1100
+ interface GlazeColorDtcgResult {
1101
+ light: DtcgColorToken;
1102
+ dark?: DtcgColorToken;
1103
+ lightContrast?: DtcgColorToken;
1104
+ darkContrast?: DtcgColorToken;
1105
+ }
1106
+ /** Options for `theme.dtcg()` / `palette.dtcg()`. */
1107
+ interface GlazeDtcgOptions {
1108
+ /** Override which scheme variants to include. */
1109
+ modes?: GlazeOutputModes;
1110
+ /**
1111
+ * DTCG color space. `'srgb'` (default) emits sRGB components plus a `hex`
1112
+ * hint — universally understood (Figma, Tokens Studio). `'oklch'` emits
1113
+ * OKLCH components with no hex — Glaze-native, wide-gamut.
1114
+ */
1115
+ colorSpace?: DtcgColorSpace;
1116
+ }
1117
+ /**
1118
+ * A node in a DTCG Resolver-Module token tree: either a leaf color token or a
1119
+ * nested group. A flat `DtcgDocument` (top-level color-name keys) is a valid
1120
+ * shallow tree, so Glaze's per-scheme documents slot directly into
1121
+ * `sets.<name>.sources` and `modifiers.<name>.contexts.<ctx>` entries.
1122
+ */
1123
+ interface DtcgTokenTree {
1124
+ [key: string]: DtcgColorToken | DtcgTokenTree;
1125
+ }
1126
+ /** A named set in a resolver document: a list of token-tree sources. */
1127
+ interface DtcgResolverSet {
1128
+ sources: DtcgTokenTree[];
1129
+ }
1130
+ /**
1131
+ * A named modifier (an axis such as `scheme`) in a resolver document.
1132
+ * `default` names the context applied when no override is selected; `contexts`
1133
+ * maps each context name to the token-tree overrides applied for it.
1134
+ */
1135
+ interface DtcgResolverModifier {
1136
+ default: string;
1137
+ contexts: Record<string, DtcgTokenTree[]>;
1138
+ }
1139
+ /** A JSON-pointer `$ref` entry in a resolver document's `resolutionOrder`. */
1140
+ interface DtcgResolverRef {
1141
+ $ref: string;
1142
+ }
1143
+ /**
1144
+ * A W3C DTCG Resolver-Module document. Describes every scheme variant in a
1145
+ * single file as `sets` (base token sources) plus `modifiers` (per-context
1146
+ * overrides) composed in `resolutionOrder`. Consumable by resolver tools such
1147
+ * as Dispersa.
1148
+ * @see https://www.designtokens.org/
1149
+ */
1150
+ interface GlazeDtcgResolverDocument {
1151
+ version: string;
1152
+ sets: Record<string, DtcgResolverSet>;
1153
+ modifiers: Record<string, DtcgResolverModifier>;
1154
+ resolutionOrder: DtcgResolverRef[];
1155
+ }
1156
+ /** Renaming of the four scheme variants as resolver-modifier context names. */
1157
+ interface GlazeDtcgResolverContextNames {
1158
+ light?: string;
1159
+ dark?: string;
1160
+ lightContrast?: string;
1161
+ darkContrast?: string;
1162
+ }
1163
+ /**
1164
+ * Options for `theme.dtcgResolver()` / `palette.dtcgResolver()`. Extends
1165
+ * `GlazeDtcgOptions` so `modes` + `colorSpace` pass through to the underlying
1166
+ * per-scheme `dtcg()` build.
1167
+ */
1168
+ interface GlazeDtcgResolverOptions extends GlazeDtcgOptions {
1169
+ /** Name of the single set holding the default (light) token tree. Default `'base'`. */
1170
+ setName?: string;
1171
+ /**
1172
+ * Name of the modifier describing the scheme axis. Default `'scheme'`
1173
+ * (Glaze's term for the light / dark / high-contrast axis).
1174
+ */
1175
+ modifierName?: string;
1176
+ /**
1177
+ * Override the four context names emitted on the modifier. Defaults to the
1178
+ * Glaze variant keys: `light` / `dark` / `lightContrast` / `darkContrast`.
1179
+ */
1180
+ contextNames?: GlazeDtcgResolverContextNames;
1181
+ /** Resolver document version. Default `'2025.10'`. */
1182
+ version?: string;
1183
+ }
1184
+ /** Options for `glaze.color().dtcgResolver()`. `name` is required. */
1185
+ interface GlazeColorDtcgResolverOptions extends GlazeDtcgResolverOptions {
1186
+ /** Token name keying the color within each token tree. Required. */
1187
+ name: string;
1188
+ }
1189
+ /** Options for `theme.tailwind()` / `palette.tailwind()`. */
1190
+ interface GlazeTailwindOptions {
1191
+ /** Override which scheme variants to include. */
1192
+ modes?: GlazeOutputModes;
1193
+ /** Output color format. Default: 'oklch'. */
1194
+ format?: GlazeColorFormat;
1195
+ /**
1196
+ * CSS custom property namespace, forming `--<namespace><name>`.
1197
+ * Default: `'color-'` → `--color-surface`. (Tailwind v4's `--color-*`
1198
+ * convention, which auto-generates `bg-*` / `text-*` / `border-*`.)
1199
+ *
1200
+ * Named `namespace` rather than `prefix` to avoid clashing with the
1201
+ * palette theme-prefix option on `palette.tailwind()`.
1202
+ */
1203
+ namespace?: string;
1204
+ /**
1205
+ * Selector wrapping the dark-scheme overrides. Default: `'.dark'`.
1206
+ * Pass a media query such as `'@media (prefers-color-scheme: dark)'` to
1207
+ * drive dark mode from the OS preference instead of a class.
1208
+ */
1209
+ darkSelector?: string;
1210
+ /**
1211
+ * Selector wrapping the light high-contrast overrides. Default:
1212
+ * `'.high-contrast'`. The combined dark + high-contrast overrides are
1213
+ * emitted under `${darkSelector}${highContrastSelector}` (e.g.
1214
+ * `.dark.high-contrast`).
1215
+ */
1216
+ highContrastSelector?: string;
1217
+ }
1218
+ /** Options for `glaze.color().tailwind()`. `name` is required. */
1219
+ interface GlazeColorTailwindOptions extends GlazeTailwindOptions {
1220
+ /** Custom property base name (without leading `--`). Required. */
1221
+ name: string;
1222
+ }
419
1223
  /** Options for `glaze.palette()` creation. */
420
1224
  interface GlazePaletteOptions {
421
1225
  /**
@@ -447,8 +1251,31 @@ interface GlazePaletteExportOptions {
447
1251
  * When omitted, inherits the palette-level `primary`.
448
1252
  */
449
1253
  primary?: string | false;
1254
+ /**
1255
+ * Emit hue as a separate custom property, referenced via `var()`.
1256
+ * Requires `format: 'oklch'` and every color to be pastel.
1257
+ */
1258
+ splitHue?: boolean;
450
1259
  }
451
1260
  interface GlazePalette {
1261
+ /** Theme names in insertion order. */
1262
+ list(): string[];
1263
+ /** Primary theme name, if set at palette creation. */
1264
+ readonly primary: string | undefined;
1265
+ /** Get a theme by name. Returns the live instance held by the palette. */
1266
+ theme(name: string): GlazeTheme | undefined;
1267
+ /**
1268
+ * Shallow copy of the theme map (same instances the palette holds).
1269
+ * Mutating a returned theme affects subsequent palette exports.
1270
+ */
1271
+ themes(): Record<string, GlazeTheme>;
1272
+ /**
1273
+ * Export the palette authoring configuration as a JSON-safe object.
1274
+ * Restorable via `glaze.paletteFrom(...)`. Distinct from `json()`, which
1275
+ * emits resolved color strings. Optional `override` is forwarded to each
1276
+ * nested `theme.export(override)`.
1277
+ */
1278
+ export(override?: GlazeConfigOverride): GlazePaletteExport;
452
1279
  /**
453
1280
  * Export all themes as a flat token map grouped by scheme variant.
454
1281
  * Prefix defaults to `true` — all tokens are prefixed with the theme name.
@@ -463,9 +1290,9 @@ interface GlazePalette {
463
1290
  tokens(options?: GlazeJsonOptions & GlazePaletteExportOptions): Record<string, Record<string, string>>;
464
1291
  /**
465
1292
  * Export all themes as tasty style-to-state bindings.
466
- * Uses `#name` color token keys and state aliases (`''`, `@dark`, etc.).
1293
+ * Uses `#name` color token keys and state aliases (`''`, `'@media(prefers-color-scheme: dark)'`, etc.).
467
1294
  * Prefix defaults to `true`. Inherits the palette-level `primary`.
468
- * @see https://cube-ui-kit.vercel.app/?path=/docs/tasty-documentation--docs
1295
+ * @see https://tasty.style/docs
469
1296
  */
470
1297
  tasty(options?: GlazeTokenOptions & GlazePaletteExportOptions): Record<string, Record<string, string>>;
471
1298
  /** Export all themes as plain JSON grouped by theme name. */
@@ -474,61 +1301,240 @@ interface GlazePalette {
474
1301
  }): Record<string, Record<string, Record<string, string>>>;
475
1302
  /** Export all themes as CSS custom property declarations. */
476
1303
  css(options?: GlazeCssOptions & GlazePaletteExportOptions): GlazeCssResult;
1304
+ /**
1305
+ * Export all themes as W3C DTCG documents, one per scheme variant.
1306
+ * Prefix defaults to `true`. Inherits the palette-level `primary`.
1307
+ * @see https://www.designtokens.org/
1308
+ */
1309
+ dtcg(options?: GlazeDtcgOptions & GlazePaletteExportOptions): GlazeDtcgResult;
1310
+ /**
1311
+ * Export all themes as a single W3C DTCG Resolver-Module document. Prefix
1312
+ * defaults to `true`. Inherits the palette-level `primary`.
1313
+ * @see https://www.designtokens.org/
1314
+ */
1315
+ dtcgResolver(options?: GlazeDtcgResolverOptions & GlazePaletteExportOptions): GlazeDtcgResolverDocument;
1316
+ /**
1317
+ * Export all themes as a Tailwind CSS v4 `@theme` block plus dark /
1318
+ * high-contrast overrides. Returns a single ready-to-paste CSS string.
1319
+ * Prefix defaults to `true`.
1320
+ * @see https://tailwindcss.com/docs/theme
1321
+ */
1322
+ tailwind(options?: GlazeTailwindOptions & GlazePaletteExportOptions): string;
477
1323
  }
478
1324
  //#endregion
1325
+ //#region src/serialize.d.ts
1326
+ /** Type guard for theme authoring snapshots (prefers `kind`, falls back to shape). */
1327
+ declare function isThemeExport(data: unknown): data is GlazeThemeExport;
1328
+ /** Type guard for color-token authoring snapshots. */
1329
+ declare function isColorTokenExport(data: unknown): data is GlazeColorTokenExport;
1330
+ /** Type guard for palette authoring snapshots. */
1331
+ declare function isPaletteExport(data: unknown): data is GlazePaletteExport;
1332
+ //#endregion
479
1333
  //#region src/glaze.d.ts
480
1334
  type PaletteInput = Record<string, GlazeTheme>;
481
1335
  /**
482
1336
  * Create a single-hue glaze theme.
483
1337
  *
1338
+ * An optional `config` override can be supplied to customize the resolve
1339
+ * behavior for this theme (tone windows, etc.). The
1340
+ * override is **merged over the live global config at resolve time** —
1341
+ * the theme still reacts to later `configure()` calls for fields it
1342
+ * didn't override.
1343
+ *
484
1344
  * @example
485
1345
  * ```ts
486
- * const primary = glaze({ hue: 280, saturation: 80 });
487
- * // or shorthand:
488
1346
  * const primary = glaze(280, 80);
1347
+ * // or shorthand:
1348
+ * const primary = glaze({ hue: 280, saturation: 80 });
1349
+ * // with config override:
1350
+ * const raw = glaze(280, 80, { lightTone: false });
489
1351
  * ```
490
1352
  */
491
1353
  declare function glaze(hueOrOptions: number | {
492
1354
  hue: number;
493
1355
  saturation: number;
494
- }, saturation?: number): GlazeTheme;
1356
+ }, saturation?: number, config?: GlazeConfigOverride): GlazeTheme;
495
1357
  declare namespace glaze {
496
1358
  var configure: (config: GlazeConfig) => void;
497
- var palette: (themes: PaletteInput, options?: GlazePaletteOptions) => {
498
- tokens(options?: GlazeJsonOptions & GlazePaletteExportOptions): Record<string, Record<string, string>>;
499
- tasty(options?: GlazeTokenOptions & GlazePaletteExportOptions): Record<string, Record<string, string>>;
500
- json(options?: GlazeJsonOptions & {
501
- prefix?: boolean | Record<string, string>;
502
- }): Record<string, Record<string, Record<string, string>>>;
503
- css(options?: GlazeCssOptions & GlazePaletteExportOptions): GlazeCssResult;
504
- };
1359
+ var palette: (themes: PaletteInput, options?: GlazePaletteOptions) => GlazePalette;
1360
+ var themeFrom: (data: GlazeThemeExport) => GlazeTheme;
505
1361
  var from: (data: GlazeThemeExport) => GlazeTheme;
506
- var color: (input: GlazeColorInput) => GlazeColorToken;
1362
+ var color: (input: GlazeFromInput | GlazeColorInput | GlazeColorValue, config?: GlazeConfigOverride) => GlazeColorToken;
507
1363
  var shadow: (input: GlazeShadowInput) => ResolvedColorVariant;
508
- var format: (variant: ResolvedColorVariant, colorFormat?: GlazeColorFormat) => string;
1364
+ var format: (variant: ResolvedColorVariant, colorFormat?: GlazeColorFormat, pastel?: boolean) => string;
509
1365
  var fromHex: (hex: string) => GlazeTheme;
510
1366
  var fromRgb: (r: number, g: number, b: number) => GlazeTheme;
1367
+ var colorFrom: (data: GlazeColorTokenExport) => GlazeColorToken;
1368
+ var paletteFrom: (data: GlazePaletteExport) => GlazePalette;
1369
+ var isThemeExport: typeof isThemeExport;
1370
+ var isColorTokenExport: typeof isColorTokenExport;
1371
+ var isPaletteExport: typeof isPaletteExport;
511
1372
  var getConfig: () => GlazeConfigResolved;
512
1373
  var resetConfig: () => void;
513
1374
  }
514
1375
  //#endregion
1376
+ //#region src/channels.d.ts
1377
+ interface HueDeclaration {
1378
+ prop: string;
1379
+ value: string;
1380
+ }
1381
+ interface HuePlan {
1382
+ /** CSS `var()` reference spliced into `oklch(L C <hueVar>)`. */
1383
+ hueVar: string;
1384
+ /** When true, emit a full inline color (shadow/mix/achromatic). */
1385
+ inline: boolean;
1386
+ /** Scheme-independent `--*-hue` declarations for this color. */
1387
+ declarations: HueDeclaration[];
1388
+ }
1389
+ interface ChannelCtx {
1390
+ seedHue: number;
1391
+ /** Theme-level hue var base name (without `--` / `-hue`). */
1392
+ baseName: string;
1393
+ /** Token / custom-property name prefix used for hue var naming (`brand-` etc.). */
1394
+ prefix: string;
1395
+ defs: ColorMap;
1396
+ mode: 'theme' | 'standalone';
1397
+ /** Standalone: resolved hue from the primary variant (scheme-independent). */
1398
+ resolvedHue?: number;
1399
+ /**
1400
+ * When false, hue declarations are not emitted (the pass only references
1401
+ * hue vars already declared by a sibling pass). Used by palette primary
1402
+ * unprefixed aliases so they reference the themed `--{themeName}-*-hue`
1403
+ * vars without re-declaring (and colliding with) other themes' base vars.
1404
+ * Defaults to true.
1405
+ */
1406
+ emitDeclarations?: boolean;
1407
+ }
1408
+ //#endregion
1409
+ //#region src/format-guard.d.ts
1410
+ /**
1411
+ * Throw when a non-native Glaze color space is requested for an export that
1412
+ * emits raw CSS or non-Tasty token maps.
1413
+ */
1414
+ declare function assertNativeFormat(format: GlazeColorFormat | undefined, method: string): void;
1415
+ /**
1416
+ * Throw when `splitHue` is enabled but any exported color is not pastel.
1417
+ * Hue rotation is only clip-free when chroma is bounded by the hue-independent
1418
+ * safe chroma (`computeSafeChromaOKLCH`).
1419
+ */
1420
+ declare function assertAllPastel(resolved: Map<string, ResolvedColor>, modes: Required<GlazeOutputModes>): void;
1421
+ //#endregion
1422
+ //#region src/roles.d.ts
1423
+ /**
1424
+ * Normalize a `RoleInput` (canonical value or alias) into a canonical `Role`.
1425
+ * Returns `undefined` for unrecognized strings so callers can fall through to
1426
+ * the next step of the resolution chain.
1427
+ */
1428
+ declare function normalizeRole(input: RoleInput | undefined): Role | undefined;
1429
+ /**
1430
+ * Infer a `Role` from a color name by matching its tokens against the role
1431
+ * keyword sets. When multiple tokens match, the **last** recognized token
1432
+ * wins (so `button-text` → `text`, `input-bg` → `surface`, `card-border` →
1433
+ * `border`). Returns `undefined` when no token matches.
1434
+ */
1435
+ declare function inferRoleFromName(name: string): Role | undefined;
1436
+ /** APCA argument order: which side the resolved color plays. */
1437
+ type Polarity = 'fg' | 'bg';
1438
+ /**
1439
+ * Map a role to its APCA polarity. `text` and `border` are foreground spots
1440
+ * against their base (the candidate is the text argument); `surface` is the
1441
+ * background (the base is the text argument).
1442
+ */
1443
+ declare function roleToPolarity(role: Role): Polarity;
1444
+ /**
1445
+ * The opposite role of `role`, used when a color with no explicit role and no
1446
+ * inferable name depends on a base: the dependent color plays the opposite
1447
+ * role of its base. `surface` ↔ `text`; `border` is treated as a foreground
1448
+ * spot, so its opposite is `surface`.
1449
+ */
1450
+ declare function oppositeRole(role: Role): Role;
1451
+ //#endregion
1452
+ //#region src/okhst.d.ts
1453
+ /**
1454
+ * Reference eps for the OKHST color space. WCAG 2 contrast is
1455
+ * `(Y_hi + 0.05) / (Y_lo + 0.05)`, so an eps of `0.05` makes equal tone
1456
+ * steps yield equal WCAG contrast. This is the canonical eps used by
1457
+ * `okhst()` input, `{ h, s, t }` input, stored `ResolvedColorVariant.t`,
1458
+ * relative `tone` offsets, and the contrast solver.
1459
+ */
1460
+ declare const REF_EPS = 0.05;
1461
+ /**
1462
+ * Map a luminance `Y` (0–1) to tone (0–100) at the given eps.
1463
+ * `toneFromY(0) === 0` and `toneFromY(1) === 100` for any eps.
1464
+ */
1465
+ declare function toneFromY(y: number, eps?: number): number;
1466
+ /** Map a tone (0–100) back to luminance (0–1). Inverse of {@link toneFromY}. */
1467
+ declare function yFromTone(t: number, eps?: number): number;
1468
+ /** OKHSL lightness (0–1) -> tone (0–100). */
1469
+ declare function toTone(l: number, eps?: number): number;
1470
+ /** Tone (0–100) -> OKHSL lightness (0–1). Inverse of {@link toTone}. */
1471
+ declare function fromTone(t: number, eps?: number): number;
1472
+ /** Convert OKHST `{ h, s, t }` (t in 0–1) to OKHSL `{ h, s, l }`. */
1473
+ declare function okhstToOkhsl(c: {
1474
+ h: number;
1475
+ s: number;
1476
+ t: number;
1477
+ }): {
1478
+ h: number;
1479
+ s: number;
1480
+ l: number;
1481
+ };
1482
+ /** Convert OKHSL `{ h, s, l }` to OKHST `{ h, s, t }` (t in 0–1). */
1483
+ declare function okhslToOkhst(c: {
1484
+ h: number;
1485
+ s: number;
1486
+ l: number;
1487
+ }): {
1488
+ h: number;
1489
+ s: number;
1490
+ t: number;
1491
+ };
1492
+ /**
1493
+ * Edge adapter: a resolved variant stores canonical tone `t` (0–1). Convert
1494
+ * it to the OKHSL `{ h, s, l }` the formatters and luminance pipeline expect.
1495
+ */
1496
+ declare function variantToOkhsl(v: {
1497
+ h: number;
1498
+ s: number;
1499
+ t: number;
1500
+ }): {
1501
+ h: number;
1502
+ s: number;
1503
+ l: number;
1504
+ };
1505
+ //#endregion
515
1506
  //#region src/okhsl-color-math.d.ts
516
1507
  /**
517
1508
  * OKHSL color math primitives for the glaze theme generator.
518
1509
  *
519
- * Provides bidirectional OKHSL ↔ sRGB conversion, relative luminance
520
- * computation for WCAG 2 contrast calculations, and multi-format output
521
- * (okhsl, rgb, hsl, oklch).
1510
+ * Provides bidirectional OKHSL ↔ sRGB conversion, luminance computation
1511
+ * for both contrast metrics (WCAG 2 relative luminance and APCA screen
1512
+ * luminance `Ys`), and multi-format output (okhsl, rgb, hsl, oklch).
522
1513
  */
1514
+ type Vec3 = [number, number, number];
1515
+ /**
1516
+ * OKHSL toe function: maps OKLab lightness L to perceptual lightness l.
1517
+ * Exported for the OKHST tone transfers in `okhst.ts`.
1518
+ */
1519
+ /**
1520
+ * OKHSL lightness of the gamut cusp for a hue — the lightness where the
1521
+ * realizable chroma peaks. Reuses the same `find_cusp` OKHSL already runs for
1522
+ * its `s` normalization (no new color math); the OKLab cusp lightness is run
1523
+ * through the OKHSL `toe` and clamped to `[0.001, 0.999]` so divisions that
1524
+ * key off it stay safe. Cached per (rounded) hue.
1525
+ *
1526
+ * @param h Hue, 0–360.
1527
+ */
1528
+ declare function cuspLightness(h: number): number;
523
1529
  /**
524
1530
  * Convert OKHSL (h: 0–360, s: 0–1, l: 0–1) to OKLab [L, a, b].
525
1531
  */
526
- declare function okhslToOklab(h: number, s: number, l: number): [number, number, number];
1532
+ declare function okhslToOklab(h: number, s: number, l: number, pastel?: boolean): [number, number, number];
527
1533
  /**
528
1534
  * Convert OKHSL (h: 0–360, s: 0–1, l: 0–1) to linear sRGB.
529
1535
  * Channels may exceed [0, 1] near gamut boundaries — caller must clamp if needed.
530
1536
  */
531
- declare function okhslToLinearSrgb(h: number, s: number, l: number): [number, number, number];
1537
+ declare function okhslToLinearSrgb(h: number, s: number, l: number, pastel?: boolean): [number, number, number];
532
1538
  /**
533
1539
  * Compute relative luminance Y from linear sRGB channels.
534
1540
  * Per WCAG 2: Y = 0.2126·R + 0.7152·G + 0.0722·B
@@ -541,44 +1547,90 @@ declare function contrastRatioFromLuminance(yA: number, yB: number): number;
541
1547
  /**
542
1548
  * Convert OKHSL to gamma-encoded sRGB (clamped to 0–1).
543
1549
  */
544
- declare function okhslToSrgb(h: number, s: number, l: number): [number, number, number];
1550
+ declare function okhslToSrgb(h: number, s: number, l: number, pastel?: boolean): [number, number, number];
545
1551
  /**
546
1552
  * Compute WCAG 2 relative luminance from linear sRGB, matching the browser
547
1553
  * rendering pipeline: gamma-encode, clamp to sRGB gamut [0,1], then linearize.
548
1554
  * This avoids over/under-estimating luminance for out-of-gamut OKHSL colors.
549
1555
  */
550
1556
  declare function gamutClampedLuminance(linearRgb: [number, number, number]): number;
1557
+ /**
1558
+ * Convert OKLab to OKHSL.
1559
+ * Input: [L, a, b] where L: 0–1, a/b: roughly -0.5 to 0.5.
1560
+ * Returns [h, s, l] where h: 0–360, s: 0–1, l: 0–1.
1561
+ */
1562
+ declare const oklabToOkhsl: (lab: Vec3, pastel?: boolean) => Vec3;
551
1563
  /**
552
1564
  * Convert gamma-encoded sRGB (0–1 per channel) to OKHSL.
553
1565
  * Returns [h, s, l] where h: 0–360, s: 0–1, l: 0–1.
554
1566
  */
555
- declare function srgbToOkhsl(rgb: [number, number, number]): [number, number, number];
1567
+ declare function srgbToOkhsl(rgb: [number, number, number], pastel?: boolean): [number, number, number];
1568
+ /**
1569
+ * Convert CSS HSL (sRGB-based) to gamma-encoded sRGB [r, g, b] in 0–1 range.
1570
+ * h: 0–360, s: 0–1, l: 0–1.
1571
+ *
1572
+ * Note: CSS HSL is not the same as OKHSL — it's HSL in the sRGB color space.
1573
+ * Use this when parsing `hsl(...)` strings before passing to `srgbToOkhsl`.
1574
+ */
1575
+ declare function hslToSrgb(h: number, s: number, l: number): [number, number, number];
556
1576
  /**
557
1577
  * Parse a hex color string (#rgb or #rrggbb) to sRGB [r, g, b] in 0–1 range.
558
1578
  * Returns null if the string is not a valid hex color.
1579
+ *
1580
+ * For 8-digit hex (`#rrggbbaa`) and 4-digit hex (`#rgba`) with alpha,
1581
+ * use {@link parseHexAlpha}.
559
1582
  */
560
1583
  declare function parseHex(hex: string): [number, number, number] | null;
1584
+ /**
1585
+ * Parse a hex color string (#rgb, #rrggbb, #rgba, or #rrggbbaa) to
1586
+ * sRGB [r, g, b] in 0–1 range plus an optional alpha (0–1).
1587
+ * Returns null if the string is not a valid hex color.
1588
+ */
1589
+ declare function parseHexAlpha(hex: string): {
1590
+ rgb: [number, number, number];
1591
+ alpha?: number;
1592
+ } | null;
561
1593
  /**
562
1594
  * Format OKHSL values as a CSS `okhsl(H S% L%)` string.
563
1595
  * h: 0–360, s: 0–100, l: 0–100 (percentage scale for s and l).
564
1596
  */
565
- declare function formatOkhsl(h: number, s: number, l: number): string;
1597
+ declare function formatOkhsl(h: number, s: number, l: number, pastel?: boolean): string;
1598
+ /**
1599
+ * Format OKHST values as a CSS `okhst(H S% T%)` string.
1600
+ * h: 0–360, s: 0–100, t: 0–100 (percentage scale for s and t).
1601
+ *
1602
+ * Pastel recompute matches `formatOkhsl`: convert via OKLab so external
1603
+ * parsers that only understand non-pastel OKHST render identically.
1604
+ */
1605
+ declare function formatOkhst(h: number, s: number, t: number, pastel?: boolean): string;
566
1606
  /**
567
1607
  * Format OKHSL values as a CSS `rgb(R G B)` string.
568
1608
  * Uses 2 decimal places to avoid 8-bit quantization contrast loss.
569
1609
  * h: 0–360, s: 0–100, l: 0–100 (percentage scale for s and l).
570
1610
  */
571
- declare function formatRgb(h: number, s: number, l: number): string;
1611
+ declare function formatRgb(h: number, s: number, l: number, pastel?: boolean): string;
572
1612
  /**
573
1613
  * Format OKHSL values as a CSS `hsl(H S% L%)` string.
574
1614
  * h: 0–360, s: 0–100, l: 0–100 (percentage scale for s and l).
575
1615
  */
576
- declare function formatHsl(h: number, s: number, l: number): string;
1616
+ declare function formatHsl(h: number, s: number, l: number, pastel?: boolean): string;
577
1617
  /**
578
1618
  * Format OKHSL values as a CSS `oklch(L C H)` string.
579
1619
  * h: 0–360, s: 0–100, l: 0–100 (percentage scale for s and l).
580
1620
  */
581
- declare function formatOklch(h: number, s: number, l: number): string;
1621
+ declare function formatOklch(h: number, s: number, l: number, pastel?: boolean): string;
1622
+ /**
1623
+ * Convert gamma-encoded sRGB channels (0–1) to a 6-digit lowercase hex
1624
+ * string (`#rrggbb`). Channels are clamped to [0,1] and rounded to 8-bit.
1625
+ * Alpha is not encoded here — DTCG carries it as a separate `alpha` field.
1626
+ */
1627
+ declare function srgbToHex(rgb: [number, number, number]): `#${string}`;
1628
+ /**
1629
+ * Convert OKHSL (h: 0–360, s: 0–1, l: 0–1) to OKLCH components `[L, C, H]`.
1630
+ * L: 0–1, C: 0–~0.4 (chroma), H: 0–360 (hue). Shared by `formatOklch` and
1631
+ * the DTCG `oklch` colorSpace exporter so the two never drift apart.
1632
+ */
1633
+ declare function okhslToOklch(h: number, s: number, l: number, pastel?: boolean): [number, number, number];
582
1634
  //#endregion
583
- export { type AdaptationMode, type ColorDef, type ColorMap, type ContrastPreset, type FindLightnessForContrastOptions, type FindLightnessForContrastResult, type FindValueForMixContrastOptions, type FindValueForMixContrastResult, type GlazeColorFormat, type GlazeColorInput, type GlazeColorToken, type GlazeConfig, type GlazeCssOptions, type GlazeCssResult, type GlazeExtendOptions, type GlazeJsonOptions, type GlazeOutputModes, type GlazePalette, type GlazePaletteExportOptions, type GlazePaletteOptions, type GlazeShadowInput, type GlazeTheme, type GlazeThemeExport, type GlazeTokenOptions, type HCPair, type HexColor, type MinContrast, type MixColorDef, type OkhslColor, type RegularColorDef, type RelativeValue, type ResolvedColor, type ResolvedColorVariant, type ShadowColorDef, type ShadowTuning, contrastRatioFromLuminance, findLightnessForContrast, findValueForMixContrast, formatHsl, formatOkhsl, formatOklch, formatRgb, gamutClampedLuminance, glaze, okhslToLinearSrgb, okhslToOklab, okhslToSrgb, parseHex, relativeLuminanceFromLinearRgb, resolveMinContrast, srgbToOkhsl };
1635
+ export { APCA_HC_ENHANCEMENT, APCA_MAX_LC, APCA_PRESETS, type AdaptationMode, type ApcaPreset, type ChannelCtx, type ColorDef, type ColorMap, type ContrastPreset, type ContrastSpec, type DtcgColorSpace, type DtcgColorToken, type DtcgColorValue, type DtcgDocument, type DtcgOklchColorValue, type DtcgResolverModifier, type DtcgResolverRef, type DtcgResolverSet, type DtcgSrgbColorValue, type DtcgTokenTree, type ExtremeValue, type FindToneForContrastOptions, type FindToneForContrastResult, type FindValueForMixContrastOptions, type FindValueForMixContrastResult, GLAZE_EXPORT_VERSION, type GlazeColorCssOptions, type GlazeColorDtcgResolverOptions, type GlazeColorDtcgResult, type GlazeColorFormat, type GlazeColorInput, type GlazeColorInputExport, type GlazeColorOverrides, type GlazeColorOverridesExport, type GlazeColorTailwindOptions, type GlazeColorToken, type GlazeColorTokenExport, type GlazeColorValue, type GlazeConfig, type GlazeConfigOverride, type GlazeConfigResolved, type GlazeCssOptions, type GlazeCssResult, type GlazeDtcgOptions, type GlazeDtcgResolverContextNames, type GlazeDtcgResolverDocument, type GlazeDtcgResolverOptions, type GlazeDtcgResult, type GlazeExportKind, type GlazeExportVersion, type GlazeExtendOptions, type GlazeFromInput, type GlazeJsonOptions, type GlazeOutputModes, type GlazePalette, type GlazePaletteExport, type GlazePaletteExportOptions, type GlazePaletteOptions, type GlazeShadowInput, type GlazeTailwindOptions, type GlazeTheme, type GlazeThemeExport, type GlazeTokenOptions, type HCPair, type HexColor, type HueDeclaration, type HuePlan, type MinContrast, type MixColorDef, type OkhslColor, type OkhstColor, type OklchColor, type Polarity, REF_EPS, type RegularColorDef, type RelativeValue, type ResolvedColor, type ResolvedColorVariant, type ResolvedContrast, type RgbColor, type Role, type RoleInput, type ShadowColorDef, type ShadowTuning, type ToneValue, type ToneWindow, apcaContrast, assertAllPastel, assertNativeFormat, contrastRatioFromLuminance, cuspLightness, findToneForContrast, findValueForMixContrast, formatHsl, formatOkhsl, formatOkhst, formatOklch, formatRgb, fromTone, gamutClampedLuminance, glaze, hslToSrgb, inferRoleFromName, isColorTokenExport, isPaletteExport, isThemeExport, normalizeRole, okhslToLinearSrgb, okhslToOkhst, okhslToOklab, okhslToOklch, okhslToSrgb, okhstToOkhsl, oklabToOkhsl, oppositeRole, parseHex, parseHexAlpha, relativeLuminanceFromLinearRgb, resolveApcaTarget, resolveContrastForMode, resolveMinContrast, roleToPolarity, srgbToHex, srgbToOkhsl, toTone, toneFromY, variantToOkhsl, yFromTone };
584
1636
  //# sourceMappingURL=index.d.cts.map