efficient-easel 0.106.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/README.md +70 -29
  2. package/dist/{LinkPicker-W2Rtxetz.d.ts → LinkPicker-hPEr1MJx.d.ts} +6 -4
  3. package/dist/autosave/index.d.ts +5 -5
  4. package/dist/chrome/chrome.css +50 -273
  5. package/dist/chrome/index.d.ts +61 -56
  6. package/dist/chrome/index.js +1 -1
  7. package/dist/chunk-4GNPKHV4.js +64 -0
  8. package/dist/chunk-5545A3PC.js +4 -0
  9. package/dist/chunk-7SQF6LZL.js +1 -0
  10. package/dist/chunk-BXMXTO36.js +1 -0
  11. package/dist/{chunk-JWMNPRTT.js → chunk-CKEPQNSQ.js} +1 -1
  12. package/dist/{chunk-LY4K2ECT.js → chunk-DJMMTWFP.js} +1 -1
  13. package/dist/chunk-EA2HTX37.js +5 -0
  14. package/dist/{chunk-VINYARYJ.js → chunk-FEK3S6HN.js} +1 -1
  15. package/dist/chunk-FPAVNX3Y.js +6 -0
  16. package/dist/chunk-HMJS344F.js +1 -0
  17. package/dist/chunk-JLTZQ4US.js +1 -0
  18. package/dist/chunk-JMGPPXNQ.js +24 -0
  19. package/dist/chunk-K56YDHYQ.js +1 -0
  20. package/dist/chunk-LOMEH6DG.js +1 -0
  21. package/dist/{chunk-FS5BLARH.js → chunk-MAEXP3KE.js} +1 -1
  22. package/dist/chunk-MJM6SFD3.js +3 -0
  23. package/dist/chunk-NLRW4BGG.js +8 -0
  24. package/dist/chunk-OJAJVH7S.js +5 -0
  25. package/dist/chunk-ONRYLR2D.js +2 -0
  26. package/dist/{chunk-WTMHT7BI.js → chunk-ORR3Q4WV.js} +1 -1
  27. package/dist/chunk-OTEXGJDU.js +5 -0
  28. package/dist/chunk-P2VEMZH5.js +1 -0
  29. package/dist/{chunk-MHKBLPQ2.js → chunk-PT6V53OO.js} +1 -1
  30. package/dist/{chunk-6WH7FA2M.js → chunk-PYCLHOSA.js} +2 -2
  31. package/dist/chunk-Q27BB5ZC.js +14 -0
  32. package/dist/chunk-QLD57GBB.js +6 -0
  33. package/dist/{chunk-PBSEUZD6.js → chunk-QMNML7XH.js} +1 -1
  34. package/dist/chunk-QR4DLZ3P.js +5 -0
  35. package/dist/chunk-TJ7YIRWQ.js +21 -0
  36. package/dist/{chunk-3P6AMTOS.js → chunk-VPFNZ7TB.js} +1 -1
  37. package/dist/chunk-W3XX2CNW.js +16 -0
  38. package/dist/chunk-X6DQWK2C.js +1 -0
  39. package/dist/chunk-XWR5YVA7.js +9 -0
  40. package/dist/chunk-YABL4EWX.js +7 -0
  41. package/dist/chunk-ZNNATBDC.js +1 -0
  42. package/dist/chunk-ZP4G3X44.js +4 -0
  43. package/dist/copy/copy.css +66 -177
  44. package/dist/copy/index.d.ts +0 -2
  45. package/dist/copy/index.js +31 -32
  46. package/dist/drag/drag.css +31 -11
  47. package/dist/drag/index.js +1 -1
  48. package/dist/easel/index.js +1 -1
  49. package/dist/fields/fields.css +35 -304
  50. package/dist/fields/index.d.ts +87 -95
  51. package/dist/fields/index.js +1 -1
  52. package/dist/gold/gold.css +3 -3
  53. package/dist/gold/index.d.ts +6 -5
  54. package/dist/gold/index.js +1 -1
  55. package/dist/index.d.ts +3 -3
  56. package/dist/index.js +1 -1
  57. package/dist/menu/index.d.ts +49 -93
  58. package/dist/menu/index.js +1 -1
  59. package/dist/menu/menu.css +37 -246
  60. package/dist/node-ops/index.d.ts +1 -1
  61. package/dist/panel/index.d.ts +46 -72
  62. package/dist/panel/index.js +17 -18
  63. package/dist/panel/panel.css +143 -372
  64. package/dist/pick/index.d.ts +52 -33
  65. package/dist/pick/index.js +7 -7
  66. package/dist/pick/pick.css +19 -150
  67. package/dist/rail/index.d.ts +48 -90
  68. package/dist/rail/index.js +1 -1
  69. package/dist/rail/rail.css +21 -108
  70. package/dist/screen/components/AddBlockRow.d.ts +8 -2
  71. package/dist/screen/components/AddBlockRow.js +1 -1
  72. package/dist/screen/components/AddChildRow.d.ts +4 -3
  73. package/dist/screen/components/AddChildRow.js +1 -1
  74. package/dist/screen/components/AddSidePanel.js +1 -1
  75. package/dist/screen/components/MediaSidePanel.d.ts +1 -1
  76. package/dist/screen/components/MediaSidePanel.js +1 -1
  77. package/dist/screen/components/NodeContextMenu.d.ts +12 -8
  78. package/dist/screen/components/NodeContextMenu.js +1 -1
  79. package/dist/screen/components/PageEditGuardNotices.js +1 -1
  80. package/dist/screen/components/ScreenChrome.js +1 -1
  81. package/dist/screen/components/ScreenDocumentContext.d.ts +1 -1
  82. package/dist/screen/components/ScreenDocumentContext.js +1 -1
  83. package/dist/screen/components/ScreenMount.d.ts +7 -7
  84. package/dist/screen/components/ScreenMount.js +1 -1
  85. package/dist/screen/components/ScreenStoreProvider.d.ts +7 -7
  86. package/dist/screen/components/ScreenStoreProvider.js +1 -1
  87. package/dist/screen/components/SectionScreenShell.js +16 -16
  88. package/dist/screen/components/SidePanelHead.d.ts +4 -2
  89. package/dist/screen/components/SidePanelHead.js +1 -1
  90. package/dist/screen/components/UiIcon.d.ts +10 -26
  91. package/dist/screen/components/UiIcon.js +2 -1
  92. package/dist/screen/components/panel-widths.js +1 -1
  93. package/dist/screen/components/usePartBridge.d.ts +7 -7
  94. package/dist/screen/components/usePartBridge.js +1 -1
  95. package/dist/screen/index.d.ts +7 -7
  96. package/dist/screen/index.js +1 -1
  97. package/dist/screen/lib/admin-bridge.d.ts +1 -1
  98. package/dist/screen/lib/admin-bridge.js +1 -1
  99. package/dist/screen/lib/chrome-theme.d.ts +20 -12
  100. package/dist/screen/lib/chrome-theme.js +1 -1
  101. package/dist/screen/lib/document-addressing.d.ts +1 -1
  102. package/dist/screen/lib/host-chrome.d.ts +1 -1
  103. package/dist/screen/lib/host.d.ts +1 -1
  104. package/dist/screen/lib/key-scope.js +1 -1
  105. package/dist/screen/lib/links/link-filters.d.ts +1 -1
  106. package/dist/screen/lib/media-panel.d.ts +1 -1
  107. package/dist/screen/lib/media-picker.d.ts +1 -1
  108. package/dist/screen/lib/page-lock.d.ts +1 -1
  109. package/dist/screen/lib/puck/style-clipboard.d.ts +7 -7
  110. package/dist/screen/lib/puck/use-section-ops.js +1 -1
  111. package/dist/screen/lib/screen-parts.d.ts +9 -8
  112. package/dist/screen/lib/screen-parts.js +1 -1
  113. package/dist/screen/lib/section-templates.d.ts +1 -1
  114. package/dist/screen/lib/session-context.d.ts +1 -1
  115. package/dist/screen/lib/session.d.ts +1 -1
  116. package/dist/screen/screen.css +33 -206
  117. package/dist/shell/index.d.ts +134 -118
  118. package/dist/shell/index.js +1 -1
  119. package/dist/shell/shell.css +130 -88
  120. package/dist/strings/catalogue.d.ts +5 -5
  121. package/dist/strings/catalogue.js +1 -1
  122. package/dist/strings/index.d.ts +5 -5
  123. package/dist/strings/index.js +1 -1
  124. package/dist/style-clipboard/index.d.ts +1 -1
  125. package/dist/text-styles/index.d.ts +12 -3
  126. package/dist/text-styles/index.js +33 -38
  127. package/dist/text-styles/text-styles.css +39 -71
  128. package/dist/tree/index.d.ts +49 -44
  129. package/dist/tree/index.js +1 -1
  130. package/dist/tree/tree.css +31 -653
  131. package/dist/{types-DJDBtdB2.d.ts → types-BqGnUVX5.d.ts} +32 -32
  132. package/dist/types-BsyPh6EW.d.ts +99 -0
  133. package/dist/{types-DWS-s9z-.d.ts → types-CsgMwHHa.d.ts} +14 -11
  134. package/dist/{types-CqY85foL.d.ts → types-Dt1CFR1S.d.ts} +4 -2
  135. package/dist/{wordFit-D4S36PvB.d.ts → wordFit-7XpmhcaW.d.ts} +3 -5
  136. package/dist/words-Cl9xMUYY.d.ts +41 -0
  137. package/dist/{words-D_Lnw1Gr.d.ts → words-CvFnwGSr.d.ts} +1 -1
  138. package/package.json +5 -1
  139. package/dist/chunk-2UX75JDP.js +0 -1
  140. package/dist/chunk-37OCQYNX.js +0 -65
  141. package/dist/chunk-3EDSDPIP.js +0 -1
  142. package/dist/chunk-3QVB4AG2.js +0 -3
  143. package/dist/chunk-3WSPDAK2.js +0 -1
  144. package/dist/chunk-5MZ3RNQQ.js +0 -13
  145. package/dist/chunk-5ZBBXZPV.js +0 -6
  146. package/dist/chunk-BZ5ASXOL.js +0 -1
  147. package/dist/chunk-C6BJB5AC.js +0 -2
  148. package/dist/chunk-DX4XELD6.js +0 -18
  149. package/dist/chunk-EOJNJCMJ.js +0 -16
  150. package/dist/chunk-EWVJSRRY.js +0 -6
  151. package/dist/chunk-H24N5TMZ.js +0 -11
  152. package/dist/chunk-I6T4TZ5Q.js +0 -8
  153. package/dist/chunk-KTVH2ZRL.js +0 -15
  154. package/dist/chunk-M7N2V4TG.js +0 -2
  155. package/dist/chunk-MS4QRBJ6.js +0 -5
  156. package/dist/chunk-ND55LTCA.js +0 -5
  157. package/dist/chunk-OWBO4WKA.js +0 -0
  158. package/dist/chunk-P6O363EE.js +0 -6
  159. package/dist/chunk-RW4XBUUW.js +0 -1
  160. package/dist/chunk-UEVTQBM7.js +0 -10
  161. package/dist/chunk-VCQVNPTG.js +0 -22
  162. package/dist/chunk-WZ7TGAAT.js +0 -3
  163. package/dist/chunk-YC4TB3CJ.js +0 -25
  164. package/dist/chunk-Z6SOLDWV.js +0 -1
  165. package/dist/chunk-ZFDCDJNZ.js +0 -16
  166. package/dist/chunk-ZNS7727Y.js +0 -12
  167. package/dist/types-Djdq6Xkd.d.ts +0 -138
  168. package/dist/words-DgHcY5qB.d.ts +0 -33
@@ -1,361 +1,42 @@
1
1
  /*
2
- * efficient-easel/tree.css — the Layers tree: one row shape at every depth.
2
+ * efficient-easel/tree.css — what the Layers tree still draws itself.
3
3
  *
4
- * EVERY VALUE HERE WAS READ OFF `efficient-storefront/components/storefront-editor.css`
5
- * on origin/main (release 14.24.0, 2026-09-17), where the website editor drew
6
- * the tree as `.sf-tree` / `.sf-row` / `.sf-subtree` / `.sf-group-label` (the
7
- * owner's "One Ladder", 2026-09-04). Its `--sf-*` tokens alias the `--es-*`
8
- * tokens spent here. New with the move: `.es-tree-preview` (0.42.0), and the
9
- * campaign editor's select button, marks, badge, end mark and plain action (0.44.0).
4
+ * The tree, its rows, groups, labels, actions and empty slot are the shell's
5
+ * (`Tree`, `TreeRow`, `TreeGroup`, `TreeGroupLabel`, `TreeEmptySlot`,
6
+ * `IconButton`; harness UI-24, efficient-easel#199), drawn by the shell's CSS,
7
+ * which a host loads first. What is left here has no shell piece:
10
8
  *
11
- * Needs `efficient-easel/shell.css`.
9
+ * · the scroll box round the tree (the shell's `Tree` does not scroll);
10
+ * · the lift of a row at the instant the browser takes its drag picture;
11
+ * · the size of the marks a row carries after its name, and the rename box.
12
+ *
13
+ * The seam, and a draggable row's grip, hint and cursor, are the shell's since
14
+ * efficient-shell 4.165.0 (`TreeSeam`; `TreeRow`'s `draggable` / `dragHint`).
15
+ *
16
+ * Shell tokens only (`--es-*` resolve to them, `--spacing` is the shell's step).
12
17
  */
13
18
 
14
19
  .es-tree {
15
20
  flex: 1;
16
21
  overflow-y: auto;
17
- /* LEFT 8 — the inset a rounded row needs. RIGHT 11 — the room a real,
18
- space-taking 11px scrollbar takes, so nothing at a row's end sits under
19
- the thumb. Words inside start on one 11px column down the panel. */
22
+ /* LEFT 8 — the inset a rounded row needs. RIGHT 12 — the room a real,
23
+ space-taking scrollbar takes, so nothing at a row's end sits under the thumb. */
20
24
  padding: 0 12px 12px 8px;
21
- /* THE TREE'S RHYTHM, under the shell's names, at the tree's own density: the
22
- owner picked 10 between groups and 6 between rows by eye (2026-08-31). They
23
- are declared HERE, not on the editor root, so the settings panel beside the
24
- tree keeps its own values for the same names. */
25
- --es-rhythm-group: 12px;
26
- --es-rhythm-between: 8px;
27
- }
28
- /* Every seam the tree stacks, spelled out: labels and subtrees interleave with
29
- rows, and a rule that knew only rows would leave those seams to chance. */
30
- .es-tree > .es-tree-row + .es-tree-row,
31
- .es-tree > .es-subtree + .es-tree-row {
32
- margin-top: var(--es-rhythm-between);
33
25
  }
34
26
 
35
- .es-tree-group {
36
- font-size: 10.5px;
37
- font-weight: 600;
38
- letter-spacing: 0.07em;
39
- text-transform: uppercase;
40
- color: var(--es-muted);
41
- padding: var(--es-rhythm-group) 12px var(--es-rhythm-between);
42
- }
43
-
44
- /* THE ONLY THING IN THE TREE THAT SAYS DEPTH: 16px of indent and a hairline
45
- that runs the height of the group. Rows inside sit exactly as far apart as
46
- rows outside, so the ladder reads as one list at several depths. */
47
- .es-subtree {
48
- margin: var(--es-rhythm-between) 0 var(--es-rhythm-between) 16px;
49
- padding-left: 8px;
50
- border-left: 1px solid var(--es-line);
51
- display: flex;
52
- flex-direction: column;
53
- gap: var(--es-rhythm-between);
54
- }
55
-
56
- .es-tree-row {
57
- display: flex;
58
- align-items: center;
59
- gap: 8px;
60
- padding: 8px 12px;
61
- border-radius: var(--es-row-radius);
62
- cursor: pointer;
63
- transition: background 0.12s;
64
- /* Anchors the drop rules and the out-of-flow drag handle. */
65
- position: relative;
66
- /* The ground this row is painted on, as a value its children can read: the
67
- actions' fade must end in the colour really behind the row. Every rule that
68
- changes the row's background changes this in the same block. */
69
- --es-row-scrim: var(--es-panel);
70
- }
71
- .es-tree-row:hover {
72
- --es-row-scrim: var(--es-hover);
73
- background: var(--es-row-scrim);
74
- }
75
- .es-tree-row.is-dragging {
76
- opacity: 0.4;
77
- }
78
- .es-tree-row.is-drop-before::before,
79
- .es-tree-row.is-drop-after::after {
80
- content: "";
81
- position: absolute;
82
- left: 8px;
83
- right: 8px;
84
- height: 2px;
85
- background: var(--es-accent);
86
- border-radius: 2px;
87
- pointer-events: none;
88
- }
89
- /* THE ONE DROP LINE (0.74.0): centred in the gap, where a seam draws its own —
90
- so a drop between two rows looks the same whether the pointer is over the
91
- lower half of one, the gap, or the upper half of the next. */
92
- .es-tree-row.is-drop-before::before {
93
- top: calc(-1px - var(--es-rhythm-between) / 2);
94
- }
95
- .es-tree-row.is-drop-after::after {
96
- bottom: calc(-1px - var(--es-rhythm-between) / 2);
97
- }
98
- /* An outline, not a border: a border would move every row below by 2px as the
99
- pointer crossed, which reads as the list flinching. */
100
- .es-tree-row.is-drop-into {
101
- outline: 2px solid var(--es-accent);
102
- outline-offset: -2px;
103
- border-radius: 6px;
104
- background: var(--es-accent-tint);
105
- }
106
- .es-tree-row.is-selected {
107
- --es-row-scrim: var(--es-accent-tint);
108
- background: var(--es-row-scrim);
109
- box-shadow: inset 2px 0 0 var(--es-accent);
110
- }
111
- .es-tree-row.is-selected .es-tree-chip {
27
+ /* On for the instant the browser takes the drag picture: the row that follows
28
+ the pointer is this one, raised. */
29
+ .es-tree-row.is-lifting {
112
30
  background: var(--es-raised);
113
- color: var(--es-accent);
114
- }
115
- .es-tree-row.is-selected .es-tree-name {
116
- color: var(--es-accent-text);
117
- font-weight: 600;
118
- }
119
-
120
- /* No ground and no rule: every row carries a glyph, so the glyph is the mark. */
121
- .es-tree-chip {
122
- width: 18px;
123
- height: 18px;
124
- border-radius: 5px;
125
- display: flex;
126
- align-items: center;
127
- justify-content: center;
128
- font-size: 12px;
129
- flex: none;
130
- background: transparent;
131
- color: var(--es-icon);
132
- }
133
- .es-tree-chip svg {
134
- width: 13px;
135
- height: 13px;
136
- }
137
-
138
- /* The name's box: what the actions are positioned against, so they cover the
139
- name's tail and never the caret. */
140
- .es-tree-name-box {
141
- position: relative;
142
- flex: 1;
143
- min-width: 0;
144
- display: flex;
145
- align-items: center;
146
- }
147
- /* One size at every depth — 12px / 500, the group pill's size at a row's weight. */
148
- .es-tree-name {
149
- flex: 1;
150
- font-size: 12px;
151
- font-weight: 500;
152
- color: var(--es-text);
153
- white-space: nowrap;
154
- overflow: hidden;
155
- text-overflow: ellipsis;
156
- }
157
- /* NEW in 0.42.0: the thing's own first words after its type — "Text BACK IN
158
- STOCK NOW" — quieter than the name, and the first thing to be cut when the
159
- panel is narrow (it sits inside the name's own ellipsis). */
160
- .es-tree-preview {
161
- margin-left: 8px;
162
- font-weight: 400;
163
- color: var(--es-muted);
164
- }
165
- .es-tree-row.is-selected .es-tree-preview {
166
- color: var(--es-accent-text);
167
- font-weight: 400;
168
- }
169
- .es-tree-row.is-hidden .es-tree-name {
170
- color: var(--es-muted);
171
- text-decoration: line-through;
172
- }
173
-
174
- .es-tree-actions {
175
- position: absolute;
176
- right: 0;
177
- top: 0;
178
- bottom: 0;
179
- display: flex;
180
- align-items: center;
181
- gap: 2px;
182
- /* 22px of fade so the name dissolves under the buttons instead of being
183
- chopped, ending in the ground this row is really painted on. */
184
- padding-left: 22px;
185
- background: linear-gradient(to right, transparent 0, var(--es-row-scrim) 22px);
186
- opacity: 0;
187
- pointer-events: none;
188
- transition: opacity 0.12s;
189
- }
190
- /* Hover AND focus. Bound to hover alone, a keyboard user who tabs to the trash
191
- gets it painted onto the name with nothing behind it. */
192
- .es-tree-row:hover .es-tree-actions,
193
- .es-tree-row:focus-within .es-tree-actions {
194
- opacity: 1;
195
- }
196
- /* THE STRIP NEVER TAKES THE POINTER — only the buttons in it do, and each arms
197
- its own as it shows (0.44.1). On a short row the fade covers most of the name,
198
- and a row that selects from its NAME button (`onSelect`) must still get the
199
- click: with the strip taking it, a hovered row could not be selected at all.
200
- A row that selects through its own onClick is unaffected — the click lands on
201
- the name and bubbles to the row as before. */
202
- /* A hidden row keeps its eye showing, back in the flow, so it can always be
203
- un-hidden without a scrim parked over its struck-through name. */
204
- .es-tree-row.is-hidden .es-tree-actions {
205
- position: static;
206
- opacity: 1;
207
- background: none;
208
- padding-left: 0;
209
- }
210
-
211
- .es-tree-del,
212
- .es-tree-eye {
213
- width: 22px;
214
- height: 22px;
215
- border: none;
216
- background: transparent;
217
- border-radius: 5px;
218
- cursor: pointer;
219
- display: flex;
220
- align-items: center;
221
- justify-content: center;
222
- padding: 0;
223
- opacity: 0;
224
- pointer-events: none;
225
- flex: none;
226
- }
227
- .es-tree-del svg,
228
- .es-tree-eye svg {
229
- width: 14px;
230
- height: 14px;
231
- }
232
- .es-tree-del {
233
- color: var(--es-danger);
234
- transition: opacity 0.12s, background 0.12s, color 0.12s;
235
- }
236
- .es-tree-eye {
237
- color: var(--es-muted);
238
- transition: opacity 0.12s, background 0.12s;
239
- }
240
- .es-tree-row:hover .es-tree-del,
241
- .es-tree-row:focus-within .es-tree-del,
242
- .es-tree-row:hover .es-tree-eye,
243
- .es-tree-row:focus-within .es-tree-eye {
244
- opacity: 0.7;
245
- pointer-events: auto;
246
- }
247
- .es-tree-del:hover {
248
- opacity: 1;
249
- background: var(--es-danger-tint);
250
- color: var(--es-danger-strong);
251
- }
252
- .es-tree-eye:hover {
253
- opacity: 1;
254
- background: var(--es-hover);
255
- }
256
- .es-tree-row.is-hidden .es-tree-eye {
257
- opacity: 1;
258
- pointer-events: auto;
259
- }
260
-
261
- /* The ONLY drag source and keyboard reorder route. It may be made invisible;
262
- it may never be made unreachable — opacity only, never display or visibility. */
263
- .es-tree-handle {
264
- position: absolute;
265
- left: 1px;
266
- top: 50%;
267
- transform: translateY(-50%);
268
- color: var(--es-disabled);
269
- font-family: inherit;
270
- font-size: 11px;
271
- line-height: 1;
272
- letter-spacing: -2px;
273
- width: 9px;
274
- flex: none;
275
- cursor: grab;
276
- opacity: 0;
277
- transition: opacity 0.12s;
278
- padding: 0;
279
- border: none;
280
- background: transparent;
281
- touch-action: none;
282
- }
283
- .es-tree-row:hover .es-tree-handle,
284
- .es-tree-handle:focus-visible {
285
- opacity: 1;
286
- }
287
- .es-tree-handle:active {
288
- cursor: grabbing;
289
- }
290
- .es-tree-handle:focus-visible {
291
- outline: 2px solid var(--es-accent);
292
- outline-offset: 1px;
293
- border-radius: 3px;
294
- color: var(--es-text-secondary);
295
- }
296
-
297
- /* The caret LEADS the row (One Ladder). A row that does not fold holds the
298
- column open with the spacer, so every glyph below lines up. */
299
- .es-tree-caret {
300
- width: 14px;
301
- height: 14px;
302
- margin-left: -2px;
303
- flex: none;
304
- padding: 0;
305
- border: none;
306
- background: transparent;
307
- border-radius: 4px;
308
- color: var(--es-muted);
309
- display: flex;
310
- align-items: center;
311
- justify-content: center;
312
- cursor: pointer;
313
- }
314
- .es-tree-caret:hover {
315
- background: var(--es-hover);
316
- color: var(--es-text);
317
- }
318
- .es-tree-caret-spacer {
319
- width: 14px;
320
- margin-left: -2px;
321
- flex: none;
322
- }
323
- .es-tree-chev {
324
- transition: transform 0.14s;
325
- }
326
- .es-tree-chev.is-open {
327
- transform: rotate(90deg);
31
+ box-shadow: var(--rosh-glass-solid-shadow);
328
32
  }
329
33
 
330
- /* ── 0.44.0 — the campaign editor's rows ─────────────────────────────────── */
331
- /* The name as a button, for keyboard selection. It must not move the row by a
332
- pixel against a row without one: no chrome, no padding, the same flex run. */
333
- .es-tree-select {
334
- all: unset;
335
- box-sizing: border-box;
336
- flex: 1;
337
- min-width: 0;
338
- display: flex;
339
- align-items: center;
340
- gap: 8px;
341
- cursor: pointer;
342
- border-radius: 4px;
343
- }
344
- .es-tree-select:focus-visible {
345
- outline: 2px solid var(--es-accent);
346
- outline-offset: 2px;
347
- }
348
- /* With a mark or a badge after it, the name hugs its words so the mark sits
349
- beside them rather than at the far end. A plain row keeps `flex: 1`. */
350
- .es-tree-select .es-tree-name,
351
- .es-tree-name:has(~ .es-tree-mark),
352
- .es-tree-name:has(~ .es-tree-badge) {
353
- flex: 0 1 auto;
354
- }
355
- /* A named state after the name — quiet, never a control. */
356
- .es-tree-mark {
357
- flex: none;
34
+ /* ── A row's marks: named pictures after its name, never controls ───────── */
35
+ .es-tree-mark,
36
+ .es-tree-trailing {
358
37
  display: inline-flex;
38
+ vertical-align: middle;
39
+ margin-left: 4px;
359
40
  color: var(--es-muted);
360
41
  }
361
42
  .es-tree-mark svg,
@@ -363,86 +44,9 @@
363
44
  width: 13px;
364
45
  height: 13px;
365
46
  }
366
- .es-tree-badge {
367
- flex: none;
368
- font-size: 10px;
369
- font-weight: 500;
370
- font-variant-numeric: tabular-nums;
371
- color: var(--es-muted);
372
- background: var(--es-chip-bg);
373
- border-radius: 4px;
374
- padding: 2px 4px;
375
- }
376
- .es-tree-trailing {
377
- flex: none;
378
- display: inline-flex;
379
- color: var(--es-muted);
380
- }
381
- /* Any other row action, in the neutral colour — the eye's twin. */
382
- .es-tree-act {
383
- width: 22px;
384
- height: 22px;
385
- border: none;
386
- background: transparent;
387
- border-radius: 5px;
388
- cursor: pointer;
389
- color: var(--es-muted);
390
- display: flex;
391
- align-items: center;
392
- justify-content: center;
393
- padding: 0;
394
- opacity: 0;
395
- pointer-events: none;
396
- flex: none;
397
- transition: opacity 0.12s, background 0.12s;
398
- }
399
- .es-tree-act svg {
400
- width: 14px;
401
- height: 14px;
402
- }
403
- .es-tree-row:hover .es-tree-act,
404
- .es-tree-row:focus-within .es-tree-act {
405
- opacity: 0.7;
406
- pointer-events: auto;
407
- }
408
- .es-tree-act:hover {
409
- opacity: 1;
410
- background: var(--es-hover);
411
- }
412
- .es-tree-act:disabled {
413
- color: var(--es-disabled);
414
- cursor: default;
415
- }
416
- /* A toggle that is ON stays visible at rest, like a hidden row's eye: the state
417
- has to be readable without hovering. */
418
- .es-tree-act[aria-pressed="true"] {
419
- opacity: 1;
420
- pointer-events: auto;
421
- color: var(--es-accent);
422
- }
423
- /* …which means its strip must show too. Same answer as a hidden row's eye: the
424
- strip goes back into the flow, with no scrim over the name, and the other
425
- actions in it still wait for hover. */
426
- .es-tree-actions:has(.es-tree-act[aria-pressed="true"]) {
427
- position: static;
428
- opacity: 1;
429
- background: none;
430
- padding-left: 0;
431
- }
432
- /* In the flow, the actions still waiting for hover must not hold their width
433
- open at rest — that would cut the name down to make room for buttons nobody
434
- can see. They come back when the row is hovered or focus enters it (the name
435
- button is the row's first tab stop, so the keyboard reaches them). */
436
- .es-tree-actions:has(.es-tree-act[aria-pressed="true"]) > :not([aria-pressed="true"]) {
437
- display: none;
438
- }
439
- .es-tree-row:hover .es-tree-actions:has(.es-tree-act[aria-pressed="true"]) > :not([aria-pressed="true"]),
440
- .es-tree-row:focus-within .es-tree-actions:has(.es-tree-act[aria-pressed="true"]) > :not([aria-pressed="true"]) {
441
- display: flex;
442
- }
443
47
 
444
48
  /* A rename box stands in for the name. It must not move the row by a pixel:
445
- same font and size, no border, no padding of its own. */
49
+ the name's own font, no border, no padding of its own. */
446
50
  .es-tree-rename {
447
51
  flex: 1 1 auto;
448
52
  min-width: 0;
@@ -450,240 +54,14 @@
450
54
  border: 0;
451
55
  background: transparent;
452
56
  font: inherit;
453
- font-size: 12px;
454
- font-weight: 500;
455
57
  color: inherit;
456
58
  outline: none;
457
59
  }
458
60
 
459
- /* ── Picking a row up (efficient-easel/drag, 0.74.0) ───────────────────────
460
- The whole row is the handle. It says so four ways, and none of them is a
461
- target of its own: the grab cursor, a faint ⋮ at its left on hover, a hint
462
- after 0.7 s, and — while it moves — the row lifted with a shadow. */
463
- .es-tree-row.is-draggable,
464
- .es-tree-row.is-draggable .es-tree-select {
465
- cursor: grab;
466
- }
467
- .es-tree-row.is-draggable:active,
468
- .es-tree-row.is-draggable:active .es-tree-select {
469
- cursor: grabbing;
470
- }
471
- .es-tree-grip {
472
- position: absolute;
473
- left: 2px;
474
- top: 50%;
475
- transform: translateY(-50%);
476
- font-size: 12px;
477
- line-height: 1;
478
- color: var(--es-disabled);
479
- opacity: 0;
480
- transition: opacity 0.12s;
481
- pointer-events: none;
482
- }
483
- .es-tree-row.is-draggable:hover .es-tree-grip {
484
- opacity: 0.8;
485
- }
486
- /* The hint waits 0.7 s on the way in and none on the way out — a delay in the
487
- transition, not a timer, so nothing re-renders while the pointer rests. */
488
- .es-tree-hint {
489
- position: absolute;
490
- left: 24px;
491
- top: calc(100% + 4px);
492
- z-index: 5;
493
- padding: 4px 8px;
494
- border-radius: 6px;
495
- background: var(--es-toast-bg);
496
- color: var(--es-on-accent);
497
- font-size: 11px;
498
- line-height: 1.3;
499
- white-space: nowrap;
500
- pointer-events: none;
501
- opacity: 0;
502
- transition: opacity 0.1s;
503
- }
504
- .es-tree-row.is-draggable:hover .es-tree-hint {
505
- opacity: 1;
506
- transition-delay: 0.7s;
507
- }
508
- .es-tree-row.is-dragging .es-tree-hint,
509
- .es-tree-row.is-lifting .es-tree-hint {
510
- display: none;
511
- }
512
- /* On for the instant the browser takes the drag picture: the row that follows
513
- the pointer is this one, raised. */
514
- .es-tree-row.is-lifting {
515
- background: var(--es-raised);
516
- box-shadow: 0 8px 20px rgba(16, 24, 40, 0.16), 0 2px 6px rgba(16, 24, 40, 0.1);
517
- }
518
-
519
- /* ── The seam — the gap between two rows, as a place (0.74.0) ───────────────
520
- A drop between rows lands here, and a host may offer a "+" that adds here.
521
- IT IS THE GAP: every rule below takes back the space a seam would otherwise
522
- add, so a list reads exactly the same with seams in it or without. A list's
523
- gaps are uniform — seams in every gap of it, or in none. */
524
- .es-tree-seam {
525
- position: relative;
526
- z-index: 1;
527
- flex: none;
528
- height: var(--es-rhythm-between);
529
- }
530
- /* A little more than the gap to aim at, over the rows' own edges. */
531
- .es-tree-seam::before {
532
- content: "";
533
- position: absolute;
534
- left: 0;
535
- right: 0;
536
- top: -4px;
537
- bottom: -4px;
538
- }
539
- .es-tree-seam::after {
540
- content: "";
541
- position: absolute;
542
- left: 8px;
543
- right: 8px;
544
- top: calc(50% - 1px);
545
- height: 2px;
546
- background: var(--es-accent);
547
- border-radius: 2px;
548
- opacity: 0;
549
- pointer-events: none;
550
- transition: opacity 0.12s;
551
- }
552
- .es-tree-seam.is-drop::after,
553
- .es-tree-seam.has-add:hover::after,
554
- .es-tree-seam.has-add:focus-within::after {
555
- opacity: 1;
556
- }
557
- .es-tree-seam-add {
558
- position: absolute;
559
- left: 50%;
560
- top: 50%;
561
- width: 18px;
562
- height: 18px;
563
- margin: -9px 0 0 -9px;
564
- padding: 0;
565
- border: none;
566
- border-radius: 50%;
567
- background: var(--es-accent);
568
- color: var(--es-on-accent);
569
- font: 600 13px/18px var(--es-font);
570
- cursor: pointer;
571
- opacity: 0;
572
- transform: scale(0.7);
573
- transition: opacity 0.12s, transform 0.12s;
574
- }
575
- .es-tree-seam.has-add:hover .es-tree-seam-add,
576
- .es-tree-seam-add:focus-visible {
577
- opacity: 1;
578
- transform: scale(1);
579
- }
580
- .es-tree-seam-add:focus-visible {
581
- outline: 2px solid var(--es-accent);
582
- outline-offset: 2px;
583
- }
584
- /* While something is being dropped, the line alone. */
585
- .es-tree-seam.is-drop .es-tree-seam-add {
586
- opacity: 0;
587
- }
588
- /* The top level stacks as blocks, and margins there collapse: a seam after a
589
- subtree, beside a group label, or at an end hands its height back. */
590
- .es-tree > .es-subtree + .es-tree-seam,
591
- .es-tree > .es-tree-group + .es-tree-seam,
592
- .es-tree > .es-tree-seam:last-child {
593
- margin-top: calc(-1 * var(--es-rhythm-between));
594
- }
595
- .es-tree > .es-tree-seam:has(+ .es-tree-group),
596
- .es-tree > .es-tree-seam:first-child {
597
- margin-bottom: calc(-1 * var(--es-rhythm-between));
598
- }
599
- /* …once: a seam both after a subtree and before a label has already handed its
600
- height back above. */
601
- .es-tree > .es-subtree + .es-tree-seam:has(+ .es-tree-group) {
602
- margin-bottom: 0;
603
- }
604
- /* One level down is a flex column with a gap: a seamed list's seams ARE its
605
- gaps, a nested list keeps the gap-and-margin it had, and the ends reach into
606
- the list's own margins. */
607
- .es-subtree:has(> .es-tree-seam) {
608
- gap: 0;
609
- }
610
- .es-subtree:has(> .es-tree-seam) > .es-subtree {
611
- margin-top: calc(2 * var(--es-rhythm-between));
612
- }
613
- .es-subtree > .es-tree-seam:first-child {
614
- margin-top: calc(-1 * var(--es-rhythm-between));
615
- }
616
- .es-subtree > .es-tree-seam:last-child {
617
- margin-bottom: calc(-1 * var(--es-rhythm-between));
618
- }
619
-
620
- /* ── An empty list, as a place (second host, 2026-10-06) ───────────────────
621
- Where a slot holds nothing yet: a box the size of a row, that takes a drop
622
- and — when the host offers it — adds there. NOT a seam: a seam is the gap
623
- between two rows and takes back the space it adds (above), so alone in a
624
- list it was a strip 8px tall with nothing drawn in it, and a drop aimed at
625
- "into this empty column" landed on whatever was really under the pointer.
626
-
627
- Dashed, because the thing is not there yet — the canvas says the same with
628
- its "+ Add block" cell (`.es-canvas-empty`, drag.css). Read off the campaign
629
- designer's `.cd-tree-add` (efficient-admin-portal), which drew one of its
630
- own; 34px is a row's height (8 + 18 + 8). */
631
- .es-tree-empty {
632
- box-sizing: border-box;
633
- flex: none;
634
- min-height: 34px;
635
- display: flex;
636
- align-items: stretch;
637
- border: 1px dashed var(--es-line);
638
- border-radius: var(--es-row-radius);
639
- color: var(--es-text-secondary);
640
- font: 500 12px/1.3 var(--es-font);
641
- transition: border-color 0.12s, color 0.12s, background 0.12s;
642
- }
643
- .es-tree-empty-add,
644
- .es-tree-empty-note {
645
- flex: 1;
646
- min-width: 0;
647
- display: flex;
648
- align-items: center;
649
- gap: 8px;
650
- padding: 0 12px;
651
- }
652
- /* The whole box is the button. A bare one: a native button ignores an author's
653
- background and border on some platforms, so the box draws them. */
654
- .es-tree-empty-add {
655
- border: none;
656
- border-radius: inherit;
657
- background: none;
658
- color: inherit;
659
- font: inherit;
660
- text-align: left;
661
- cursor: pointer;
662
- }
663
- .es-tree-empty-add:focus-visible {
664
- outline: 2px solid var(--es-accent);
665
- outline-offset: -2px;
666
- }
667
- /* Nothing to do here: the list is empty, and that is all it says. It SAYS it,
668
- so it is a grey that can be read: it was `--es-disabled` (#9ca3af), 2.5:1 on
669
- the panel, which axe-core failed on a read-only tree (2026-10-07). Held by
670
- ratio in tests/contrast-small-text.test.ts. */
671
- .es-tree-empty-note {
672
- color: var(--es-muted);
673
- }
674
- .es-tree-empty.has-add:hover,
675
- .es-tree-empty.is-drop {
676
- border-color: var(--es-accent);
677
- color: var(--es-accent-text);
678
- }
679
- .es-tree-empty.is-drop {
680
- background: var(--es-accent-tint);
681
- }
682
- .es-tree-empty.is-drop .es-tree-empty-note {
683
- color: inherit;
684
- }
685
- /* At the top level rows stack as blocks: keep the row's own distance from one above. */
686
- .es-tree > .es-tree-row + .es-tree-empty,
687
- .es-tree > .es-subtree + .es-tree-empty {
688
- margin-top: var(--es-rhythm-between);
61
+ /* A row action off WITH A REASON (`aria-disabled`, so the keyboard reaches it
62
+ and its Tooltip says why): the shell IconButton's own disabled fade, which
63
+ only `:disabled` draws. SHELL GAP: the kit has no focusable-disabled look. */
64
+ .es-tree-act-off {
65
+ opacity: 0.6;
66
+ cursor: not-allowed;
689
67
  }