efficient-easel 0.100.0 → 0.101.1

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 (53) hide show
  1. package/dist/chrome/index.js +24 -16
  2. package/dist/{chunk-QKVR3K73.js → chunk-2FZJWH24.js} +1 -1
  3. package/dist/chunk-546BBOPE.js +1 -0
  4. package/dist/{chunk-LGKQXSKO.js → chunk-EOJNJCMJ.js} +8 -8
  5. package/dist/{chunk-A5UK76FC.js → chunk-EWVJSRRY.js} +6 -6
  6. package/dist/chunk-FPOKPNO4.js +1 -0
  7. package/dist/chunk-H24N5TMZ.js +11 -0
  8. package/dist/chunk-IG3U5NWJ.js +1 -0
  9. package/dist/chunk-KTVH2ZRL.js +15 -0
  10. package/dist/{chunk-6EIVTKZZ.js → chunk-L5KW4HG5.js} +21 -20
  11. package/dist/{chunk-TRVZ7C23.js → chunk-QTLAVDJE.js} +1 -1
  12. package/dist/chunk-UH7IGZKF.js +1 -0
  13. package/dist/{chunk-V7GIIXFB.js → chunk-ZFDCDJNZ.js} +1 -1
  14. package/dist/{chunk-DICUMYMG.js → chunk-ZNS7727Y.js} +1 -1
  15. package/dist/copy/copy.css +83 -29
  16. package/dist/copy/index.d.ts +41 -7
  17. package/dist/copy/index.js +32 -31
  18. package/dist/drag/index.js +4 -4
  19. package/dist/fields/fields.css +185 -30
  20. package/dist/fields/index.d.ts +165 -20
  21. package/dist/fields/index.js +22 -37
  22. package/dist/gold/index.js +1 -1
  23. package/dist/icons/index.d.ts +4 -1
  24. package/dist/icons/index.js +1 -1
  25. package/dist/index.js +1 -1
  26. package/dist/markup/index.d.ts +18 -1
  27. package/dist/markup/index.js +1 -1
  28. package/dist/menu/index.js +1 -15
  29. package/dist/node-ops/index.js +1 -1
  30. package/dist/panel/index.d.ts +49 -38
  31. package/dist/panel/index.js +18 -18
  32. package/dist/panel/panel.css +99 -81
  33. package/dist/pick/index.d.ts +40 -2
  34. package/dist/pick/index.js +1 -1
  35. package/dist/pick/pick.css +183 -10
  36. package/dist/rail/index.js +1 -1
  37. package/dist/strings/catalogue.d.ts +3 -3
  38. package/dist/strings/catalogue.js +1 -1
  39. package/dist/strings/index.d.ts +3 -3
  40. package/dist/strings/index.js +1 -1
  41. package/dist/style-clipboard/index.js +1 -1
  42. package/dist/text-styles/index.js +13 -13
  43. package/dist/tree/index.js +1 -1
  44. package/dist/{words-CJjUKcV5.d.ts → words-BGrHZAJJ.d.ts} +13 -4
  45. package/dist/{words-CzoyDNHm.d.ts → words-D8kf071T.d.ts} +40 -2
  46. package/dist/{words-DBq7vfHy.d.ts → words-XH0TvZPg.d.ts} +8 -5
  47. package/package.json +1 -1
  48. package/dist/chunk-AZT7V4UM.js +0 -10
  49. package/dist/chunk-HDVD27VB.js +0 -1
  50. package/dist/chunk-JQM3V7XQ.js +0 -1
  51. package/dist/chunk-LA54QLP5.js +0 -1
  52. package/dist/chunk-MH5GUZFQ.js +0 -9
  53. package/dist/chunk-SAJUCHOX.js +0 -1
@@ -330,61 +330,38 @@
330
330
  box-shadow: 0 0 0 3px var(--es-accent-ring);
331
331
  }
332
332
 
333
- /* THE CHOSEN CHIP IS THE DARKEST THING IN THE ROW (card 66302).
334
-
335
- IT WAS A RAISED WHITE CHIP, AND THAT WAS NOT A MISTAKE. Card 66138 put white
336
- on the grey track with a soft lift, and Lewis picked that look himself from
337
- six treatments. He picked it BY EYE, AT A WIDTH WHERE THE WORDS WERE STILL
338
- THERE — which is the whole reason this is a revision and not a correction.
339
-
340
- WHAT CHANGED IS THE CONDITION, TWICE.
341
-
342
- First the words went. A four-tab strip is already wordless below 200px, and
343
- the panel's drag band bottoms out at 181px, so that state is live in the
344
- editor today; card 66246 then made the shop's Weight row show one word of
345
- four at the DEFAULT panel and none at the narrow end. A chip that used to sit
346
- beside a word became the only thing saying which option is set.
347
-
348
- Then the second mark went, and nobody noticed. Card 66248 moved the strip
349
- into this package and the quiet label darkened from the muted grey to
350
- `--es-text-secondary`. That darkening is right on its own terms — it is card
351
- 66138's AA fix, 4.39:1 to 9.37:1 on the track — but it also cut the
352
- chosen-vs-quiet GLYPH contrast from 3.67:1 to 1.72:1. The strip lost the one
353
- state cue that was already above 3:1, and the change was described as
354
- cosmetic when it merged.
355
-
356
- So the raised white chip was left carrying the whole message alone, at
357
- 1.10:1 against its own track, where WCAG 1.4.11 asks 3:1 of anything
358
- identifying a control's STATE.
359
-
360
- WHY DARK AND NOT A RING. Four treatments were drawn and measured for Lewis;
361
- two of the routes were closed by arithmetic before he saw them (darkening the
362
- track drops the quiet label to 3.40:1 and fails AA; pushing the glyph delta
363
- only reaches 3:1 by putting that label back where 66138 moved it FROM). Of
364
- what was left, this is the one that survives the DISABLED state:
365
- `.es-segs[data-disabled]` fades the strip to 0.5 over the panel, and a ring
366
- at 4.39:1 composites down to 1.89:1 while this holds 3.24:1. A cue that only
367
- works while the control is live is a cue with a hole in it.
368
-
369
- ⚠️ THE LIFT STAYS, AND IT IS NO LONGER THE MESSAGE. `--es-raised-shadow`
370
- still seats the chip on the track. What it must not go back to being is the
371
- thing telling the two states apart — a shadow is not a colour, so no
372
- contrast ratio can score it, and that is exactly how this got to 1.10:1
373
- without any guard noticing. `tests/panel-chip-contrast.test.ts` pins the
374
- RATIO and not this colour, so a better answer is free to replace it. */
333
+ /* THE CHOSEN CHIP IS BLUE (Lewis, 2026-10-06): 「用蓝色的背景, 不要黑色的了」.
334
+
335
+ Said while the shop's hand-built "pick one of 2-3" rungs were merged into
336
+ this control. It was `--es-text`, near-black, since card 66302; before that a
337
+ raised white chip (card 66138). Both editors draw every segmented control and
338
+ the settings tab strip from this one rule, so this is the whole change.
339
+
340
+ THE NUMBERS STILL HOLD, which is why the colour could move at all. Card 66302
341
+ made the chip the ONLY state cue once the words drop at the narrow end, and
342
+ WCAG 1.4.11 asks 3:1 of it: `--es-accent` on `--es-track-bg` is
343
+ 4.70:1, and the white word on it is 5.17:1 (1.4.3 asks 4.5:1 at 12px).
344
+
345
+ ⚠️ THE LIFT STAYS, AND IT IS NOT THE MESSAGE. `--es-raised-shadow` seats the
346
+ chip on the track; the colour is what tells the states apart, because a
347
+ shadow cannot be scored and that is how this once sat at 1.10:1 unnoticed.
348
+ `tests/panel-chip-contrast.test.ts` pins the ratios AND, since the ruling,
349
+ the colour itself. */
375
350
  .es-tab.is-active,
376
351
  .es-seg.is-active {
377
- background: var(--es-text);
352
+ background: var(--es-accent);
378
353
  color: var(--es-on-accent);
379
354
  box-shadow: var(--es-raised-shadow);
380
355
  border-radius: 6px;
381
356
  }
382
357
 
383
- /* Focused AND chosen: keep the lift, or the chip drops flat the moment a
384
- keyboard reaches it. */
358
+ /* Focused AND chosen. The quiet chip's ring is a translucent accent wash, and
359
+ laid against a chip that is itself the accent it reads as the chip growing,
360
+ not as focus. So this ring stands OFF the chip: a 2px gap in the panel
361
+ colour, then a solid accent ring — the blue chip, a white gap, a blue line. */
385
362
  .es-tab.is-active:focus-visible,
386
363
  .es-seg.is-active:focus-visible {
387
- box-shadow: var(--es-raised-shadow), 0 0 0 3px var(--es-accent-ring);
364
+ box-shadow: 0 0 0 2px var(--es-panel), 0 0 0 4px var(--es-accent);
388
365
  }
389
366
 
390
367
  .es-tab-badge {
@@ -689,26 +666,36 @@
689
666
  merchant's answer — a pressed chip faded to the same grey as the ones beside
690
667
  it stops saying which answer that was.
691
668
 
692
- ⚠️ THIS COLOUR BELONGS TO THE CHIP'S GROUND, NOT TO THE TRACK (card 66302).
693
- It was `--es-text-secondary`, which was right while the chip was white:
694
- 10.31:1 on it. The moment the chip went dark that same rule drew
695
- `--es-text-secondary` on `--es-text` — 1.72:1, an unreadable label on a
696
- control that had just been made MORE visible. Nothing about the rule changed; what it sat on moved underneath
697
- it. So it reads `--es-on-accent` for the same reason the enabled chip does,
698
- and the strip says which option is out of force through the track's fade and
699
- its quiet siblings rather than by dimming the one word still worth reading. */
700
- .es-seg:disabled.is-active { color: var(--es-on-accent); }
669
+ GREY, NOT BLUE, AND NOT FADED (2026-10-06). The live chip is the accent now,
670
+ and blue is the colour that says "this is in force" — so an answer out of
671
+ force drops to `--es-muted`. The arithmetic decided the rest: the blue chip
672
+ faded to half over the panel is 2.04:1 against its faded track, under the
673
+ 3:1 a state cue needs. `--es-muted` with no fade is 4.39:1 on the track and
674
+ its white word 4.83:1. That is why the whole strip no longer fades (below):
675
+ any fade took this chip under 3:1 again.
676
+
677
+ ⚠️ THE WORD COLOUR BELONGS TO THE CHIP'S GROUND, NOT TO THE TRACK (card
678
+ 66302): a label written for one ground went unreadable when the ground moved
679
+ under it. So the ground and the word are declared together, here. */
680
+ .es-seg:disabled.is-active {
681
+ background: var(--es-muted);
682
+ color: var(--es-on-accent);
683
+ }
701
684
 
702
685
  /* And none of them answers the pointer any more: the hover rule above would
703
686
  otherwise keep lighting a segment that cannot be chosen. */
704
687
  .es-seg:disabled:hover:not(.is-active) { color: var(--es-disabled); }
705
688
 
706
- /* THE WHOLE CONTROL, when every option went at once — one statement instead of
707
- three identically faded chips. The track is the part that says "these buttons
708
- are one control", so it is the right place to say the control is not in force.
709
- A single option out of force leaves the track alone, because the strip still
710
- is. */
711
- .es-segs[data-disabled] { opacity: 0.5; cursor: not-allowed; }
689
+ /* THE WHOLE CONTROL, when every option went at once. Every button is then
690
+ `:disabled`, so the quiet words are already `--es-disabled` and the chosen
691
+ chip is already grey — the strip says "out of force" through them.
692
+
693
+ IT USED TO FADE TO 0.5, and that fade is gone on purpose (2026-10-06). An
694
+ opacity on the track composites the chosen chip with it, and no chip colour
695
+ the ruling allows survives that above 3:1: blue faded is 2.04:1, the grey
696
+ above faded is about 2:1. The chip is the one thing a disabled strip must
697
+ still say clearly, so the fade went rather than the chip. */
698
+ .es-segs[data-disabled] { cursor: not-allowed; }
712
699
 
713
700
  /* ── a group: the soft pill row that folds ─────────────────────────────────── */
714
701
 
@@ -897,9 +884,23 @@ button.es-group-head:hover { background: var(--es-chip-bg); }
897
884
 
898
885
  .es-field.is-changed .es-field-label { color: var(--es-accent-text); }
899
886
 
887
+ /* The same cue, read off the row itself: a row whose Default / Reset part says
888
+ Reset is changed, whether or not its host passed `changed`. A host that draws
889
+ the part inside a component of its own (it reads a live value through a
890
+ hook) is invisible to SettingsField, and without this its label stayed grey
891
+ beside a Reset — measured on the website's section Width row. */
892
+ .es-field:has(> .es-field-head > .es-default-reset.is-changed) > .es-field-head .es-field-label {
893
+ color: var(--es-accent-text);
894
+ }
895
+
900
896
  .es-field-value {
901
897
  margin-left: auto;
902
898
  font-size: 12px;
899
+ /* The part's own 16px, and the head's min-height: so a row is one height
900
+ whether its value is drawn or not. Left to the host's line-height (18px in
901
+ the website editor) a press on Reset, which empties the value, moved every
902
+ row below it by 1.5px. */
903
+ line-height: 16px;
903
904
  color: var(--es-text);
904
905
  font-variant-numeric: tabular-nums;
905
906
  }
@@ -922,31 +923,42 @@ button.es-group-head:hover { background: var(--es-chip-bg); }
922
923
  }
923
924
 
924
925
  /* ── Default / Reset: the end of a label line ─────────────────────────────────
925
- Owner 2026-10-06: a value that follows its default says "Default", and a
926
- changed one offers a "Reset" button, in the same place. ONE element in both
927
- states (see SettingsDefaultReset.tsx), so both states share the box: same
928
- font, same padding, same height. Only the colour and the press change, and
929
- the row does not jump when a press turns one into the other.
930
-
931
- It sits at the END of the label line. With a value on the row, the value's
932
- own `margin-left: auto` has already pushed both right, and the gap between
933
- them is the head's own 8px; with no value, the part pushes itself. */
926
+ Owner 2026-10-06: ONE part puts a changed setting back. Option E, final
927
+ 2026-10-07: a ↺ icon button while the setting is changed, NOTHING while it is
928
+ not (the row's grey value already says it is the default).
929
+
930
+ ONE FIXED 22px SLOT IN BOTH STATES. The unchanged state is an empty span of
931
+ the same box, so every row's end lines up whether it can be reset or not.
932
+ It replaced PR 154's two hidden words, which sized the box to the wider of
933
+ "Default" and "Reset": there is no word to size for now.
934
+
935
+ Straight after the label the slot pushes itself to the row's end. After a
936
+ value it sits 4px from it (the head's 8px gap less 4, option E). After
937
+ anything else on the line — a colour row's readout — that thing has already
938
+ been pushed right; pick.css sets the gap there. A second `auto` would split
939
+ the free space and strand the slot mid-row (PR 163: 295px apart). */
934
940
  .es-default-reset {
935
941
  appearance: none;
936
942
  -webkit-appearance: none;
943
+ box-sizing: border-box;
937
944
  flex: none;
938
- margin: 0 -4px 0 0;
939
- padding: 2px 4px;
945
+ display: inline-flex;
946
+ align-items: center;
947
+ justify-content: center;
948
+ width: 22px;
949
+ height: 22px;
950
+ margin: 0;
951
+ padding: 0;
940
952
  border: 0;
941
- border-radius: 4px;
953
+ border-radius: 6px;
942
954
  background: transparent;
943
- font: inherit;
944
- font-size: 11px;
945
- font-weight: 500;
946
- line-height: 12px;
947
955
  color: var(--es-muted);
948
- white-space: nowrap;
949
- cursor: default;
956
+ }
957
+
958
+ .es-default-reset svg {
959
+ display: block;
960
+ width: 15px;
961
+ height: 15px;
950
962
  }
951
963
 
952
964
  .es-default-reset.is-changed {
@@ -971,8 +983,14 @@ button.es-group-head:hover { background: var(--es-chip-bg); }
971
983
  outline-offset: 1px;
972
984
  }
973
985
 
974
- .es-field-head > .es-default-reset { margin-left: auto; }
975
- .es-field-value + .es-default-reset { margin-left: 0; }
986
+ .es-field-name + .es-default-reset { margin-left: auto; }
987
+
988
+ /* THE GREY VALUE IS THE "DEFAULT" WORD NOW (option E): a row whose slot is
989
+ empty draws its value grey, and the value takes the text colour once the
990
+ setting is changed. Scoped to rows that carry the part, so a value on a row
991
+ with nothing to reset keeps its colour. */
992
+ .es-field:has(> .es-field-head > span.es-default-reset) .es-field-value { color: var(--es-muted); }
993
+ .es-field-value + .es-default-reset { margin-left: -4px; }
976
994
 
977
995
  /* A boolean row is ONE line (card 8801, Option A). The switch rides the label
978
996
  line in the `action` slot, so there is no control row under it — and with no
@@ -1,4 +1,5 @@
1
1
  import * as react from 'react';
2
+ import { ReactNode } from 'react';
2
3
  import { P as PickWords } from '../words-is_Vy6hn.js';
3
4
 
4
5
  /** One colour the site's theme names — offered first, by name. */
@@ -24,6 +25,28 @@ type ColourPickerProps = {
24
25
  * caption that IS the value's hex is no word, and the row's hex box stays.
25
26
  */
26
27
  caption?: string;
28
+ /**
29
+ * The colour IN FORCE while `value` is `''`: the setting has none of its own
30
+ * and follows a style (the email's body text, `#333333`). The swatch paints
31
+ * it (`is-inherited`, not the not-set look), the row prints `caption` or
32
+ * else that colour's hex in grey (no word: the row's Default part already
33
+ * says the state, one idea one word, GG 2026-10-07) — in the hex BOX, so a
34
+ * press selects it all for copying (GG for Lewis, 2026-10-07: the colour a
35
+ * row follows is the one most often copied); and the window starts
36
+ * from it with its hex as a placeholder. ⚠️ Nothing is written until the merchant moves something:
37
+ * showing the colour a setting follows must not pin it. Left out, or `''`,
38
+ * an empty value is "Not set", exactly as before.
39
+ */
40
+ inherited?: string;
41
+ /**
42
+ * A control drawn at the END of the row, after the hex: the panel's Default /
43
+ * Reset part (`SettingsDefaultReset`, Lewis 2026-10-06). ⚠️ INSIDE the row,
44
+ * not after the picker: a line that holds the picker wraps item by item, and
45
+ * a part beside the picker could drop onto a line of its own at a narrow
46
+ * panel (measured at 220px on a short label) while the swatch stayed above.
47
+ * In the row, the swatch, the hex and the part wrap as one.
48
+ */
49
+ after?: ReactNode;
27
50
  /** The swatch's DOM id, for a row whose own `<label for>` points at it. */
28
51
  id?: string;
29
52
  readOnly?: boolean;
@@ -52,8 +75,21 @@ type ColourPickerProps = {
52
75
  * The hex box is always a box you can type into — pasting a brand colour
53
76
  * costs no clicks — live on the keystroke that makes it a colour, and put back
54
77
  * to what is stored on Enter, Escape or leaving it.
78
+ *
79
+ * ONE LINE (Lewis, 2026-10-07, option E, final v9). In a line that holds it
80
+ * (`.es-field-head`, `.es-pick-line`) the label, the swatch, the hex and the
81
+ * host's `after` never wrap: short of room the label fades at its end (it
82
+ * keeps 56px), then the hex (it keeps 36px) — pick.css. What is cut is
83
+ * MEASURED here (`data-clipped` turns the fade on; text that fits is never
84
+ * faded), and over a cut label or hex a small dark tag shows the whole text.
85
+ * A press on the hex edits it IN PLACE: pick.css widens it to seven
86
+ * characters from its own left edge, never past the row's end
87
+ * (`--es-pick-edit-room`, measured here), and the `after` part steps aside
88
+ * only when that box reaches it (`data-editing="over"`). The swatch and the
89
+ * label never move. The accessible names are whole throughout: the fade and
90
+ * the tag are for the eye.
55
91
  */
56
- declare function ColourPicker({ value, onChange, label, theme, caption, id: swatchId, readOnly, words, }: ColourPickerProps): react.JSX.Element;
92
+ declare function ColourPicker({ value, onChange, label, theme, caption, inherited, after, id: swatchId, readOnly, words, }: ColourPickerProps): react.JSX.Element;
57
93
  type ColourWindowProps = {
58
94
  /** The colour, `#rrggbb`, or `''` while there is none. */
59
95
  value: string;
@@ -67,6 +103,8 @@ type ColourWindowProps = {
67
103
  onClose?: () => void;
68
104
  /** The window's DOM id, for the opener's `aria-controls`. */
69
105
  id?: string;
106
+ /** The colour in force while `value` is `''` (see `ColourPicker`): the window starts from it, its hex a placeholder. */
107
+ inherited?: string;
70
108
  readOnly?: boolean;
71
109
  words?: PickWords['colour'];
72
110
  /**
@@ -91,7 +129,7 @@ type ColourWindowProps = {
91
129
  * color, plan step E6) opens the same one, so there is one window, not two.
92
130
  * The opener owns when it is open and puts it in the panel's own flow.
93
131
  */
94
- declare function ColourWindow({ value, onChange, label, theme, onClose, id, readOnly, words, swatch, dragWrites, }: ColourWindowProps): react.JSX.Element;
132
+ declare function ColourWindow({ value, onChange, label, theme, onClose, id, inherited, readOnly, words, swatch, dragWrites, }: ColourWindowProps): react.JSX.Element;
95
133
 
96
134
  type ImageBoxProps = {
97
135
  /** The file's URL, or `''` while the setting has none. */
@@ -1,4 +1,4 @@
1
- import{mediaName as e}from"../chunk-AZT7V4UM.js";export{ColourPicker,ColourWindow,HEX_MAX_LENGTH,hexReadout,hexToHsv,hsvToHex,hueFromPoint,mediaName,svFromPoint,typedHex}from"../chunk-AZT7V4UM.js";import{DEFAULT_PICK_WORDS as a}from"../chunk-ZAOM6PFH.js";import{useState as i}from"react";import{jsx as l,jsxs as s}from"react/jsx-runtime";function c({value:c,onChange:n,label:o,openLibrary:r,kind:t="image",placeholder:m,readOnly:d,words:p=a.image}){const[u,h]=i(!1),[b,g]=i(!1),k=Boolean(r)&&!d,N=async()=>{if(r&&!u&&!d){h(!0),g(!1);try{const e=await r();e&&n(e)}catch{g(!0)}finally{h(!1)}}},f=u?/* @__PURE__ */l("p",{className:"es-pick-image-status",role:"status",children:p.choosing}):b?/* @__PURE__ */l("p",{className:"es-pick-image-status is-error",role:"alert",children:p.failed}):null;if(!c)/* @__PURE__ */
1
+ import{mediaName as e}from"../chunk-H24N5TMZ.js";export{ColourPicker,ColourWindow,HEX_MAX_LENGTH,hexReadout,hexToHsv,hsvToHex,hueFromPoint,mediaName,svFromPoint,typedHex}from"../chunk-H24N5TMZ.js";import{DEFAULT_PICK_WORDS as a}from"../chunk-ZAOM6PFH.js";import{useState as i}from"react";import{jsx as l,jsxs as s}from"react/jsx-runtime";function c({value:c,onChange:n,label:o,openLibrary:r,kind:t="image",placeholder:m,readOnly:d,words:p=a.image}){const[u,h]=i(!1),[b,g]=i(!1),k=Boolean(r)&&!d,N=async()=>{if(r&&!u&&!d){h(!0),g(!1);try{const e=await r();e&&n(e)}catch{g(!0)}finally{h(!1)}}},f=u?/* @__PURE__ */l("p",{className:"es-pick-image-status",role:"status",children:p.choosing}):b?/* @__PURE__ */l("p",{className:"es-pick-image-status is-error",role:"alert",children:p.failed}):null;if(!c)/* @__PURE__ */
2
2
  return s("div",{className:"es-pick-image",children:[
3
3
  /* @__PURE__ */s("button",{type:"button",className:"es-pick-image-slot",onClick:N,disabled:!k||u,"aria-label":p.empty({label:o,kind:t,placeholder:m}),children:[
4
4
  /* @__PURE__ */l("span",{className:"es-pick-image-slot-name",children:m??("video"===t?p.chooseVideo:p.chooseImage)}),k?/* @__PURE__ */l("span",{className:"es-pick-image-slot-hint",children:p.hint}):null]}),f]});const v=e(c),y=v?p.named({label:o,name:v}):o;/* @__PURE__ */
@@ -7,12 +7,14 @@
7
7
  /* The hex box and the word that stands in for it ("Auto", "Not set") are
8
8
  ONE width. A row is right-aligned as a unit, so a word narrower than a hex
9
9
  pushes its swatch out of line down a column of colour rows. */
10
- --es-pick-readout-w: 80px;
10
+ --es-pick-readout-w: 68px;
11
11
  display: flex;
12
12
  flex-direction: column;
13
13
  gap: 12px;
14
14
  }
15
15
  .es-pick-colour-row {
16
+ /* The tag is placed against the row. */
17
+ position: relative;
16
18
  display: flex;
17
19
  align-items: center;
18
20
  gap: 8px;
@@ -46,16 +48,27 @@
46
48
  .es-pick-swatch:disabled {
47
49
  cursor: default;
48
50
  }
51
+ /* THE HEX'S SLOT (Lewis 2026-10-07, option E): 68px, and down to 36px when
52
+ the line is short of room — after the label has given way to its 56px. The
53
+ hex or the word that stands in for it fills it. */
54
+ .es-pick-hexwrap {
55
+ position: relative;
56
+ display: flex;
57
+ align-items: center;
58
+ flex: 0 1 var(--es-pick-readout-w);
59
+ max-width: var(--es-pick-readout-w);
60
+ min-width: 36px;
61
+ }
49
62
  .es-pick-hex {
50
63
  box-sizing: border-box;
51
- width: var(--es-pick-readout-w);
64
+ width: 100%;
52
65
  min-width: 0;
53
66
  padding: 4px 8px;
54
67
  border: 1px solid transparent;
55
68
  border-radius: 6px;
56
69
  background: transparent;
57
70
  color: var(--es-text);
58
- font: 500 12px/1.3 ui-monospace, SFMono-Regular, Menlo, monospace;
71
+ font: 500 11px/1.3 ui-monospace, SFMono-Regular, Menlo, monospace;
59
72
  letter-spacing: 0.02em;
60
73
  }
61
74
  .es-pick-hex:hover {
@@ -66,13 +79,171 @@
66
79
  border-color: var(--es-accent);
67
80
  background: var(--es-panel);
68
81
  }
82
+ /* The hex a row FOLLOWS, in the row's box: grey at rest, so it does not read
83
+ as a value of its own; normal ink while it is edited (GG for Lewis,
84
+ 2026-10-07: pressed to copy it, or to paste over it). */
85
+ .es-pick-hex.is-inherited {
86
+ color: var(--es-muted);
87
+ }
88
+ .es-pick-hex.is-inherited:focus {
89
+ color: var(--es-text);
90
+ }
91
+ /* The inherited hex, while nothing is stored: grey, so it does not read as a
92
+ value. */
93
+ .es-pick-hex::placeholder {
94
+ color: var(--es-muted);
95
+ opacity: 1;
96
+ }
69
97
  .es-pick-caption {
70
98
  box-sizing: border-box;
71
- width: var(--es-pick-readout-w);
99
+ width: 100%;
100
+ min-width: 0;
101
+ overflow: hidden;
72
102
  padding: 0 8px;
103
+ white-space: nowrap;
73
104
  font-size: 12px;
74
105
  color: var(--es-muted);
75
106
  }
107
+ /* Cut text fades at its end, never cut hard. `data-clipped` is MEASURED
108
+ (ColourPicker): text that fits is never faded. */
109
+ .es-pick-hex[data-clipped],
110
+ .es-pick-caption[data-clipped] {
111
+ -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 16px), transparent);
112
+ mask-image: linear-gradient(to right, #000 calc(100% - 16px), transparent);
113
+ }
114
+ /* EDITED IN PLACE: a press widens the hex to seven characters (`#RRGGBB`
115
+ with its letter-spacing, the 8px insets and the 1px border), from its own
116
+ left edge, so the text does not jump and the swatch and the label do not
117
+ move; never past the row's end (`--es-pick-edit-room`, measured). */
118
+ .es-pick-colour-row .es-pick-hex:focus {
119
+ position: absolute;
120
+ z-index: 2;
121
+ left: 0;
122
+ top: 50%;
123
+ transform: translateY(-50%);
124
+ width: calc(7ch + 0.14em + 18px);
125
+ max-width: var(--es-pick-edit-room, none);
126
+ -webkit-mask-image: none;
127
+ mask-image: none;
128
+ box-shadow: 0 0 0 2px var(--es-accent-tint);
129
+ }
130
+ /* 4px from the hex to the part after it (the reset): the row's 8px, less 4. */
131
+ .es-pick-colour-row > .es-pick-hexwrap + * {
132
+ margin-left: -4px;
133
+ }
134
+ /* The part after the hex steps aside ONLY when the edit box reaches it. */
135
+ .es-pick-colour-row[data-editing='over'] > .es-pick-hexwrap ~ * {
136
+ visibility: hidden;
137
+ }
138
+ /* The tag over a cut label or hex: the whole text, small and dark, above it. */
139
+ .es-pick-tag {
140
+ position: absolute;
141
+ z-index: 3;
142
+ transform: translateY(calc(-100% - 6px));
143
+ padding: 4px 8px;
144
+ border-radius: 6px;
145
+ background: #111827;
146
+ color: #fff;
147
+ font-size: 12px;
148
+ font-weight: 500;
149
+ line-height: 1.3;
150
+ white-space: nowrap;
151
+ pointer-events: none;
152
+ box-shadow: 0 4px 12px rgb(0 0 0 / 0.2);
153
+ }
154
+ /* `.es-pick-swatch.is-inherited` (no rule of its own): the swatch is painted
155
+ with the colour the setting follows, like any colour. The class is there
156
+ for a host that wants to mark it. */
157
+
158
+ /* ── A line that holds the picker ───────────────────────────────────────── */
159
+ /* BOTH EDITORS HOLD THE PICKER IN A LINE: `SettingsField`'s `action` slot
160
+ (`.es-field-head`, this package's own class), or a colour SUB-row inside one
161
+ setting (the email's Logo "Color 1" / "Color 2", a button's Fill / Border /
162
+ Text), which is not a SettingsField and takes `.es-pick-line`: the host's
163
+ label first, then the picker.
164
+
165
+ The picker's own box steps aside (`display: contents`), so its two halves
166
+ become items of that line: the swatch and hex at the line's end
167
+ (`margin-left: auto`), and the window wrapping onto a line of its own at the
168
+ FULL width. Left in the picker's box, the window opens in the few pixels the
169
+ action slot has.
170
+
171
+ Moved here from the storefront's stylesheet (2026-10-06), so the email does
172
+ not copy it: one rule for both editors. The shop's `.sf-field--row` can move
173
+ onto `.es-pick-line` later. */
174
+ .es-pick-line {
175
+ display: flex;
176
+ flex-wrap: wrap;
177
+ align-items: center;
178
+ gap: 8px;
179
+ }
180
+ /* The sub-row's label. A host may use its own instead. */
181
+ .es-pick-line-label {
182
+ min-width: 0;
183
+ font-size: 12px;
184
+ color: var(--es-text-secondary);
185
+ }
186
+ .es-field-head:has(> .es-pick-colour),
187
+ .es-pick-line:has(> .es-pick-colour) {
188
+ flex-wrap: wrap;
189
+ }
190
+ .es-field-head > .es-pick-colour,
191
+ .es-pick-line > .es-pick-colour {
192
+ display: contents;
193
+ }
194
+ /* ONE LINE (Lewis 2026-10-07, option E). The row steps aside too, so the
195
+ label, the swatch, the hex's slot and the part after it are items of ONE
196
+ line, sized by rule and never by how wide their text is:
197
+ - the hex's slot is laid out at its 36px (so the line never wraps) and
198
+ grows FIRST, to its 68px;
199
+ - the label takes what is left, never under 56px, so it gives way first;
200
+ - the swatch is pushed to the end with what follows it, so a column of
201
+ rows lines up. The tag is placed against the line. */
202
+ .es-field-head:has(> .es-pick-colour),
203
+ .es-pick-line:has(> .es-pick-colour) {
204
+ position: relative;
205
+ }
206
+ .es-field-head > .es-pick-colour > .es-pick-colour-row,
207
+ .es-pick-line > .es-pick-colour > .es-pick-colour-row {
208
+ display: contents;
209
+ }
210
+ .es-field-head > .es-pick-colour > .es-pick-colour-row > .es-pick-swatch,
211
+ .es-pick-line > .es-pick-colour > .es-pick-colour-row > .es-pick-swatch {
212
+ margin-left: auto;
213
+ }
214
+ .es-field-head > .es-pick-colour > .es-pick-colour-row > .es-pick-hexwrap,
215
+ .es-pick-line > .es-pick-colour > .es-pick-colour-row > .es-pick-hexwrap {
216
+ flex: 1000 1 0;
217
+ }
218
+ /* The label: whatever is left, never under 56px, fading at its end when cut. */
219
+ .es-field-head:has(> .es-pick-colour) > .es-field-name,
220
+ .es-pick-line:has(> .es-pick-colour) > .es-pick-line-label {
221
+ flex: 1 1 0;
222
+ min-width: 56px;
223
+ overflow: hidden;
224
+ white-space: nowrap;
225
+ }
226
+ .es-field-head:has(> .es-pick-colour) .es-field-label {
227
+ min-width: 0;
228
+ overflow: hidden;
229
+ white-space: nowrap;
230
+ }
231
+ .es-field-head:has(> .es-pick-colour) .es-field-label[data-clipped],
232
+ .es-pick-line > .es-pick-line-label[data-clipped] {
233
+ -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
234
+ mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
235
+ }
236
+ .es-field-head > .es-pick-colour > .es-pick-window,
237
+ .es-pick-line > .es-pick-colour > .es-pick-window {
238
+ flex: 1 0 100%;
239
+ min-width: 0;
240
+ /* ⚠️ What a host puts AFTER the picker on the same line (the panel's
241
+ Default / Reset part, `SettingsDefaultReset`) comes after the window in
242
+ DOM order once the picker's box is `contents`, and the window's 100%
243
+ basis would push it onto a line of its own UNDER the open window. Ordered
244
+ last, the window keeps that control beside the swatch. */
245
+ order: 1;
246
+ }
76
247
 
77
248
  /* ── The window under the row ───────────────────────────────────────────── */
78
249
  .es-pick-window {
@@ -84,10 +255,13 @@
84
255
  border-radius: 10px;
85
256
  background: var(--es-panel);
86
257
  }
258
+ /* ONE theme row, for the colour picker and the text box's colour window
259
+ (Lewis 2026-10-07). The swatches are one group: the scale's step for the
260
+ cells of one group. */
87
261
  .es-pick-theme {
88
262
  display: flex;
89
263
  flex-wrap: wrap;
90
- gap: 8px;
264
+ gap: 4px;
91
265
  }
92
266
  .es-pick-theme-swatch {
93
267
  width: 22px;
@@ -98,11 +272,11 @@
98
272
  box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.1);
99
273
  cursor: pointer;
100
274
  }
275
+ /* The chosen one: the ring INSIDE the swatch (Lewis 2026-10-07, option A) —
276
+ 2px of accent, then 2px of panel before the colour. Outside, it touched the
277
+ next swatch. Focus is the outline, outside it, so both show at once. */
101
278
  .es-pick-theme-swatch[aria-pressed='true'] {
102
- box-shadow:
103
- inset 0 0 0 1px rgb(0 0 0 / 0.1),
104
- 0 0 0 2px var(--es-panel),
105
- 0 0 0 4px var(--es-accent);
279
+ box-shadow: inset 0 0 0 2px var(--es-accent), inset 0 0 0 4px var(--es-panel);
106
280
  }
107
281
  /* The square: the hue at full strength, washed to white left-to-right and to
108
282
  black top-to-bottom — which is what saturation and brightness ARE. */
@@ -152,7 +326,6 @@
152
326
  border-radius: 6px;
153
327
  box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.1);
154
328
  }
155
-
156
329
  /* ── The image box ──────────────────────────────────────────────────────── */
157
330
  .es-pick-image {
158
331
  display: flex;
@@ -1 +1 @@
1
- import"../chunk-OWBO4WKA.js";export{EaselRail,EaselRailButton,railCssVars,railTokens}from"../chunk-WZ7TGAAT.js";import"../chunk-2OAZYSWJ.js";import"../chunk-BZ5ASXOL.js";export{AddIcon,LayersIcon,MediaIcon,PageIcon as PagesIcon,SitemapIcon,StylesIcon}from"../chunk-6EIVTKZZ.js";
1
+ import"../chunk-OWBO4WKA.js";export{EaselRail,EaselRailButton,railCssVars,railTokens}from"../chunk-WZ7TGAAT.js";import"../chunk-2OAZYSWJ.js";import"../chunk-BZ5ASXOL.js";export{AddIcon,LayersIcon,MediaIcon,PageIcon as PagesIcon,SitemapIcon,StylesIcon}from"../chunk-L5KW4HG5.js";
@@ -1,11 +1,11 @@
1
1
  import { S as SaveWords } from '../words-BMzV04b1.js';
2
2
  import { N as NoticeWords, C as ChromeWords } from '../words-AHHfiaRY.js';
3
- import { C as CopyWords } from '../words-DBq7vfHy.js';
3
+ import { C as CopyWords } from '../words-XH0TvZPg.js';
4
4
  import { D as DragWords } from '../words-BDignMl_.js';
5
5
  import { LockWords } from '../edit-lock/index.js';
6
- import { F as FieldsWords } from '../words-CzoyDNHm.js';
6
+ import { F as FieldsWords } from '../words-D8kf071T.js';
7
7
  import { N as NodeMenuWords } from '../words-DMG4dYq2.js';
8
- import { P as PanelWords } from '../words-CJjUKcV5.js';
8
+ import { P as PanelWords } from '../words-BGrHZAJJ.js';
9
9
  import { P as PickWords } from '../words-is_Vy6hn.js';
10
10
  import { S as StyleClipboardWords } from '../words-CnnHb9jo.js';
11
11
  import { T as TextStylesWords } from '../words-CRYvAiHX.js';
@@ -1 +1 @@
1
- export{DEFAULT_EASEL_STRINGS,mergeEaselStrings}from"../chunk-SAJUCHOX.js";import"../chunk-M6F6LS3H.js";import"../chunk-6WY6ZXJG.js";import"../chunk-AELNNAFM.js";import"../chunk-3EDSDPIP.js";import"../chunk-TRVZ7C23.js";import"../chunk-WK3AFPXY.js";import"../chunk-H6DDIBQ4.js";import"../chunk-RE4LP46F.js";import"../chunk-ZJEBF4NB.js";import"../chunk-2OAZYSWJ.js";import"../chunk-JQM3V7XQ.js";import"../chunk-ZAOM6PFH.js";import"../chunk-LA54QLP5.js";import"../chunk-HDVD27VB.js";import"../chunk-O2NLQBFX.js";
1
+ export{DEFAULT_EASEL_STRINGS,mergeEaselStrings}from"../chunk-IG3U5NWJ.js";import"../chunk-M6F6LS3H.js";import"../chunk-6WY6ZXJG.js";import"../chunk-AELNNAFM.js";import"../chunk-3EDSDPIP.js";import"../chunk-QTLAVDJE.js";import"../chunk-WK3AFPXY.js";import"../chunk-H6DDIBQ4.js";import"../chunk-ZJEBF4NB.js";import"../chunk-RE4LP46F.js";import"../chunk-2OAZYSWJ.js";import"../chunk-UH7IGZKF.js";import"../chunk-ZAOM6PFH.js";import"../chunk-FPOKPNO4.js";import"../chunk-546BBOPE.js";import"../chunk-O2NLQBFX.js";
@@ -3,12 +3,12 @@ export { CanvasWords, DEFAULT_EASEL_STRINGS, RailWords, mergeEaselStrings } from
3
3
  import * as react from 'react';
4
4
  import { ReactNode } from 'react';
5
5
  export { C as ChromeWords, N as NoticeWords } from '../words-AHHfiaRY.js';
6
- export { C as CopyWords } from '../words-DBq7vfHy.js';
6
+ export { C as CopyWords } from '../words-XH0TvZPg.js';
7
7
  export { D as DragWords } from '../words-BDignMl_.js';
8
- export { F as FieldsWords } from '../words-CzoyDNHm.js';
8
+ export { F as FieldsWords } from '../words-D8kf071T.js';
9
9
  export { LockWords } from '../edit-lock/index.js';
10
10
  export { N as NodeMenuWords } from '../words-DMG4dYq2.js';
11
- export { P as PanelWords } from '../words-CJjUKcV5.js';
11
+ export { P as PanelWords } from '../words-BGrHZAJJ.js';
12
12
  export { P as PickWords } from '../words-is_Vy6hn.js';
13
13
  export { S as SaveWords } from '../words-BMzV04b1.js';
14
14
  export { S as StyleClipboardWords } from '../words-CnnHb9jo.js';
@@ -1,2 +1,2 @@
1
- import{DEFAULT_EASEL_STRINGS as r,mergeEaselStrings as n}from"../chunk-SAJUCHOX.js";export{DEFAULT_EASEL_STRINGS,mergeEaselStrings}from"../chunk-SAJUCHOX.js";import"../chunk-M6F6LS3H.js";import"../chunk-6WY6ZXJG.js";import"../chunk-AELNNAFM.js";import"../chunk-3EDSDPIP.js";import"../chunk-TRVZ7C23.js";import"../chunk-WK3AFPXY.js";import"../chunk-H6DDIBQ4.js";import"../chunk-RE4LP46F.js";import"../chunk-ZJEBF4NB.js";import"../chunk-2OAZYSWJ.js";import"../chunk-JQM3V7XQ.js";import"../chunk-ZAOM6PFH.js";import"../chunk-LA54QLP5.js";import"../chunk-HDVD27VB.js";import{stringsContext as o}from"../chunk-MFIRYGHW.js";import"../chunk-O2NLQBFX.js";import{useContext as t,useMemo as c}from"react";import{jsx as i}from"react/jsx-runtime";function s({value:s,locale:u,children:m}){const e=o(),p=t(e),h=p?.strings??r,j=u??p?.locale??"en",k=c(()=>({strings:n(h,s),locale:j}),[h,s,j]);/* @__PURE__ */
1
+ import{DEFAULT_EASEL_STRINGS as r,mergeEaselStrings as n}from"../chunk-IG3U5NWJ.js";export{DEFAULT_EASEL_STRINGS,mergeEaselStrings}from"../chunk-IG3U5NWJ.js";import"../chunk-M6F6LS3H.js";import"../chunk-6WY6ZXJG.js";import"../chunk-AELNNAFM.js";import"../chunk-3EDSDPIP.js";import"../chunk-QTLAVDJE.js";import"../chunk-WK3AFPXY.js";import"../chunk-H6DDIBQ4.js";import"../chunk-ZJEBF4NB.js";import"../chunk-RE4LP46F.js";import"../chunk-2OAZYSWJ.js";import"../chunk-UH7IGZKF.js";import"../chunk-ZAOM6PFH.js";import"../chunk-FPOKPNO4.js";import"../chunk-546BBOPE.js";import{stringsContext as o}from"../chunk-MFIRYGHW.js";import"../chunk-O2NLQBFX.js";import{useContext as t,useMemo as c}from"react";import{jsx as i}from"react/jsx-runtime";function s({value:s,locale:u,children:m}){const e=o(),p=t(e),h=p?.strings??r,j=u??p?.locale??"en",k=c(()=>({strings:n(h,s),locale:j}),[h,s,j]);/* @__PURE__ */
2
2
  return i(e.Provider,{value:k,children:m})}function u(){return t(o())?.strings??r}function m(){return t(o())?.locale??"en"}export{s as EaselStringsProvider,m as useEaselLocale,u as useEaselStrings};