@ixfx/components 0.10.1 → 0.10.2

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 (138) hide show
  1. package/bundle/index.d.ts +173 -20
  2. package/bundle/index.d.ts.map +1 -1
  3. package/bundle/index.js +1847 -123
  4. package/bundle/index.js.map +1 -1
  5. package/dist/ac-text.d.ts +1 -1
  6. package/dist/ac-text.js +1 -1
  7. package/dist/{ac-token-TCLAZeVg.d.ts → ac-token--_vCHXWw.d.ts} +2 -2
  8. package/dist/{ac-token-TCLAZeVg.d.ts.map → ac-token--_vCHXWw.d.ts.map} +1 -1
  9. package/dist/ac-token.d.ts +1 -1
  10. package/dist/ac-token.js +2 -2
  11. package/dist/button.d.ts +1 -1
  12. package/dist/button.d.ts.map +1 -1
  13. package/dist/{colour-picker-R73i0QTP.js → colour-picker-WDrPuqoO.js} +2 -2
  14. package/dist/{colour-picker-R73i0QTP.js.map → colour-picker-WDrPuqoO.js.map} +1 -1
  15. package/dist/colour-picker.d.ts +1 -1
  16. package/dist/colour-picker.js +1 -1
  17. package/dist/crumbs.d.ts +1 -1
  18. package/dist/crumbs.js +2 -2
  19. package/dist/{data-grid-BT1d_nlu.d.ts → data-grid-pv6eaJCZ.d.ts} +4 -3
  20. package/dist/data-grid-pv6eaJCZ.d.ts.map +1 -0
  21. package/dist/data-grid.d.ts +1 -1
  22. package/dist/data-grid.js +27 -9
  23. package/dist/data-grid.js.map +1 -1
  24. package/dist/defaults-kVl1t2tT.js +59 -0
  25. package/dist/defaults-kVl1t2tT.js.map +1 -0
  26. package/dist/{detail-list-BCaIN7nx.d.ts → detail-list-BA3RVVCB.d.ts} +4 -4
  27. package/dist/{detail-list-BCaIN7nx.d.ts.map → detail-list-BA3RVVCB.d.ts.map} +1 -1
  28. package/dist/detail-list.d.ts +2 -2
  29. package/dist/detail-list.js +3 -3
  30. package/dist/{grid-list-DLfw5HI4.js → grid-list-CIc4jo-x.js} +25 -3
  31. package/dist/grid-list-CIc4jo-x.js.map +1 -0
  32. package/dist/{grid-list-CiwlNE4c.d.ts → grid-list-DWXJoRnK.d.ts} +2 -2
  33. package/dist/{grid-list-CiwlNE4c.d.ts.map → grid-list-DWXJoRnK.d.ts.map} +1 -1
  34. package/dist/grid-list.d.ts +1 -1
  35. package/dist/grid-list.js +1 -1
  36. package/dist/{grouped-item-lister-CEZ72VOs.d.ts → grouped-item-lister-fdZHVxFM.d.ts} +2 -2
  37. package/dist/{grouped-item-lister-CEZ72VOs.d.ts.map → grouped-item-lister-fdZHVxFM.d.ts.map} +1 -1
  38. package/dist/grouped-item-lister.d.ts +1 -1
  39. package/dist/handle-DAXs7kbJ.js +656 -0
  40. package/dist/handle-DAXs7kbJ.js.map +1 -0
  41. package/dist/{icon-BCJJYEpm.js → icon-1gpwtPx8.js} +10 -1
  42. package/dist/icon-1gpwtPx8.js.map +1 -0
  43. package/dist/{icon-DR_3rSyZ.d.ts → icon-CDGprSdE.d.ts} +2 -2
  44. package/dist/icon-CDGprSdE.d.ts.map +1 -0
  45. package/dist/icons.d.ts +2 -2
  46. package/dist/icons.js +2 -2
  47. package/dist/{incr-search-C05WjbZh.js → incr-search-D91M4Ozq.js} +5 -4
  48. package/dist/incr-search-D91M4Ozq.js.map +1 -0
  49. package/dist/incr-search.d.ts +1 -1
  50. package/dist/incr-search.js +1 -1
  51. package/dist/{index-C59-JEPl.d.ts → index-9AhaHIT2.d.ts} +3 -3
  52. package/dist/{index-C59-JEPl.d.ts.map → index-9AhaHIT2.d.ts.map} +1 -1
  53. package/dist/index-CYndvTWH.d.ts +38 -0
  54. package/dist/index-CYndvTWH.d.ts.map +1 -0
  55. package/dist/{index-BUB5SICW.d.ts → index-CoqtMSd9.d.ts} +2 -2
  56. package/dist/{index-BUB5SICW.d.ts.map → index-CoqtMSd9.d.ts.map} +1 -1
  57. package/dist/{index-DPFrRhKL.d.ts → index-CsaQwNkz.d.ts} +2 -1
  58. package/dist/index-CsaQwNkz.d.ts.map +1 -0
  59. package/dist/{index-CJ5fshD3.d.ts → index-UvnoZUAo.d.ts} +2 -2
  60. package/dist/{index-CJ5fshD3.d.ts.map → index-UvnoZUAo.d.ts.map} +1 -1
  61. package/dist/{index-BOUaDIW-.d.ts → index-tq6f8007.d.ts} +2 -2
  62. package/dist/{index-BOUaDIW-.d.ts.map → index-tq6f8007.d.ts.map} +1 -1
  63. package/dist/index.d.ts +169 -19
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +1053 -18
  66. package/dist/index.js.map +1 -1
  67. package/dist/{labelled-input-base-Dp_9KP0G.d.ts → labelled-input-base-DiTme1JO.d.ts} +2 -2
  68. package/dist/{labelled-input-base-Dp_9KP0G.d.ts.map → labelled-input-base-DiTme1JO.d.ts.map} +1 -1
  69. package/dist/labelled-radial-input.d.ts +2 -2
  70. package/dist/labelled-radial-input.d.ts.map +1 -1
  71. package/dist/labelled-range-input.d.ts +1 -1
  72. package/dist/labelled-slider-input.d.ts +1 -1
  73. package/dist/{menu-C8a-84S5.js → menu-B2Qv3Oiz.js} +6 -5
  74. package/dist/menu-B2Qv3Oiz.js.map +1 -0
  75. package/dist/{menu-item-ZmkXNjek.d.ts → menu-item-CZi9vy5O.d.ts} +2 -2
  76. package/dist/{menu-item-ZmkXNjek.d.ts.map → menu-item-CZi9vy5O.d.ts.map} +1 -1
  77. package/dist/{menu-item-DzizkMH-.js → menu-item-Woc8jJc1.js} +4 -4
  78. package/dist/menu-item-Woc8jJc1.js.map +1 -0
  79. package/dist/menu.d.ts +2 -2
  80. package/dist/menu.js +2 -2
  81. package/dist/miller.d.ts +1 -1
  82. package/dist/miller.js +1 -1
  83. package/dist/narrowed-text.js +1 -1
  84. package/dist/panel.d.ts +1 -1
  85. package/dist/{scroll-fade-CAs1EabA.js → scroll-fade-BrNUIYnm.js} +16 -3
  86. package/dist/scroll-fade-BrNUIYnm.js.map +1 -0
  87. package/dist/select-horiz.js +1 -1
  88. package/dist/{split-layout-3yBOEVZW.js → split-layout-BJEU1W0d.js} +2 -2
  89. package/dist/{split-layout-3yBOEVZW.js.map → split-layout-BJEU1W0d.js.map} +1 -1
  90. package/dist/{split-layout-C5SYbDrq.d.ts → split-layout-JK3xWVX2.d.ts} +2 -2
  91. package/dist/{split-layout-C5SYbDrq.d.ts.map → split-layout-JK3xWVX2.d.ts.map} +1 -1
  92. package/dist/split-layout.d.ts +1 -1
  93. package/dist/split-layout.js +1 -1
  94. package/dist/{tab-list-DbMIL520.d.ts → tab-list-CGyPt07Z.d.ts} +2 -2
  95. package/dist/{tab-list-DbMIL520.d.ts.map → tab-list-CGyPt07Z.d.ts.map} +1 -1
  96. package/dist/tabs.d.ts +1 -1
  97. package/dist/tabs.js +1 -1
  98. package/dist/{timeline-CFlBFFGZ.js → timeline-BP1Ux2EV.js} +2 -2
  99. package/dist/{timeline-CFlBFFGZ.js.map → timeline-BP1Ux2EV.js.map} +1 -1
  100. package/dist/timeline.js +1 -1
  101. package/dist/{titlebar-B5zSTZnF.d.ts → titlebar-Tqu-VvMU.d.ts} +2 -2
  102. package/dist/{titlebar-B5zSTZnF.d.ts.map → titlebar-Tqu-VvMU.d.ts.map} +1 -1
  103. package/dist/titlebar.d.ts +1 -1
  104. package/dist/titlebar.js +1 -1
  105. package/dist/{tree-BuzWn18_.js → tree-Bm2TzTfe.js} +233 -14
  106. package/dist/tree-Bm2TzTfe.js.map +1 -0
  107. package/dist/tree.d.ts +13 -1
  108. package/dist/tree.d.ts.map +1 -1
  109. package/dist/tree.js +1 -1
  110. package/dist/{vertical-list-BLvJ4-Zf.d.ts → vertical-list-BWLqy3PJ.d.ts} +2 -2
  111. package/dist/{vertical-list-BLvJ4-Zf.d.ts.map → vertical-list-BWLqy3PJ.d.ts.map} +1 -1
  112. package/dist/vertical-list.d.ts +1 -1
  113. package/dist/vertical-list.js +1 -1
  114. package/docs-user/README.md +1 -0
  115. package/docs-user/icons.md +24 -10
  116. package/docs-user/index.json +8 -3
  117. package/docs-user/llms.txt +2 -1
  118. package/docs-user/multicol-list.md +128 -0
  119. package/docs-user/tree.md +12 -0
  120. package/docs-user/vertical-list.md +65 -9
  121. package/llms.txt +2 -1
  122. package/package.json +1 -1
  123. package/dist/data-grid-BT1d_nlu.d.ts.map +0 -1
  124. package/dist/defaults-BJwDsMH4.js +0 -86
  125. package/dist/defaults-BJwDsMH4.js.map +0 -1
  126. package/dist/grid-list-DLfw5HI4.js.map +0 -1
  127. package/dist/handle-BPOxBOKf.js +0 -219
  128. package/dist/handle-BPOxBOKf.js.map +0 -1
  129. package/dist/icon-BCJJYEpm.js.map +0 -1
  130. package/dist/icon-DR_3rSyZ.d.ts.map +0 -1
  131. package/dist/incr-search-C05WjbZh.js.map +0 -1
  132. package/dist/index-DPFrRhKL.d.ts.map +0 -1
  133. package/dist/index-DsjpDksO.d.ts +0 -47
  134. package/dist/index-DsjpDksO.d.ts.map +0 -1
  135. package/dist/menu-C8a-84S5.js.map +0 -1
  136. package/dist/menu-item-DzizkMH-.js.map +0 -1
  137. package/dist/scroll-fade-CAs1EabA.js.map +0 -1
  138. package/dist/tree-BuzWn18_.js.map +0 -1
package/bundle/index.js CHANGED
@@ -1545,6 +1545,15 @@ let IxfxIconElement = class IxfxIconElement extends i {
1545
1545
  if (this.rotate?.length > 0) this.style.setProperty(`--rotate`, this.rotate);
1546
1546
  else this.style.removeProperty(`--rotate`);
1547
1547
  }
1548
+ if (changed.has(`size`)) {
1549
+ if (this.size !== void 0) {
1550
+ this.style.width = `${this.size}px`;
1551
+ this.style.height = `${this.size}px`;
1552
+ } else {
1553
+ this.style.removeProperty(`width`);
1554
+ this.style.removeProperty(`height`);
1555
+ }
1556
+ }
1548
1557
  }
1549
1558
  static {
1550
1559
  this.styles = [themeFallbacks, i$3`
@@ -3019,10 +3028,10 @@ var ListSearchController = class {
3019
3028
  />
3020
3029
  ${hasQuery ? b`<span class="list-search-count">${this.#matches.length === 0 ? `0` : this.#matchIndex + 1} / ${this.#matches.length}</span>` : A}
3021
3030
  ${this.#mode === `navigate` && this.#matches.length > 1 ? b`
3022
- <button class="list-search-icon-btn" title="Previous match (↑)" @click=${() => this.prevMatch()}>‹</button>
3023
- <button class="list-search-icon-btn" title="Next match (↓)" @click=${() => this.nextMatch()}>›</button>
3031
+ <button class="list-search-icon-btn" title="Previous match (↑)" @click=${() => this.prevMatch()}><ixfx-icon name="chevron-left" size="14"></ixfx-icon></button>
3032
+ <button class="list-search-icon-btn" title="Next match (↓)" @click=${() => this.nextMatch()}><ixfx-icon name="chevron-right" size="14"></ixfx-icon></button>
3024
3033
  ` : A}
3025
- <button class="list-search-icon-btn" title="Close (Esc)" @click=${() => this.close()}>✕</button>
3034
+ <button class="list-search-icon-btn" title="Close (Esc)" @click=${() => this.close()}><ixfx-icon name="close" size="14"></ixfx-icon></button>
3026
3035
  </div>
3027
3036
  ${others.length > 0 || showSelectMatches ? b`
3028
3037
  <div class="list-search-switch">
@@ -3926,11 +3935,20 @@ AcTokenElement = __decorate([safeCustomElement(`ixfx-ac-token`)], AcTokenElement
3926
3935
  * - **flat** — a solid rounded capsule (bar) or dot (`spot`), filled with
3927
3936
  * `--ixfx-handle-color`.
3928
3937
  * - **dotted** — marks in the [Lucide *grip*](https://lucide.dev/icons/grip)
3929
- * arrangement: three in a row (`horizontal`), three in a column (`vertical`) or a
3930
- * 3×3 block (`spot`). Tinted by `--ixfx-handle-color`. Each mark's corner
3931
- * rounding is `--ixfx-handle-radius` (→ the theme `--radius-l`), so a flat,
3932
- * squared-off theme renders them as **squares** instead of circles.
3933
- * - **dimpled** — that same layout, but each bar mark is pressed in: a lighter
3938
+ * arrangement: one or more marks along the long axis (`horizontal`: a row,
3939
+ * `vertical`: a column), repeated in one or more rows/columns across the
3940
+ * bar's cross axis (or a 3×3 block for `spot`, unaffected by the row/column
3941
+ * / mark-count behaviour below). Tinted by `--ixfx-handle-color`. Each
3942
+ * mark's corner rounding is `--ixfx-handle-radius` (→ the theme
3943
+ * `--radius-l`), so a flat, squared-off theme renders them as **squares**
3944
+ * instead of circles. For `horizontal` / `vertical`, `--ixfx-handle-length`
3945
+ * decides how many marks (1-7) fit along the long axis — spaced by
3946
+ * `--ixfx-handle-dot-gap` — the same way `--ixfx-handle-thickness` decides
3947
+ * how many rows (or columns) of marks (1-7) fit across the cross axis —
3948
+ * spaced by `--ixfx-handle-dot-pitch`. Both the bar's rendered length and
3949
+ * its thickness snap to the nearest whole multiple of the relevant spacing
3950
+ * so marks never clip at the edges.
3951
+ * - **dimpled** — that same layout, but each mark is pressed in: a lighter
3934
3952
  * copy peeking out above-left and a darker copy below-right of the base mark.
3935
3953
  * - **grated** — fine 45° knurling: each ridge is a lit edge, the base colour,
3936
3954
  * then a shaded edge. `spot` is the same hatch on a square crop.
@@ -3961,14 +3979,26 @@ AcTokenElement = __decorate([safeCustomElement(`ixfx-ac-token`)], AcTokenElement
3961
3979
  * ## CSS variables (defaults shown; override on the element or any ancestor)
3962
3980
  * - `--ixfx-handle-color` `var(--surface-muted-text)` — `flat` / `dotted` fill
3963
3981
  * - `--ixfx-handle-color-active` `var(--accent)` — `flat` / `dotted` hover / focus
3964
- * - `--ixfx-handle-thickness` `6px` — cross-axis size of a bar
3965
- * - `--ixfx-handle-length` `44px` — long-axis size of a bar (`100%` to fill)
3982
+ * - `--ixfx-handle-thickness` `6px` — cross-axis size of a bar (dotted /
3983
+ * dimpled `horizontal` / `vertical` bars snap this to the nearest whole multiple
3984
+ * of `--ixfx-handle-dot-pitch` so their mark rows / columns fit exactly)
3985
+ * - `--ixfx-handle-length` `44px` — long-axis size of a bar (`100%` to
3986
+ * fill). For dotted / dimpled `horizontal` / `vertical` bars this also decides
3987
+ * how many marks (1-7) fit along the long axis — spaced by
3988
+ * `--ixfx-handle-dot-gap` — the same way `--ixfx-handle-thickness` decides row /
3989
+ * column count across the cross axis, and the bar's rendered length likewise
3990
+ * snaps to the nearest whole multiple of `--ixfx-handle-dot-gap` so marks
3991
+ * never clip at the edges.
3966
3992
  * - `--ixfx-handle-spot-size` `14px` — width = height of a `spot`
3967
3993
  * - `--ixfx-handle-radius` `var(--radius-l)` — `flat` capsule / dotted & dimpled mark rounding
3968
3994
  * - `--ixfx-handle-opacity` `0.55` — rest opacity
3969
3995
  * - `--ixfx-handle-opacity-active` `1`
3970
3996
  * - `--ixfx-handle-dot-size` `3px` — mark size (dotted / dimpled)
3971
- * - `--ixfx-handle-dot-gap` `length/4` (bar) · `spot/3` — mark centre-to-centre step
3997
+ * - `--ixfx-handle-dot-gap` `length/4` (bar) · `spot/3` — mark centre-to-centre
3998
+ * step along the long axis (dotted / dimpled `horizontal` / `vertical` bars fit up
3999
+ * to 7 marks, driven by `--ixfx-handle-length`; `spot` is a fixed 3×3 block)
4000
+ * - `--ixfx-handle-dot-pitch` `dot-size * 2` — row/column centre-to-centre step across
4001
+ * the cross axis (dotted / dimpled `horizontal` / `vertical` only; up to 7 rows/columns)
3972
4002
  * - `--ixfx-handle-tile` `5px` — knurl period (grated)
3973
4003
  * - `--ixfx-handle-highlight` `color-mix(currentColor 35%, #fff)` — lit deboss edge
3974
4004
  * - `--ixfx-handle-shadow` `color-mix(currentColor 60%, #000)` — shaded deboss edge
@@ -3989,6 +4019,28 @@ const handleStyles = i$3`
3989
4019
  /* Centre-to-centre step of the dotted / dimpled marks (a length). Defaults to
3990
4020
  a share of the long axis; a bar shows ~3 marks. */
3991
4021
  --_handle-gap: var(--ixfx-handle-dot-gap, calc(var(--_handle-length) / 4));
4022
+ /* Centre-to-centre step between rows (horizontal) / columns (vertical) of
4023
+ marks across the bar's cross axis. */
4024
+ --_handle-pitch: var(--ixfx-handle-dot-pitch, calc(var(--_handle-dot) * 2));
4025
+ /* How many whole pitch-steps fit across the thickness, rounded to the
4026
+ nearest step and clamped to 1-7 rows/columns. */
4027
+ --_handle-rows: clamp(1, round(nearest, calc(var(--_handle-thickness) / var(--_handle-pitch)), 1), 7);
4028
+ /* An even row/column count has no centre step, so the whole grid (the
4029
+ ::before mark and its box-shadow copies, spaced at whole --_handle-pitch
4030
+ steps from it) is nudged by half a pitch to stay centred and symmetric. */
4031
+ --_handle-row-shift: calc((1 - mod(var(--_handle-rows), 2)) * var(--_handle-pitch) / 2);
4032
+ /* The bar's cross-axis size snapped to exactly --_handle-rows steps of
4033
+ --_handle-pitch, so mark rows/columns fit without clipping. */
4034
+ --_handle-thickness-snapped: calc(var(--_handle-rows) * var(--_handle-pitch));
4035
+ /* How many whole gap-steps fit across the long axis, rounded to the
4036
+ nearest step and clamped to 1-7 marks. */
4037
+ --_handle-cols: clamp(1, round(nearest, calc(var(--_handle-length) / var(--_handle-gap)), 1), 7);
4038
+ /* An even mark count has no centre step, so the whole grid is nudged by
4039
+ half a gap along the long axis to stay centred and symmetric. */
4040
+ --_handle-col-shift: calc((1 - mod(var(--_handle-cols), 2)) * var(--_handle-gap) / 2);
4041
+ /* The bar's long-axis size snapped to exactly --_handle-cols steps of
4042
+ --_handle-gap, so marks fit without clipping. */
4043
+ --_handle-length-snapped: calc(var(--_handle-cols) * var(--_handle-gap));
3992
4044
  /* How far a dimpled mark's highlight / shadow copy is offset. */
3993
4045
  --_dimple-off: calc(var(--_handle-dot) * 0.15);
3994
4046
  /* The mark colour lightened / darkened for the two deboss edges. */
@@ -4038,14 +4090,32 @@ const handleStyles = i$3`
4038
4090
  border-radius: 50%;
4039
4091
  }
4040
4092
 
4041
- /* ── dotted / dimpled: 3 marks in a row / column (or 3×3 for spot), drawn as
4042
- one ::before mark whose border-radius follows the theme — round normally,
4043
- square in a flat / squared-off theme (--radius-l: 0). box-shadow paints
4044
- the rest of the marks. ─────────────────────────────────────────────── */
4093
+ /* ── dotted / dimpled: 3 marks in a row / column (or 3×3 for spot), repeated
4094
+ in --_handle-rows rows/columns across the cross axis for horizontal /
4095
+ vertical, drawn as one ::before mark whose border-radius follows the
4096
+ theme — round normally, square in a flat / squared-off theme
4097
+ (--radius-l: 0). box-shadow paints the rest of the marks. The extra
4098
+ rows/columns beyond --_handle-rows are still emitted (a fixed 7-row
4099
+ grid, CSS can't loop) but land outside the snapped, overflow: hidden
4100
+ bar, so they're clipped cleanly rather than shown or partially cut. ── */
4045
4101
  .ixfx-handle[data-handle='dotted'],
4046
4102
  .ixfx-handle[data-handle='dimpled'] {
4047
4103
  position: relative;
4048
4104
  }
4105
+ .ixfx-handle[data-handle='dotted']:not([data-shape='spot']),
4106
+ .ixfx-handle[data-handle='dimpled']:not([data-shape='spot']) {
4107
+ overflow: hidden;
4108
+ }
4109
+ .ixfx-handle[data-handle='dotted']:not([data-shape='vertical']):not([data-shape='spot']),
4110
+ .ixfx-handle[data-handle='dimpled']:not([data-shape='vertical']):not([data-shape='spot']) {
4111
+ width: var(--_handle-length-snapped);
4112
+ height: var(--_handle-thickness-snapped);
4113
+ }
4114
+ .ixfx-handle[data-handle='dotted'][data-shape='vertical'],
4115
+ .ixfx-handle[data-handle='dimpled'][data-shape='vertical'] {
4116
+ width: var(--_handle-thickness-snapped);
4117
+ height: var(--_handle-length-snapped);
4118
+ }
4049
4119
  .ixfx-handle[data-handle='dotted']::before,
4050
4120
  .ixfx-handle[data-handle='dimpled']::before {
4051
4121
  content: '';
@@ -4059,16 +4129,112 @@ const handleStyles = i$3`
4059
4129
  background: currentColor;
4060
4130
  }
4061
4131
 
4062
- /* dotted — the two other marks are plain copies along the axis. */
4063
- .ixfx-handle[data-handle='dotted']::before {
4132
+ /* dotted — the other marks are plain copies: 2 more along the long axis,
4133
+ repeated across up to 7 rows/columns on the cross axis (clipped to
4134
+ --_handle-rows by the snapped, overflow: hidden bar — see above). */
4135
+ .ixfx-handle[data-handle='dotted']:not([data-shape='vertical']):not([data-shape='spot'])::before {
4136
+ transform: translate(calc(-50% + var(--_handle-col-shift)), calc(-50% + var(--_handle-row-shift)));
4064
4137
  box-shadow:
4138
+ calc(-3 * var(--_handle-gap)) calc(-3 * var(--_handle-pitch)) 0 0 currentColor,
4139
+ calc(-2 * var(--_handle-gap)) calc(-3 * var(--_handle-pitch)) 0 0 currentColor,
4140
+ calc(-1 * var(--_handle-gap)) calc(-3 * var(--_handle-pitch)) 0 0 currentColor,
4141
+ 0 calc(-3 * var(--_handle-pitch)) 0 0 currentColor,
4142
+ calc(var(--_handle-gap)) calc(-3 * var(--_handle-pitch)) 0 0 currentColor,
4143
+ calc(2 * var(--_handle-gap)) calc(-3 * var(--_handle-pitch)) 0 0 currentColor,
4144
+ calc(3 * var(--_handle-gap)) calc(-3 * var(--_handle-pitch)) 0 0 currentColor,
4145
+ calc(-3 * var(--_handle-gap)) calc(-2 * var(--_handle-pitch)) 0 0 currentColor,
4146
+ calc(-2 * var(--_handle-gap)) calc(-2 * var(--_handle-pitch)) 0 0 currentColor,
4147
+ calc(-1 * var(--_handle-gap)) calc(-2 * var(--_handle-pitch)) 0 0 currentColor,
4148
+ 0 calc(-2 * var(--_handle-pitch)) 0 0 currentColor,
4149
+ calc(var(--_handle-gap)) calc(-2 * var(--_handle-pitch)) 0 0 currentColor,
4150
+ calc(2 * var(--_handle-gap)) calc(-2 * var(--_handle-pitch)) 0 0 currentColor,
4151
+ calc(3 * var(--_handle-gap)) calc(-2 * var(--_handle-pitch)) 0 0 currentColor,
4152
+ calc(-3 * var(--_handle-gap)) calc(-1 * var(--_handle-pitch)) 0 0 currentColor,
4153
+ calc(-2 * var(--_handle-gap)) calc(-1 * var(--_handle-pitch)) 0 0 currentColor,
4154
+ calc(-1 * var(--_handle-gap)) calc(-1 * var(--_handle-pitch)) 0 0 currentColor,
4155
+ 0 calc(-1 * var(--_handle-pitch)) 0 0 currentColor,
4156
+ calc(var(--_handle-gap)) calc(-1 * var(--_handle-pitch)) 0 0 currentColor,
4157
+ calc(2 * var(--_handle-gap)) calc(-1 * var(--_handle-pitch)) 0 0 currentColor,
4158
+ calc(3 * var(--_handle-gap)) calc(-1 * var(--_handle-pitch)) 0 0 currentColor,
4159
+ calc(-3 * var(--_handle-gap)) 0 0 0 currentColor,
4160
+ calc(-2 * var(--_handle-gap)) 0 0 0 currentColor,
4065
4161
  calc(-1 * var(--_handle-gap)) 0 0 0 currentColor,
4066
- var(--_handle-gap) 0 0 0 currentColor;
4162
+ calc(var(--_handle-gap)) 0 0 0 currentColor,
4163
+ calc(2 * var(--_handle-gap)) 0 0 0 currentColor,
4164
+ calc(3 * var(--_handle-gap)) 0 0 0 currentColor,
4165
+ calc(-3 * var(--_handle-gap)) calc(var(--_handle-pitch)) 0 0 currentColor,
4166
+ calc(-2 * var(--_handle-gap)) calc(var(--_handle-pitch)) 0 0 currentColor,
4167
+ calc(-1 * var(--_handle-gap)) calc(var(--_handle-pitch)) 0 0 currentColor,
4168
+ 0 calc(var(--_handle-pitch)) 0 0 currentColor,
4169
+ calc(var(--_handle-gap)) calc(var(--_handle-pitch)) 0 0 currentColor,
4170
+ calc(2 * var(--_handle-gap)) calc(var(--_handle-pitch)) 0 0 currentColor,
4171
+ calc(3 * var(--_handle-gap)) calc(var(--_handle-pitch)) 0 0 currentColor,
4172
+ calc(-3 * var(--_handle-gap)) calc(2 * var(--_handle-pitch)) 0 0 currentColor,
4173
+ calc(-2 * var(--_handle-gap)) calc(2 * var(--_handle-pitch)) 0 0 currentColor,
4174
+ calc(-1 * var(--_handle-gap)) calc(2 * var(--_handle-pitch)) 0 0 currentColor,
4175
+ 0 calc(2 * var(--_handle-pitch)) 0 0 currentColor,
4176
+ calc(var(--_handle-gap)) calc(2 * var(--_handle-pitch)) 0 0 currentColor,
4177
+ calc(2 * var(--_handle-gap)) calc(2 * var(--_handle-pitch)) 0 0 currentColor,
4178
+ calc(3 * var(--_handle-gap)) calc(2 * var(--_handle-pitch)) 0 0 currentColor,
4179
+ calc(-3 * var(--_handle-gap)) calc(3 * var(--_handle-pitch)) 0 0 currentColor,
4180
+ calc(-2 * var(--_handle-gap)) calc(3 * var(--_handle-pitch)) 0 0 currentColor,
4181
+ calc(-1 * var(--_handle-gap)) calc(3 * var(--_handle-pitch)) 0 0 currentColor,
4182
+ 0 calc(3 * var(--_handle-pitch)) 0 0 currentColor,
4183
+ calc(var(--_handle-gap)) calc(3 * var(--_handle-pitch)) 0 0 currentColor,
4184
+ calc(2 * var(--_handle-gap)) calc(3 * var(--_handle-pitch)) 0 0 currentColor,
4185
+ calc(3 * var(--_handle-gap)) calc(3 * var(--_handle-pitch)) 0 0 currentColor;
4067
4186
  }
4068
4187
  .ixfx-handle[data-handle='dotted'][data-shape='vertical']::before {
4188
+ transform: translate(calc(-50% + var(--_handle-row-shift)), calc(-50% + var(--_handle-col-shift)));
4069
4189
  box-shadow:
4190
+ calc(-3 * var(--_handle-pitch)) calc(-3 * var(--_handle-gap)) 0 0 currentColor,
4191
+ calc(-3 * var(--_handle-pitch)) calc(-2 * var(--_handle-gap)) 0 0 currentColor,
4192
+ calc(-3 * var(--_handle-pitch)) calc(-1 * var(--_handle-gap)) 0 0 currentColor,
4193
+ calc(-3 * var(--_handle-pitch)) 0 0 0 currentColor,
4194
+ calc(-3 * var(--_handle-pitch)) calc(var(--_handle-gap)) 0 0 currentColor,
4195
+ calc(-3 * var(--_handle-pitch)) calc(2 * var(--_handle-gap)) 0 0 currentColor,
4196
+ calc(-3 * var(--_handle-pitch)) calc(3 * var(--_handle-gap)) 0 0 currentColor,
4197
+ calc(-2 * var(--_handle-pitch)) calc(-3 * var(--_handle-gap)) 0 0 currentColor,
4198
+ calc(-2 * var(--_handle-pitch)) calc(-2 * var(--_handle-gap)) 0 0 currentColor,
4199
+ calc(-2 * var(--_handle-pitch)) calc(-1 * var(--_handle-gap)) 0 0 currentColor,
4200
+ calc(-2 * var(--_handle-pitch)) 0 0 0 currentColor,
4201
+ calc(-2 * var(--_handle-pitch)) calc(var(--_handle-gap)) 0 0 currentColor,
4202
+ calc(-2 * var(--_handle-pitch)) calc(2 * var(--_handle-gap)) 0 0 currentColor,
4203
+ calc(-2 * var(--_handle-pitch)) calc(3 * var(--_handle-gap)) 0 0 currentColor,
4204
+ calc(-1 * var(--_handle-pitch)) calc(-3 * var(--_handle-gap)) 0 0 currentColor,
4205
+ calc(-1 * var(--_handle-pitch)) calc(-2 * var(--_handle-gap)) 0 0 currentColor,
4206
+ calc(-1 * var(--_handle-pitch)) calc(-1 * var(--_handle-gap)) 0 0 currentColor,
4207
+ calc(-1 * var(--_handle-pitch)) 0 0 0 currentColor,
4208
+ calc(-1 * var(--_handle-pitch)) calc(var(--_handle-gap)) 0 0 currentColor,
4209
+ calc(-1 * var(--_handle-pitch)) calc(2 * var(--_handle-gap)) 0 0 currentColor,
4210
+ calc(-1 * var(--_handle-pitch)) calc(3 * var(--_handle-gap)) 0 0 currentColor,
4211
+ 0 calc(-3 * var(--_handle-gap)) 0 0 currentColor,
4212
+ 0 calc(-2 * var(--_handle-gap)) 0 0 currentColor,
4070
4213
  0 calc(-1 * var(--_handle-gap)) 0 0 currentColor,
4071
- 0 var(--_handle-gap) 0 0 currentColor;
4214
+ 0 calc(var(--_handle-gap)) 0 0 currentColor,
4215
+ 0 calc(2 * var(--_handle-gap)) 0 0 currentColor,
4216
+ 0 calc(3 * var(--_handle-gap)) 0 0 currentColor,
4217
+ calc(var(--_handle-pitch)) calc(-3 * var(--_handle-gap)) 0 0 currentColor,
4218
+ calc(var(--_handle-pitch)) calc(-2 * var(--_handle-gap)) 0 0 currentColor,
4219
+ calc(var(--_handle-pitch)) calc(-1 * var(--_handle-gap)) 0 0 currentColor,
4220
+ calc(var(--_handle-pitch)) 0 0 0 currentColor,
4221
+ calc(var(--_handle-pitch)) calc(var(--_handle-gap)) 0 0 currentColor,
4222
+ calc(var(--_handle-pitch)) calc(2 * var(--_handle-gap)) 0 0 currentColor,
4223
+ calc(var(--_handle-pitch)) calc(3 * var(--_handle-gap)) 0 0 currentColor,
4224
+ calc(2 * var(--_handle-pitch)) calc(-3 * var(--_handle-gap)) 0 0 currentColor,
4225
+ calc(2 * var(--_handle-pitch)) calc(-2 * var(--_handle-gap)) 0 0 currentColor,
4226
+ calc(2 * var(--_handle-pitch)) calc(-1 * var(--_handle-gap)) 0 0 currentColor,
4227
+ calc(2 * var(--_handle-pitch)) 0 0 0 currentColor,
4228
+ calc(2 * var(--_handle-pitch)) calc(var(--_handle-gap)) 0 0 currentColor,
4229
+ calc(2 * var(--_handle-pitch)) calc(2 * var(--_handle-gap)) 0 0 currentColor,
4230
+ calc(2 * var(--_handle-pitch)) calc(3 * var(--_handle-gap)) 0 0 currentColor,
4231
+ calc(3 * var(--_handle-pitch)) calc(-3 * var(--_handle-gap)) 0 0 currentColor,
4232
+ calc(3 * var(--_handle-pitch)) calc(-2 * var(--_handle-gap)) 0 0 currentColor,
4233
+ calc(3 * var(--_handle-pitch)) calc(-1 * var(--_handle-gap)) 0 0 currentColor,
4234
+ calc(3 * var(--_handle-pitch)) 0 0 0 currentColor,
4235
+ calc(3 * var(--_handle-pitch)) calc(var(--_handle-gap)) 0 0 currentColor,
4236
+ calc(3 * var(--_handle-pitch)) calc(2 * var(--_handle-gap)) 0 0 currentColor,
4237
+ calc(3 * var(--_handle-pitch)) calc(3 * var(--_handle-gap)) 0 0 currentColor;
4072
4238
  }
4073
4239
  .ixfx-handle[data-handle='dotted'][data-shape='spot']::before,
4074
4240
  .ixfx-handle[data-handle='dimpled'][data-shape='spot']::before {
@@ -4083,29 +4249,309 @@ const handleStyles = i$3`
4083
4249
  var(--_handle-gap) var(--_handle-gap) 0 0 currentColor;
4084
4250
  }
4085
4251
 
4086
- /* dimpled — each bar mark also gets a lighter copy up-left and a darker copy
4087
- down-right (spot stays plain — the 3D is imperceptible at that size). */
4088
- .ixfx-handle[data-handle='dimpled']:not([data-shape='spot'])::before {
4252
+ /* dimpled — each mark also gets a lighter copy up-left and a darker copy
4253
+ down-right, repeated across up to 7 rows/columns on the cross axis
4254
+ (clipped to --_handle-rows — see above). Spot stays plain — the 3D is
4255
+ imperceptible at that size. */
4256
+ .ixfx-handle[data-handle='dimpled']:not([data-shape='vertical']):not([data-shape='spot'])::before {
4257
+ transform: translate(calc(-50% + var(--_handle-col-shift)), calc(-50% + var(--_handle-row-shift)));
4089
4258
  box-shadow:
4090
4259
  calc(-1 * var(--_dimple-off)) calc(-1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4091
4260
  var(--_dimple-off) var(--_dimple-off) 0 0 var(--_handle-lo),
4261
+ calc(-3 * var(--_handle-gap)) calc(-3 * var(--_handle-pitch)) 0 0 currentColor,
4262
+ calc(-3 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4263
+ calc(-3 * var(--_handle-gap) + var(--_dimple-off)) calc(-3 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4264
+ calc(-2 * var(--_handle-gap)) calc(-3 * var(--_handle-pitch)) 0 0 currentColor,
4265
+ calc(-2 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4266
+ calc(-2 * var(--_handle-gap) + var(--_dimple-off)) calc(-3 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4267
+ calc(-1 * var(--_handle-gap)) calc(-3 * var(--_handle-pitch)) 0 0 currentColor,
4268
+ calc(-1 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4269
+ calc(-1 * var(--_handle-gap) + var(--_dimple-off)) calc(-3 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4270
+ 0 calc(-3 * var(--_handle-pitch)) 0 0 currentColor,
4271
+ calc(-1 * var(--_dimple-off)) calc(-3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4272
+ var(--_dimple-off) calc(-3 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4273
+ calc(var(--_handle-gap)) calc(-3 * var(--_handle-pitch)) 0 0 currentColor,
4274
+ calc(var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4275
+ calc(var(--_handle-gap) + var(--_dimple-off)) calc(-3 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4276
+ calc(2 * var(--_handle-gap)) calc(-3 * var(--_handle-pitch)) 0 0 currentColor,
4277
+ calc(2 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4278
+ calc(2 * var(--_handle-gap) + var(--_dimple-off)) calc(-3 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4279
+ calc(3 * var(--_handle-gap)) calc(-3 * var(--_handle-pitch)) 0 0 currentColor,
4280
+ calc(3 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4281
+ calc(3 * var(--_handle-gap) + var(--_dimple-off)) calc(-3 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4282
+ calc(-3 * var(--_handle-gap)) calc(-2 * var(--_handle-pitch)) 0 0 currentColor,
4283
+ calc(-3 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4284
+ calc(-3 * var(--_handle-gap) + var(--_dimple-off)) calc(-2 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4285
+ calc(-2 * var(--_handle-gap)) calc(-2 * var(--_handle-pitch)) 0 0 currentColor,
4286
+ calc(-2 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4287
+ calc(-2 * var(--_handle-gap) + var(--_dimple-off)) calc(-2 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4288
+ calc(-1 * var(--_handle-gap)) calc(-2 * var(--_handle-pitch)) 0 0 currentColor,
4289
+ calc(-1 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4290
+ calc(-1 * var(--_handle-gap) + var(--_dimple-off)) calc(-2 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4291
+ 0 calc(-2 * var(--_handle-pitch)) 0 0 currentColor,
4292
+ calc(-1 * var(--_dimple-off)) calc(-2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4293
+ var(--_dimple-off) calc(-2 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4294
+ calc(var(--_handle-gap)) calc(-2 * var(--_handle-pitch)) 0 0 currentColor,
4295
+ calc(var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4296
+ calc(var(--_handle-gap) + var(--_dimple-off)) calc(-2 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4297
+ calc(2 * var(--_handle-gap)) calc(-2 * var(--_handle-pitch)) 0 0 currentColor,
4298
+ calc(2 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4299
+ calc(2 * var(--_handle-gap) + var(--_dimple-off)) calc(-2 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4300
+ calc(3 * var(--_handle-gap)) calc(-2 * var(--_handle-pitch)) 0 0 currentColor,
4301
+ calc(3 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4302
+ calc(3 * var(--_handle-gap) + var(--_dimple-off)) calc(-2 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4303
+ calc(-3 * var(--_handle-gap)) calc(-1 * var(--_handle-pitch)) 0 0 currentColor,
4304
+ calc(-3 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-1 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4305
+ calc(-3 * var(--_handle-gap) + var(--_dimple-off)) calc(-1 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4306
+ calc(-2 * var(--_handle-gap)) calc(-1 * var(--_handle-pitch)) 0 0 currentColor,
4307
+ calc(-2 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-1 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4308
+ calc(-2 * var(--_handle-gap) + var(--_dimple-off)) calc(-1 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4309
+ calc(-1 * var(--_handle-gap)) calc(-1 * var(--_handle-pitch)) 0 0 currentColor,
4310
+ calc(-1 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-1 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4311
+ calc(-1 * var(--_handle-gap) + var(--_dimple-off)) calc(-1 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4312
+ 0 calc(-1 * var(--_handle-pitch)) 0 0 currentColor,
4313
+ calc(-1 * var(--_dimple-off)) calc(-1 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4314
+ var(--_dimple-off) calc(-1 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4315
+ calc(var(--_handle-gap)) calc(-1 * var(--_handle-pitch)) 0 0 currentColor,
4316
+ calc(var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-1 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4317
+ calc(var(--_handle-gap) + var(--_dimple-off)) calc(-1 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4318
+ calc(2 * var(--_handle-gap)) calc(-1 * var(--_handle-pitch)) 0 0 currentColor,
4319
+ calc(2 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-1 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4320
+ calc(2 * var(--_handle-gap) + var(--_dimple-off)) calc(-1 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4321
+ calc(3 * var(--_handle-gap)) calc(-1 * var(--_handle-pitch)) 0 0 currentColor,
4322
+ calc(3 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-1 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4323
+ calc(3 * var(--_handle-gap) + var(--_dimple-off)) calc(-1 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4324
+ calc(-3 * var(--_handle-gap)) 0 0 0 currentColor,
4325
+ calc(-3 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4326
+ calc(-3 * var(--_handle-gap) + var(--_dimple-off)) var(--_dimple-off) 0 0 var(--_handle-lo),
4327
+ calc(-2 * var(--_handle-gap)) 0 0 0 currentColor,
4328
+ calc(-2 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4329
+ calc(-2 * var(--_handle-gap) + var(--_dimple-off)) var(--_dimple-off) 0 0 var(--_handle-lo),
4092
4330
  calc(-1 * var(--_handle-gap)) 0 0 0 currentColor,
4093
- calc(-1 * var(--_handle-gap) - var(--_dimple-off)) calc(-1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4331
+ calc(-1 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4094
4332
  calc(-1 * var(--_handle-gap) + var(--_dimple-off)) var(--_dimple-off) 0 0 var(--_handle-lo),
4095
- var(--_handle-gap) 0 0 0 currentColor,
4096
- calc(var(--_handle-gap) - var(--_dimple-off)) calc(-1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4097
- calc(var(--_handle-gap) + var(--_dimple-off)) var(--_dimple-off) 0 0 var(--_handle-lo);
4333
+ calc(var(--_handle-gap)) 0 0 0 currentColor,
4334
+ calc(var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4335
+ calc(var(--_handle-gap) + var(--_dimple-off)) var(--_dimple-off) 0 0 var(--_handle-lo),
4336
+ calc(2 * var(--_handle-gap)) 0 0 0 currentColor,
4337
+ calc(2 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4338
+ calc(2 * var(--_handle-gap) + var(--_dimple-off)) var(--_dimple-off) 0 0 var(--_handle-lo),
4339
+ calc(3 * var(--_handle-gap)) 0 0 0 currentColor,
4340
+ calc(3 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(-1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4341
+ calc(3 * var(--_handle-gap) + var(--_dimple-off)) var(--_dimple-off) 0 0 var(--_handle-lo),
4342
+ calc(-3 * var(--_handle-gap)) calc(var(--_handle-pitch)) 0 0 currentColor,
4343
+ calc(-3 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4344
+ calc(-3 * var(--_handle-gap) + var(--_dimple-off)) calc(var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4345
+ calc(-2 * var(--_handle-gap)) calc(var(--_handle-pitch)) 0 0 currentColor,
4346
+ calc(-2 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4347
+ calc(-2 * var(--_handle-gap) + var(--_dimple-off)) calc(var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4348
+ calc(-1 * var(--_handle-gap)) calc(var(--_handle-pitch)) 0 0 currentColor,
4349
+ calc(-1 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4350
+ calc(-1 * var(--_handle-gap) + var(--_dimple-off)) calc(var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4351
+ 0 calc(var(--_handle-pitch)) 0 0 currentColor,
4352
+ calc(-1 * var(--_dimple-off)) calc(var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4353
+ var(--_dimple-off) calc(var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4354
+ calc(var(--_handle-gap)) calc(var(--_handle-pitch)) 0 0 currentColor,
4355
+ calc(var(--_handle-gap) + -1 * var(--_dimple-off)) calc(var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4356
+ calc(var(--_handle-gap) + var(--_dimple-off)) calc(var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4357
+ calc(2 * var(--_handle-gap)) calc(var(--_handle-pitch)) 0 0 currentColor,
4358
+ calc(2 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4359
+ calc(2 * var(--_handle-gap) + var(--_dimple-off)) calc(var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4360
+ calc(3 * var(--_handle-gap)) calc(var(--_handle-pitch)) 0 0 currentColor,
4361
+ calc(3 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4362
+ calc(3 * var(--_handle-gap) + var(--_dimple-off)) calc(var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4363
+ calc(-3 * var(--_handle-gap)) calc(2 * var(--_handle-pitch)) 0 0 currentColor,
4364
+ calc(-3 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4365
+ calc(-3 * var(--_handle-gap) + var(--_dimple-off)) calc(2 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4366
+ calc(-2 * var(--_handle-gap)) calc(2 * var(--_handle-pitch)) 0 0 currentColor,
4367
+ calc(-2 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4368
+ calc(-2 * var(--_handle-gap) + var(--_dimple-off)) calc(2 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4369
+ calc(-1 * var(--_handle-gap)) calc(2 * var(--_handle-pitch)) 0 0 currentColor,
4370
+ calc(-1 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4371
+ calc(-1 * var(--_handle-gap) + var(--_dimple-off)) calc(2 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4372
+ 0 calc(2 * var(--_handle-pitch)) 0 0 currentColor,
4373
+ calc(-1 * var(--_dimple-off)) calc(2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4374
+ var(--_dimple-off) calc(2 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4375
+ calc(var(--_handle-gap)) calc(2 * var(--_handle-pitch)) 0 0 currentColor,
4376
+ calc(var(--_handle-gap) + -1 * var(--_dimple-off)) calc(2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4377
+ calc(var(--_handle-gap) + var(--_dimple-off)) calc(2 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4378
+ calc(2 * var(--_handle-gap)) calc(2 * var(--_handle-pitch)) 0 0 currentColor,
4379
+ calc(2 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4380
+ calc(2 * var(--_handle-gap) + var(--_dimple-off)) calc(2 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4381
+ calc(3 * var(--_handle-gap)) calc(2 * var(--_handle-pitch)) 0 0 currentColor,
4382
+ calc(3 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4383
+ calc(3 * var(--_handle-gap) + var(--_dimple-off)) calc(2 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4384
+ calc(-3 * var(--_handle-gap)) calc(3 * var(--_handle-pitch)) 0 0 currentColor,
4385
+ calc(-3 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4386
+ calc(-3 * var(--_handle-gap) + var(--_dimple-off)) calc(3 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4387
+ calc(-2 * var(--_handle-gap)) calc(3 * var(--_handle-pitch)) 0 0 currentColor,
4388
+ calc(-2 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4389
+ calc(-2 * var(--_handle-gap) + var(--_dimple-off)) calc(3 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4390
+ calc(-1 * var(--_handle-gap)) calc(3 * var(--_handle-pitch)) 0 0 currentColor,
4391
+ calc(-1 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4392
+ calc(-1 * var(--_handle-gap) + var(--_dimple-off)) calc(3 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4393
+ 0 calc(3 * var(--_handle-pitch)) 0 0 currentColor,
4394
+ calc(-1 * var(--_dimple-off)) calc(3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4395
+ var(--_dimple-off) calc(3 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4396
+ calc(var(--_handle-gap)) calc(3 * var(--_handle-pitch)) 0 0 currentColor,
4397
+ calc(var(--_handle-gap) + -1 * var(--_dimple-off)) calc(3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4398
+ calc(var(--_handle-gap) + var(--_dimple-off)) calc(3 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4399
+ calc(2 * var(--_handle-gap)) calc(3 * var(--_handle-pitch)) 0 0 currentColor,
4400
+ calc(2 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4401
+ calc(2 * var(--_handle-gap) + var(--_dimple-off)) calc(3 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4402
+ calc(3 * var(--_handle-gap)) calc(3 * var(--_handle-pitch)) 0 0 currentColor,
4403
+ calc(3 * var(--_handle-gap) + -1 * var(--_dimple-off)) calc(3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4404
+ calc(3 * var(--_handle-gap) + var(--_dimple-off)) calc(3 * var(--_handle-pitch) + var(--_dimple-off)) 0 0 var(--_handle-lo);
4098
4405
  }
4099
4406
  .ixfx-handle[data-handle='dimpled'][data-shape='vertical']::before {
4407
+ transform: translate(calc(-50% + var(--_handle-row-shift)), calc(-50% + var(--_handle-col-shift)));
4100
4408
  box-shadow:
4101
4409
  calc(-1 * var(--_dimple-off)) calc(-1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4102
4410
  var(--_dimple-off) var(--_dimple-off) 0 0 var(--_handle-lo),
4411
+ calc(-3 * var(--_handle-pitch)) calc(-3 * var(--_handle-gap)) 0 0 currentColor,
4412
+ calc(-3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-3 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4413
+ calc(-3 * var(--_handle-pitch) + var(--_dimple-off)) calc(-3 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4414
+ calc(-3 * var(--_handle-pitch)) calc(-2 * var(--_handle-gap)) 0 0 currentColor,
4415
+ calc(-3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-2 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4416
+ calc(-3 * var(--_handle-pitch) + var(--_dimple-off)) calc(-2 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4417
+ calc(-3 * var(--_handle-pitch)) calc(-1 * var(--_handle-gap)) 0 0 currentColor,
4418
+ calc(-3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-1 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4419
+ calc(-3 * var(--_handle-pitch) + var(--_dimple-off)) calc(-1 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4420
+ calc(-3 * var(--_handle-pitch)) 0 0 0 currentColor,
4421
+ calc(-3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4422
+ calc(-3 * var(--_handle-pitch) + var(--_dimple-off)) var(--_dimple-off) 0 0 var(--_handle-lo),
4423
+ calc(-3 * var(--_handle-pitch)) calc(var(--_handle-gap)) 0 0 currentColor,
4424
+ calc(-3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4425
+ calc(-3 * var(--_handle-pitch) + var(--_dimple-off)) calc(var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4426
+ calc(-3 * var(--_handle-pitch)) calc(2 * var(--_handle-gap)) 0 0 currentColor,
4427
+ calc(-3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(2 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4428
+ calc(-3 * var(--_handle-pitch) + var(--_dimple-off)) calc(2 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4429
+ calc(-3 * var(--_handle-pitch)) calc(3 * var(--_handle-gap)) 0 0 currentColor,
4430
+ calc(-3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(3 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4431
+ calc(-3 * var(--_handle-pitch) + var(--_dimple-off)) calc(3 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4432
+ calc(-2 * var(--_handle-pitch)) calc(-3 * var(--_handle-gap)) 0 0 currentColor,
4433
+ calc(-2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-3 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4434
+ calc(-2 * var(--_handle-pitch) + var(--_dimple-off)) calc(-3 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4435
+ calc(-2 * var(--_handle-pitch)) calc(-2 * var(--_handle-gap)) 0 0 currentColor,
4436
+ calc(-2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-2 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4437
+ calc(-2 * var(--_handle-pitch) + var(--_dimple-off)) calc(-2 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4438
+ calc(-2 * var(--_handle-pitch)) calc(-1 * var(--_handle-gap)) 0 0 currentColor,
4439
+ calc(-2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-1 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4440
+ calc(-2 * var(--_handle-pitch) + var(--_dimple-off)) calc(-1 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4441
+ calc(-2 * var(--_handle-pitch)) 0 0 0 currentColor,
4442
+ calc(-2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4443
+ calc(-2 * var(--_handle-pitch) + var(--_dimple-off)) var(--_dimple-off) 0 0 var(--_handle-lo),
4444
+ calc(-2 * var(--_handle-pitch)) calc(var(--_handle-gap)) 0 0 currentColor,
4445
+ calc(-2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4446
+ calc(-2 * var(--_handle-pitch) + var(--_dimple-off)) calc(var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4447
+ calc(-2 * var(--_handle-pitch)) calc(2 * var(--_handle-gap)) 0 0 currentColor,
4448
+ calc(-2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(2 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4449
+ calc(-2 * var(--_handle-pitch) + var(--_dimple-off)) calc(2 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4450
+ calc(-2 * var(--_handle-pitch)) calc(3 * var(--_handle-gap)) 0 0 currentColor,
4451
+ calc(-2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(3 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4452
+ calc(-2 * var(--_handle-pitch) + var(--_dimple-off)) calc(3 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4453
+ calc(-1 * var(--_handle-pitch)) calc(-3 * var(--_handle-gap)) 0 0 currentColor,
4454
+ calc(-1 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-3 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4455
+ calc(-1 * var(--_handle-pitch) + var(--_dimple-off)) calc(-3 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4456
+ calc(-1 * var(--_handle-pitch)) calc(-2 * var(--_handle-gap)) 0 0 currentColor,
4457
+ calc(-1 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-2 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4458
+ calc(-1 * var(--_handle-pitch) + var(--_dimple-off)) calc(-2 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4459
+ calc(-1 * var(--_handle-pitch)) calc(-1 * var(--_handle-gap)) 0 0 currentColor,
4460
+ calc(-1 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-1 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4461
+ calc(-1 * var(--_handle-pitch) + var(--_dimple-off)) calc(-1 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4462
+ calc(-1 * var(--_handle-pitch)) 0 0 0 currentColor,
4463
+ calc(-1 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4464
+ calc(-1 * var(--_handle-pitch) + var(--_dimple-off)) var(--_dimple-off) 0 0 var(--_handle-lo),
4465
+ calc(-1 * var(--_handle-pitch)) calc(var(--_handle-gap)) 0 0 currentColor,
4466
+ calc(-1 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4467
+ calc(-1 * var(--_handle-pitch) + var(--_dimple-off)) calc(var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4468
+ calc(-1 * var(--_handle-pitch)) calc(2 * var(--_handle-gap)) 0 0 currentColor,
4469
+ calc(-1 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(2 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4470
+ calc(-1 * var(--_handle-pitch) + var(--_dimple-off)) calc(2 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4471
+ calc(-1 * var(--_handle-pitch)) calc(3 * var(--_handle-gap)) 0 0 currentColor,
4472
+ calc(-1 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(3 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4473
+ calc(-1 * var(--_handle-pitch) + var(--_dimple-off)) calc(3 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4474
+ 0 calc(-3 * var(--_handle-gap)) 0 0 currentColor,
4475
+ calc(-1 * var(--_dimple-off)) calc(-3 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4476
+ var(--_dimple-off) calc(-3 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4477
+ 0 calc(-2 * var(--_handle-gap)) 0 0 currentColor,
4478
+ calc(-1 * var(--_dimple-off)) calc(-2 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4479
+ var(--_dimple-off) calc(-2 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4103
4480
  0 calc(-1 * var(--_handle-gap)) 0 0 currentColor,
4104
- calc(-1 * var(--_dimple-off)) calc(-1 * var(--_handle-gap) - var(--_dimple-off)) 0 0 var(--_handle-hi),
4481
+ calc(-1 * var(--_dimple-off)) calc(-1 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4105
4482
  var(--_dimple-off) calc(-1 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4106
- 0 var(--_handle-gap) 0 0 currentColor,
4107
- calc(-1 * var(--_dimple-off)) calc(var(--_handle-gap) - var(--_dimple-off)) 0 0 var(--_handle-hi),
4108
- var(--_dimple-off) calc(var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo);
4483
+ 0 calc(var(--_handle-gap)) 0 0 currentColor,
4484
+ calc(-1 * var(--_dimple-off)) calc(var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4485
+ var(--_dimple-off) calc(var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4486
+ 0 calc(2 * var(--_handle-gap)) 0 0 currentColor,
4487
+ calc(-1 * var(--_dimple-off)) calc(2 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4488
+ var(--_dimple-off) calc(2 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4489
+ 0 calc(3 * var(--_handle-gap)) 0 0 currentColor,
4490
+ calc(-1 * var(--_dimple-off)) calc(3 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4491
+ var(--_dimple-off) calc(3 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4492
+ calc(var(--_handle-pitch)) calc(-3 * var(--_handle-gap)) 0 0 currentColor,
4493
+ calc(var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-3 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4494
+ calc(var(--_handle-pitch) + var(--_dimple-off)) calc(-3 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4495
+ calc(var(--_handle-pitch)) calc(-2 * var(--_handle-gap)) 0 0 currentColor,
4496
+ calc(var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-2 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4497
+ calc(var(--_handle-pitch) + var(--_dimple-off)) calc(-2 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4498
+ calc(var(--_handle-pitch)) calc(-1 * var(--_handle-gap)) 0 0 currentColor,
4499
+ calc(var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-1 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4500
+ calc(var(--_handle-pitch) + var(--_dimple-off)) calc(-1 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4501
+ calc(var(--_handle-pitch)) 0 0 0 currentColor,
4502
+ calc(var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4503
+ calc(var(--_handle-pitch) + var(--_dimple-off)) var(--_dimple-off) 0 0 var(--_handle-lo),
4504
+ calc(var(--_handle-pitch)) calc(var(--_handle-gap)) 0 0 currentColor,
4505
+ calc(var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4506
+ calc(var(--_handle-pitch) + var(--_dimple-off)) calc(var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4507
+ calc(var(--_handle-pitch)) calc(2 * var(--_handle-gap)) 0 0 currentColor,
4508
+ calc(var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(2 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4509
+ calc(var(--_handle-pitch) + var(--_dimple-off)) calc(2 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4510
+ calc(var(--_handle-pitch)) calc(3 * var(--_handle-gap)) 0 0 currentColor,
4511
+ calc(var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(3 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4512
+ calc(var(--_handle-pitch) + var(--_dimple-off)) calc(3 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4513
+ calc(2 * var(--_handle-pitch)) calc(-3 * var(--_handle-gap)) 0 0 currentColor,
4514
+ calc(2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-3 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4515
+ calc(2 * var(--_handle-pitch) + var(--_dimple-off)) calc(-3 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4516
+ calc(2 * var(--_handle-pitch)) calc(-2 * var(--_handle-gap)) 0 0 currentColor,
4517
+ calc(2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-2 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4518
+ calc(2 * var(--_handle-pitch) + var(--_dimple-off)) calc(-2 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4519
+ calc(2 * var(--_handle-pitch)) calc(-1 * var(--_handle-gap)) 0 0 currentColor,
4520
+ calc(2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-1 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4521
+ calc(2 * var(--_handle-pitch) + var(--_dimple-off)) calc(-1 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4522
+ calc(2 * var(--_handle-pitch)) 0 0 0 currentColor,
4523
+ calc(2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4524
+ calc(2 * var(--_handle-pitch) + var(--_dimple-off)) var(--_dimple-off) 0 0 var(--_handle-lo),
4525
+ calc(2 * var(--_handle-pitch)) calc(var(--_handle-gap)) 0 0 currentColor,
4526
+ calc(2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4527
+ calc(2 * var(--_handle-pitch) + var(--_dimple-off)) calc(var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4528
+ calc(2 * var(--_handle-pitch)) calc(2 * var(--_handle-gap)) 0 0 currentColor,
4529
+ calc(2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(2 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4530
+ calc(2 * var(--_handle-pitch) + var(--_dimple-off)) calc(2 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4531
+ calc(2 * var(--_handle-pitch)) calc(3 * var(--_handle-gap)) 0 0 currentColor,
4532
+ calc(2 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(3 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4533
+ calc(2 * var(--_handle-pitch) + var(--_dimple-off)) calc(3 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4534
+ calc(3 * var(--_handle-pitch)) calc(-3 * var(--_handle-gap)) 0 0 currentColor,
4535
+ calc(3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-3 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4536
+ calc(3 * var(--_handle-pitch) + var(--_dimple-off)) calc(-3 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4537
+ calc(3 * var(--_handle-pitch)) calc(-2 * var(--_handle-gap)) 0 0 currentColor,
4538
+ calc(3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-2 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4539
+ calc(3 * var(--_handle-pitch) + var(--_dimple-off)) calc(-2 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4540
+ calc(3 * var(--_handle-pitch)) calc(-1 * var(--_handle-gap)) 0 0 currentColor,
4541
+ calc(3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-1 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4542
+ calc(3 * var(--_handle-pitch) + var(--_dimple-off)) calc(-1 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4543
+ calc(3 * var(--_handle-pitch)) 0 0 0 currentColor,
4544
+ calc(3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(-1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4545
+ calc(3 * var(--_handle-pitch) + var(--_dimple-off)) var(--_dimple-off) 0 0 var(--_handle-lo),
4546
+ calc(3 * var(--_handle-pitch)) calc(var(--_handle-gap)) 0 0 currentColor,
4547
+ calc(3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4548
+ calc(3 * var(--_handle-pitch) + var(--_dimple-off)) calc(var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4549
+ calc(3 * var(--_handle-pitch)) calc(2 * var(--_handle-gap)) 0 0 currentColor,
4550
+ calc(3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(2 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4551
+ calc(3 * var(--_handle-pitch) + var(--_dimple-off)) calc(2 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo),
4552
+ calc(3 * var(--_handle-pitch)) calc(3 * var(--_handle-gap)) 0 0 currentColor,
4553
+ calc(3 * var(--_handle-pitch) + -1 * var(--_dimple-off)) calc(3 * var(--_handle-gap) + -1 * var(--_dimple-off)) 0 0 var(--_handle-hi),
4554
+ calc(3 * var(--_handle-pitch) + var(--_dimple-off)) calc(3 * var(--_handle-gap) + var(--_dimple-off)) 0 0 var(--_handle-lo);
4109
4555
  }
4110
4556
 
4111
4557
  /* ── grated: fine 45° knurling — each ridge is a lit edge, the base colour,
@@ -5021,71 +5467,41 @@ __decorate([state()], BottomDrawerElement.prototype, "_dragHeight", void 0);
5021
5467
  BottomDrawerElement = __decorate([safeCustomElement(`ixfx-bottom-drawer`)], BottomDrawerElement);
5022
5468
  //#endregion
5023
5469
  //#region src/icons/defaults.ts
5470
+ /** Chevron pointing down (Lucide `chevron-down`). Used for split-button dropdown toggle. */
5471
+ const ICON_CHEVRON_DOWN = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg>`;
5024
5472
  /**
5025
- * Chevron pointing down. Used for split-button dropdown toggle.
5026
- * fill="currentColor" so it inherits CSS color.
5027
- */
5028
- const ICON_CHEVRON_DOWN = `<svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"/></svg>`;
5029
- /**
5030
- * Caret pointing right. Used for tree-basic expand indicator as a CSS mask.
5031
- * fill="black" is correct for CSS mask-image use (shape only, color comes from background-color).
5032
- */
5033
- const ICON_CARET_RIGHT = `<svg viewBox="0 0 24 24" fill="black" xmlns="http://www.w3.org/2000/svg"><path d="M10 7l6 5-6 5V7z"/></svg>`;
5034
- /**
5035
- * Checkmark. Useful for menu-check-item or confirmation states.
5036
- * fill="currentColor" so it inherits CSS color.
5037
- */
5038
- const ICON_CHECK = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"/></svg>`;
5039
- /**
5040
- * Close / X icon. Useful for dialogs, notifications, dismissible elements.
5041
- * fill="currentColor" so it inherits CSS color.
5042
- */
5043
- const ICON_CLOSE = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/></svg>`;
5044
- /**
5045
- * Plus / add icon. Pairs with `close` for add/remove actions.
5046
- * fill="currentColor" so it inherits CSS color.
5047
- */
5048
- const ICON_ADD = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>`;
5049
- /**
5050
- * Error / warning icon. Useful for error notifications.
5051
- * fill="currentColor" so it inherits CSS color.
5052
- */
5053
- const ICON_ERROR = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/></svg>`;
5054
- /**
5055
- * Info icon. Useful for info notifications.
5056
- * fill="currentColor" so it inherits CSS color.
5057
- */
5058
- const ICON_INFO = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg>`;
5059
- /**
5060
- * Warning icon. Useful for warning notifications.
5061
- * fill="currentColor" so it inherits CSS color.
5062
- */
5063
- const ICON_WARNING = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></svg>`;
5064
- /**
5065
- * Chevron pointing right. Used for split-button switcher toggle.
5066
- * fill="currentColor" so it inherits CSS color.
5067
- */
5068
- const ICON_CHEVRON_RIGHT = `<svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"/></svg>`;
5069
- /**
5070
- * Folder with up arrow. Angled line style for navigating up one level.
5071
- * fill="currentColor" so it inherits CSS color.
5072
- */
5073
- const ICON_FOLDER_UP = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 4L4 12h5v8h6v-8h5L12 4z"/></svg>`;
5074
- /**
5075
- * Folder. Useful for file explorers and sidebars.
5076
- * fill="currentColor" so it inherits CSS color.
5077
- */
5078
- const ICON_FOLDER = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 1.99-.9 1.99-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/></svg>`;
5079
- /**
5080
- * Document / file page. Useful for file lists and document tabs.
5081
- * fill="currentColor" so it inherits CSS color.
5473
+ * Chevron pointing right (Lucide `chevron-right`). Used for tree-basic expand
5474
+ * indicator as a CSS mask — shape only, color comes from background-color.
5082
5475
  */
5083
- const ICON_FILE = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"/></svg>`;
5084
- /**
5085
- * Magnifying glass. Useful for search panels and inputs.
5086
- * fill="currentColor" so it inherits CSS color.
5087
- */
5088
- const ICON_SEARCH = `<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>`;
5476
+ const ICON_CARET_RIGHT = `<svg viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><path d="m9 18 6-6-6-6"/></svg>`;
5477
+ /** Checkmark (Lucide `check`). Useful for menu-check-item or confirmation states. */
5478
+ const ICON_CHECK = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>`;
5479
+ /** Close / X icon (Lucide `x`). Useful for dialogs, notifications, dismissible elements. */
5480
+ const ICON_CLOSE = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>`;
5481
+ /** Plus / add icon (Lucide `plus`). Pairs with `close` for add/remove actions. */
5482
+ const ICON_ADD = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14"/><path d="M12 5v14"/></svg>`;
5483
+ /** Error icon (Lucide `circle-alert`). Useful for error notifications. */
5484
+ const ICON_ERROR = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" x2="12" y1="8" y2="12"/><line x1="12" x2="12.01" y1="16" y2="16"/></svg>`;
5485
+ /** Info icon (Lucide `info`). Useful for info notifications. */
5486
+ const ICON_INFO = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>`;
5487
+ /** Warning icon (Lucide `triangle-alert`). Useful for warning notifications. */
5488
+ const ICON_WARNING = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m21.73 18-8-14a2 2 0 0 0-3.46 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>`;
5489
+ /** Chevron pointing right (Lucide `chevron-right`). Used for split-button switcher toggle. */
5490
+ const ICON_CHEVRON_RIGHT = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 18 6-6-6-6"/></svg>`;
5491
+ /** Folder with up arrow (Lucide `folder-up`). Angled line style for navigating up one level. */
5492
+ const ICON_FOLDER_UP = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 9V5c0-1.1.9-2 2-2h3.93a2 2 0 0 1 1.66.9l.82 1.2a2 2 0 0 0 1.66.9H20a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-1"/><path d="M12 10v6"/><path d="m9 13 3-3 3 3"/></svg>`;
5493
+ /** Folder (Lucide `folder`). Useful for file explorers and sidebars. */
5494
+ const ICON_FOLDER = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"/></svg>`;
5495
+ /** Document / file page (Lucide `file`). Useful for file lists and document tabs. */
5496
+ const ICON_FILE = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/></svg>`;
5497
+ /** Magnifying glass (Lucide `search`). Useful for search panels and inputs. */
5498
+ const ICON_SEARCH = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>`;
5499
+ /** Chevron pointing up (Lucide `chevron-up`). Sort/collapse direction indicators. */
5500
+ const ICON_CHEVRON_UP = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m18 15-6-6-6 6"/></svg>`;
5501
+ /** Chevron pointing left (Lucide `chevron-left`). Previous/back affordances. */
5502
+ const ICON_CHEVRON_LEFT = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m15 18-6-6 6-6"/></svg>`;
5503
+ /** Vertical ellipsis (Lucide `ellipsis-vertical`). Default glyph for an unlabelled menu trigger. */
5504
+ const ICON_ELLIPSIS_VERTICAL = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg>`;
5089
5505
  function registerDefaults() {
5090
5506
  registerIcon(`chevron-down`, ICON_CHEVRON_DOWN);
5091
5507
  registerIcon(`chevron-right`, ICON_CHEVRON_RIGHT);
@@ -5100,6 +5516,9 @@ function registerDefaults() {
5100
5516
  registerIcon(`folder-up`, ICON_FOLDER_UP);
5101
5517
  registerIcon(`info`, ICON_INFO);
5102
5518
  registerIcon(`warning`, ICON_WARNING);
5519
+ registerIcon(`chevron-up`, ICON_CHEVRON_UP);
5520
+ registerIcon(`chevron-left`, ICON_CHEVRON_LEFT);
5521
+ registerIcon(`ellipsis-vertical`, ICON_ELLIPSIS_VERTICAL);
5103
5522
  }
5104
5523
  //#endregion
5105
5524
  //#region src/icons/index.ts
@@ -7375,7 +7794,7 @@ let MenuTrigger = class MenuTrigger extends i {
7375
7794
  constructor(..._args) {
7376
7795
  super(..._args);
7377
7796
  this.mode = `trigger`;
7378
- this.label = `⋮`;
7797
+ this.label = ``;
7379
7798
  this.iconName = ``;
7380
7799
  this.placement = `bottom-start`;
7381
7800
  this.tabStop = true;
@@ -7662,7 +8081,7 @@ let MenuTrigger = class MenuTrigger extends i {
7662
8081
  @click=${this._handleTriggerClick}
7663
8082
  @contextmenu=${this._handleContextMenu}
7664
8083
  >
7665
- ${showButton ? b`<button class="trigger-btn" part="base" tabindex=${this.tabStop ? `0` : `-1`}>${this.iconName ? b`<ixfx-icon name=${this.iconName}></ixfx-icon>` : this.label}</button>` : null}
8084
+ ${showButton ? b`<button class="trigger-btn" part="base" tabindex=${this.tabStop ? `0` : `-1`}>${this.iconName ? b`<ixfx-icon name=${this.iconName}></ixfx-icon>` : this.label || b`<ixfx-icon name="ellipsis-vertical"></ixfx-icon>`}</button>` : null}
7666
8085
  <slot name="trigger" @slotchange=${this._handleTriggerSlotChange}></slot>
7667
8086
  </div>
7668
8087
  <div
@@ -10204,8 +10623,21 @@ var TreeDataModel = class {
10204
10623
  * Apply the returned `.scroll-fade-x` / `.scroll-fade-y` class to
10205
10624
  * whichever element actually has `overflow` scrolling on that axis.
10206
10625
  *
10626
+ * NOTE: apply only one axis class per element. Each class sets
10627
+ * `mask-image`, so putting both on the same element makes the second
10628
+ * overwrite the first. An element that scrolls on both axes at once (e.g.
10629
+ * a grid viewport with `overflow: auto`) should use the vertical fade on
10630
+ * the viewport itself and handle the horizontal axis separately (e.g. a
10631
+ * synced header strip with its own `scroll-fade-x`).
10632
+ *
10207
10633
  * CSS variables:
10208
10634
  * - `--scroll-fade-width` (default `30px`): how far the fade extends from each edge.
10635
+ * - `--scroll-fade-strength` (default `1`): how completely content fades out
10636
+ * at the edge, `0`–`1`. `1` fades to fully transparent (current behaviour);
10637
+ * `0` disables the fade entirely. Dense layouts (e.g. a data grid) typically
10638
+ * want something like `0.7`–`0.8` so the edge row stays partly readable.
10639
+ * Deliberately *not* `@property`-registered, so it inherits normally and a
10640
+ * consumer override on the host reaches the shadow-DOM scroller.
10209
10641
  *
10210
10642
  * ```ts
10211
10643
  * import { scrollFadeStyles } from '../styles/scroll-fade.js';
@@ -10248,9 +10680,9 @@ function scrollFadeStyles(axis) {
10248
10680
  animation: ${r$2(keyframesName)};
10249
10681
  animation-timeline: ${r$2(timeline)};
10250
10682
  mask-image: linear-gradient(${r$2(gradientDirection)},
10251
- transparent,
10683
+ rgb(0 0 0 / calc(1 - var(--scroll-fade-strength, 1))),
10252
10684
  black var(${r$2(start)}, 0px) calc(100% - var(${r$2(end)}, 0px)),
10253
- transparent
10685
+ rgb(0 0 0 / calc(1 - var(--scroll-fade-strength, 1)))
10254
10686
  );
10255
10687
  }
10256
10688
  `;
@@ -13323,7 +13755,8 @@ let MenuCheckItem = class MenuCheckItem extends i {
13323
13755
  .check {
13324
13756
  width: 1em;
13325
13757
  margin-left: var(--space-xs);
13326
- font-size: var(--text-m);
13758
+ display: inline-flex;
13759
+ align-items: center;
13327
13760
  color: var(--accent);
13328
13761
  }
13329
13762
 
@@ -13366,7 +13799,7 @@ let MenuCheckItem = class MenuCheckItem extends i {
13366
13799
  role="menuitemcheckbox"
13367
13800
  aria-checked="${this.checked}"
13368
13801
  >
13369
- <span class="check">${this.checked ? `✓` : ``}</span>
13802
+ <span class="check">${this.checked ? b`<ixfx-icon name="check" size="14"></ixfx-icon>` : ``}</span>
13370
13803
  <span class="icon-slot">${resolvedIcon ? b`<ixfx-icon name="${resolvedIcon}"></ixfx-icon>` : null}</span>
13371
13804
  <span class="label">${this._resolvedLabel()}</span>
13372
13805
  ${shortcut ? b`<span class="shortcut">${shortcut}</span>` : null}
@@ -14489,6 +14922,8 @@ let DataGridElement = class DataGridElement extends i {
14489
14922
  tickledItemStyles,
14490
14923
  listItemFadeKeyframes,
14491
14924
  listSearchStyles,
14925
+ scrollFadeStyles(`x`),
14926
+ scrollFadeStyles(`y`),
14492
14927
  i$3`
14493
14928
  :host {
14494
14929
  --data-grid-row-height: 28px;
@@ -14505,6 +14940,11 @@ let DataGridElement = class DataGridElement extends i {
14505
14940
  autoSizeColumn(). Read back in JS (_columnResizeAnimationMs) to know
14506
14941
  when the animation has finished, so keep it a plain time value. */
14507
14942
  --data-grid-column-resize-duration: 180ms;
14943
+ /* Dense 28px rows read badly under the global 30px full-strength fade,
14944
+ so default to a shorter, shallower edge hint. Consumers can override
14945
+ --scroll-fade-width / --scroll-fade-strength per instance. */
14946
+ --scroll-fade-width: 20px;
14947
+ --scroll-fade-strength: 0.8;
14508
14948
  position: relative;
14509
14949
  display: block;
14510
14950
  overflow: hidden;
@@ -14524,6 +14964,9 @@ let DataGridElement = class DataGridElement extends i {
14524
14964
  }
14525
14965
  .header-scroll {
14526
14966
  display: flex; flex: 1; overflow: hidden;
14967
+ /* Horizontal edge fade comes from the shared .scroll-fade-x class
14968
+ (see ../styles/scroll-fade.ts). Its scrollLeft is synced from the
14969
+ viewport in _onScroll, which drives its own scroll-timeline. */
14527
14970
  }
14528
14971
  .header-cell {
14529
14972
  display: flex; align-items: center; gap: var(--space-xs);
@@ -14542,7 +14985,7 @@ let DataGridElement = class DataGridElement extends i {
14542
14985
  .header-cell.width-animating, .cell.width-animating { transition: none; }
14543
14986
  }
14544
14987
  .header-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
14545
- .sort-icon { font-size: 10px; opacity: 0.7; }
14988
+ .sort-icon { display: inline-flex; align-items: center; opacity: 0.7; }
14546
14989
  .resize-handle {
14547
14990
  position: absolute; right: -4px; top: 0; bottom: 0; width: 8px; cursor: col-resize; z-index: 1;
14548
14991
  display: flex; align-items: stretch; justify-content: center;
@@ -14553,10 +14996,16 @@ let DataGridElement = class DataGridElement extends i {
14553
14996
  }
14554
14997
  .resize-handle:hover::before { background: var(--split-gutter-hover-color, var(--surface-6)); }
14555
14998
  .resize-handle[data-active]::before { background: var(--split-gutter-active-color, var(--accent)); }
14556
- .reorder-handle { cursor: grab; opacity: 0.5; display: inline-flex; align-items: center; }
14999
+ .reorder-handle { cursor: grab; opacity: 0; display: inline-flex; align-items: center; transition: opacity var(--transition, 0.15s ease-out); }
15000
+ .header-cell:hover .reorder-handle, .header-cell:focus-within .reorder-handle, .header-cell[drag-source] .reorder-handle { opacity: var(--ixfx-handle-opacity, 0.5); }
14557
15001
  .reorder-handle .ixfx-handle { --ixfx-handle-length: 14px; --ixfx-handle-thickness: var(--data-grid-reorder-handle-width, 10px); --ixfx-handle-dot-size: 3px; }
14558
15002
  .flyout-trigger { flex-shrink: 0; width: 36px; display: flex; align-items: center; justify-content: center; cursor: pointer; border-left: var(--border-subtle); background: var(--data-grid-header-bg); }
14559
15003
  .viewport { flex: 1; overflow: auto; position: relative; }
15004
+ /* Vertical edge fade from the shared .scroll-fade-y class
15005
+ (see ../styles/scroll-fade.ts). The mask lives on the viewport —
15006
+ below the header bar — so the top fade never covers the column
15007
+ headers. Reach/strength tune via --scroll-fade-width /
15008
+ --scroll-fade-strength (defaults set on :host above). */
14560
15009
  .spacer { position: relative; }
14561
15010
  .row.item {
14562
15011
  position: absolute; left: 0; right: 0; display: flex; align-items: stretch;
@@ -15598,7 +16047,7 @@ let DataGridElement = class DataGridElement extends i {
15598
16047
  return b`
15599
16048
  <div class="grid">
15600
16049
  <div class="header-bar">
15601
- <div class="header-scroll">
16050
+ <div class="header-scroll scroll-fade-x">
15602
16051
  ${showCheckbox ? b`<div class="header-cell checkbox-col"></div>` : A}
15603
16052
  ${repeat(this._visibleColumns, (c) => c.key, (col, idx) => b`
15604
16053
  <div class="header-cell ${this._animatingColKeys.has(col.key) ? `width-animating` : ``}" style="width:${col.width ?? 150}px" ?drag-source=${this._drag?.active && this._drag.sourceCol.key === col.key}
@@ -15608,7 +16057,7 @@ let DataGridElement = class DataGridElement extends i {
15608
16057
  @pointerdown=${(e) => this._beginHeaderDrag(e, col, idx)}
15609
16058
  ><span class="ixfx-handle" data-handle="dotted" data-shape="vertical" part="reorder-handle"></span></span>` : A}
15610
16059
  <span class="header-label">${col.label}</span>
15611
- ${this.sortState?.key === col.key ? b`<span class="sort-icon">${this.sortState.direction === `asc` ? `▲` : `▼`}</span>` : A}
16060
+ ${this.sortState?.key === col.key ? b`<span class="sort-icon"><ixfx-icon name=${this.sortState.direction === `asc` ? `chevron-up` : `chevron-down`} size="12"></ixfx-icon></span>` : A}
15612
16061
  ${col.resizable !== false ? b`<span class="resize-handle" ?data-active=${this._resizingColKey === col.key} @pointerdown=${(e) => this._onResizePointerDown(e, col)} @click=${(e) => e.stopPropagation()} @dblclick=${(e) => {
15613
16062
  e.preventDefault();
15614
16063
  e.stopPropagation();
@@ -15665,14 +16114,14 @@ let DataGridElement = class DataGridElement extends i {
15665
16114
  </ixfx-menu-container>
15666
16115
  </ixfx-menu-trigger>`}
15667
16116
  </div>
15668
- <div class="viewport" @scroll=${this._onScroll}>
16117
+ <div class="viewport scroll-fade-y" @scroll=${this._onScroll}>
15669
16118
  <div class="spacer" style="height:${this._flat.length * rh}px; width:${this._colWidthSum}px">
15670
16119
  ${repeat(visibleFlat, (f) => f.key, (entry, i) => {
15671
16120
  const absIdx = startRow + i;
15672
16121
  if (entry.type === `group`) {
15673
16122
  const gKey = entry.key.replace(/^__group__/, ``);
15674
16123
  const collapsed = this._collapsedGroups.has(gKey);
15675
- return b`<div class="group-row ${collapsed ? `collapsed` : ``}" style="top:${absIdx * rh}px; height:${rh}px" @click=${() => this._toggleGroup(gKey)}><span class="caret">▼</span><span>${entry.label}</span><span class="count">(${entry.count})</span><span class="divider"></span></div>`;
16124
+ return b`<div class="group-row ${collapsed ? `collapsed` : ``}" style="top:${absIdx * rh}px; height:${rh}px" @click=${() => this._toggleGroup(gKey)}><span class="caret"><ixfx-icon name="chevron-down" size="12"></ixfx-icon></span><span>${entry.label}</span><span class="count">(${entry.count})</span><span class="divider"></span></div>`;
15676
16125
  }
15677
16126
  const row = entry.row;
15678
16127
  const absIdx2 = entry.idx;
@@ -23333,6 +23782,16 @@ let GridListElement = class GridListElement extends i {
23333
23782
  });
23334
23783
  this.#scheduleSnap();
23335
23784
  };
23785
+ this.#onWheel = (e) => {
23786
+ if (this.orientation !== `row`) return;
23787
+ if (e.ctrlKey || e.metaKey) return;
23788
+ if (e.deltaY === 0) return;
23789
+ const vp = this.#viewportRef.value ?? e.currentTarget;
23790
+ if (!vp) return;
23791
+ if (vp.scrollWidth <= vp.clientWidth + 1) return;
23792
+ vp.scrollLeft += e.deltaX + e.deltaY;
23793
+ e.preventDefault();
23794
+ };
23336
23795
  this._onKeyDown = (e) => {
23337
23796
  if ((e.ctrlKey || e.metaKey) && e.key === `f`) return;
23338
23797
  if ((e.ctrlKey || e.metaKey) && e.key === `a`) {
@@ -24515,6 +24974,7 @@ let GridListElement = class GridListElement extends i {
24515
24974
  ${ref(this.#viewportRef)}
24516
24975
  data-input-mode=${this.tickled.inputMode}
24517
24976
  @scroll=${this.#onScroll}
24977
+ @wheel=${this.#onWheel}
24518
24978
  >
24519
24979
  <div class="spacer" style=${spacerStyle}>
24520
24980
  ${this.#source instanceof DataGridListSource ? this.#renderDataCells(win) : this.#renderElementCells(win)}
@@ -24652,6 +25112,17 @@ let GridListElement = class GridListElement extends i {
24652
25112
  `;
24653
25113
  }
24654
25114
  #onScroll;
25115
+ /**
25116
+ * Translate vertical wheel deltas into horizontal scroll when the list runs
25117
+ * in `row` orientation. Without this the default browser behaviour needs
25118
+ * Shift+wheel or a physical horizontal wheel — neither of which most users
25119
+ * reach for on a single-row strip.
25120
+ *
25121
+ * Only kicks in for a plain vertical wheel over a viewport that can actually
25122
+ * scroll horizontally; native horizontal deltas (trackpad, Shift+wheel) are
25123
+ * left to the browser when there is no vertical component.
25124
+ */
25125
+ #onWheel;
24655
25126
  #cancelScrollRaf() {
24656
25127
  if (this.#scrollRaf !== 0) {
24657
25128
  cancelAnimationFrame(this.#scrollRaf);
@@ -25554,6 +26025,7 @@ let TreeBaseElement = class TreeBaseElement extends i {
25554
26025
  this.itemDnd = `none`;
25555
26026
  this.dndExpandHoverMs = 500;
25556
26027
  this.reorderable = true;
26028
+ this.stickyHeaders = true;
25557
26029
  this.applyInternalDrop = true;
25558
26030
  this._expandedKeys = /* @__PURE__ */ new Set();
25559
26031
  this.tickled = new TickledController(this, {
@@ -25586,6 +26058,18 @@ let TreeBaseElement = class TreeBaseElement extends i {
25586
26058
  this.#onContainerScroll = () => {
25587
26059
  this.#rowsCache = void 0;
25588
26060
  };
26061
+ this.#onStickyScroll = () => {
26062
+ if (this.#stickyRaf !== 0) return;
26063
+ this.#stickyRaf = requestAnimationFrame(() => {
26064
+ this.#stickyRaf = 0;
26065
+ this.#updateStickyHeaders();
26066
+ });
26067
+ };
26068
+ this._stickyKeys = [];
26069
+ this.#stickyEntries = /* @__PURE__ */ new Map();
26070
+ this.#stickyDirty = true;
26071
+ this.#stickyRaf = 0;
26072
+ this.#stickyScrollBound = false;
25589
26073
  this.#onKeyDown = (event) => {
25590
26074
  if (this.search.isOpen) return;
25591
26075
  const nodes = this.#getAllNodes();
@@ -25689,7 +26173,7 @@ let TreeBaseElement = class TreeBaseElement extends i {
25689
26173
  }
25690
26174
  };
25691
26175
  this.#onDblClick = (e) => {
25692
- const li = e.target.closest(`li`);
26176
+ const li = e.target.closest(`ul.tree-list li`);
25693
26177
  if (!li) return;
25694
26178
  const key = li.dataset.key;
25695
26179
  if (!key) return;
@@ -25751,6 +26235,157 @@ let TreeBaseElement = class TreeBaseElement extends i {
25751
26235
  /** Per-drag cache of measured rows; invalidated on scroll / update. */
25752
26236
  #rowsCache;
25753
26237
  #onContainerScroll;
26238
+ /** Bind the sticky scroll listener once the container exists; unbind on opt-out. */
26239
+ #syncStickyScroll() {
26240
+ const container = this.#container();
26241
+ if (this.stickyHeaders && container) {
26242
+ if (!this.#stickyScrollBound || this.#stickyScrollContainer !== container) {
26243
+ this.#stickyScrollContainer?.removeEventListener(`scroll`, this.#onStickyScroll);
26244
+ container.addEventListener(`scroll`, this.#onStickyScroll, { passive: true });
26245
+ this.#stickyScrollContainer = container;
26246
+ this.#stickyScrollBound = true;
26247
+ }
26248
+ } else if (this.#stickyScrollBound) {
26249
+ this.#stickyScrollContainer?.removeEventListener(`scroll`, this.#onStickyScroll);
26250
+ this.#stickyScrollContainer = void 0;
26251
+ this.#stickyScrollBound = false;
26252
+ }
26253
+ }
26254
+ #onStickyScroll;
26255
+ /** Real (non-sticky) row element for `key`, or `null`. */
26256
+ #stickyRowEl(key) {
26257
+ return this.renderRoot.querySelector(`ul.tree-list li[data-key="${CSS.escape(key)}"]`);
26258
+ }
26259
+ /**
26260
+ * Recompute which ancestors stick to the top: the ancestors of the first
26261
+ * row whose bottom clears the container top, minus any ancestor that is
26262
+ * itself still visible below the overlay. Synchronous — reads current
26263
+ * geometry, renders nothing, expands nothing.
26264
+ */
26265
+ #updateStickyHeaders() {
26266
+ this.#stickyDirty = false;
26267
+ const empty = /* @__PURE__ */ new Map();
26268
+ if (!this.stickyHeaders || !this.root) {
26269
+ this.#setStickyKeys([], empty);
26270
+ return;
26271
+ }
26272
+ const container = this.#container();
26273
+ if (!container) {
26274
+ this.#setStickyKeys([], empty);
26275
+ return;
26276
+ }
26277
+ const nodes = this.#getAllNodes();
26278
+ if (nodes.length === 0) {
26279
+ this.#setStickyKeys([], empty);
26280
+ return;
26281
+ }
26282
+ const parent = /* @__PURE__ */ new Map();
26283
+ const walk = (n) => {
26284
+ for (const child of n.children ?? []) {
26285
+ parent.set(child.item.key, n.item.key);
26286
+ walk(child);
26287
+ }
26288
+ };
26289
+ walk(this.root);
26290
+ const containerTop = container.getBoundingClientRect().top;
26291
+ const visibleThreshold = containerTop + (this.renderRoot.querySelector(`.sticky-headers`)?.getBoundingClientRect().height ?? 0);
26292
+ let topKey;
26293
+ for (const { node } of nodes) {
26294
+ const li = this.#stickyRowEl(node.item.key);
26295
+ if (!li || li.classList.contains(`leaving`)) continue;
26296
+ if (li.getBoundingClientRect().bottom > containerTop) {
26297
+ topKey = node.item.key;
26298
+ break;
26299
+ }
26300
+ }
26301
+ if (topKey === void 0) {
26302
+ this.#setStickyKeys([], empty);
26303
+ return;
26304
+ }
26305
+ const rootKey = this.root.item.key;
26306
+ const chain = [];
26307
+ let cursor = parent.get(topKey);
26308
+ while (cursor !== void 0 && cursor !== rootKey) {
26309
+ chain.unshift(cursor);
26310
+ cursor = parent.get(cursor);
26311
+ }
26312
+ const byKey = new Map(nodes.map((entry) => [entry.node.item.key, entry]));
26313
+ const entries = /* @__PURE__ */ new Map();
26314
+ const stuck = [];
26315
+ for (const key of chain) {
26316
+ const li = this.#stickyRowEl(key);
26317
+ if (!li || li.getBoundingClientRect().bottom > visibleThreshold) continue;
26318
+ const entry = byKey.get(key);
26319
+ if (!entry) continue;
26320
+ stuck.push(key);
26321
+ entries.set(key, entry);
26322
+ }
26323
+ this.#setStickyKeys(stuck, entries);
26324
+ }
26325
+ #setStickyKeys(keys, entries) {
26326
+ const prev = this._stickyKeys;
26327
+ if (prev.length === keys.length && prev.every((key, i) => key === keys[i])) return;
26328
+ this.#stickyEntries = entries;
26329
+ this._stickyKeys = keys;
26330
+ }
26331
+ #renderStickyHeaders() {
26332
+ if (!this.stickyHeaders || this._stickyKeys.length === 0) return A;
26333
+ return b`
26334
+ <div class="sticky-headers" part="sticky-headers">
26335
+ ${this._stickyKeys.map((key) => {
26336
+ const entry = this.#stickyEntries.get(key);
26337
+ if (!entry) return A;
26338
+ return this.#renderStickyHeader(entry.node, entry.depth);
26339
+ })}
26340
+ </div>
26341
+ `;
26342
+ }
26343
+ #renderStickyHeader(node, depth) {
26344
+ const selected = this._isSelected(node);
26345
+ const isBranch = node.item.isLeaf !== true;
26346
+ return b`
26347
+ <div
26348
+ class="item ${isBranch ? `branch` : `leaf`} sticky-header${selected ? ` selected` : ``}"
26349
+ part="sticky-header"
26350
+ role="button"
26351
+ tabindex="0"
26352
+ aria-label="Go to ${node.item.label}"
26353
+ data-key=${node.item.key}
26354
+ style=${`--depth: ${depth}`}
26355
+ @click=${(e) => this.#onStickyClick(e, node)}
26356
+ @keydown=${(e) => {
26357
+ if (e.key === `Enter` || e.key === ` `) {
26358
+ e.preventDefault();
26359
+ this.#activateSticky(node);
26360
+ }
26361
+ }}
26362
+ >${this.renderNodeContent(node, depth)}</div>
26363
+ `;
26364
+ }
26365
+ #onStickyClick(event, node) {
26366
+ if (this.#drop?.isDragging || this.#nativeDrag?.isDragging) return;
26367
+ if (node.item.isLeaf !== true && event.target instanceof Element && event.target.closest(`.tree-caret`)) {
26368
+ const depth = this.#stickyEntries.get(node.item.key)?.depth ?? 0;
26369
+ this.#toggleExpand(node, depth);
26370
+ this.#stickyDirty = true;
26371
+ this.requestUpdate();
26372
+ return;
26373
+ }
26374
+ this.#activateSticky(node);
26375
+ }
26376
+ #activateSticky(node) {
26377
+ if (this.#canSelect(node)) this.select(node);
26378
+ this.#scrollKeyIntoView(node.item.key);
26379
+ this.#stickyDirty = true;
26380
+ this.requestUpdate();
26381
+ }
26382
+ /** Visible `{ node, depth }` entries for `_stickyKeys` — depths drive the indent. */
26383
+ #stickyEntries;
26384
+ /** Set when expansion / data / filter changes may have altered the sticky set. Consumed in `updated()`. */
26385
+ #stickyDirty;
26386
+ #stickyRaf;
26387
+ #stickyScrollContainer;
26388
+ #stickyScrollBound;
25754
26389
  get nativeDrag() {
25755
26390
  return this.#nativeDrag;
25756
26391
  }
@@ -25774,6 +26409,8 @@ let TreeBaseElement = class TreeBaseElement extends i {
25774
26409
  willUpdate(changedProps) {
25775
26410
  super.willUpdate(changedProps);
25776
26411
  this.#diffVisibleNodes();
26412
+ if (changedProps.has(`root`) || changedProps.has(`model`) || changedProps.has(`filterPredicate`) || changedProps.has(`stickyHeaders`)) this.#stickyDirty = true;
26413
+ if (this.#stickyDirty) this.#updateStickyHeaders();
25777
26414
  }
25778
26415
  #diffVisibleNodes() {
25779
26416
  const nodes = this.root ? this.#getAllNodes() : [];
@@ -25873,6 +26510,7 @@ let TreeBaseElement = class TreeBaseElement extends i {
25873
26510
  }
25874
26511
  updated(changedProps) {
25875
26512
  this.#rowsCache = void 0;
26513
+ this.#syncStickyScroll();
25876
26514
  if (changedProps.has(`root`) && this.root) {
25877
26515
  this.#abortPending();
25878
26516
  this._expandedKeys.clear();
@@ -25896,6 +26534,7 @@ let TreeBaseElement = class TreeBaseElement extends i {
25896
26534
  } else if (event.type === `invalidate`) {
25897
26535
  if (this._expandedKeys.has(event.key)) {
25898
26536
  this._expandedKeys.delete(event.key);
26537
+ this.#stickyDirty = true;
25899
26538
  this.requestUpdate();
25900
26539
  }
25901
26540
  }
@@ -25938,7 +26577,7 @@ let TreeBaseElement = class TreeBaseElement extends i {
25938
26577
  isEnabled: () => this.itemDnd !== `none` && this.#anyRowDraggable(),
25939
26578
  resolveEventToKey: (target) => {
25940
26579
  if (!(target instanceof Element)) return void 0;
25941
- return target.closest(`li[data-key]`)?.getAttribute(`data-key`) ?? void 0;
26580
+ return target.closest(`ul.tree-list li[data-key]`)?.getAttribute(`data-key`) ?? void 0;
25942
26581
  },
25943
26582
  prepareSelection: (originKey) => {
25944
26583
  const allNodes = this.#getAllNodes();
@@ -25953,7 +26592,7 @@ let TreeBaseElement = class TreeBaseElement extends i {
25953
26592
  key: n.node.item.key,
25954
26593
  index: i,
25955
26594
  item: n.node,
25956
- element: this.shadowRoot?.querySelector(`li[data-key="${CSS.escape(n.node.item.key)}"]`) ?? void 0
26595
+ element: this.shadowRoot?.querySelector(`ul.tree-list li[data-key="${CSS.escape(n.node.item.key)}"]`) ?? void 0
25957
26596
  }));
25958
26597
  const origin = selected.find((e) => e.key === originKey) ?? {
25959
26598
  key: originKey,
@@ -26108,7 +26747,7 @@ let TreeBaseElement = class TreeBaseElement extends i {
26108
26747
  if (this.#rowsCache) return this.#rowsCache;
26109
26748
  const rows = [];
26110
26749
  for (const { node, depth } of this.#getAllNodes()) {
26111
- const li = this.shadowRoot?.querySelector(`li[data-key="${CSS.escape(node.item.key)}"]`);
26750
+ const li = this.shadowRoot?.querySelector(`ul.tree-list li[data-key="${CSS.escape(node.item.key)}"]`);
26112
26751
  if (li) rows.push({
26113
26752
  key: node.item.key,
26114
26753
  node,
@@ -26230,6 +26869,15 @@ let TreeBaseElement = class TreeBaseElement extends i {
26230
26869
  this.#postDragSuppressTimer = void 0;
26231
26870
  }
26232
26871
  this.#container()?.removeEventListener(`scroll`, this.#onContainerScroll);
26872
+ if (this.#stickyScrollBound) {
26873
+ this.#stickyScrollContainer?.removeEventListener(`scroll`, this.#onStickyScroll);
26874
+ this.#stickyScrollContainer = void 0;
26875
+ this.#stickyScrollBound = false;
26876
+ }
26877
+ if (this.#stickyRaf !== 0) {
26878
+ cancelAnimationFrame(this.#stickyRaf);
26879
+ this.#stickyRaf = 0;
26880
+ }
26233
26881
  treeDragUnregister(this.#dragSourceId);
26234
26882
  if (this.#ownedRegistry) {
26235
26883
  this.#ownedRegistry.unregister(`select-all`);
@@ -26318,6 +26966,7 @@ let TreeBaseElement = class TreeBaseElement extends i {
26318
26966
  }
26319
26967
  currentNode = found;
26320
26968
  }
26969
+ this.#stickyDirty = true;
26321
26970
  this.requestUpdate();
26322
26971
  this.#scrollKeyIntoView(keys.at(-1));
26323
26972
  return true;
@@ -26338,6 +26987,7 @@ let TreeBaseElement = class TreeBaseElement extends i {
26338
26987
  this._expandedKeys.add(path[i]);
26339
26988
  }
26340
26989
  this.tickled.setTickled(key);
26990
+ this.#stickyDirty = true;
26341
26991
  this.requestUpdate();
26342
26992
  this.updateComplete.then(() => this.#scrollKeyIntoView(key));
26343
26993
  return true;
@@ -26573,7 +27223,9 @@ let TreeBaseElement = class TreeBaseElement extends i {
26573
27223
  this.requestUpdate();
26574
27224
  }
26575
27225
  #toggleExpand(node, depth) {
26576
- if (this._expandedKeys.has(node.item.key)) {
27226
+ const isExpanded = this._expandedKeys.has(node.item.key);
27227
+ this.#stickyDirty = true;
27228
+ if (isExpanded) {
26577
27229
  this._expandedKeys.delete(node.item.key);
26578
27230
  this.dispatchEvent(new CustomEvent(`collapse`, {
26579
27231
  detail: {
@@ -26666,6 +27318,7 @@ let TreeBaseElement = class TreeBaseElement extends i {
26666
27318
  node.children = children;
26667
27319
  this.#applyExclusivity(node.item.key);
26668
27320
  this._expandedKeys.add(node.item.key);
27321
+ this.#stickyDirty = true;
26669
27322
  this.#pendingNode = void 0;
26670
27323
  this.#pendingController = void 0;
26671
27324
  this.dispatchEvent(new CustomEvent(`expand`, {
@@ -26706,14 +27359,16 @@ let TreeBaseElement = class TreeBaseElement extends i {
26706
27359
  }
26707
27360
  #scrollKeyIntoView(key) {
26708
27361
  requestAnimationFrame(() => {
26709
- const el = this.shadowRoot?.querySelector(`[data-key="${CSS.escape(key)}"]`);
26710
- if (!el) return;
27362
+ const container = this.#container();
27363
+ const el = this.shadowRoot?.querySelector(`ul.tree-list [data-key="${CSS.escape(key)}"]`);
27364
+ if (!el || !container) return;
26711
27365
  const elRect = el.getBoundingClientRect();
26712
- const hostRect = this.getBoundingClientRect();
26713
- const relativeTop = elRect.top - hostRect.top;
27366
+ const containerRect = container.getBoundingClientRect();
27367
+ const relativeTop = elRect.top - containerRect.top;
26714
27368
  const relativeBottom = relativeTop + elRect.height;
26715
- if (relativeTop < 0) this.scrollTop += relativeTop;
26716
- else if (relativeBottom > this.clientHeight) this.scrollTop += relativeBottom - this.clientHeight;
27369
+ const overlayHeight = this.renderRoot.querySelector(`.sticky-headers`)?.getBoundingClientRect().height ?? 0;
27370
+ if (relativeTop < overlayHeight) container.scrollTop += relativeTop - overlayHeight;
27371
+ else if (relativeBottom > container.clientHeight) container.scrollTop += relativeBottom - container.clientHeight;
26717
27372
  });
26718
27373
  }
26719
27374
  #abortPending() {
@@ -26802,7 +27457,7 @@ let TreeBaseElement = class TreeBaseElement extends i {
26802
27457
  #scrollTickledIntoView() {
26803
27458
  const tickledKey = this.tickled.tickledId;
26804
27459
  if (tickledKey === void 0) return;
26805
- (this.shadowRoot?.querySelector(`[data-key="${tickledKey}"]`))?.scrollIntoView({
27460
+ (this.shadowRoot?.querySelector(`ul.tree-list [data-key="${CSS.escape(tickledKey)}"]`))?.scrollIntoView({
26806
27461
  block: `nearest`,
26807
27462
  behavior: `smooth`
26808
27463
  });
@@ -26822,6 +27477,7 @@ let TreeBaseElement = class TreeBaseElement extends i {
26822
27477
  @pointerleave=${(e) => this.tickled.handlePointerLeave(e)}
26823
27478
  tabindex="0"
26824
27479
  >
27480
+ ${this.#renderStickyHeaders()}
26825
27481
  ${this.root ? this.#renderNodes(nodes) : A}
26826
27482
  </div>
26827
27483
  ${this.search.renderField()}
@@ -26920,6 +27576,9 @@ let TreeBaseElement = class TreeBaseElement extends i {
26920
27576
  --tree-drop-nub-size: 5px;
26921
27577
  --tree-drop-into-outline: 2px solid var(--accent);
26922
27578
  --tree-drop-into-bg: color-mix(in srgb, var(--accent) 14%, transparent);
27579
+ --tree-sticky-bg: var(--tree-bg);
27580
+ --tree-sticky-border: var(--border, transparent);
27581
+ --tree-sticky-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
26923
27582
 
26924
27583
  position: relative;
26925
27584
  display: block;
@@ -26946,6 +27605,28 @@ let TreeBaseElement = class TreeBaseElement extends i {
26946
27605
  padding: var(--space-xs);
26947
27606
  }
26948
27607
 
27608
+ /* VS Code-style sticky headers: ancestors of the top-visible row, pinned
27609
+ to the top of the scroll container. Rows reuse the item class for
27610
+ identical metrics; the overlay itself is opaque so rows slide under it. */
27611
+ .sticky-headers {
27612
+ position: sticky;
27613
+ top: 0;
27614
+ z-index: 5;
27615
+ background: var(--tree-sticky-bg);
27616
+ border-bottom: 1px solid var(--tree-sticky-border);
27617
+ box-shadow: var(--tree-sticky-shadow);
27618
+ }
27619
+
27620
+ .sticky-header {
27621
+ margin: 0;
27622
+ border-radius: 0;
27623
+ }
27624
+
27625
+ .sticky-header:focus-visible {
27626
+ outline: 2px solid var(--accent);
27627
+ outline-offset: -2px;
27628
+ }
27629
+
26949
27630
  .item {
26950
27631
  position: relative; /* anchor for the .drop-line before/after indicator */
26951
27632
  display: flex;
@@ -27119,6 +27800,14 @@ __decorate([property({
27119
27800
  toAttribute: (value) => value ? null : `false`
27120
27801
  }
27121
27802
  })], TreeBaseElement.prototype, "reorderable", void 0);
27803
+ __decorate([property({
27804
+ reflect: true,
27805
+ attribute: `sticky-headers`,
27806
+ converter: {
27807
+ fromAttribute: (value) => value !== `false`,
27808
+ toAttribute: (value) => value ? null : `false`
27809
+ }
27810
+ })], TreeBaseElement.prototype, "stickyHeaders", void 0);
27122
27811
  __decorate([property({ attribute: false })], TreeBaseElement.prototype, "dragPreviewRenderer", void 0);
27123
27812
  __decorate([property({ attribute: false })], TreeBaseElement.prototype, "dragPreviewSource", void 0);
27124
27813
  __decorate([property({ attribute: false })], TreeBaseElement.prototype, "canDrag", void 0);
@@ -27127,6 +27816,7 @@ __decorate([property({ attribute: false })], TreeBaseElement.prototype, "parseEx
27127
27816
  __decorate([property({ attribute: false })], TreeBaseElement.prototype, "applyInternalDrop", void 0);
27128
27817
  __decorate([state()], TreeBaseElement.prototype, "_expandedKeys", void 0);
27129
27818
  __decorate([state()], TreeBaseElement.prototype, "_focusedDepth", void 0);
27819
+ __decorate([state()], TreeBaseElement.prototype, "_stickyKeys", void 0);
27130
27820
  TreeBaseElement = __decorate([safeCustomElement(`ixfx-tree-base`)], TreeBaseElement);
27131
27821
  //#endregion
27132
27822
  //#region src/tree/tree-list.ts
@@ -36159,6 +36849,973 @@ var MillerTreeController = class {
36159
36849
  }
36160
36850
  };
36161
36851
  //#endregion
36852
+ //#region src/multicol-list/types.ts
36853
+ const ALL_KEY = `__all__`;
36854
+ //#endregion
36855
+ //#region src/multicol-list/column.ts
36856
+ /** Sorts by label, honouring direction. 'All' lives outside the list, so it is not special-cased. */
36857
+ function sortItems(items, direction) {
36858
+ const dir = direction === `desc` ? -1 : 1;
36859
+ return [...items].sort((a, b) => dir * a.label.localeCompare(b.label, void 0, {
36860
+ sensitivity: `base`,
36861
+ numeric: true
36862
+ }));
36863
+ }
36864
+ /**
36865
+ * Nearest-gap math for header drag-reorder (per data-grid's `_beginHeaderDrag`).
36866
+ *
36867
+ * `offsets` is a prefix-sum of column widths (length = count + 1). `x` is the
36868
+ * pointer position in content space (already adjusted for scroll). Returns the
36869
+ * final insertion index once the source column is removed (`insert`), plus the
36870
+ * un-normalised gap offset for the drop caret (`caretOffset`).
36871
+ */
36872
+ function computeDropGap(offsets, x, count, from) {
36873
+ if (count === 0) return {
36874
+ insert: 0,
36875
+ caretOffset: 0
36876
+ };
36877
+ let bestDist = Number.MAX_SAFE_INTEGER;
36878
+ let caretGap = from;
36879
+ for (let i = 0; i < count; i++) {
36880
+ if (i === from) continue;
36881
+ const left = offsets[i];
36882
+ const right = offsets[i + 1] ?? offsets[offsets.length - 1];
36883
+ const mid = (left + right) / 2;
36884
+ const dist = Math.abs(x - (x < mid ? left : right));
36885
+ if (dist < bestDist) {
36886
+ bestDist = dist;
36887
+ caretGap = x < mid ? i : i + 1;
36888
+ }
36889
+ }
36890
+ const insert = caretGap > from ? caretGap - 1 : caretGap;
36891
+ return {
36892
+ insert: Math.max(0, Math.min(count - 1, insert)),
36893
+ caretOffset: offsets[caretGap] ?? offsets[offsets.length - 1]
36894
+ };
36895
+ }
36896
+ var MulticolColumnController = class {
36897
+ #category;
36898
+ #categoryDefaults;
36899
+ #selectionMode;
36900
+ #dataProvider;
36901
+ #onSelectionChange;
36902
+ #onRequestData;
36903
+ #abortController = void 0;
36904
+ #host;
36905
+ #allRow;
36906
+ #listerEl;
36907
+ #selectedValues = [];
36908
+ #allSelected = true;
36909
+ #lastItems = [];
36910
+ #syncingSelection = false;
36911
+ #state;
36912
+ constructor(options) {
36913
+ this.id = options.id;
36914
+ this.#category = options.category;
36915
+ this.#categoryDefaults = options.categoryDefaults;
36916
+ this.#selectionMode = options.selectionMode;
36917
+ this.#dataProvider = options.dataProvider;
36918
+ this.#onSelectionChange = options.onSelectionChange;
36919
+ this.#onRequestData = options.onRequestData;
36920
+ this.#state = {
36921
+ id: options.id,
36922
+ categoryKey: options.category.key,
36923
+ sort: options.categoryDefaults?.sort ?? `asc`,
36924
+ grouped: options.categoryDefaults?.grouped ?? false,
36925
+ width: 220
36926
+ };
36927
+ }
36928
+ get state() {
36929
+ return this.getState();
36930
+ }
36931
+ /** Always derived from the live category so a swap is visible everywhere. */
36932
+ get categoryKey() {
36933
+ return this.#category.key;
36934
+ }
36935
+ getState() {
36936
+ return { ...this.#state };
36937
+ }
36938
+ updateState(partial) {
36939
+ const sortChanged = partial.sort !== void 0 && partial.sort !== this.#state.sort;
36940
+ const groupedChanged = partial.grouped !== void 0 && partial.grouped !== this.#state.grouped;
36941
+ this.#state = {
36942
+ ...this.#state,
36943
+ ...partial
36944
+ };
36945
+ if (sortChanged) this.#repush();
36946
+ if (groupedChanged) this.#syncGrouping();
36947
+ }
36948
+ setWidth(width) {
36949
+ this.#state = {
36950
+ ...this.#state,
36951
+ width: Math.max(80, Math.min(480, Math.round(width)))
36952
+ };
36953
+ }
36954
+ setSort(sort) {
36955
+ if (sort === this.#state.sort) return;
36956
+ this.#state = {
36957
+ ...this.#state,
36958
+ sort
36959
+ };
36960
+ this.#repush();
36961
+ }
36962
+ setGrouped(grouped) {
36963
+ if (grouped === this.#state.grouped) return;
36964
+ this.#state = {
36965
+ ...this.#state,
36966
+ grouped
36967
+ };
36968
+ this.#syncGrouping();
36969
+ }
36970
+ setSelectionMode(mode) {
36971
+ if (mode === this.#selectionMode) return;
36972
+ this.#selectionMode = mode;
36973
+ for (const sub of this.#subComponents()) sub.selectionMode = mode;
36974
+ }
36975
+ setCategory(category) {
36976
+ this.#category = category;
36977
+ this.#categoryDefaults = category.defaults;
36978
+ this.#state = {
36979
+ ...this.#state,
36980
+ categoryKey: category.key,
36981
+ sort: category.defaults?.sort ?? `asc`,
36982
+ grouped: category.defaults?.grouped ?? false
36983
+ };
36984
+ this.clearSelection();
36985
+ this.#syncGrouping();
36986
+ }
36987
+ get listerHost() {
36988
+ return this.#host;
36989
+ }
36990
+ get isMounted() {
36991
+ return this.#host !== void 0;
36992
+ }
36993
+ setDataProvider(provider) {
36994
+ this.#dataProvider = provider;
36995
+ }
36996
+ mount(host) {
36997
+ if (this.#host) return;
36998
+ this.#host = host;
36999
+ const allRow = document.createElement(`div`);
37000
+ allRow.className = `all-row`;
37001
+ allRow.dataset.key = ALL_KEY;
37002
+ allRow.setAttribute(`role`, `button`);
37003
+ allRow.setAttribute(`tabindex`, `0`);
37004
+ const allLabel = document.createElement(`span`);
37005
+ allLabel.className = `all-label`;
37006
+ allRow.appendChild(allLabel);
37007
+ const applyAll = () => {
37008
+ if (this.#allSelected) return;
37009
+ this.#setAllSelection();
37010
+ };
37011
+ allRow.addEventListener(`click`, applyAll);
37012
+ allRow.addEventListener(`keydown`, (e) => {
37013
+ if (e.key === `Enter` || e.key === ` `) {
37014
+ e.preventDefault();
37015
+ applyAll();
37016
+ }
37017
+ });
37018
+ this.#allRow = allRow;
37019
+ const lister = document.createElement(`ixfx-grouped-item-lister`);
37020
+ lister.crossGroupSelection = true;
37021
+ lister.factory = () => createVerticalListAdapter(renderItem, {
37022
+ selectionMode: this.#selectionMode,
37023
+ interactionMode: `standard`
37024
+ });
37025
+ lister.addEventListener(`select`, this.#handleSelect);
37026
+ this.#listerEl = lister;
37027
+ this.#syncGrouping();
37028
+ this.#syncAllRow();
37029
+ host.append(allRow, lister);
37030
+ if (this.#lastItems.length > 0) {
37031
+ this.#pushItems();
37032
+ this.#restoreAfterSync();
37033
+ }
37034
+ }
37035
+ unmount() {
37036
+ this.#abortPending();
37037
+ this.#allRow?.remove();
37038
+ this.#listerEl?.remove();
37039
+ this.#allRow = void 0;
37040
+ this.#listerEl = void 0;
37041
+ this.#host = void 0;
37042
+ }
37043
+ requestData(query) {
37044
+ if (!this.#dataProvider) return;
37045
+ this.#abortPending();
37046
+ const controller = new AbortController();
37047
+ this.#abortController = controller;
37048
+ const { signal } = controller;
37049
+ this.#onRequestData(this.id, query, signal);
37050
+ Promise.resolve().then(async () => {
37051
+ const items = await collectDataResult(this.#dataProvider(query, signal), signal);
37052
+ if (signal.aborted) return;
37053
+ this.#applyItems(items);
37054
+ }).catch(() => {});
37055
+ }
37056
+ #applyItems(items) {
37057
+ this.#lastItems = items;
37058
+ const valid = this.#selectedValues.filter((v) => items.some((i) => i.key === v));
37059
+ const changed = valid.length !== this.#selectedValues.length;
37060
+ this.#selectedValues = valid;
37061
+ if (valid.length === 0) this.#allSelected = true;
37062
+ if (!this.#listerEl) {
37063
+ if (changed) this.#onSelectionChange(this.id, valid);
37064
+ return;
37065
+ }
37066
+ this.#pushItems();
37067
+ this.#restoreAfterSync();
37068
+ if (changed) this.#onSelectionChange(this.id, valid);
37069
+ }
37070
+ #pushItems() {
37071
+ if (!this.#listerEl) return;
37072
+ const sorted = sortItems(this.#lastItems, this.#state.sort);
37073
+ this.#listerEl.provider = () => sorted;
37074
+ }
37075
+ #repush() {
37076
+ if (!this.#listerEl || this.#lastItems.length === 0) return;
37077
+ this.#pushItems();
37078
+ this.#restoreAfterSync();
37079
+ }
37080
+ /** Grouping config from category defaults; grouping without groupBy is a no-op. */
37081
+ #syncGrouping() {
37082
+ if (!this.#listerEl) return;
37083
+ const groupBy = this.#categoryDefaults?.groupBy;
37084
+ this.#listerEl.groupBy = groupBy;
37085
+ this.#listerEl.grouped = this.#state.grouped && groupBy !== void 0;
37086
+ if (this.#lastItems.length > 0) this.#restoreAfterSync();
37087
+ }
37088
+ #subComponents() {
37089
+ if (!this.#listerEl) return [];
37090
+ return this.#listerEl.querySelectorAll(`:scope > .ungrouped-host > *, :scope > ixfx-panel > *`);
37091
+ }
37092
+ #handleSelect = () => {
37093
+ if (this.#syncingSelection) return;
37094
+ const values = [...this.#listerEl?.selectedItems ?? []].map((i) => i.key).filter((k) => k !== ALL_KEY);
37095
+ if (values.length === this.#selectedValues.length && values.every((v) => this.#selectedValues.includes(v))) {
37096
+ this.#syncAllRow();
37097
+ return;
37098
+ }
37099
+ this.#selectedValues = values;
37100
+ this.#allSelected = values.length === 0;
37101
+ this.#syncAllRow();
37102
+ this.#onSelectionChange(this.id, values);
37103
+ };
37104
+ #setAllSelection() {
37105
+ const previous = this.#selectedValues;
37106
+ this.#syncingSelection = true;
37107
+ try {
37108
+ this.#selectedValues = [];
37109
+ this.#allSelected = true;
37110
+ for (const sub of this.#subComponents()) sub.clearSelection();
37111
+ } finally {
37112
+ this.#syncingSelection = false;
37113
+ }
37114
+ this.#syncAllRow();
37115
+ if (previous.length > 0) this.#onSelectionChange(this.id, []);
37116
+ }
37117
+ clearSelection() {
37118
+ this.#setAllSelection();
37119
+ }
37120
+ get selectedValues() {
37121
+ return this.#selectedValues;
37122
+ }
37123
+ #restoreAfterSync() {
37124
+ if (!this.#listerEl) return;
37125
+ this.#listerEl.updateComplete.then(() => {
37126
+ if (!this.#listerEl || !this.#host) return;
37127
+ this.#syncingSelection = true;
37128
+ try {
37129
+ const wanted = this.#selectedValues;
37130
+ for (const list of this.#listerEl.querySelectorAll(`ixfx-vertical-list`)) list.selectKeys(wanted);
37131
+ const selected = [...this.#listerEl.selectedItems].map((i) => i.key).filter((k) => k !== ALL_KEY);
37132
+ this.#selectedValues = selected;
37133
+ this.#allSelected = selected.length === 0;
37134
+ } finally {
37135
+ this.#syncingSelection = false;
37136
+ }
37137
+ this.#syncAllRow();
37138
+ });
37139
+ }
37140
+ #syncAllRow() {
37141
+ if (!this.#allRow) return;
37142
+ const label = this.#categoryDefaults?.allLabel ?? `All`;
37143
+ const labelEl = this.#allRow.querySelector(`.all-label`);
37144
+ if (labelEl) labelEl.textContent = label;
37145
+ this.#allRow.toggleAttribute(`data-selected`, this.#allSelected);
37146
+ }
37147
+ #abortPending() {
37148
+ if (this.#abortController) {
37149
+ this.#abortController.abort();
37150
+ this.#abortController = void 0;
37151
+ }
37152
+ }
37153
+ };
37154
+ function renderItem(item) {
37155
+ const li = document.createElement(`li`);
37156
+ li.dataset.key = item.key;
37157
+ const labelSpan = document.createElement(`span`);
37158
+ labelSpan.className = `item-label`;
37159
+ labelSpan.textContent = item.label;
37160
+ li.appendChild(labelSpan);
37161
+ if (item.count !== void 0) {
37162
+ const countSpan = document.createElement(`span`);
37163
+ countSpan.className = `count`;
37164
+ countSpan.textContent = String(item.count);
37165
+ li.appendChild(countSpan);
37166
+ }
37167
+ return li;
37168
+ }
37169
+ //#endregion
37170
+ //#region src/multicol-list/multicol-list.ts
37171
+ registerIcon(`menu`, `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12h16"/><path d="M4 18h16"/><path d="M4 6h16"/></svg>`);
37172
+ const DEFAULT_COLUMN_WIDTH = 220;
37173
+ const MIN_COLUMN_WIDTH = 80;
37174
+ const MAX_COLUMN_WIDTH = 480;
37175
+ const DRAG_THRESHOLD = 5;
37176
+ let MulticolListElement = class MulticolListElement extends i {
37177
+ constructor(..._args) {
37178
+ super(..._args);
37179
+ this.categories = [];
37180
+ this.selectionMode = `multiple`;
37181
+ this.minColumns = 1;
37182
+ this.maxColumns = 5;
37183
+ this._columns = [];
37184
+ this._colOffsets = [0];
37185
+ this._resizingColumnId = void 0;
37186
+ this._draggingColumnId = void 0;
37187
+ this._dropCaretX = void 0;
37188
+ this._idCounter = 0;
37189
+ this._autoSeeded = false;
37190
+ this._drag = {
37191
+ pointerId: -1,
37192
+ from: -1,
37193
+ startX: 0,
37194
+ startY: 0,
37195
+ active: false,
37196
+ ghost: null,
37197
+ insert: -1
37198
+ };
37199
+ }
37200
+ static {
37201
+ this.styles = [
37202
+ themeFallbacks,
37203
+ handleStyles,
37204
+ i$3`
37205
+ :host {
37206
+ --multicol-list-bg: var(--surface-3);
37207
+ --multicol-list-header-bg: var(--surface-2);
37208
+ --multicol-list-header-text: var(--surface-3-text);
37209
+ --multicol-list-border: var(--border);
37210
+ --multicol-list-min-column-width: ${MIN_COLUMN_WIDTH}px;
37211
+ --multicol-list-max-column-width: ${MAX_COLUMN_WIDTH}px;
37212
+
37213
+ display: block;
37214
+ overflow: hidden;
37215
+ background: var(--multicol-list-bg);
37216
+ color: var(--surface-3-text);
37217
+ font-family: var(--font-family);
37218
+ }
37219
+ #container {
37220
+ display: flex;
37221
+ flex-direction: row;
37222
+ align-items: stretch;
37223
+ overflow-x: auto;
37224
+ overflow-y: hidden;
37225
+ position: relative;
37226
+ height: 100%;
37227
+ }
37228
+ .column {
37229
+ flex-shrink: 0;
37230
+ display: flex;
37231
+ flex-direction: column;
37232
+ border-right: var(--multicol-list-border);
37233
+ min-width: var(--multicol-list-min-column-width);
37234
+ max-width: var(--multicol-list-max-column-width);
37235
+ background: var(--surface-3);
37236
+ }
37237
+ .column-header {
37238
+ display: flex;
37239
+ align-items: center;
37240
+ gap: var(--space-xs);
37241
+ height: 32px;
37242
+ background: var(--multicol-list-header-bg);
37243
+ color: var(--multicol-list-header-text);
37244
+ border-bottom: var(--border);
37245
+ position: relative;
37246
+ user-select: none;
37247
+ min-width: var(--multicol-list-min-column-width);
37248
+ box-sizing: border-box;
37249
+ }
37250
+ .column-header[data-dragging] {
37251
+ opacity: 0.4;
37252
+ }
37253
+ .reorder-handle {
37254
+ cursor: grab;
37255
+ opacity: 0;
37256
+ display: inline-flex;
37257
+ align-items: center;
37258
+ flex-shrink: 0;
37259
+ padding-left: var(--space-xs);
37260
+ touch-action: none;
37261
+ transition: opacity var(--transition, 0.15s ease-out);
37262
+ }
37263
+ .column-header:hover .reorder-handle, .column-header:focus-within .reorder-handle, .column-header[data-dragging] .reorder-handle { opacity: var(--ixfx-handle-opacity, 0.5); }
37264
+ .reorder-handle:active {
37265
+ cursor: grabbing;
37266
+ }
37267
+ .reorder-handle .ixfx-handle {
37268
+ --ixfx-handle-length: 14px;
37269
+ --ixfx-handle-thickness: var(--multicol-list-reorder-handle-width, 10px);
37270
+ --ixfx-handle-dot-size: 3px;
37271
+ }
37272
+ .column-label {
37273
+ flex: 1;
37274
+ overflow: hidden;
37275
+ text-overflow: ellipsis;
37276
+ white-space: nowrap;
37277
+ padding: 0 var(--space-s);
37278
+ font-size: var(--text-m);
37279
+ font-weight: 600;
37280
+ background: transparent;
37281
+ border: none;
37282
+ color: inherit;
37283
+ cursor: pointer;
37284
+ text-align: left;
37285
+ min-width: 0;
37286
+ }
37287
+ .column-label:hover {
37288
+ text-decoration: underline;
37289
+ }
37290
+ .burger-btn {
37291
+ flex-shrink: 0;
37292
+ width: 28px;
37293
+ height: 28px;
37294
+ display: flex;
37295
+ align-items: center;
37296
+ justify-content: center;
37297
+ background: transparent;
37298
+ border: none;
37299
+ cursor: pointer;
37300
+ color: var(--surface-3-text);
37301
+ opacity: 0;
37302
+ transition: opacity var(--transition);
37303
+ border-radius: var(--radius-s);
37304
+ }
37305
+ .column:hover .burger-btn,
37306
+ .column-header:focus-within .burger-btn {
37307
+ opacity: 1;
37308
+ }
37309
+ .burger-btn:hover {
37310
+ background: var(--surface-4);
37311
+ }
37312
+ .resize-handle {
37313
+ position: absolute;
37314
+ right: -4px;
37315
+ top: 0;
37316
+ bottom: 0;
37317
+ width: 8px;
37318
+ cursor: col-resize;
37319
+ z-index: 1;
37320
+ display: flex;
37321
+ align-items: stretch;
37322
+ justify-content: center;
37323
+ touch-action: none;
37324
+ }
37325
+ .resize-handle::before {
37326
+ content: '';
37327
+ width: 2px;
37328
+ margin: 2px 0;
37329
+ border-radius: 1px;
37330
+ background: transparent;
37331
+ transition: background-color var(--transition);
37332
+ }
37333
+ .resize-handle:hover::before,
37334
+ .resize-handle[data-active]::before {
37335
+ background: var(--accent);
37336
+ }
37337
+ .lister-host {
37338
+ flex: 1;
37339
+ overflow-y: auto;
37340
+ overflow-x: hidden;
37341
+ position: relative;
37342
+ display: flex;
37343
+ flex-direction: column;
37344
+ }
37345
+ .all-row {
37346
+ display: flex;
37347
+ align-items: center;
37348
+ padding: var(--space-xs) var(--space-s);
37349
+ cursor: pointer;
37350
+ user-select: none;
37351
+ min-height: 28px;
37352
+ box-sizing: border-box;
37353
+ outline: 1px solid transparent;
37354
+ background: var(--surface-3);
37355
+ }
37356
+ .all-row:hover,
37357
+ .all-row[data-selected] {
37358
+ background: var(--surface-5);
37359
+ }
37360
+ .all-row[data-selected] {
37361
+ outline-color: var(--accent);
37362
+ font-weight: 600;
37363
+ }
37364
+ ixfx-grouped-item-lister {
37365
+ display: block;
37366
+ }
37367
+ .drop-caret {
37368
+ position: absolute;
37369
+ top: 0;
37370
+ bottom: 0;
37371
+ width: 2px;
37372
+ background: var(--accent);
37373
+ border-radius: 1px;
37374
+ pointer-events: none;
37375
+ z-index: 10;
37376
+ }
37377
+ .item-label {
37378
+ flex: 1;
37379
+ }
37380
+ .count {
37381
+ opacity: 0.6;
37382
+ margin-left: var(--space-s);
37383
+ font-size: var(--text-s);
37384
+ }
37385
+ `
37386
+ ];
37387
+ }
37388
+ get columns() {
37389
+ return this._columns.map((c) => c.getState());
37390
+ }
37391
+ setColumns(states) {
37392
+ const existingMap = new Map(this._columns.map((c) => [c.id, c]));
37393
+ const newColumns = [];
37394
+ for (const colState of states) {
37395
+ const existing = existingMap.get(colState.id);
37396
+ if (existing) {
37397
+ if (existing.categoryKey !== colState.categoryKey) {
37398
+ const newCategory = this.categories.find((c) => c.key === colState.categoryKey);
37399
+ if (newCategory) existing.setCategory(newCategory);
37400
+ }
37401
+ existing.updateState(colState);
37402
+ newColumns.push(existing);
37403
+ existingMap.delete(colState.id);
37404
+ continue;
37405
+ }
37406
+ const category = this.categories.find((c) => c.key === colState.categoryKey);
37407
+ if (!category) continue;
37408
+ const controller = this.#createController(colState.id, category);
37409
+ controller.updateState(colState);
37410
+ newColumns.push(controller);
37411
+ }
37412
+ for (const col of existingMap.values()) col.unmount();
37413
+ this._columns = newColumns;
37414
+ this._updateColOffsets();
37415
+ this._emitColumnsChange(`add`);
37416
+ this._requeryAllColumns();
37417
+ this.requestUpdate();
37418
+ }
37419
+ addColumn(categoryKey, position) {
37420
+ if (this.maxColumns > 0 && this._columns.length >= this.maxColumns) return;
37421
+ const category = this.categories.find((c) => c.key === categoryKey);
37422
+ if (!category) return;
37423
+ const id = `col-${++this._idCounter}`;
37424
+ const controller = this.#createController(id, category);
37425
+ if (position !== void 0 && position >= 0 && position < this._columns.length) this._columns.splice(position, 0, controller);
37426
+ else this._columns.push(controller);
37427
+ this._updateColOffsets();
37428
+ this._emitColumnsChange(`add`);
37429
+ this._requeryAllColumns();
37430
+ this.requestUpdate();
37431
+ }
37432
+ removeColumn(columnId) {
37433
+ if (this._columns.length <= this.minColumns) return;
37434
+ const idx = this._columns.findIndex((c) => c.id === columnId);
37435
+ if (idx < 0) return;
37436
+ this._columns[idx].unmount();
37437
+ this._columns.splice(idx, 1);
37438
+ this._updateColOffsets();
37439
+ this._emitColumnsChange(`remove`);
37440
+ this._requeryAllColumns();
37441
+ this.requestUpdate();
37442
+ }
37443
+ getSelection() {
37444
+ return this._columns.map((c) => ({
37445
+ columnId: c.id,
37446
+ categoryKey: c.categoryKey,
37447
+ values: c.selectedValues
37448
+ }));
37449
+ }
37450
+ clearSelection() {
37451
+ for (const col of this._columns) col.clearSelection();
37452
+ this.requestUpdate();
37453
+ }
37454
+ render() {
37455
+ return b`
37456
+ <div id="container">
37457
+ ${repeat(this._columns, (col) => col.id, (col, idx) => this._renderColumn(col, idx))}
37458
+ ${this._dropCaretX !== void 0 ? b`<div class="drop-caret" style="left: ${this._dropCaretX}px"></div>` : A}
37459
+ </div>
37460
+ `;
37461
+ }
37462
+ updated(changedProperties) {
37463
+ if (!this._autoSeeded && this._columns.length === 0 && this.categories.length > 0) {
37464
+ this._autoSeeded = true;
37465
+ this.addColumn(this.categories[0].key);
37466
+ }
37467
+ if (changedProperties.has(`selectionMode`)) for (const col of this._columns) col.setSelectionMode(this.selectionMode);
37468
+ if (changedProperties.has(`dataProvider`)) for (const col of this._columns) col.setDataProvider(this.dataProvider);
37469
+ for (const col of this._columns) if (!col.isMounted) {
37470
+ const hostEl = this.shadowRoot?.querySelector(`[data-col-id="${col.id}"] .lister-host`);
37471
+ if (hostEl) col.mount(hostEl);
37472
+ }
37473
+ if (changedProperties.has(`categories`)) this._syncColumnsWithCategories();
37474
+ if (changedProperties.has(`categories`) || changedProperties.has(`dataProvider`)) this._requeryAllColumns();
37475
+ this._updateColOffsets();
37476
+ }
37477
+ _renderColumn(col, idx) {
37478
+ const width = col.getState().width ?? DEFAULT_COLUMN_WIDTH;
37479
+ return b`
37480
+ <div
37481
+ class="column"
37482
+ data-col-id="${col.id}"
37483
+ style="width: ${width}px"
37484
+ >
37485
+ <div
37486
+ class="column-header"
37487
+ ?data-dragging=${this._draggingColumnId === col.id}
37488
+ data-col-idx=${idx}
37489
+ >
37490
+ <span
37491
+ class="reorder-handle"
37492
+ data-tooltip="Drag to reorder"
37493
+ @pointerdown=${(e) => this._onHeaderPointerDown(e, col, idx)}
37494
+ ><span class="ixfx-handle" data-handle="dotted" data-shape="vertical" part="reorder-handle"></span></span>
37495
+ <button
37496
+ class="column-label"
37497
+ data-tooltip="Change category"
37498
+ @click=${(e) => {
37499
+ e.stopPropagation();
37500
+ this._openCategoryPicker(col, e.currentTarget);
37501
+ }}
37502
+ >${this._getCategoryLabel(col.categoryKey)}</button>
37503
+ <button
37504
+ class="burger-btn"
37505
+ data-tooltip="Column options"
37506
+ @click=${(e) => {
37507
+ e.stopPropagation();
37508
+ this._openBurgerMenu(col, e.currentTarget);
37509
+ }}
37510
+ >
37511
+ <ixfx-icon name="menu" size="14"></ixfx-icon>
37512
+ </button>
37513
+ <span
37514
+ class="resize-handle"
37515
+ ?data-active=${this._resizingColumnId === col.id}
37516
+ @pointerdown=${(e) => this._onResizePointerDown(e, col)}
37517
+ @click=${(e) => e.stopPropagation()}
37518
+ ></span>
37519
+ </div>
37520
+ <div class="lister-host"></div>
37521
+ </div>
37522
+ `;
37523
+ }
37524
+ _getCategoryLabel(key) {
37525
+ return this.categories.find((c) => c.key === key)?.label ?? key;
37526
+ }
37527
+ #createController(id, category) {
37528
+ return new MulticolColumnController({
37529
+ id,
37530
+ category,
37531
+ categoryDefaults: category.defaults,
37532
+ selectionMode: this.selectionMode,
37533
+ dataProvider: this.dataProvider,
37534
+ onSelectionChange: this._onColumnSelectionChange.bind(this),
37535
+ onRequestData: this._onColumnRequestData.bind(this)
37536
+ });
37537
+ }
37538
+ _onHeaderPointerDown(e, col, idx) {
37539
+ e.stopPropagation();
37540
+ this._drag = {
37541
+ pointerId: e.pointerId,
37542
+ from: idx,
37543
+ startX: e.clientX,
37544
+ startY: e.clientY,
37545
+ active: false,
37546
+ ghost: null,
37547
+ insert: idx
37548
+ };
37549
+ const onMove = (ev) => {
37550
+ if (ev.pointerId !== this._drag.pointerId) return;
37551
+ const dx = ev.clientX - this._drag.startX;
37552
+ const dy = ev.clientY - this._drag.startY;
37553
+ if (!this._drag.active) {
37554
+ if (Math.hypot(dx, dy) < DRAG_THRESHOLD) return;
37555
+ this._drag.active = true;
37556
+ this._draggingColumnId = col.id;
37557
+ const headerEl = this.shadowRoot?.querySelector(`[data-col-id="${col.id}"] .column-header`);
37558
+ const content = document.createElement(`span`);
37559
+ content.textContent = this._getCategoryLabel(col.categoryKey);
37560
+ try {
37561
+ if (headerEl) {
37562
+ this._drag.ghost = createDragGhost({
37563
+ anchor: headerEl,
37564
+ content
37565
+ });
37566
+ this._drag.ghost.move(ev.clientX, ev.clientY);
37567
+ }
37568
+ } catch {}
37569
+ try {
37570
+ this._containerEl?.setPointerCapture(ev.pointerId);
37571
+ } catch {}
37572
+ }
37573
+ this._drag.ghost?.move(ev.clientX, ev.clientY);
37574
+ const containerEl = this._containerEl;
37575
+ if (!containerEl) return;
37576
+ const rect = containerEl.getBoundingClientRect();
37577
+ const x = ev.clientX - rect.left + containerEl.scrollLeft;
37578
+ const gap = computeDropGap(this._colOffsets, x, this._columns.length, this._drag.from);
37579
+ this._drag.insert = gap.insert;
37580
+ this._dropCaretX = gap.caretOffset;
37581
+ this.requestUpdate();
37582
+ };
37583
+ const finish = (ev) => {
37584
+ if (ev.pointerId !== this._drag.pointerId) return;
37585
+ const wasActive = this._drag.active;
37586
+ const from = this._drag.from;
37587
+ const insert = this._drag.insert;
37588
+ this._drag.ghost?.destroy();
37589
+ this._drag.ghost = null;
37590
+ this._draggingColumnId = void 0;
37591
+ this._dropCaretX = void 0;
37592
+ try {
37593
+ this._containerEl?.releasePointerCapture(ev.pointerId);
37594
+ } catch {}
37595
+ window.removeEventListener(`pointermove`, onMove);
37596
+ window.removeEventListener(`pointerup`, finish);
37597
+ window.removeEventListener(`pointercancel`, finish);
37598
+ if (wasActive && insert !== from) {
37599
+ const [moved] = this._columns.splice(from, 1);
37600
+ this._columns.splice(insert, 0, moved);
37601
+ this._updateColOffsets();
37602
+ this._emitColumnsChange(`reorder`);
37603
+ this.requestUpdate();
37604
+ }
37605
+ };
37606
+ window.addEventListener(`pointermove`, onMove);
37607
+ window.addEventListener(`pointerup`, finish);
37608
+ window.addEventListener(`pointercancel`, finish);
37609
+ }
37610
+ _onResizePointerDown(e, col) {
37611
+ e.preventDefault();
37612
+ e.stopPropagation();
37613
+ const startX = e.clientX;
37614
+ const startW = col.getState().width ?? DEFAULT_COLUMN_WIDTH;
37615
+ this._resizingColumnId = col.id;
37616
+ const applyWidth = (clientX) => {
37617
+ const w = Math.max(MIN_COLUMN_WIDTH, Math.min(MAX_COLUMN_WIDTH, startW + clientX - startX));
37618
+ col.setWidth(w);
37619
+ return w;
37620
+ };
37621
+ const onMove = (ev) => {
37622
+ if (ev.pointerId !== e.pointerId) return;
37623
+ applyWidth(ev.clientX);
37624
+ this._updateColOffsets();
37625
+ this.requestUpdate();
37626
+ };
37627
+ const finish = (ev) => {
37628
+ window.removeEventListener(`pointermove`, onMove);
37629
+ window.removeEventListener(`pointerup`, finish);
37630
+ window.removeEventListener(`pointercancel`, finish);
37631
+ applyWidth(ev.type === `pointercancel` ? startX : ev.clientX);
37632
+ this._resizingColumnId = void 0;
37633
+ this._updateColOffsets();
37634
+ this._emitColumnsChange(`resize`);
37635
+ this.requestUpdate();
37636
+ };
37637
+ window.addEventListener(`pointermove`, onMove);
37638
+ window.addEventListener(`pointerup`, finish);
37639
+ window.addEventListener(`pointercancel`, finish);
37640
+ }
37641
+ /** Floats a dropdown menu trigger over `anchorEl` and opens it immediately. */
37642
+ #openMenuAt(anchorEl, placement, buildMenu) {
37643
+ const rect = anchorEl.getBoundingClientRect();
37644
+ const trigger = document.createElement(`ixfx-menu-trigger`);
37645
+ trigger.mode = `dropdown`;
37646
+ trigger.tabStop = false;
37647
+ trigger.placement = placement;
37648
+ trigger.style.position = `fixed`;
37649
+ trigger.style.left = `${rect.left}px`;
37650
+ trigger.style.top = `${rect.bottom}px`;
37651
+ const container = document.createElement(`ixfx-menu-container`);
37652
+ container.setAttribute(`slot`, `menu`);
37653
+ buildMenu(container);
37654
+ trigger.appendChild(container);
37655
+ trigger.addEventListener(`menu-trigger-close`, () => trigger.remove(), { once: true });
37656
+ document.body.appendChild(trigger);
37657
+ trigger.updateComplete.then(() => trigger.openMenu());
37658
+ }
37659
+ #categoryToNode(cat) {
37660
+ return {
37661
+ item: {
37662
+ key: cat.key,
37663
+ label: cat.label
37664
+ },
37665
+ children: cat.children && cat.children.length > 0 ? cat.children.map((c) => this.#categoryToNode(c)) : void 0
37666
+ };
37667
+ }
37668
+ _openCategoryPicker(col, anchorEl) {
37669
+ this.#openMenuAt(anchorEl, `bottom-start`, (container) => {
37670
+ const items = menuFromTreeToElements(this.categories.map((c) => this.#categoryToNode(c)), { onCommand: (detail) => {
37671
+ if (detail.command === void 0) return;
37672
+ this._changeColumnCategory(col, detail.command);
37673
+ } });
37674
+ for (const el of items) container.appendChild(el);
37675
+ for (const item of container.querySelectorAll(`ixfx-menu-item`)) if (item.getAttribute(`command`) === col.categoryKey) item.setAttribute(`disabled`, ``);
37676
+ });
37677
+ }
37678
+ #menuItem(label, command, onCommand, iconName) {
37679
+ const el = document.createElement(`ixfx-menu-item`);
37680
+ el.setAttribute(`command`, command);
37681
+ el.setAttribute(`label`, label);
37682
+ if (iconName) el.setAttribute(`icon-name`, iconName);
37683
+ if (onCommand) el.addEventListener(`command`, () => onCommand());
37684
+ return el;
37685
+ }
37686
+ _openBurgerMenu(col, anchorEl) {
37687
+ this.#openMenuAt(anchorEl, `bottom-end`, (container) => {
37688
+ const removeItem = this.#menuItem(`Remove this column`, `remove`, () => this.removeColumn(col.id));
37689
+ removeItem.toggleAttribute(`disabled`, this._columns.length <= this.minColumns);
37690
+ container.appendChild(removeItem);
37691
+ const separator = document.createElement(`ixfx-menu-separator`);
37692
+ container.appendChild(separator);
37693
+ const atMax = this.maxColumns > 0 && this._columns.length >= this.maxColumns;
37694
+ const usedCats = new Set(this._columns.map((c) => c.categoryKey));
37695
+ const unused = this.categories.filter((c) => !usedCats.has(c.key));
37696
+ const canAdd = !atMax && unused.length > 0;
37697
+ const addSub = document.createElement(`ixfx-menu-sub-trigger`);
37698
+ addSub.setAttribute(`label`, `Add column`);
37699
+ const addContainer = document.createElement(`ixfx-menu-container`);
37700
+ addContainer.setAttribute(`slot`, `submenu`);
37701
+ const idx = this._columns.findIndex((c) => c.id === col.id);
37702
+ for (const [label, offset] of [[`Left`, -1], [`Right`, 1]]) {
37703
+ const item = this.#menuItem(label, `add-${label.toLowerCase()}`, () => {
37704
+ this.#insertColumn(unused[0].key, Math.max(0, idx + Math.max(0, offset)));
37705
+ });
37706
+ item.toggleAttribute(`disabled`, !canAdd);
37707
+ addContainer.appendChild(item);
37708
+ }
37709
+ addSub.appendChild(addContainer);
37710
+ container.appendChild(addSub);
37711
+ const sortSub = document.createElement(`ixfx-menu-sub-trigger`);
37712
+ sortSub.setAttribute(`label`, `Sort`);
37713
+ const sortContainer = document.createElement(`ixfx-menu-container`);
37714
+ sortContainer.setAttribute(`slot`, `submenu`);
37715
+ sortContainer.appendChild(this.#menuItem(`Ascending`, `sort-asc`, () => {
37716
+ col.setSort(`asc`);
37717
+ this._emitColumnsChange(`sort`);
37718
+ this.requestUpdate();
37719
+ }, col.getState().sort === `asc` ? `check` : void 0));
37720
+ sortContainer.appendChild(this.#menuItem(`Descending`, `sort-desc`, () => {
37721
+ col.setSort(`desc`);
37722
+ this._emitColumnsChange(`sort`);
37723
+ this.requestUpdate();
37724
+ }, col.getState().sort === `desc` ? `check` : void 0));
37725
+ sortSub.appendChild(sortContainer);
37726
+ container.appendChild(sortSub);
37727
+ const grouped = col.getState().grouped;
37728
+ container.appendChild(this.#menuItem(grouped ? `Ungroup` : `Group`, `toggle-group`, () => {
37729
+ col.setGrouped(!grouped);
37730
+ this._emitColumnsChange(`grouping`);
37731
+ this.requestUpdate();
37732
+ }, grouped ? `check` : void 0));
37733
+ });
37734
+ }
37735
+ #insertColumn(categoryKey, position) {
37736
+ this.addColumn(categoryKey, position);
37737
+ }
37738
+ _changeColumnCategory(col, categoryKey) {
37739
+ const category = this.categories.find((c) => c.key === categoryKey);
37740
+ if (!category) return;
37741
+ col.setCategory(category);
37742
+ this._emitColumnsChange(`category`);
37743
+ this._requeryAllColumns();
37744
+ this.requestUpdate();
37745
+ }
37746
+ _onColumnSelectionChange(columnId, _values) {
37747
+ if (!this._columns.find((c) => c.id === columnId)) return;
37748
+ for (const otherCol of this._columns) if (otherCol.id !== columnId) otherCol.requestData(this._buildQuery(otherCol));
37749
+ const detail = {
37750
+ columnId,
37751
+ columns: this.getSelection()
37752
+ };
37753
+ this.dispatchEvent(new CustomEvent(`multicol-select`, {
37754
+ detail,
37755
+ bubbles: true,
37756
+ composed: true
37757
+ }));
37758
+ this.requestUpdate();
37759
+ }
37760
+ _onColumnRequestData(_columnId, _query, _signal) {}
37761
+ _buildQuery(col) {
37762
+ const otherSelections = /* @__PURE__ */ new Map();
37763
+ for (const c of this._columns) if (c.id !== col.id) otherSelections.set(c.id, c.selectedValues);
37764
+ return {
37765
+ columnId: col.id,
37766
+ categoryKey: col.categoryKey,
37767
+ otherSelections
37768
+ };
37769
+ }
37770
+ _requeryAllColumns() {
37771
+ for (const col of this._columns) col.requestData(this._buildQuery(col));
37772
+ }
37773
+ _syncColumnsWithCategories() {
37774
+ let changed = false;
37775
+ for (const col of this._columns) {
37776
+ if (this.categories.some((c) => c.key === col.categoryKey)) continue;
37777
+ if (this.categories.length === 0) continue;
37778
+ col.setCategory(this.categories[0]);
37779
+ changed = true;
37780
+ }
37781
+ if (changed) this._emitColumnsChange(`category`);
37782
+ }
37783
+ _updateColOffsets() {
37784
+ const offsets = [0];
37785
+ let sum = 0;
37786
+ for (const col of this._columns) {
37787
+ sum += col.getState().width ?? DEFAULT_COLUMN_WIDTH;
37788
+ offsets.push(sum);
37789
+ }
37790
+ if (!(offsets.length === this._colOffsets.length && offsets.every((v, i) => v === this._colOffsets[i]))) this._colOffsets = offsets;
37791
+ }
37792
+ _emitColumnsChange(reason) {
37793
+ this.dispatchEvent(new CustomEvent(`multicol-columns-change`, {
37794
+ detail: {
37795
+ columns: this.columns,
37796
+ reason
37797
+ },
37798
+ bubbles: true,
37799
+ composed: true
37800
+ }));
37801
+ }
37802
+ };
37803
+ __decorate([property({ attribute: false })], MulticolListElement.prototype, "categories", void 0);
37804
+ __decorate([property({ attribute: false })], MulticolListElement.prototype, "dataProvider", void 0);
37805
+ __decorate([property({
37806
+ type: String,
37807
+ attribute: `selection-mode`
37808
+ })], MulticolListElement.prototype, "selectionMode", void 0);
37809
+ __decorate([property({ type: Number })], MulticolListElement.prototype, "minColumns", void 0);
37810
+ __decorate([property({ type: Number })], MulticolListElement.prototype, "maxColumns", void 0);
37811
+ __decorate([state()], MulticolListElement.prototype, "_columns", void 0);
37812
+ __decorate([state()], MulticolListElement.prototype, "_colOffsets", void 0);
37813
+ __decorate([state()], MulticolListElement.prototype, "_resizingColumnId", void 0);
37814
+ __decorate([state()], MulticolListElement.prototype, "_draggingColumnId", void 0);
37815
+ __decorate([state()], MulticolListElement.prototype, "_dropCaretX", void 0);
37816
+ __decorate([query(`#container`)], MulticolListElement.prototype, "_containerEl", void 0);
37817
+ MulticolListElement = __decorate([customElement(`ixfx-multicol-list`)], MulticolListElement);
37818
+ //#endregion
36162
37819
  //#region src/notifier/notification-pill.ts
36163
37820
  let NotificationPillElement = class NotificationPillElement extends i {
36164
37821
  constructor(..._args) {
@@ -45863,12 +47520,25 @@ function squarifyInto(items, box) {
45863
47520
  }
45864
47521
  return out;
45865
47522
  }
47523
+ /** Clamp a raw cascade offset fraction to a sane range. */
47524
+ function normaliseOffset(raw) {
47525
+ return typeof raw === `number` && Number.isFinite(raw) && raw > 0 ? Math.min(raw, 1) : 0;
47526
+ }
45866
47527
  /**
45867
47528
  * Subdivide `box` among `weights` (same length as the child list) using
45868
47529
  * `method` at `relativeDepth`. Returns one absolute box per weight, in order.
45869
47530
  * Zero-share children get degenerate (zero-area) boxes at the box origin.
47531
+ * Degenerate (zero/negative-extent) containers also yield zero-area boxes
47532
+ * rather than `NaN` — this matters for cascaded layouts where deep insets
47533
+ * can consume the whole box.
45870
47534
  */
45871
47535
  function subdivide(box, weights, method, relativeDepth) {
47536
+ if (box.width <= 0 || box.height <= 0) return weights.map(() => ({
47537
+ x: box.x,
47538
+ y: box.y,
47539
+ width: 0,
47540
+ height: 0
47541
+ }));
45872
47542
  const total = weights.reduce((a, b) => a + b, 0);
45873
47543
  const shares = total > 0 ? weights.map((w) => w / total) : weights.map(() => 1 / weights.length);
45874
47544
  const dice = method === `dice` || method === `slice-dice` && relativeDepth % 2 === 0;
@@ -45935,12 +47605,16 @@ function subdivide(box, weights, method, relativeDepth) {
45935
47605
  * @param options `valueAccessor` (default equal weights), `maxDepth` (nesting
45936
47606
  * levels, default unlimited), `zoomKey` (visual root, default true root;
45937
47607
  * unknown keys fall back to the true root), `tilingMethod` (default
45938
- * `'squarify'`).
47608
+ * `'squarify'`), `presentation` (default `'nested'`) plus `cascadeOffsetX/Y`
47609
+ * (per-level shift as a viewport fraction, cascaded only).
45939
47610
  */
45940
47611
  function computeTreemapLayout(root, options = {}) {
45941
47612
  if (!root?.children?.length) return [];
45942
- const { maxDepth = Number.POSITIVE_INFINITY, valueAccessor = () => 1, zoomKey, tilingMethod = `squarify`, hideLeaves = false } = options;
47613
+ const { maxDepth = Number.POSITIVE_INFINITY, valueAccessor = () => 1, zoomKey, tilingMethod = `squarify`, hideLeaves = false, presentation = `nested`, cascadeOffsetX: rawOx, cascadeOffsetY: rawOy } = options;
45943
47614
  if (maxDepth <= 0) return [];
47615
+ const cascaded = presentation === `cascaded`;
47616
+ const ox = cascaded ? normaliseOffset(rawOx) : 0;
47617
+ const oy = cascaded ? normaliseOffset(rawOy) : 0;
45944
47618
  const visibleChildren = (node) => {
45945
47619
  const children = node.children ?? [];
45946
47620
  return hideLeaves ? children.filter((n) => n.item.isLeaf !== true) : children;
@@ -45971,7 +47645,15 @@ function computeTreemapLayout(root, options = {}) {
45971
47645
  setSize,
45972
47646
  hasChildren: children.length > 0 || node.children === void 0 && node.item.isLeaf !== true
45973
47647
  });
45974
- if (children.length > 0) layoutLevel(children, childBox, depth + 1, relativeDepth + 1, node.item.key);
47648
+ if (children.length > 0) {
47649
+ const contentBox = ox <= 0 && oy <= 0 ? childBox : {
47650
+ x: childBox.x + ox,
47651
+ y: childBox.y + oy,
47652
+ width: Math.max(0, childBox.width - ox),
47653
+ height: Math.max(0, childBox.height - oy)
47654
+ };
47655
+ layoutLevel(children, contentBox, depth + 1, relativeDepth + 1, node.item.key);
47656
+ }
45975
47657
  });
45976
47658
  };
45977
47659
  layoutLevel(siblings, {
@@ -45991,6 +47673,8 @@ let TreemapListElement = class TreemapListElement extends i {
45991
47673
  this.selectionFilter = `all`;
45992
47674
  this.interactionMode = `standard`;
45993
47675
  this.tilingMethod = `squarify`;
47676
+ this.presentation = `nested`;
47677
+ this.cascadeOffset = 6;
45994
47678
  this.maxDepth = 4;
45995
47679
  this.hideLeaves = false;
45996
47680
  this.minLabelArea = 1600;
@@ -46062,9 +47746,28 @@ let TreemapListElement = class TreemapListElement extends i {
46062
47746
  maxDepth: this.maxDepth,
46063
47747
  zoomKey,
46064
47748
  tilingMethod: this.tilingMethod,
46065
- hideLeaves: this.hideLeaves
47749
+ hideLeaves: this.hideLeaves,
47750
+ presentation: this.presentation,
47751
+ ...this.#cascadeFractions()
46066
47752
  });
46067
47753
  }
47754
+ /**
47755
+ * Pixel `cascadeOffset` as viewport fractions for the current host size.
47756
+ * Returns `{}` when nested, unmeasured, or non-positive — layout then falls
47757
+ * back to classic nesting for that pass (the `ResizeObserver` re-renders
47758
+ * once measured).
47759
+ */
47760
+ #cascadeFractions() {
47761
+ if (this.presentation !== `cascaded`) return {};
47762
+ if (!Number.isFinite(this.cascadeOffset) || this.cascadeOffset <= 0) return {};
47763
+ const w = this.clientWidth || 0;
47764
+ const h = this.clientHeight || 0;
47765
+ if (w <= 0 || h <= 0) return {};
47766
+ return {
47767
+ cascadeOffsetX: this.cascadeOffset / w,
47768
+ cascadeOffsetY: this.cascadeOffset / h
47769
+ };
47770
+ }
46068
47771
  connectedCallback() {
46069
47772
  super.connectedCallback();
46070
47773
  this.setAttribute(`data-input-mode`, `mouse`);
@@ -46679,7 +48382,11 @@ let TreemapListElement = class TreemapListElement extends i {
46679
48382
  #canDescend(rect) {
46680
48383
  const size = this.#pixelSize(rect);
46681
48384
  if (size === void 0) return true;
46682
- return size.width * size.height >= this.minChildArea && size.width >= this.minTileWidth;
48385
+ const offset = this.presentation === `cascaded` && Number.isFinite(this.cascadeOffset) && this.cascadeOffset > 0 ? this.cascadeOffset : 0;
48386
+ const w = size.width - offset;
48387
+ const h = size.height - offset;
48388
+ if (w <= 0 || h <= 0) return false;
48389
+ return w * h >= this.minChildArea && w >= this.minTileWidth;
46683
48390
  }
46684
48391
  /** Slugify a category name into a CSS custom-property-safe token. */
46685
48392
  #categorySlug(category) {
@@ -46791,6 +48498,7 @@ let TreemapListElement = class TreemapListElement extends i {
46791
48498
  class="treemap"
46792
48499
  role="tree"
46793
48500
  tabindex="0"
48501
+ data-presentation=${this.presentation}
46794
48502
  data-input-mode=${this.tickled.inputMode}
46795
48503
  style=${`--treemap-padding:${this.padding}px`}
46796
48504
  @keydown=${(e) => this.#handleKeyDown(e)}
@@ -46921,6 +48629,14 @@ let TreemapListElement = class TreemapListElement extends i {
46921
48629
  margin-top: 0;
46922
48630
  }
46923
48631
 
48632
+ /* Cascaded presentation (Lü & Fogarty 2008): the geometric inset is
48633
+ already in the layout rects — this adds the stack-of-cards depth
48634
+ cue on top. Parent tiles read as cards sitting behind their
48635
+ children. */
48636
+ .treemap[data-presentation="cascaded"] .tile {
48637
+ box-shadow: 2px 2px 0 rgb(0 0 0 / 0.25);
48638
+ }
48639
+
46924
48640
  .tile-header {
46925
48641
  flex-shrink: 0;
46926
48642
  padding: 1px var(--space-xs);
@@ -46991,6 +48707,14 @@ __decorate([property({
46991
48707
  type: String,
46992
48708
  attribute: `tiling-method`
46993
48709
  })], TreemapListElement.prototype, "tilingMethod", void 0);
48710
+ __decorate([property({
48711
+ type: String,
48712
+ attribute: `presentation`
48713
+ })], TreemapListElement.prototype, "presentation", void 0);
48714
+ __decorate([property({
48715
+ type: Number,
48716
+ attribute: `cascade-offset`
48717
+ })], TreemapListElement.prototype, "cascadeOffset", void 0);
46994
48718
  __decorate([property({
46995
48719
  type: Number,
46996
48720
  attribute: `max-depth`
@@ -48143,6 +49867,6 @@ function init() {
48143
49867
  console.log(`Init`);
48144
49868
  }
48145
49869
  //#endregion
48146
- export { AcTextElement, AcTokenElement, BottomDrawerElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DataController, DataDisplayComponent, DataGridElement, DataTableElement, DetailListElement, DockHostElement, DockPanelElement, EditableLabel, EditableNumber, FormElement, FormGroupElement, FormPartElement, GridListElement, GroupedItemListerElement, ICON_CARET_RIGHT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CLOSE, IcicleTreeListElement, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, KeyedElementIndex, LIST_ITEM_MOTION_MS, LIST_SEARCH_COMMAND_IDS, LIST_SEARCH_MODES, LabelledRadialInput, LabelledRangeInput, LabelledSliderInput, LedElement, ListDragSelectController, ListNativeDragController, ListSearchController, ListSelectionController, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, NarrowedTextElement, NotificationManager, NotificationPillElement, PanTextElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, RatingElement, SelectHorizElement, SliderInputElement, SlidingNumberElement, SnackbarElement, SnapContainer, SplitButton, SplitLayoutElement, SplitPanelElement, SwipeElement, TabController, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, TextShimmerElement, TickledController, TimelineController, TimelineTrackTabElement, TitlebarElement, ToolbarElement, ToolbarGroupElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeDropController, TreeKeyboardNavController, TreeListElement, TreemapListElement, TwoSplitLayoutElement, VerticalListElement, XyPad, addPanelToStack, animateListItemIn, animateListItemOut, applyAgeModification, applyHighlights, applySnapshot, applyTreeDrop, attachTimelineInteractions, bottomDrawerCommandId, buildHighlightTargets, buildModel, captionForEntry, clearHighlights, collectContainerNames, collectDataResult, collectPanelIds, collectStackPaths, computeColour, computeIcicleLayout, computeLeafGeoms, computeTreemapLayout, createAcCompletionProvider, createDataListSearchAdapter, createDefaultListDragPreview, createElementIncrSearch, createElementListSearchAdapter, createEmptyLayout, createEmptyStack, createFuzzySearch, createIncrSearch, createPillRenderer, createSplit, createStack, createTreeListAdapter, createTreeListSearchAdapter, createVerticalListAdapter, distribute, dropTargetFor, extractStack, findIcicleNode, findIciclePath, findNode, findParentOf, findStackOf, findStackPathByName, findTreemapNode, findTreemapPath, getActiveDragPanelId, getIcon, getIconEntry, getIconFont, getLeafNeighbours, hasIcon, iconBus, init, insertBeside, isDragging, isMultiMode, isSplit, isStack, keyForElement, listItemFadeKeyframes, listSearchStyles, monitorIndeterminate, moveLeafNodeToEdge, moveLeafStep, normalise, normaliseValue, normalize, panelGapIndex, parseColourScaleAttr, parseLayout, pointerOverAnyHost, prefersReducedMotion, pruneDraggedDescendants, readBaseColour, registerFontIcon, registerIcon, registerListSearchCommands, removePanelFromStack, resolveCssVars, resolveGrid, resolveLeafPath, resolveTracks, serializeLayout, setActive, setIconFont, startListItemOutAnimation, svgToDataUri, swapLeaves, tickledItemStyles, tickledStyles, timelineStyles, toSnapshot, toolbarGapIndex, walk, wrapRoot };
49870
+ export { AcTextElement, AcTokenElement, BottomDrawerElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DataController, DataDisplayComponent, DataGridElement, DataTableElement, DetailListElement, DockHostElement, DockPanelElement, EditableLabel, EditableNumber, FormElement, FormGroupElement, FormPartElement, GridListElement, GroupedItemListerElement, ICON_CARET_RIGHT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CLOSE, IcicleTreeListElement, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, KeyedElementIndex, LIST_ITEM_MOTION_MS, LIST_SEARCH_COMMAND_IDS, LIST_SEARCH_MODES, LabelledRadialInput, LabelledRangeInput, LabelledSliderInput, LedElement, ListDragSelectController, ListNativeDragController, ListSearchController, ListSelectionController, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, MulticolListElement, NarrowedTextElement, NotificationManager, NotificationPillElement, PanTextElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, RatingElement, SelectHorizElement, SliderInputElement, SlidingNumberElement, SnackbarElement, SnapContainer, SplitButton, SplitLayoutElement, SplitPanelElement, SwipeElement, TabController, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, TextShimmerElement, TickledController, TimelineController, TimelineTrackTabElement, TitlebarElement, ToolbarElement, ToolbarGroupElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeDropController, TreeKeyboardNavController, TreeListElement, TreemapListElement, TwoSplitLayoutElement, VerticalListElement, XyPad, addPanelToStack, animateListItemIn, animateListItemOut, applyAgeModification, applyHighlights, applySnapshot, applyTreeDrop, attachTimelineInteractions, bottomDrawerCommandId, buildHighlightTargets, buildModel, captionForEntry, clearHighlights, collectContainerNames, collectDataResult, collectPanelIds, collectStackPaths, computeColour, computeIcicleLayout, computeLeafGeoms, computeTreemapLayout, createAcCompletionProvider, createDataListSearchAdapter, createDefaultListDragPreview, createElementIncrSearch, createElementListSearchAdapter, createEmptyLayout, createEmptyStack, createFuzzySearch, createIncrSearch, createPillRenderer, createSplit, createStack, createTreeListAdapter, createTreeListSearchAdapter, createVerticalListAdapter, distribute, dropTargetFor, extractStack, findIcicleNode, findIciclePath, findNode, findParentOf, findStackOf, findStackPathByName, findTreemapNode, findTreemapPath, getActiveDragPanelId, getIcon, getIconEntry, getIconFont, getLeafNeighbours, hasIcon, iconBus, init, insertBeside, isDragging, isMultiMode, isSplit, isStack, keyForElement, listItemFadeKeyframes, listSearchStyles, monitorIndeterminate, moveLeafNodeToEdge, moveLeafStep, normalise, normaliseValue, normalize, panelGapIndex, parseColourScaleAttr, parseLayout, pointerOverAnyHost, prefersReducedMotion, pruneDraggedDescendants, readBaseColour, registerFontIcon, registerIcon, registerListSearchCommands, removePanelFromStack, resolveCssVars, resolveGrid, resolveLeafPath, resolveTracks, serializeLayout, setActive, setIconFont, startListItemOutAnimation, svgToDataUri, swapLeaves, tickledItemStyles, tickledStyles, timelineStyles, toSnapshot, toolbarGapIndex, walk, wrapRoot };
48147
49871
 
48148
49872
  //# sourceMappingURL=index.js.map