silvery 0.17.3 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/README.md +7 -13
  2. package/dist/{UPNG-AVSMjiFE.mjs → UPNG-DvKjM6wE.mjs} +1 -1
  3. package/dist/{UPNG-AVSMjiFE.mjs.map → UPNG-DvKjM6wE.mjs.map} +1 -1
  4. package/dist/{__vite-browser-external-2447137e-D3GdsvS_.mjs → __vite-browser-external-2447137e-DPKHHqQK.mjs} +1 -1
  5. package/dist/{__vite-browser-external-2447137e-D3GdsvS_.mjs.map → __vite-browser-external-2447137e-DPKHHqQK.mjs.map} +1 -1
  6. package/dist/{animation-C_PTO0uH.mjs → animation-DhINOJk8.mjs} +1 -1
  7. package/dist/{animation-C_PTO0uH.mjs.map → animation-DhINOJk8.mjs.map} +1 -1
  8. package/dist/{ansi-CXLE_pt1.mjs → ansi-C6Qs1Wn2.mjs} +1 -1
  9. package/dist/{ansi-CXLE_pt1.mjs.map → ansi-C6Qs1Wn2.mjs.map} +1 -1
  10. package/dist/{ansi-zmNzgkPB.d.mts → ansi-CsjnZtAw.d.mts} +1 -1
  11. package/dist/{ansi-zmNzgkPB.d.mts.map → ansi-CsjnZtAw.d.mts.map} +1 -1
  12. package/dist/apng-CvSlLBtc.mjs +3 -0
  13. package/dist/{apng-ENBAJk-H.mjs → apng-DFFVOItr.mjs} +3 -3
  14. package/dist/{apng-ENBAJk-H.mjs.map → apng-DFFVOItr.mjs.map} +1 -1
  15. package/dist/{backend-CkIkIHR-.mjs → backend-DU0Y938U.mjs} +1 -1
  16. package/dist/{backend-CkIkIHR-.mjs.map → backend-DU0Y938U.mjs.map} +1 -1
  17. package/dist/{backends-CkvbG3js.mjs → backends-BihMKFY_.mjs} +3 -3
  18. package/dist/{backends-CkvbG3js.mjs.map → backends-BihMKFY_.mjs.map} +1 -1
  19. package/dist/backends-Dk_5G_gC.mjs +3 -0
  20. package/dist/cli-GwJ0S2In.mjs +4 -0
  21. package/dist/{context-QreF3UHr.mjs → context-BjWgrikx.mjs} +1 -1
  22. package/dist/{context-QreF3UHr.mjs.map → context-BjWgrikx.mjs.map} +1 -1
  23. package/dist/{derive-D7bFJdfU.d.mts → derive-O_Kb1Bk_.d.mts} +3 -3
  24. package/dist/derive-O_Kb1Bk_.d.mts.map +1 -0
  25. package/dist/{devtools-owvUPfBi.mjs → devtools-CeO9X_uv.mjs} +4 -4
  26. package/dist/{devtools-owvUPfBi.mjs.map → devtools-CeO9X_uv.mjs.map} +1 -1
  27. package/dist/devtools-nX4tj6OH.mjs +2 -0
  28. package/dist/{eta-DLiVPaSD.mjs → eta-BnQSZcWf.mjs} +1 -1
  29. package/dist/{eta-DLiVPaSD.mjs.map → eta-BnQSZcWf.mjs.map} +1 -1
  30. package/dist/{flexily-zero-adapter-DmG4Ge8t.mjs → flexily-zero-adapter-BOM0cl8R.mjs} +61 -9
  31. package/dist/flexily-zero-adapter-BOM0cl8R.mjs.map +1 -0
  32. package/dist/{flexily-zero-adapter-GHwEW11s.mjs → flexily-zero-adapter-V8R3HQtK.mjs} +1 -1
  33. package/dist/{gif-Bp6fIyN3.mjs → gif-B9Uq4qZA.mjs} +3 -3
  34. package/dist/{gif-Bp6fIyN3.mjs.map → gif-B9Uq4qZA.mjs.map} +1 -1
  35. package/dist/gif-BdrLRBmM.mjs +3 -0
  36. package/dist/{gifenc-GiVCZ9-3.mjs → gifenc-DfhOb4xr.mjs} +1 -1
  37. package/dist/{gifenc-GiVCZ9-3.mjs.map → gifenc-DfhOb4xr.mjs.map} +1 -1
  38. package/dist/{image-Dx7gYjkq.mjs → image-B0zMbVUr.mjs} +136 -5
  39. package/dist/image-B0zMbVUr.mjs.map +1 -0
  40. package/dist/index-Bh3U1K09.d.mts +10823 -0
  41. package/dist/index-Bh3U1K09.d.mts.map +1 -0
  42. package/dist/{index-p-wBs_wH.d.mts → index-C4vrhbud.d.mts} +1 -1
  43. package/dist/{index-p-wBs_wH.d.mts.map → index-C4vrhbud.d.mts.map} +1 -1
  44. package/dist/{index-DCVL3jHo.d.mts → index-dehZ18K-.d.mts} +144 -99
  45. package/dist/index-dehZ18K-.d.mts.map +1 -0
  46. package/dist/index.d.mts +7 -7219
  47. package/dist/index.d.mts.map +1 -1
  48. package/dist/index.mjs +13 -9343
  49. package/dist/index.mjs.map +1 -1
  50. package/dist/{key-mapping-BsUHe_nk.mjs → key-mapping-7k2ufK2b.mjs} +1 -1
  51. package/dist/{key-mapping-DsyfLEdC.mjs → key-mapping-WLUmxjx1.mjs} +1 -1
  52. package/dist/{key-mapping-DsyfLEdC.mjs.map → key-mapping-WLUmxjx1.mjs.map} +1 -1
  53. package/dist/{layout-engine-D_lSR4i9.mjs → layout-engine--drvrWjD.mjs} +1 -1
  54. package/dist/{layout-engine-B3dsnVLU.mjs → layout-engine-Dr3cY5U4.mjs} +3 -3
  55. package/dist/{layout-engine-B3dsnVLU.mjs.map → layout-engine-Dr3cY5U4.mjs.map} +1 -1
  56. package/dist/{multi-progress-CQVB9lES.mjs → multi-progress-CcdqJFlf.mjs} +3 -3
  57. package/dist/{multi-progress-CQVB9lES.mjs.map → multi-progress-CcdqJFlf.mjs.map} +1 -1
  58. package/dist/{multi-progress-C0-rkn86.d.mts → multi-progress-DQ-uUzLf.d.mts} +2 -2
  59. package/dist/{multi-progress-C0-rkn86.d.mts.map → multi-progress-DQ-uUzLf.d.mts.map} +1 -1
  60. package/dist/{node-Dedx-6xF.mjs → node-CP5WChgr.mjs} +1 -1
  61. package/dist/{node-Dedx-6xF.mjs.map → node-CP5WChgr.mjs.map} +1 -1
  62. package/dist/{progress-bar-COPSBlT9.mjs → progress-bar-IrUjkLfU.mjs} +4 -4
  63. package/dist/{progress-bar-COPSBlT9.mjs.map → progress-bar-IrUjkLfU.mjs.map} +1 -1
  64. package/dist/{reconciler-B-NaZvbO.mjs → reconciler-B8uxQxaU.mjs} +57 -81
  65. package/dist/reconciler-B8uxQxaU.mjs.map +1 -0
  66. package/dist/{render-string-CZKpuKXo.mjs → render-string-BwLG7rIX.mjs} +1 -1
  67. package/dist/{pipeline-BmfaZb1O.mjs → render-string-DVfgc8xr.mjs} +836 -508
  68. package/dist/render-string-DVfgc8xr.mjs.map +1 -0
  69. package/dist/{resvg-js-V6oMi8CY.mjs → resvg-js-Cwipz-_J.mjs} +1 -1
  70. package/dist/{resvg-js-V6oMi8CY.mjs.map → resvg-js-Cwipz-_J.mjs.map} +1 -1
  71. package/dist/runtime.d.mts +2 -2
  72. package/dist/runtime.mjs +3 -3
  73. package/dist/{spinner-Cgej6Vnb.d.mts → spinner-BRkaJI0N.d.mts} +2 -2
  74. package/dist/{spinner-Cgej6Vnb.d.mts.map → spinner-BRkaJI0N.d.mts.map} +1 -1
  75. package/dist/{spinner-DSByknyx.mjs → spinner-BmldKx0M.mjs} +3 -3
  76. package/dist/{spinner-DSByknyx.mjs.map → spinner-BmldKx0M.mjs.map} +1 -1
  77. package/dist/{src-C9f3hiVG.mjs → src-C0sOQW-t.mjs} +402 -156
  78. package/dist/src-C0sOQW-t.mjs.map +1 -0
  79. package/dist/src-CJPXf3fC.mjs +18348 -0
  80. package/dist/src-CJPXf3fC.mjs.map +1 -0
  81. package/dist/{src-fJVbhdn-.mjs → src-D8kLrQBT.mjs} +1 -1
  82. package/dist/{src-fJVbhdn-.mjs.map → src-D8kLrQBT.mjs.map} +1 -1
  83. package/dist/{src-9B5k0JmY.mjs → src-D_BS-as7.mjs} +1130 -100
  84. package/dist/src-D_BS-as7.mjs.map +1 -0
  85. package/dist/theme.d.mts +45 -30
  86. package/dist/theme.d.mts.map +1 -1
  87. package/dist/theme.mjs +3 -3
  88. package/dist/{types-CDgkE-Rw.d.mts → types-B4A8Ebba.d.mts} +1 -1
  89. package/dist/{types-CDgkE-Rw.d.mts.map → types-B4A8Ebba.d.mts.map} +1 -1
  90. package/dist/types-e4dpfbSa.mjs +468 -0
  91. package/dist/types-e4dpfbSa.mjs.map +1 -0
  92. package/dist/ui/animation.d.mts +1 -1
  93. package/dist/ui/animation.mjs +1 -1
  94. package/dist/ui/ansi.d.mts +1 -1
  95. package/dist/ui/ansi.mjs +1 -1
  96. package/dist/ui/cli.d.mts +3 -3
  97. package/dist/ui/cli.mjs +5 -5
  98. package/dist/ui/display.d.mts +2 -2
  99. package/dist/ui/display.mjs +1 -1
  100. package/dist/ui/display.mjs.map +1 -1
  101. package/dist/ui/image.d.mts +1 -1
  102. package/dist/ui/image.mjs +1 -1
  103. package/dist/ui/input.d.mts +3 -3
  104. package/dist/ui/input.mjs +2 -2
  105. package/dist/ui/input.mjs.map +1 -1
  106. package/dist/ui/progress.d.mts +3 -3
  107. package/dist/ui/progress.mjs +4 -4
  108. package/dist/ui/progress.mjs.map +1 -1
  109. package/dist/ui/react.d.mts +3 -3
  110. package/dist/ui/react.mjs +4 -4
  111. package/dist/ui/react.mjs.map +1 -1
  112. package/dist/ui/utils.mjs +1 -1
  113. package/dist/ui/wrappers.d.mts +2 -2
  114. package/dist/ui/wrappers.mjs +1 -1
  115. package/dist/ui.d.mts +5 -5
  116. package/dist/ui.mjs +6 -6
  117. package/dist/{useLatest-BMIYXd6e.d.mts → useLatest-6xqnGIU6.d.mts} +1 -1
  118. package/dist/{useLatest-BMIYXd6e.d.mts.map → useLatest-6xqnGIU6.d.mts.map} +1 -1
  119. package/dist/{with-text-input-CmHf_9d6.d.mts → with-text-input-lUh9gYAG.d.mts} +3 -3
  120. package/dist/{with-text-input-CmHf_9d6.d.mts.map → with-text-input-lUh9gYAG.d.mts.map} +1 -1
  121. package/dist/{wrapper-Dqh0zi2W.mjs → wrapper-CE6GQ27z.mjs} +1 -1
  122. package/dist/{wrapper-Dqh0zi2W.mjs.map → wrapper-CE6GQ27z.mjs.map} +1 -1
  123. package/dist/{wrappers-hhL8EQ_n.mjs → wrappers-JrEYTuKA.mjs} +4 -4
  124. package/dist/wrappers-JrEYTuKA.mjs.map +1 -0
  125. package/dist/yoga-adapter-B8LZpQcE.mjs +2 -0
  126. package/dist/{yoga-adapter-BJ9SOhTY.mjs → yoga-adapter-Bc8XT9cN.mjs} +11 -2
  127. package/dist/yoga-adapter-Bc8XT9cN.mjs.map +1 -0
  128. package/package.json +20 -17
  129. package/dist/apng-DCWY913R.mjs +0 -3
  130. package/dist/backends-CyJqNLeK.mjs +0 -3
  131. package/dist/cli-B-k7Bm56.mjs +0 -4
  132. package/dist/derive-D7bFJdfU.d.mts.map +0 -1
  133. package/dist/devtools-DS9NseGT.mjs +0 -2
  134. package/dist/flexily-zero-adapter-DmG4Ge8t.mjs.map +0 -1
  135. package/dist/gif-BaJNREpP.mjs +0 -3
  136. package/dist/image-Dx7gYjkq.mjs.map +0 -1
  137. package/dist/index-CBcSpGSM.d.mts +0 -3416
  138. package/dist/index-CBcSpGSM.d.mts.map +0 -1
  139. package/dist/index-DCVL3jHo.d.mts.map +0 -1
  140. package/dist/pipeline-BmfaZb1O.mjs.map +0 -1
  141. package/dist/reconciler-B-NaZvbO.mjs.map +0 -1
  142. package/dist/render-string-Bvh1XzBv.mjs +0 -201
  143. package/dist/render-string-Bvh1XzBv.mjs.map +0 -1
  144. package/dist/runtime-PH2xY1DM.mjs +0 -8723
  145. package/dist/runtime-PH2xY1DM.mjs.map +0 -1
  146. package/dist/src-9B5k0JmY.mjs.map +0 -1
  147. package/dist/src-C9f3hiVG.mjs.map +0 -1
  148. package/dist/types-Bhj5QkIQ.mjs +0 -13
  149. package/dist/types-Bhj5QkIQ.mjs.map +0 -1
  150. package/dist/useLayout-BG2cGl15.mjs +0 -139
  151. package/dist/useLayout-BG2cGl15.mjs.map +0 -1
  152. package/dist/wrappers-hhL8EQ_n.mjs.map +0 -1
  153. package/dist/yoga-adapter-BJ9SOhTY.mjs.map +0 -1
  154. package/dist/yoga-adapter-Daq6-dw1.mjs +0 -2
@@ -486,6 +486,169 @@ var init_terminal_control = __esmMin((() => {
486
486
  `${ESC$3}`;
487
487
  }));
488
488
  //#endregion
489
+ //#region packages/color/src/oklch.ts
490
+ function parseHex(hex) {
491
+ if (hex[0] !== "#") return null;
492
+ const h = hex.slice(1);
493
+ if (h.length === 3) {
494
+ const r = parseInt(h[0] + h[0], 16);
495
+ const g = parseInt(h[1] + h[1], 16);
496
+ const b = parseInt(h[2] + h[2], 16);
497
+ if (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) return null;
498
+ return [
499
+ r,
500
+ g,
501
+ b
502
+ ];
503
+ }
504
+ if (h.length === 6) {
505
+ const r = parseInt(h.slice(0, 2), 16);
506
+ const g = parseInt(h.slice(2, 4), 16);
507
+ const b = parseInt(h.slice(4, 6), 16);
508
+ if (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) return null;
509
+ return [
510
+ r,
511
+ g,
512
+ b
513
+ ];
514
+ }
515
+ return null;
516
+ }
517
+ /** sRGB channel (0–255) → linear RGB (0–1). Inverse gamma. */
518
+ function srgbToLinear(c) {
519
+ const s = c / 255;
520
+ return s <= .04045 ? s / 12.92 : ((s + .055) / 1.055) ** 2.4;
521
+ }
522
+ /** Linear RGB (0–1) → sRGB channel (0–255). Forward gamma. */
523
+ function linearToSrgb(c) {
524
+ const clamped = Math.max(0, Math.min(1, c));
525
+ return clamped <= .0031308 ? 12.92 * clamped * 255 : (1.055 * clamped ** (1 / 2.4) - .055) * 255;
526
+ }
527
+ /** Linear RGB → OKLab (Ottosson 2020 matrix). */
528
+ function linearRgbToOklab(r, g, b) {
529
+ const l = .4122214708 * r + .5363325363 * g + .0514459929 * b;
530
+ const m = .2119034982 * r + .6806995451 * g + .1073969566 * b;
531
+ const s = .0883024619 * r + .2817188376 * g + .6299787005 * b;
532
+ const lCbrt = Math.cbrt(l);
533
+ const mCbrt = Math.cbrt(m);
534
+ const sCbrt = Math.cbrt(s);
535
+ return [
536
+ .2104542553 * lCbrt + .793617785 * mCbrt - .0040720468 * sCbrt,
537
+ 1.9779984951 * lCbrt - 2.428592205 * mCbrt + .4505937099 * sCbrt,
538
+ .0259040371 * lCbrt + .7827717662 * mCbrt - .808675766 * sCbrt
539
+ ];
540
+ }
541
+ /** OKLab → linear RGB (inverse of the above). */
542
+ function oklabToLinearRgb(L, a, bb) {
543
+ const lCbrt = L + .3963377774 * a + .2158037573 * bb;
544
+ const mCbrt = L - .1055613458 * a - .0638541728 * bb;
545
+ const sCbrt = L - .0894841775 * a - 1.291485548 * bb;
546
+ const l = lCbrt ** 3;
547
+ const m = mCbrt ** 3;
548
+ const s = sCbrt ** 3;
549
+ return [
550
+ 4.0767416621 * l - 3.3077115913 * m + .2309699292 * s,
551
+ -1.2684380046 * l + 2.6097574011 * m - .3413193965 * s,
552
+ -.0041960863 * l - .7034186147 * m + 1.707614701 * s
553
+ ];
554
+ }
555
+ /** Hex (`#RRGGBB`) → OKLCH. Returns `null` for invalid hex. */
556
+ function hexToOklch(hex) {
557
+ const rgb = parseHex(hex);
558
+ if (!rgb) return null;
559
+ const [r, g, b] = rgb;
560
+ const [lr, lg, lb] = [
561
+ srgbToLinear(r),
562
+ srgbToLinear(g),
563
+ srgbToLinear(b)
564
+ ];
565
+ const [L, a, bb] = linearRgbToOklab(lr, lg, lb);
566
+ const C = Math.sqrt(a * a + bb * bb);
567
+ let H = Math.atan2(bb, a) * 180 / Math.PI;
568
+ if (H < 0) H += 360;
569
+ return {
570
+ L,
571
+ C,
572
+ H
573
+ };
574
+ }
575
+ /** Check whether linear RGB is inside sRGB gamut (each channel in [0, 1]). */
576
+ function inGamut(r, g, b) {
577
+ const e = 1e-5;
578
+ return r >= -e && r <= 1 + e && g >= -e && g <= 1 + e && b >= -e && b <= 1 + e;
579
+ }
580
+ /**
581
+ * OKLCH → hex. Gamut-maps out-of-sRGB colors by reducing chroma until in-gamut
582
+ * (preserves L and H — the perceptual anchors). This is the CSS Color 4
583
+ * recommended approach for rendering OKLCH on sRGB displays.
584
+ */
585
+ function oklchToHex(c) {
586
+ const L = Math.max(0, Math.min(1, c.L));
587
+ const Crad = (c.H % 360 + 360) % 360 * Math.PI / 180;
588
+ let lo = 0;
589
+ let hi = Math.max(0, c.C);
590
+ let [rHi, gHi, bHi] = oklabToLinearRgb(L, hi * Math.cos(Crad), hi * Math.sin(Crad));
591
+ if (inGamut(rHi, gHi, bHi)) return rgbToHexInternal(linearToSrgb(rHi), linearToSrgb(gHi), linearToSrgb(bHi));
592
+ for (let i = 0; i < 20; i++) {
593
+ const mid = (lo + hi) / 2;
594
+ const [rr, gg, bbLin] = oklabToLinearRgb(L, mid * Math.cos(Crad), mid * Math.sin(Crad));
595
+ if (inGamut(rr, gg, bbLin)) lo = mid;
596
+ else hi = mid;
597
+ }
598
+ const a = lo * Math.cos(Crad);
599
+ const bb = lo * Math.sin(Crad);
600
+ [rHi, gHi, bHi] = oklabToLinearRgb(L, a, bb);
601
+ return rgbToHexInternal(linearToSrgb(rHi), linearToSrgb(gHi), linearToSrgb(bHi));
602
+ }
603
+ function rgbToHexInternal(r, g, b) {
604
+ const clamp = (n) => Math.max(0, Math.min(255, Math.round(n)));
605
+ return `#${clamp(r).toString(16).padStart(2, "0")}${clamp(g).toString(16).padStart(2, "0")}${clamp(b).toString(16).padStart(2, "0")}`.toUpperCase();
606
+ }
607
+ /**
608
+ * Linear interpolate in OKLab (rectangular — a, b, L interpolated directly).
609
+ *
610
+ * CSS Color Module 4's default interpolation space. Avoids the hue-arc
611
+ * weirdness of `lerpOklch` when one endpoint is near-neutral (its H is
612
+ * effectively undefined). Produces the expected "tinted surface" when blending
613
+ * `bg` with an accent color.
614
+ */
615
+ function lerpOklabHex(aHex, bHex, t) {
616
+ const aOk = hexToOklch(aHex);
617
+ const bOk = hexToOklch(bHex);
618
+ if (!aOk || !bOk) return null;
619
+ const aRad = aOk.H * Math.PI / 180;
620
+ const bRad = bOk.H * Math.PI / 180;
621
+ const aA = aOk.C * Math.cos(aRad);
622
+ const aB = aOk.C * Math.sin(aRad);
623
+ const bA = bOk.C * Math.cos(bRad);
624
+ const bB = bOk.C * Math.sin(bRad);
625
+ const L = aOk.L + (bOk.L - aOk.L) * t;
626
+ const A = aA + (bA - aA) * t;
627
+ const B = aB + (bB - aB) * t;
628
+ const C = Math.sqrt(A * A + B * B);
629
+ let H = Math.atan2(B, A) * 180 / Math.PI;
630
+ if (H < 0) H += 360;
631
+ return oklchToHex({
632
+ L,
633
+ C,
634
+ H
635
+ });
636
+ }
637
+ /**
638
+ * ΔE in OKLCH (≈ ΔE₀₀ quality in practice — OKLCH was designed to make Euclidean
639
+ * distance perceptually meaningful). Hue is weighted by chroma so near-neutral
640
+ * colors don't produce spurious large ΔH contributions.
641
+ */
642
+ function deltaE(a, b) {
643
+ const dL = a.L - b.L;
644
+ const dC = a.C - b.C;
645
+ const dh = ((a.H - b.H + 540) % 360 - 180) * (Math.PI / 180);
646
+ (a.C + b.C) / 2;
647
+ const dH = 2 * Math.sqrt(a.C * b.C) * Math.sin(dh / 2);
648
+ return Math.sqrt(dL * dL + dC * dC + dH * dH);
649
+ }
650
+ var init_oklch = __esmMin((() => {}));
651
+ //#endregion
489
652
  //#region packages/color/src/color.ts
490
653
  /** Parse #rrggbb or #rgb to [r, g, b]. Returns null for invalid input. */
491
654
  function hexToRgb(hex) {
@@ -509,33 +672,90 @@ function rgbToHex(r, g, b) {
509
672
  return `#${clamp(r).toString(16).padStart(2, "0")}${clamp(g).toString(16).padStart(2, "0")}${clamp(b).toString(16).padStart(2, "0")}`.toUpperCase();
510
673
  }
511
674
  /**
512
- * Blend two hex colors. t=0 returns a, t=1 returns b.
675
+ * Blend two hex colors in OKLab space. t=0 returns a, t=1 returns b.
676
+ * Perceptually-uniform midpoints (unlike naive RGB blending which produces
677
+ * muddy halfway colors).
678
+ *
679
+ * Interpolation is done in OKLab (rectangular a/b), not OKLCH (polar). This
680
+ * matches CSS Color Module 4's default interpolation space and avoids hue-arc
681
+ * weirdness when one endpoint is near-neutral (its hue is effectively
682
+ * undefined). For explicit hue-rotation blending, use `lerpOklch` directly.
683
+ *
513
684
  * For non-hex inputs (ANSI names), returns `a` unchanged.
514
685
  */
515
686
  function blend(a, b, t) {
516
- const rgbA = hexToRgb(a);
517
- const rgbB = hexToRgb(b);
518
- if (!rgbA || !rgbB) return a;
519
- return rgbToHex(rgbA[0] + (rgbB[0] - rgbA[0]) * t, rgbA[1] + (rgbB[1] - rgbA[1]) * t, rgbA[2] + (rgbB[2] - rgbA[2]) * t);
687
+ return lerpOklabHex(a, b, t) ?? a;
520
688
  }
521
689
  /**
522
- * Brighten a hex color. amount=0.1 adds 10% lightness toward white.
523
- * For non-hex inputs (ANSI names), returns the color unchanged.
690
+ * Brighten a hex color by raising OKLCH lightness. amount=0.1 adds 0.1 to L
691
+ * (perceptually linear 10% brighter looks 10% brighter regardless of hue).
692
+ *
693
+ * For non-hex inputs, returns the color unchanged.
524
694
  */
525
695
  function brighten(color, amount) {
526
- return blend(color, "#FFFFFF", amount);
696
+ const o = hexToOklch(color);
697
+ if (!o) return color;
698
+ return oklchToHex({
699
+ L: Math.min(1, o.L + amount),
700
+ C: o.C,
701
+ H: o.H
702
+ });
527
703
  }
528
704
  /**
529
- * Darken a hex color. amount=0.1 adds 10% darkness toward black.
530
- * For non-hex inputs (ANSI names), returns the color unchanged.
705
+ * Darken a hex color by lowering OKLCH lightness. amount=0.1 subtracts 0.1 from L.
706
+ *
707
+ * For non-hex inputs, returns the color unchanged.
531
708
  */
532
709
  function darken(color, amount) {
533
- return blend(color, "#000000", amount);
710
+ const o = hexToOklch(color);
711
+ if (!o) return color;
712
+ return oklchToHex({
713
+ L: Math.max(0, o.L - amount),
714
+ C: o.C,
715
+ H: o.H
716
+ });
717
+ }
718
+ /**
719
+ * Desaturate a hex color by lowering OKLCH chroma. amount=0.4 reduces C by 40%
720
+ * (relative — consistent with the original HSL-based contract). For a flat
721
+ * subtraction, use `saturate(color, -amount)`.
722
+ *
723
+ * For non-hex inputs, returns the color unchanged.
724
+ */
725
+ function desaturate(color, amount) {
726
+ const o = hexToOklch(color);
727
+ if (!o) return color;
728
+ return oklchToHex({
729
+ L: o.L,
730
+ C: Math.max(0, o.C * (1 - amount)),
731
+ H: o.H
732
+ });
733
+ }
734
+ /**
735
+ * Get the complementary color (180° hue rotation) in OKLCH. Preserves L + C,
736
+ * so the complement has the same perceived brightness and colorfulness.
737
+ *
738
+ * For non-hex inputs, returns the color unchanged.
739
+ */
740
+ function complement(color) {
741
+ const o = hexToOklch(color);
742
+ if (!o) return color;
743
+ return oklchToHex({
744
+ L: o.L,
745
+ C: o.C,
746
+ H: (o.H + 180) % 360
747
+ });
748
+ }
749
+ /** Perceptual color distance (ΔE) between two hex colors, in OKLCH. */
750
+ function colorDistance(a, b) {
751
+ const oa = hexToOklch(a);
752
+ const ob = hexToOklch(b);
753
+ if (!oa || !ob) return null;
754
+ return deltaE(oa, ob);
534
755
  }
535
756
  /**
536
- * Linearize an sRGB channel value (0-255) for luminance calculation.
537
- * Per WCAG 2.1: values below the threshold use a linear scale,
538
- * above use the gamma-corrected formula.
757
+ * Linearize an sRGB channel value (0-255) for WCAG 2.1 luminance.
758
+ * Kept for WCAG contrast checking OKLCH uses its own linearization.
539
759
  */
540
760
  function channelLuminance(c) {
541
761
  const s = c / 255;
@@ -552,7 +772,7 @@ function relativeLuminance(hex) {
552
772
  }
553
773
  /**
554
774
  * Pick black or white text for readability on the given background.
555
- * Uses relative luminance (WCAG formula).
775
+ * Uses WCAG 2.1 relative luminance.
556
776
  */
557
777
  function contrastFg(bg) {
558
778
  const luminance = relativeLuminance(bg);
@@ -596,28 +816,9 @@ function hexToHsl(hex) {
596
816
  if (!rgb) return null;
597
817
  return rgbToHsl(rgb[0], rgb[1], rgb[2]);
598
818
  }
599
- /**
600
- * Desaturate a hex color by reducing saturation.
601
- * amount=0.4 reduces saturation by 40%.
602
- * For non-hex inputs, returns the color unchanged.
603
- */
604
- function desaturate(color, amount) {
605
- const hsl = hexToHsl(color);
606
- if (!hsl) return color;
607
- const [h, s, l] = hsl;
608
- return hslToHex(h, s * (1 - amount), l);
609
- }
610
- /**
611
- * Get the complementary color (180° hue rotation).
612
- * For non-hex inputs, returns the color unchanged.
613
- */
614
- function complement(color) {
615
- const hsl = hexToHsl(color);
616
- if (!hsl) return color;
617
- const [h, s, l] = hsl;
618
- return hslToHex(h + 180, s, l);
619
- }
620
- var init_color = __esmMin((() => {}));
819
+ var init_color = __esmMin((() => {
820
+ init_oklch();
821
+ }));
621
822
  //#endregion
622
823
  //#region packages/color/src/contrast.ts
623
824
  /**
@@ -653,24 +854,24 @@ function checkContrast(fg, bg) {
653
854
  };
654
855
  }
655
856
  /**
656
- * Adjust a color's lightness until it meets a minimum contrast ratio
657
- * against a reference color. Preserves hue and saturation — only
658
- * lightness is shifted, and only as much as needed.
857
+ * Adjust a color's OKLCH lightness until it meets a minimum WCAG contrast ratio
858
+ * against a reference color. Preserves hue and chroma — only lightness shifts,
859
+ * and only as much as needed.
659
860
  *
660
861
  * Returns the original color unchanged if it already meets the target.
661
862
  *
863
+ * For impossible targets (e.g. 21:1 against mid-gray), returns the
864
+ * best achievable color (near-black or near-white in the same hue).
865
+ *
662
866
  * @param color - The color to adjust (hex)
663
867
  * @param against - The reference background color (hex)
664
868
  * @param minRatio - Minimum contrast ratio to achieve (e.g. 4.5 for AA)
665
869
  * @returns Adjusted hex color meeting the target, or original if already OK
666
870
  *
667
- * For impossible targets (e.g. 21:1 against mid-gray), returns the
668
- * best achievable color (near-black or near-white in the same hue).
669
- *
670
871
  * @example
671
872
  * ```typescript
672
- * // Yellow on white — too low contrast, gets darkened
673
- * ensureContrast("#FFAB91", "#FFFFFF", 4.5) // → "#B35600" (darker orange)
873
+ * // Yellow on white — too low contrast, gets darkened (perceptually; same hue preserved)
874
+ * ensureContrast("#FFAB91", "#FFFFFF", 4.5)
674
875
  *
675
876
  * // Blue on dark bg — already fine, returned unchanged
676
877
  * ensureContrast("#5C9FFF", "#1A1A2E", 4.5) // → "#5C9FFF"
@@ -680,36 +881,45 @@ function ensureContrast(color, against, minRatio) {
680
881
  const current = checkContrast(color, against);
681
882
  if (!current) return color;
682
883
  if (current.ratio >= minRatio) return color;
683
- const hsl = hexToHsl(color);
684
- if (!hsl) return color;
685
- const [h, s] = hsl;
884
+ const o = hexToOklch(color);
885
+ if (!o) return color;
686
886
  const lightBg = contrastFg(against) === "#000000";
687
887
  let lo, hi;
688
888
  if (lightBg) {
689
889
  lo = 0;
690
- hi = hsl[2];
890
+ hi = o.L;
691
891
  } else {
692
- lo = hsl[2];
892
+ lo = o.L;
693
893
  hi = 1;
694
894
  }
695
- for (let i = 0; i < 20; i++) {
895
+ for (let i = 0; i < 24; i++) {
696
896
  const mid = (lo + hi) / 2;
697
- const r = checkContrast(hslToHex(h, s, mid), against);
897
+ const r = checkContrast(oklchToHex({
898
+ L: mid,
899
+ C: o.C,
900
+ H: o.H
901
+ }), against);
698
902
  if (!r) break;
699
903
  if (lightBg) if (r.ratio >= minRatio) lo = mid;
700
904
  else hi = mid;
701
905
  else if (r.ratio >= minRatio) hi = mid;
702
906
  else lo = mid;
703
907
  }
704
- return hslToHex(h, s, lightBg ? lo : hi);
908
+ return oklchToHex({
909
+ L: lightBg ? lo : hi,
910
+ C: o.C,
911
+ H: o.H
912
+ });
705
913
  }
706
914
  var init_contrast = __esmMin((() => {
915
+ init_oklch();
707
916
  init_color();
708
917
  }));
709
918
  //#endregion
710
919
  //#region packages/color/src/index.ts
711
920
  var init_src$1 = __esmMin((() => {
712
921
  init_color();
922
+ init_oklch();
713
923
  init_contrast();
714
924
  }));
715
925
  //#endregion
@@ -757,8 +967,15 @@ function resolveToken(name, theme) {
757
967
  const idx = parseInt(token.slice(5), 10);
758
968
  if (idx >= 0 && idx < 16 && theme.palette && idx < theme.palette.length) return theme.palette[idx];
759
969
  }
760
- const val = theme[token.replace(/-/g, "")];
761
- return typeof val === "string" ? val : void 0;
970
+ const key = token.replace(/-/g, "");
971
+ const themeObj = theme;
972
+ const direct = themeObj[key];
973
+ if (typeof direct === "string") return direct;
974
+ const aliased = PRIMER_ALIASES[key];
975
+ if (aliased) {
976
+ const val = themeObj[aliased];
977
+ if (typeof val === "string") return val;
978
+ }
762
979
  }
763
980
  /** Convert chalk numeric level (0-3) to ColorLevel. */
764
981
  function fromChalkLevel(n) {
@@ -971,10 +1188,44 @@ function createChainWithRef(state, ref) {
971
1188
  proxyRef.proxy = proxy;
972
1189
  return proxy;
973
1190
  }
974
- var ESC$2, KNOWN_METHODS, THEME_TOKENS;
1191
+ var PRIMER_ALIASES, ESC$2, KNOWN_METHODS, THEME_TOKENS;
975
1192
  var init_style = __esmMin((() => {
976
1193
  init_detection();
977
1194
  init_colors();
1195
+ PRIMER_ALIASES = {
1196
+ fgmuted: "muted",
1197
+ fgdisabled: "disabledfg",
1198
+ fgcursor: "cursor",
1199
+ fgselected: "selection",
1200
+ fginverse: "inverse",
1201
+ fgonsurface: "surface",
1202
+ fgonpopover: "popover",
1203
+ fgonprimary: "primaryfg",
1204
+ fgonsecondary: "secondaryfg",
1205
+ fgonaccent: "accentfg",
1206
+ fgonerror: "errorfg",
1207
+ fgonwarning: "warningfg",
1208
+ fgonsuccess: "successfg",
1209
+ fgoninfo: "infofg",
1210
+ bgmuted: "mutedbg",
1211
+ bgsurface: "surfacebg",
1212
+ bgpopover: "popoverbg",
1213
+ bginverse: "inversebg",
1214
+ bgselected: "selectionbg",
1215
+ bgcursor: "cursorbg",
1216
+ borderfocus: "focusborder",
1217
+ borderinput: "inputborder",
1218
+ brandhover: "brandHover",
1219
+ brandactive: "brandActive",
1220
+ brandred: "brandRed",
1221
+ brandorange: "brandOrange",
1222
+ brandyellow: "brandYellow",
1223
+ brandgreen: "brandGreen",
1224
+ brandteal: "brandTeal",
1225
+ brandblue: "brandBlue",
1226
+ brandpurple: "brandPurple",
1227
+ brandpink: "brandPink"
1228
+ };
978
1229
  ESC$2 = "\x1B[";
979
1230
  KNOWN_METHODS = new Set([
980
1231
  "hex",
@@ -1074,11 +1325,302 @@ var init_mixed_proxy = __esmMin((() => {
1074
1325
  ]);
1075
1326
  }));
1076
1327
  //#endregion
1328
+ //#region packages/ansi/src/theme/invariants.ts
1329
+ function lightness(hex) {
1330
+ const o = hexToOklch(hex);
1331
+ return o ? o.L : null;
1332
+ }
1333
+ /**
1334
+ * Validate post-derivation invariants on a Theme.
1335
+ *
1336
+ * Default: visibility checks only (selection ΔL, cursor ΔE). These are
1337
+ * invariants that `deriveTheme` doesn't enforce and that matter for every
1338
+ * theme regardless of authoring pedigree.
1339
+ *
1340
+ * Opt into WCAG contrast checks via `{ wcag: true }`. Use at build-time to
1341
+ * verify bundled themes, or when loading hand-authored Theme objects that
1342
+ * didn't flow through `deriveTheme`'s `ensureContrast` pass.
1343
+ *
1344
+ * Non-hex values (ANSI names from `ansi16` mode) are skipped with no
1345
+ * violation — ANSI 16 themes can't be contrast-checked in hex space.
1346
+ *
1347
+ * @example
1348
+ * ```ts
1349
+ * // Default — visibility only, fast
1350
+ * const { ok, violations } = validateThemeInvariants(theme)
1351
+ *
1352
+ * // Build-time audit — full WCAG check
1353
+ * const audit = validateThemeInvariants(theme, { wcag: true })
1354
+ * ```
1355
+ */
1356
+ function validateThemeInvariants(theme, opts = {}) {
1357
+ const checkWcag = opts.wcag ?? false;
1358
+ const checkVisibility = opts.visibility ?? true;
1359
+ const violations = [];
1360
+ if (checkWcag) for (const pair of CONTRAST_PAIRS) {
1361
+ const fg = theme[pair.fg];
1362
+ const bg = theme[pair.bg];
1363
+ if (typeof fg !== "string" || typeof bg !== "string") continue;
1364
+ const r = checkContrast(fg, bg);
1365
+ if (r === null) continue;
1366
+ if (r.ratio < pair.min) violations.push({
1367
+ rule: pair.rule,
1368
+ tokens: [String(pair.fg), String(pair.bg)],
1369
+ actual: r.ratio,
1370
+ required: pair.min,
1371
+ message: `${pair.fg} (${fg}) on ${pair.bg} (${bg}) is ${r.ratio.toFixed(2)}:1, needs ${pair.min.toFixed(1)}:1`
1372
+ });
1373
+ }
1374
+ if (checkVisibility) {
1375
+ const lBg = lightness(theme.bg);
1376
+ const lSelBg = lightness(theme.selectionbg);
1377
+ if (lBg !== null && lSelBg !== null) {
1378
+ const dL = Math.abs(lSelBg - lBg);
1379
+ if (dL < .08) violations.push({
1380
+ rule: "visibility:selection",
1381
+ tokens: ["selectionbg", "bg"],
1382
+ actual: dL,
1383
+ required: SELECTION_DELTA_L,
1384
+ message: `selectionbg (${theme.selectionbg}) differs from bg (${theme.bg}) by ΔL=${dL.toFixed(3)}, needs ≥ ${SELECTION_DELTA_L.toFixed(2)}`
1385
+ });
1386
+ }
1387
+ const oBg = hexToOklch(theme.bg);
1388
+ const oCursorBg = hexToOklch(theme.cursorbg);
1389
+ if (oBg && oCursorBg) {
1390
+ const de = deltaE(oBg, oCursorBg);
1391
+ if (de < .15) violations.push({
1392
+ rule: "visibility:cursor",
1393
+ tokens: ["cursorbg", "bg"],
1394
+ actual: de,
1395
+ required: CURSOR_DELTA_E,
1396
+ message: `cursorbg (${theme.cursorbg}) differs from bg (${theme.bg}) by ΔE=${de.toFixed(3)}, needs ≥ ${CURSOR_DELTA_E.toFixed(2)}`
1397
+ });
1398
+ }
1399
+ }
1400
+ return {
1401
+ ok: violations.length === 0,
1402
+ violations
1403
+ };
1404
+ }
1405
+ /**
1406
+ * Format violations as a multiline error message for throws/logs.
1407
+ */
1408
+ function formatViolations(violations) {
1409
+ if (violations.length === 0) return "";
1410
+ return violations.map((v) => ` - [${v.rule}] ${v.message}`).join("\n");
1411
+ }
1412
+ var AA_RATIO, FAINT_RATIO, SELECTION_DELTA_L, CURSOR_DELTA_E, CONTRAST_PAIRS, ThemeInvariantError;
1413
+ var init_invariants = __esmMin((() => {
1414
+ init_src$1();
1415
+ AA_RATIO = 4.5;
1416
+ FAINT_RATIO = 1.5;
1417
+ SELECTION_DELTA_L = .08;
1418
+ CURSOR_DELTA_E = .15;
1419
+ CONTRAST_PAIRS = [
1420
+ {
1421
+ rule: "contrast:fg/bg",
1422
+ fg: "fg",
1423
+ bg: "bg",
1424
+ min: AA_RATIO
1425
+ },
1426
+ {
1427
+ rule: "contrast:fg/surfacebg",
1428
+ fg: "fg",
1429
+ bg: "surfacebg",
1430
+ min: AA_RATIO
1431
+ },
1432
+ {
1433
+ rule: "contrast:fg/popoverbg",
1434
+ fg: "fg",
1435
+ bg: "popoverbg",
1436
+ min: AA_RATIO
1437
+ },
1438
+ {
1439
+ rule: "contrast:muted/mutedbg",
1440
+ fg: "muted",
1441
+ bg: "mutedbg",
1442
+ min: 3
1443
+ },
1444
+ {
1445
+ rule: "contrast:primary/bg",
1446
+ fg: "primary",
1447
+ bg: "bg",
1448
+ min: AA_RATIO
1449
+ },
1450
+ {
1451
+ rule: "contrast:secondary/bg",
1452
+ fg: "secondary",
1453
+ bg: "bg",
1454
+ min: AA_RATIO
1455
+ },
1456
+ {
1457
+ rule: "contrast:accent/bg",
1458
+ fg: "accent",
1459
+ bg: "bg",
1460
+ min: AA_RATIO
1461
+ },
1462
+ {
1463
+ rule: "contrast:error/bg",
1464
+ fg: "error",
1465
+ bg: "bg",
1466
+ min: AA_RATIO
1467
+ },
1468
+ {
1469
+ rule: "contrast:warning/bg",
1470
+ fg: "warning",
1471
+ bg: "bg",
1472
+ min: AA_RATIO
1473
+ },
1474
+ {
1475
+ rule: "contrast:success/bg",
1476
+ fg: "success",
1477
+ bg: "bg",
1478
+ min: AA_RATIO
1479
+ },
1480
+ {
1481
+ rule: "contrast:info/bg",
1482
+ fg: "info",
1483
+ bg: "bg",
1484
+ min: AA_RATIO
1485
+ },
1486
+ {
1487
+ rule: "contrast:link/bg",
1488
+ fg: "link",
1489
+ bg: "bg",
1490
+ min: AA_RATIO
1491
+ },
1492
+ {
1493
+ rule: "contrast:inverse/inversebg",
1494
+ fg: "inverse",
1495
+ bg: "inversebg",
1496
+ min: AA_RATIO
1497
+ },
1498
+ {
1499
+ rule: "contrast:selection/selectionbg",
1500
+ fg: "selection",
1501
+ bg: "selectionbg",
1502
+ min: AA_RATIO
1503
+ },
1504
+ {
1505
+ rule: "contrast:cursor/cursorbg",
1506
+ fg: "cursor",
1507
+ bg: "cursorbg",
1508
+ min: AA_RATIO
1509
+ },
1510
+ {
1511
+ rule: "contrast:primaryfg/primary",
1512
+ fg: "primaryfg",
1513
+ bg: "primary",
1514
+ min: AA_RATIO
1515
+ },
1516
+ {
1517
+ rule: "contrast:secondaryfg/secondary",
1518
+ fg: "secondaryfg",
1519
+ bg: "secondary",
1520
+ min: AA_RATIO
1521
+ },
1522
+ {
1523
+ rule: "contrast:accentfg/accent",
1524
+ fg: "accentfg",
1525
+ bg: "accent",
1526
+ min: AA_RATIO
1527
+ },
1528
+ {
1529
+ rule: "contrast:errorfg/error",
1530
+ fg: "errorfg",
1531
+ bg: "error",
1532
+ min: AA_RATIO
1533
+ },
1534
+ {
1535
+ rule: "contrast:warningfg/warning",
1536
+ fg: "warningfg",
1537
+ bg: "warning",
1538
+ min: AA_RATIO
1539
+ },
1540
+ {
1541
+ rule: "contrast:successfg/success",
1542
+ fg: "successfg",
1543
+ bg: "success",
1544
+ min: AA_RATIO
1545
+ },
1546
+ {
1547
+ rule: "contrast:infofg/info",
1548
+ fg: "infofg",
1549
+ bg: "info",
1550
+ min: AA_RATIO
1551
+ },
1552
+ {
1553
+ rule: "contrast:inputborder/bg",
1554
+ fg: "inputborder",
1555
+ bg: "bg",
1556
+ min: 3
1557
+ },
1558
+ {
1559
+ rule: "contrast:focusborder/bg",
1560
+ fg: "focusborder",
1561
+ bg: "bg",
1562
+ min: 3
1563
+ },
1564
+ {
1565
+ rule: "contrast:disabledfg/bg",
1566
+ fg: "disabledfg",
1567
+ bg: "bg",
1568
+ min: 3
1569
+ },
1570
+ {
1571
+ rule: "contrast:border/bg",
1572
+ fg: "border",
1573
+ bg: "bg",
1574
+ min: FAINT_RATIO
1575
+ }
1576
+ ];
1577
+ ThemeInvariantError = class extends Error {
1578
+ violations;
1579
+ constructor(violations) {
1580
+ super(`Theme invariants failed (${violations.length} violation${violations.length === 1 ? "" : "s"}):\n${formatViolations(violations)}`);
1581
+ this.name = "ThemeInvariantError";
1582
+ this.violations = violations;
1583
+ }
1584
+ };
1585
+ }));
1586
+ //#endregion
1077
1587
  //#region packages/ansi/src/theme/derive.ts
1078
1588
  function deriveTheme(palette, mode = "truecolor", adjustments) {
1079
1589
  if (mode === "ansi16") return deriveAnsi16Theme(palette);
1080
1590
  return deriveTruecolorTheme(palette, adjustments);
1081
1591
  }
1592
+ /**
1593
+ * Load and validate a theme from a ColorScheme.
1594
+ *
1595
+ * Combines `deriveTheme()` (auto-adjust via ensureContrast with project-tuned
1596
+ * thresholds) with `validateThemeInvariants()` (post-derivation visibility +
1597
+ * optional WCAG).
1598
+ *
1599
+ * We don't re-impose WCAG on top of derive's tweaked thresholds — default
1600
+ * validation checks visibility invariants only (selection/cursor vs bg) that
1601
+ * derive doesn't handle.
1602
+ *
1603
+ * @example
1604
+ * ```ts
1605
+ * // Default: lenient + visibility-only (derive already handled contrast)
1606
+ * const theme = loadTheme(myScheme)
1607
+ *
1608
+ * // Build-time audit: strict + full WCAG
1609
+ * const theme = loadTheme(myScheme, { enforce: "strict", wcag: true })
1610
+ * ```
1611
+ */
1612
+ function loadTheme(palette, opts = {}) {
1613
+ const mode = opts.mode ?? "truecolor";
1614
+ const enforce = opts.enforce ?? "lenient";
1615
+ const theme = deriveTheme(palette, mode, opts.adjustments);
1616
+ if (enforce === "off") return theme;
1617
+ const { ok, violations } = validateThemeInvariants(theme, { wcag: opts.wcag });
1618
+ if (!ok) {
1619
+ if (enforce === "strict") throw new ThemeInvariantError(violations);
1620
+ if (opts.violations) opts.violations.push(...violations);
1621
+ }
1622
+ return theme;
1623
+ }
1082
1624
  function deriveTruecolorTheme(p, adjustments) {
1083
1625
  const dark = p.dark ?? true;
1084
1626
  const bg = p.background;
@@ -1110,13 +1652,26 @@ function deriveTruecolorTheme(p, adjustments) {
1110
1652
  const success = ensure("success", p.green, bg, AA);
1111
1653
  const info = ensure("info", blend(fg, accent, .5), bg, AA);
1112
1654
  const link = ensure("link", dark ? p.brightBlue : p.blue, bg, AA);
1655
+ const brand = primary;
1656
+ const brandHover = dark ? brighten(primary, .04) : darken(primary, .04);
1657
+ const brandActive = dark ? brighten(primary, .08) : darken(primary, .08);
1658
+ const red = ensure("red", p.red, bg, AA);
1659
+ const orange = ensure("orange", blend(p.red, p.yellow, .5), bg, AA);
1660
+ const yellow = ensure("yellow", p.yellow, bg, AA);
1661
+ const green = ensure("green", p.green, bg, AA);
1662
+ const teal = ensure("teal", blend(p.green, p.cyan, .5), bg, AA);
1663
+ const blue = ensure("blue", dark ? p.brightBlue : p.blue, bg, AA);
1664
+ const purple = ensure("purple", p.magenta, bg, AA);
1665
+ const pink = ensure("pink", blend(p.magenta, p.red, .5), bg, AA);
1113
1666
  const mutedbg = blend(bg, p.foreground, .04);
1114
1667
  const muted = ensure("muted", blend(fg, bg, .4), mutedbg, AA);
1115
1668
  const disabledfg = ensure("disabledfg", blend(fg, bg, .5), bg, DIM);
1116
1669
  const border = ensure("border", blend(bg, p.foreground, .15), bg, FAINT);
1117
1670
  const inputborder = ensure("inputborder", blend(bg, p.foreground, .25), bg, CONTROL);
1118
- const selection = ensure("selection", p.selectionForeground, p.selectionBackground, AA);
1119
- const cursor = ensure("cursor", p.cursorText, p.cursorColor, AA);
1671
+ const selectionBg = repairSelectionBg(p.selectionBackground, bg);
1672
+ const selection = ensure("selection", p.selectionForeground, selectionBg, AA);
1673
+ const cursorBgRepaired = repairCursorBg(p.cursorColor, bg);
1674
+ const cursor = ensure("cursor", p.cursorText, cursorBgRepaired, AA);
1120
1675
  return {
1121
1676
  name: p.name ?? (dark ? "derived-dark" : "derived-light"),
1122
1677
  bg,
@@ -1130,9 +1685,9 @@ function deriveTruecolorTheme(p, adjustments) {
1130
1685
  inverse: contrastFg(blend(fg, bg, .1)),
1131
1686
  inversebg: blend(fg, bg, .1),
1132
1687
  cursor,
1133
- cursorbg: p.cursorColor,
1688
+ cursorbg: cursorBgRepaired,
1134
1689
  selection,
1135
- selectionbg: p.selectionBackground,
1690
+ selectionbg: selectionBg,
1136
1691
  primary,
1137
1692
  primaryfg: contrastFg(primary),
1138
1693
  secondary,
@@ -1169,7 +1724,26 @@ function deriveTruecolorTheme(p, adjustments) {
1169
1724
  p.brightMagenta,
1170
1725
  p.brightCyan,
1171
1726
  p.brightWhite
1172
- ]
1727
+ ],
1728
+ brand,
1729
+ brandHover,
1730
+ brandActive,
1731
+ red,
1732
+ orange,
1733
+ yellow,
1734
+ green,
1735
+ teal,
1736
+ blue,
1737
+ purple,
1738
+ pink,
1739
+ brandRed: red,
1740
+ brandOrange: orange,
1741
+ brandYellow: yellow,
1742
+ brandGreen: green,
1743
+ brandTeal: teal,
1744
+ brandBlue: blue,
1745
+ brandPurple: purple,
1746
+ brandPink: pink
1173
1747
  };
1174
1748
  }
1175
1749
  function deriveAnsi16Theme(p) {
@@ -1227,21 +1801,281 @@ function deriveAnsi16Theme(p) {
1227
1801
  p.brightMagenta,
1228
1802
  p.brightCyan,
1229
1803
  p.brightWhite
1230
- ]
1804
+ ],
1805
+ brand: primaryColor,
1806
+ brandHover: primaryColor,
1807
+ brandActive: primaryColor,
1808
+ brandRed: dark ? p.brightRed : p.red,
1809
+ brandOrange: dark ? p.brightRed : p.red,
1810
+ brandYellow: p.yellow,
1811
+ brandGreen: dark ? p.brightGreen : p.green,
1812
+ brandTeal: p.cyan,
1813
+ brandBlue: dark ? p.brightBlue : p.blue,
1814
+ brandPurple: p.magenta,
1815
+ brandPink: dark ? p.brightMagenta : p.magenta
1231
1816
  };
1232
1817
  }
1818
+ /**
1819
+ * Nudge `selectionBg`'s OKLCH lightness until it differs from `bg` by at least
1820
+ * `SELECTION_DELTA_L`. Preserves hue + chroma. Non-hex input returns unchanged.
1821
+ *
1822
+ * Direction: shift away from bg — if bg is dark, lift L; if bg is light, drop L.
1823
+ * If the input already meets the threshold, it's returned unchanged.
1824
+ */
1825
+ function repairSelectionBg(selectionBg, bg) {
1826
+ const oSel = hexToOklch(selectionBg);
1827
+ const oBg = hexToOklch(bg);
1828
+ if (!oSel || !oBg) return selectionBg;
1829
+ const dL = Math.abs(oSel.L - oBg.L);
1830
+ if (dL >= .08) return selectionBg;
1831
+ const needed = SELECTION_DELTA_L - dL + .005;
1832
+ const direction = oSel.L >= oBg.L ? 1 : -1;
1833
+ return oklchToHex({
1834
+ L: Math.max(0, Math.min(1, oSel.L + direction * needed)),
1835
+ C: oSel.C,
1836
+ H: oSel.H
1837
+ });
1838
+ }
1839
+ /**
1840
+ * Nudge `cursorBg`'s OKLCH values until it differs from `bg` by at least
1841
+ * `CURSOR_DELTA_E`. Shifts lightness first (preserves hue/chroma aesthetics).
1842
+ * Non-hex input returns unchanged.
1843
+ */
1844
+ function repairCursorBg(cursorBg, bg) {
1845
+ const d = colorDistance(cursorBg, bg);
1846
+ if (d === null || d >= .15) return cursorBg;
1847
+ const oCur = hexToOklch(cursorBg);
1848
+ const oBg = hexToOklch(bg);
1849
+ const lGap = SELECTION_DELTA_L + .02;
1850
+ const direction = oCur.L >= oBg.L ? 1 : -1;
1851
+ const candidate = oklchToHex({
1852
+ L: Math.max(0, Math.min(1, oCur.L + direction * lGap)),
1853
+ C: oCur.C,
1854
+ H: oCur.H
1855
+ });
1856
+ const d2 = colorDistance(candidate, bg);
1857
+ if (d2 !== null && d2 >= .15) return candidate;
1858
+ return oBg.L > .5 ? "#000000" : "#FFFFFF";
1859
+ }
1233
1860
  var AA, DIM, FAINT, CONTROL;
1234
1861
  var init_derive = __esmMin((() => {
1235
1862
  init_src$1();
1863
+ init_invariants();
1236
1864
  AA = 4.5;
1237
1865
  DIM = 3;
1238
1866
  FAINT = 1.5;
1239
1867
  CONTROL = 3;
1240
1868
  }));
1241
1869
  //#endregion
1242
- //#region packages/ansi/src/theme/default-palettes.ts
1243
- var ansi16DarkTheme, ansi16LightTheme;
1244
- var init_default_palettes = __esmMin((() => {
1870
+ //#region packages/ansi/src/theme/monochrome.ts
1871
+ /**
1872
+ * Produce per-token monochrome attrs from a base Theme.
1873
+ *
1874
+ * Currently returns `DEFAULT_MONO_ATTRS` — a canonical mapping. Passed the
1875
+ * theme to allow per-theme overrides in the future (e.g., a palette that
1876
+ * prefers `underline` for accents over `italic`). The argument is reserved.
1877
+ */
1878
+ function deriveMonochromeTheme(theme) {
1879
+ return DEFAULT_MONO_ATTRS;
1880
+ }
1881
+ /**
1882
+ * Resolve mono-attrs from a color *string* — the high-level entry point
1883
+ * consumed by the render pipeline.
1884
+ *
1885
+ * Accepts strings like `"$primary"`, `"$fg-muted"`, `"$border-focus"`. Strips
1886
+ * the `$` prefix and hyphens, tries direct Theme key lookup, then falls back
1887
+ * to the Primer alias table. Returns `undefined` for non-token strings (hex,
1888
+ * rgb(), named ANSI colors) — callers should treat this as "no attrs".
1889
+ *
1890
+ * @param color The color string (e.g. `"$primary"`, `"#ff0000"`, `"red"`)
1891
+ * @param theme Active theme (reserved for per-theme overrides)
1892
+ * @returns Array of mono-attrs for the token, or `undefined` if not a
1893
+ * recognized token.
1894
+ */
1895
+ function monoAttrsForColorString(color, theme) {
1896
+ if (!color.startsWith("$")) return void 0;
1897
+ const raw = color.slice(1).replace(/-/g, "");
1898
+ const attrs = deriveMonochromeTheme(theme);
1899
+ const direct = attrs[raw];
1900
+ if (direct !== void 0) return direct;
1901
+ const aliased = PRIMER_ALIASES_FOR_MONO[raw];
1902
+ if (aliased) {
1903
+ const v = attrs[aliased];
1904
+ if (v !== void 0) return v;
1905
+ }
1906
+ }
1907
+ var DEFAULT_MONO_ATTRS, PRIMER_ALIASES_FOR_MONO;
1908
+ var init_monochrome = __esmMin((() => {
1909
+ DEFAULT_MONO_ATTRS = {
1910
+ bg: [],
1911
+ mutedbg: [],
1912
+ surfacebg: [],
1913
+ popoverbg: [],
1914
+ border: [],
1915
+ cursorbg: [],
1916
+ fg: [],
1917
+ muted: ["dim"],
1918
+ disabledfg: ["dim"],
1919
+ surface: [],
1920
+ popover: [],
1921
+ inverse: ["inverse"],
1922
+ primary: ["bold"],
1923
+ secondary: ["bold"],
1924
+ accent: ["italic", "bold"],
1925
+ error: ["bold", "inverse"],
1926
+ warning: ["bold"],
1927
+ success: ["bold"],
1928
+ info: ["italic"],
1929
+ primaryfg: [],
1930
+ secondaryfg: [],
1931
+ accentfg: [],
1932
+ errorfg: ["inverse"],
1933
+ warningfg: [],
1934
+ successfg: [],
1935
+ infofg: [],
1936
+ link: ["underline"],
1937
+ focusborder: ["bold"],
1938
+ inputborder: [],
1939
+ selection: [],
1940
+ selectionbg: ["inverse"],
1941
+ cursor: []
1942
+ };
1943
+ PRIMER_ALIASES_FOR_MONO = {
1944
+ fgmuted: "muted",
1945
+ fgdisabled: "disabledfg",
1946
+ fgcursor: "cursor",
1947
+ fgselected: "selection",
1948
+ fginverse: "inverse",
1949
+ fgonsurface: "surface",
1950
+ fgonpopover: "popover",
1951
+ fgonprimary: "primaryfg",
1952
+ fgonsecondary: "secondaryfg",
1953
+ fgonaccent: "accentfg",
1954
+ fgonerror: "errorfg",
1955
+ fgonwarning: "warningfg",
1956
+ fgonsuccess: "successfg",
1957
+ fgoninfo: "infofg",
1958
+ bgmuted: "mutedbg",
1959
+ bgsurface: "surfacebg",
1960
+ bgpopover: "popoverbg",
1961
+ bginverse: "inversebg",
1962
+ bgselected: "selectionbg",
1963
+ bgcursor: "cursorbg",
1964
+ borderfocus: "focusborder",
1965
+ borderinput: "inputborder"
1966
+ };
1967
+ }));
1968
+ //#endregion
1969
+ //#region packages/ansi/src/theme/fingerprint.ts
1970
+ /**
1971
+ * Map ΔE thresholds into a 0–1 confidence.
1972
+ *
1973
+ * sumΔE=0 + maxΔE=0 → 1.0 (perfect match)
1974
+ * sumΔE=30 (threshold) → ~0.5
1975
+ * sumΔE≥60 → ~0.0
1976
+ */
1977
+ function computeConfidence(sumDE, maxDE, sumThreshold) {
1978
+ const sumScore = Math.max(0, 1 - sumDE / (sumThreshold * 2));
1979
+ const maxScore = Math.max(0, 1 - maxDE / 16);
1980
+ return Math.max(0, Math.min(1, .7 * sumScore + .3 * maxScore));
1981
+ }
1982
+ /**
1983
+ * Match probed slots against a catalog, returning the best candidate if it
1984
+ * satisfies both sum and per-slot thresholds. Returns `null` if nothing matches.
1985
+ *
1986
+ * `probed` is a partial ColorScheme — whatever slots OSC queries returned. Missing
1987
+ * slots are skipped (still counted as "not compared"). Non-hex values are
1988
+ * ignored (ΔE can't be computed).
1989
+ */
1990
+ function fingerprintMatch(probed, catalog, opts = {}) {
1991
+ const sumThreshold = opts.sumThreshold ?? 30;
1992
+ const perSlotThreshold = opts.perSlotThreshold ?? 8;
1993
+ let best = null;
1994
+ for (const scheme of catalog) {
1995
+ let sumDE = 0;
1996
+ let maxDE = 0;
1997
+ let slotsCompared = 0;
1998
+ for (const field of FINGERPRINT_FIELDS) {
1999
+ const probedVal = probed[field];
2000
+ const catalogVal = scheme[field];
2001
+ if (typeof probedVal !== "string" || typeof catalogVal !== "string") continue;
2002
+ const de = colorDistance(probedVal, catalogVal);
2003
+ if (de === null) continue;
2004
+ const scaled = de * 100;
2005
+ sumDE += scaled;
2006
+ if (scaled > maxDE) maxDE = scaled;
2007
+ slotsCompared++;
2008
+ }
2009
+ if (slotsCompared === 0) continue;
2010
+ if (maxDE > perSlotThreshold) continue;
2011
+ if (sumDE > sumThreshold) continue;
2012
+ if (best === null || sumDE < best.sumDeltaE) best = {
2013
+ scheme,
2014
+ sumDeltaE: sumDE,
2015
+ maxDeltaE: maxDE,
2016
+ slotsCompared,
2017
+ confidence: computeConfidence(sumDE, maxDE, sumThreshold)
2018
+ };
2019
+ }
2020
+ return best;
2021
+ }
2022
+ var FINGERPRINT_FIELDS;
2023
+ var init_fingerprint = __esmMin((() => {
2024
+ init_src$1();
2025
+ FINGERPRINT_FIELDS = [
2026
+ "foreground",
2027
+ "background",
2028
+ "black",
2029
+ "red",
2030
+ "green",
2031
+ "yellow",
2032
+ "blue",
2033
+ "magenta",
2034
+ "cyan",
2035
+ "white",
2036
+ "brightBlack",
2037
+ "brightRed",
2038
+ "brightGreen",
2039
+ "brightYellow",
2040
+ "brightBlue",
2041
+ "brightMagenta",
2042
+ "brightCyan",
2043
+ "brightWhite"
2044
+ ];
2045
+ }));
2046
+ //#endregion
2047
+ //#region packages/ansi/src/theme/types.ts
2048
+ var COLOR_SCHEME_FIELDS;
2049
+ var init_types = __esmMin((() => {
2050
+ COLOR_SCHEME_FIELDS = [
2051
+ "black",
2052
+ "red",
2053
+ "green",
2054
+ "yellow",
2055
+ "blue",
2056
+ "magenta",
2057
+ "cyan",
2058
+ "white",
2059
+ "brightBlack",
2060
+ "brightRed",
2061
+ "brightGreen",
2062
+ "brightYellow",
2063
+ "brightBlue",
2064
+ "brightMagenta",
2065
+ "brightCyan",
2066
+ "brightWhite",
2067
+ "foreground",
2068
+ "background",
2069
+ "cursorColor",
2070
+ "cursorText",
2071
+ "selectionBackground",
2072
+ "selectionForeground"
2073
+ ];
2074
+ }));
2075
+ //#endregion
2076
+ //#region packages/ansi/src/theme/default-schemes.ts
2077
+ var ansi16DarkTheme, ansi16LightTheme, defaultDarkScheme, defaultLightScheme;
2078
+ var init_default_schemes = __esmMin((() => {
1245
2079
  ansi16DarkTheme = {
1246
2080
  name: "dark-ansi16",
1247
2081
  bg: "",
@@ -1294,7 +2128,26 @@ var init_default_palettes = __esmMin((() => {
1294
2128
  "magentaBright",
1295
2129
  "cyanBright",
1296
2130
  "whiteBright"
1297
- ]
2131
+ ],
2132
+ brand: "yellow",
2133
+ brandHover: "yellow",
2134
+ brandActive: "yellow",
2135
+ red: "redBright",
2136
+ orange: "redBright",
2137
+ yellow: "yellow",
2138
+ green: "greenBright",
2139
+ teal: "cyan",
2140
+ blue: "blueBright",
2141
+ purple: "magenta",
2142
+ pink: "magentaBright",
2143
+ brandRed: "redBright",
2144
+ brandOrange: "redBright",
2145
+ brandYellow: "yellow",
2146
+ brandGreen: "greenBright",
2147
+ brandTeal: "cyan",
2148
+ brandBlue: "blueBright",
2149
+ brandPurple: "magenta",
2150
+ brandPink: "magentaBright"
1298
2151
  };
1299
2152
  ansi16LightTheme = {
1300
2153
  name: "light-ansi16",
@@ -1348,37 +2201,79 @@ var init_default_palettes = __esmMin((() => {
1348
2201
  "magentaBright",
1349
2202
  "cyanBright",
1350
2203
  "whiteBright"
1351
- ]
2204
+ ],
2205
+ brand: "blue",
2206
+ brandHover: "blue",
2207
+ brandActive: "blue",
2208
+ red: "red",
2209
+ orange: "red",
2210
+ yellow: "yellow",
2211
+ green: "green",
2212
+ teal: "cyan",
2213
+ blue: "blue",
2214
+ purple: "magenta",
2215
+ pink: "magenta",
2216
+ brandRed: "red",
2217
+ brandOrange: "red",
2218
+ brandYellow: "yellow",
2219
+ brandGreen: "green",
2220
+ brandTeal: "cyan",
2221
+ brandBlue: "blue",
2222
+ brandPurple: "magenta",
2223
+ brandPink: "magenta"
2224
+ };
2225
+ defaultDarkScheme = {
2226
+ name: "default-dark",
2227
+ dark: true,
2228
+ black: "#2e3440",
2229
+ red: "#bf616a",
2230
+ green: "#a3be8c",
2231
+ yellow: "#ebcb8b",
2232
+ blue: "#81a1c1",
2233
+ magenta: "#b48ead",
2234
+ cyan: "#88c0d0",
2235
+ white: "#d8dee9",
2236
+ brightBlack: "#4c566a",
2237
+ brightRed: "#bf616a",
2238
+ brightGreen: "#a3be8c",
2239
+ brightYellow: "#ebcb8b",
2240
+ brightBlue: "#81a1c1",
2241
+ brightMagenta: "#b48ead",
2242
+ brightCyan: "#8fbcbb",
2243
+ brightWhite: "#eceff4",
2244
+ foreground: "#d8dee9",
2245
+ background: "#2e3440",
2246
+ cursorColor: "#d8dee9",
2247
+ cursorText: "#2e3440",
2248
+ selectionBackground: "#434c5e",
2249
+ selectionForeground: "#d8dee9"
2250
+ };
2251
+ defaultLightScheme = {
2252
+ name: "default-light",
2253
+ dark: false,
2254
+ black: "#5c6370",
2255
+ red: "#d20f39",
2256
+ green: "#40a02b",
2257
+ yellow: "#df8e1d",
2258
+ blue: "#1e66f5",
2259
+ magenta: "#8839ef",
2260
+ cyan: "#179299",
2261
+ white: "#dce0e8",
2262
+ brightBlack: "#6c7086",
2263
+ brightRed: "#d20f39",
2264
+ brightGreen: "#40a02b",
2265
+ brightYellow: "#df8e1d",
2266
+ brightBlue: "#1e66f5",
2267
+ brightMagenta: "#8839ef",
2268
+ brightCyan: "#179299",
2269
+ brightWhite: "#eff1f5",
2270
+ foreground: "#4c4f69",
2271
+ background: "#eff1f5",
2272
+ cursorColor: "#dc8a78",
2273
+ cursorText: "#eff1f5",
2274
+ selectionBackground: "#ccd0da",
2275
+ selectionForeground: "#4c4f69"
1352
2276
  };
1353
- }));
1354
- //#endregion
1355
- //#region packages/ansi/src/theme/types.ts
1356
- var COLOR_PALETTE_FIELDS;
1357
- var init_types = __esmMin((() => {
1358
- COLOR_PALETTE_FIELDS = [
1359
- "black",
1360
- "red",
1361
- "green",
1362
- "yellow",
1363
- "blue",
1364
- "magenta",
1365
- "cyan",
1366
- "white",
1367
- "brightBlack",
1368
- "brightRed",
1369
- "brightGreen",
1370
- "brightYellow",
1371
- "brightBlue",
1372
- "brightMagenta",
1373
- "brightCyan",
1374
- "brightWhite",
1375
- "foreground",
1376
- "background",
1377
- "cursorColor",
1378
- "cursorText",
1379
- "selectionBackground",
1380
- "selectionForeground"
1381
- ];
1382
2277
  }));
1383
2278
  //#endregion
1384
2279
  //#region packages/ansi/src/osc-palette.ts
@@ -1495,7 +2390,7 @@ var init_osc_colors = __esmMin((() => {
1495
2390
  }));
1496
2391
  //#endregion
1497
2392
  //#region packages/ansi/src/theme/detect.ts
1498
- async function detectTerminalPalette(timeoutMs = 150) {
2393
+ async function detectTerminalScheme(timeoutMs = 150) {
1499
2394
  const stdin = process.stdin;
1500
2395
  const stdout = process.stdout;
1501
2396
  if (!stdin.isTTY || !stdout.isTTY) return null;
@@ -1601,6 +2496,139 @@ function isDarkColor(hex) {
1601
2496
  var init_detect = __esmMin((() => {
1602
2497
  init_osc_palette();
1603
2498
  init_osc_colors();
2499
+ }));
2500
+ //#endregion
2501
+ //#region packages/ansi/src/theme/orchestrator.ts
2502
+ function envOverride() {
2503
+ const v = process.env.SILVERY_COLOR;
2504
+ if (!v) return null;
2505
+ if (v === "truecolor" || v === "256" || v === "ansi16" || v === "scheme" || v === "mono" || v === "auto") return v;
2506
+ return null;
2507
+ }
2508
+ /**
2509
+ * Detect the terminal's color scheme + derive a theme in one call.
2510
+ *
2511
+ * Runs the 4-layer detection cascade (override → probe → fingerprint →
2512
+ * fallback) and returns a fully-resolved Theme along with provenance metadata
2513
+ * so callers can log how the scheme was determined.
2514
+ *
2515
+ * This is the recommended entry point for apps — it handles all the gotchas
2516
+ * (non-TTY environments, failed probes, partial OSC responses, catalog matches,
2517
+ * bg-mode inference) and returns something you can hand to `ThemeProvider`.
2518
+ *
2519
+ * @example
2520
+ * ```ts
2521
+ * import { detectScheme } from "@silvery/ansi"
2522
+ * import { builtinPalettes } from "@silvery/theme/schemes"
2523
+ *
2524
+ * const { scheme, theme, source, matchedName, confidence } = await detectScheme({
2525
+ * catalog: Object.values(builtinPalettes),
2526
+ * enforce: "lenient",
2527
+ * })
2528
+ * console.log(`${source === "fingerprint" ? `detected ${matchedName}` : source} (${(confidence * 100).toFixed(0)}%)`)
2529
+ * ```
2530
+ */
2531
+ async function detectScheme(opts = {}) {
2532
+ const enforce = opts.enforce ?? "lenient";
2533
+ const wcag = opts.wcag ?? false;
2534
+ if (opts.override) {
2535
+ const theme = loadTheme(opts.override, {
2536
+ enforce,
2537
+ wcag
2538
+ });
2539
+ return {
2540
+ scheme: opts.override,
2541
+ theme,
2542
+ source: "override",
2543
+ confidence: 1,
2544
+ slotSources: allSlotsFrom("fallback"),
2545
+ matchedName: opts.override.name
2546
+ };
2547
+ }
2548
+ const envMode = envOverride();
2549
+ if (envMode === "mono" || envMode === "ansi16") {
2550
+ const fallback = opts.darkFallback !== false ? defaultDarkScheme : defaultLightScheme;
2551
+ return {
2552
+ scheme: fallback,
2553
+ theme: loadTheme(fallback, {
2554
+ enforce,
2555
+ wcag
2556
+ }),
2557
+ source: "override",
2558
+ confidence: 1,
2559
+ slotSources: allSlotsFrom("fallback"),
2560
+ matchedName: fallback.name
2561
+ };
2562
+ }
2563
+ const detected = await detectTerminalScheme(opts.timeoutMs);
2564
+ if (!detected) {
2565
+ const fallback = opts.darkFallback !== false ? defaultDarkScheme : defaultLightScheme;
2566
+ return {
2567
+ scheme: fallback,
2568
+ theme: loadTheme(fallback, {
2569
+ enforce,
2570
+ wcag
2571
+ }),
2572
+ source: "fallback",
2573
+ confidence: 0,
2574
+ slotSources: allSlotsFrom("fallback"),
2575
+ matchedName: fallback.name
2576
+ };
2577
+ }
2578
+ const catalog = opts.catalog ?? [];
2579
+ if (catalog.length > 0) {
2580
+ const match = fingerprintMatch(detected.palette, catalog);
2581
+ if (match) {
2582
+ const theme = loadTheme(match.scheme, {
2583
+ enforce,
2584
+ wcag
2585
+ });
2586
+ return {
2587
+ scheme: match.scheme,
2588
+ theme,
2589
+ source: "fingerprint",
2590
+ confidence: match.confidence,
2591
+ slotSources: allSlotsFrom("catalog"),
2592
+ matchedName: match.scheme.name
2593
+ };
2594
+ }
2595
+ }
2596
+ const merged = {
2597
+ ...detected.dark ? defaultDarkScheme : defaultLightScheme,
2598
+ ...stripNulls(detected.palette)
2599
+ };
2600
+ const theme = loadTheme(merged, {
2601
+ enforce,
2602
+ wcag
2603
+ });
2604
+ const slotSources = {};
2605
+ for (const field of COLOR_SCHEME_FIELDS) slotSources[field] = typeof detected.palette[field] === "string" ? "probed" : "fallback";
2606
+ const probedCount = Object.values(slotSources).filter((s) => s === "probed").length;
2607
+ return {
2608
+ scheme: merged,
2609
+ theme,
2610
+ source: "probed",
2611
+ confidence: Math.min(1, probedCount / 18),
2612
+ slotSources,
2613
+ matchedName: void 0
2614
+ };
2615
+ }
2616
+ function stripNulls(partial) {
2617
+ const result = {};
2618
+ for (const [k, v] of Object.entries(partial)) if (v != null) result[k] = v;
2619
+ return result;
2620
+ }
2621
+ function allSlotsFrom(src) {
2622
+ const out = {};
2623
+ for (const field of COLOR_SCHEME_FIELDS) out[field] = src;
2624
+ return out;
2625
+ }
2626
+ var init_orchestrator = __esmMin((() => {
2627
+ init_types();
2628
+ init_derive();
2629
+ init_detect();
2630
+ init_fingerprint();
2631
+ init_default_schemes();
1604
2632
  })), CSI;
1605
2633
  var init_color_scheme = __esmMin((() => {
1606
2634
  CSI = `[`;
@@ -1617,13 +2645,15 @@ var init_src = __esmMin((() => {
1617
2645
  init_style();
1618
2646
  init_mixed_proxy();
1619
2647
  init_derive();
1620
- init_default_palettes();
2648
+ init_monochrome();
2649
+ init_orchestrator();
2650
+ init_default_schemes();
1621
2651
  init_types();
1622
2652
  init_detect();
1623
2653
  init_osc_palette();
1624
2654
  init_color_scheme();
1625
2655
  }));
1626
2656
  //#endregion
1627
- export { contrastFg as A, enableKittyKeyboard as B, resolveThemeColor as C, blend as D, ensureContrast as E, hslToHex as F, detectColor as G, bgColorCode as H, rgbToHex as I, detectTerminalCaps as J, detectCursor as K, rgbToHsl as L, desaturate as M, hexToHsl as N, brighten as O, hexToRgb as P, disableKittyKeyboard as R, createStyle as S, checkContrast as T, fgColorCode as U, enableMouse as V, defaultCaps as W, detectUnicode as Y, COLOR_PALETTE_FIELDS as _, queryCursorColor as a, deriveTheme as b, resetCursorColor as c, setCursorColor as d, setForegroundColor as f, setPaletteColor as g, queryPaletteColor as h, queryBackgroundColor as i, darken as j, complement as k, resetForegroundColor as l, queryMultiplePaletteColors as m, detectTerminalPalette as n, queryForegroundColor as o, parsePaletteResponse as p, detectInput as q, detectColorScheme as r, resetBackgroundColor as s, init_src as t, setBackgroundColor as u, ansi16DarkTheme as v, init_src$1 as w, createMixedStyle as x, ansi16LightTheme as y, disableMouse as z };
2657
+ export { detectTerminalCaps as $, brighten as A, rgbToHsl as B, createMixedStyle as C, checkContrast as D, init_src$1 as E, hexToHsl as F, enableKittyKeyboard as G, oklchToHex as H, hexToRgb as I, fgColorCode as J, enableMouse as K, hslToHex as L, contrastFg as M, darken as N, ensureContrast as O, desaturate as P, detectInput as Q, relativeLuminance as R, deriveTheme as S, resolveThemeColor as T, disableKittyKeyboard as U, hexToOklch as V, disableMouse as W, detectColor as X, defaultCaps as Y, detectCursor as Z, setPaletteColor as _, queryBackgroundColor as a, COLOR_SCHEME_FIELDS as b, resetBackgroundColor as c, setBackgroundColor as d, detectUnicode as et, setCursorColor as f, queryPaletteColor as g, queryMultiplePaletteColors as h, detectColorScheme as i, complement as j, blend as k, resetCursorColor as l, parsePaletteResponse as m, detectScheme as n, queryCursorColor as o, setForegroundColor as p, bgColorCode as q, detectTerminalScheme as r, queryForegroundColor as s, init_src as t, resetForegroundColor as u, ansi16DarkTheme as v, createStyle as w, monoAttrsForColorString as x, ansi16LightTheme as y, rgbToHex as z };
1628
2658
 
1629
- //# sourceMappingURL=src-9B5k0JmY.mjs.map
2659
+ //# sourceMappingURL=src-D_BS-as7.mjs.map