@docx-editor.dev/core 2.4.1 → 2.6.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 (107) hide show
  1. package/THIRD_PARTY_NOTICES.md +39 -1
  2. package/dist/automation.cjs +1 -1
  3. package/dist/automation.js +1 -1
  4. package/dist/binding.cjs +1 -1
  5. package/dist/binding.d.cts +8 -8
  6. package/dist/binding.d.ts +8 -8
  7. package/dist/binding.js +1 -1
  8. package/dist/chunk-4GQXAXTZ.js +5 -0
  9. package/dist/chunk-DGUHCJPF.cjs +18 -0
  10. package/dist/chunk-DY3QVCWC.cjs +10 -0
  11. package/dist/chunk-E7BXJ4BF.js +1 -0
  12. package/dist/chunk-F7Z6PWAZ.cjs +2 -0
  13. package/dist/chunk-IJ4V3LGV.cjs +2 -0
  14. package/dist/chunk-JEMP5YI5.cjs +15 -0
  15. package/dist/{chunk-YMIMLEX4.cjs → chunk-JZXK4DKV.cjs} +1 -1
  16. package/dist/chunk-NIGGABAA.js +15 -0
  17. package/dist/chunk-OPKOTVQQ.js +18 -0
  18. package/dist/{chunk-GOEBQ26R.js → chunk-PSZH2VXP.js} +1 -1
  19. package/dist/chunk-R75OLPL6.js +10 -0
  20. package/dist/chunk-SFMAIFEN.cjs +2 -0
  21. package/dist/chunk-SKWYEZCO.cjs +5 -0
  22. package/dist/chunk-SMRD66T5.js +2 -0
  23. package/dist/chunk-UVIUNAQ6.js +2 -0
  24. package/dist/chunk-WAVN7MAT.js +2 -0
  25. package/dist/chunk-WU7PUTVA.js +2 -0
  26. package/dist/{chunk-OHJQ7GPZ.cjs → chunk-YMYCPY5Y.cjs} +1 -1
  27. package/dist/contracts/editor.cjs +1 -1
  28. package/dist/contracts/editor.d.cts +8 -8
  29. package/dist/contracts/editor.d.ts +8 -8
  30. package/dist/contracts/editor.js +1 -1
  31. package/dist/contracts/interaction.d.cts +7 -7
  32. package/dist/contracts/interaction.d.ts +7 -7
  33. package/dist/contracts/modules.d.cts +4 -4
  34. package/dist/contracts/modules.d.ts +4 -4
  35. package/dist/contracts/types.d.cts +3 -1
  36. package/dist/contracts/types.d.ts +3 -1
  37. package/dist/{custom-node-writes-C5YRoPcc.d.cts → custom-node-writes-D9G3GKQ7.d.cts} +18 -3
  38. package/dist/{custom-node-writes-BkMgMXxs.d.ts → custom-node-writes-tJw8U9MO.d.ts} +18 -3
  39. package/dist/dist-YFULGVS3.js +2 -0
  40. package/dist/{editor-DYvC9CZs.d.cts → editor-BZEJL3vv.d.cts} +50 -19
  41. package/dist/{editor-D1qHfzOt.d.ts → editor-D2zOJztO.d.ts} +50 -19
  42. package/dist/editor.cjs +1 -1
  43. package/dist/editor.css +407 -38
  44. package/dist/editor.d.cts +38 -22
  45. package/dist/editor.d.ts +38 -22
  46. package/dist/editor.js +1 -1
  47. package/dist/harfbuzz.wasm +0 -0
  48. package/dist/{image-resources-DXvPZvXD.d.cts → image-resources-BaHz4QAd.d.cts} +1 -1
  49. package/dist/{image-resources-BG9DLyW7.d.ts → image-resources-Cl5_cNi9.d.ts} +1 -1
  50. package/dist/{index-DpY3WZuP.d.ts → index-D8L8WrNF.d.ts} +178 -23
  51. package/dist/{index-Bb-QAg_f.d.cts → index-_xF7n_z0.d.cts} +178 -23
  52. package/dist/index.cjs +1 -1
  53. package/dist/index.d.cts +16 -16
  54. package/dist/index.d.ts +16 -16
  55. package/dist/index.js +1 -1
  56. package/dist/layout.cjs +1 -1
  57. package/dist/layout.d.cts +159 -47
  58. package/dist/layout.d.ts +159 -47
  59. package/dist/layout.js +1 -1
  60. package/dist/node-module-shim-TTKTT66I.js +1 -0
  61. package/dist/output.cjs +1 -1
  62. package/dist/output.d.cts +20 -6
  63. package/dist/output.d.ts +20 -6
  64. package/dist/output.js +1 -1
  65. package/dist/{review-reads-CxgN62yp.d.cts → review-reads-Dr0CpW6u.d.cts} +25 -1
  66. package/dist/{review-reads-CQmU9Lcl.d.ts → review-reads-HDvoQXK2.d.ts} +25 -1
  67. package/dist/{review-support-DgXTIYBW.d.ts → review-support-D4ZBdUXa.d.ts} +46 -2
  68. package/dist/{review-support-BJ-YjGmD.d.cts → review-support-T-riLz4Y.d.cts} +46 -2
  69. package/dist/{revision-projection-DHAkcD_L.d.ts → revision-projection-UKqvPa4-.d.ts} +53 -2
  70. package/dist/{revision-projection-72ZApe-g.d.cts → revision-projection-WzlQGBJx.d.cts} +53 -2
  71. package/dist/{semantic-cell-selection-DZtyMXkH.d.ts → semantic-cell-selection-B5vfPz4Q.d.ts} +7 -4
  72. package/dist/{semantic-cell-selection--ezfezTe.d.cts → semantic-cell-selection-BTQFpN0S.d.cts} +7 -4
  73. package/dist/{semantic-interaction-DrgbgKg6.d.ts → semantic-interaction-CDNEU_Tx.d.cts} +2 -30
  74. package/dist/{semantic-interaction-2yxdv7q0.d.cts → semantic-interaction-lvpzZRpA.d.ts} +2 -30
  75. package/dist/{semantic-paint-BedBxkyY.d.ts → semantic-paint-BBPL3u5w.d.ts} +111 -3
  76. package/dist/{semantic-paint-BYjE0Xbl.d.cts → semantic-paint-IjbL-4CT.d.cts} +111 -3
  77. package/dist/{semantic-records-CR5hTqMK.d.ts → semantic-records-CdQvpUj1.d.ts} +106 -8
  78. package/dist/{semantic-records-DSD8WENa.d.cts → semantic-records-DEOs3_tE.d.cts} +106 -8
  79. package/dist/{shaped-measurer-CBOTJTV_.d.cts → shaped-measurer-C2SJAjV0.d.cts} +1 -1
  80. package/dist/{shaped-measurer-BL8g4AcW.d.ts → shaped-measurer-l4o5ITJ0.d.ts} +1 -1
  81. package/dist/store.cjs +1 -1
  82. package/dist/store.d.cts +38 -15
  83. package/dist/store.d.ts +38 -15
  84. package/dist/store.js +1 -1
  85. package/dist/{tree-op-types-EZXbR8bW.d.cts → tree-op-types-CUCwPWjT.d.cts} +1 -1
  86. package/dist/{tree-op-types-8a6xyRCN.d.ts → tree-op-types-D0fTNBVW.d.ts} +1 -1
  87. package/dist/{tree-session-SucW0znF.d.ts → tree-session-CH1oA75f.d.ts} +64 -42
  88. package/dist/{tree-session-DrMm8Cj2.d.cts → tree-session-b7bggR-S.d.cts} +64 -42
  89. package/dist/{tree-store-UYrGKF_Q.d.cts → tree-store-BqgeCa1Q.d.cts} +29 -2
  90. package/dist/{tree-store-BoM6eXaL.d.ts → tree-store-CIKASRHk.d.ts} +29 -2
  91. package/licenses/HarfBuzz-COPYING.txt +42 -0
  92. package/package.json +6 -4
  93. package/dist/chunk-33F6TRXO.js +0 -2
  94. package/dist/chunk-4WWEDTTE.js +0 -2
  95. package/dist/chunk-BS554B6D.cjs +0 -2
  96. package/dist/chunk-DQ5HGUWG.cjs +0 -12
  97. package/dist/chunk-EQO762XH.cjs +0 -10
  98. package/dist/chunk-F6WNPYOM.js +0 -2
  99. package/dist/chunk-FL4GWK76.js +0 -12
  100. package/dist/chunk-GWG5IVVX.cjs +0 -5
  101. package/dist/chunk-IZIL6BAW.cjs +0 -12
  102. package/dist/chunk-LIJPSHRA.js +0 -5
  103. package/dist/chunk-MHDO6HLI.cjs +0 -2
  104. package/dist/chunk-SG7OH2EK.js +0 -12
  105. package/dist/chunk-TCX3PVWR.js +0 -10
  106. package/dist/chunk-YTYKNA6X.cjs +0 -2
  107. package/dist/chunk-ZACHY6OS.js +0 -1
package/dist/editor.css CHANGED
@@ -188,6 +188,10 @@
188
188
  display: contents;
189
189
  }
190
190
 
191
+ .docx-editor .\!hidden {
192
+ display: none !important;
193
+ }
194
+
191
195
  .docx-editor .hidden {
192
196
  display: none;
193
197
  }
@@ -858,6 +862,7 @@
858
862
 
859
863
  /* Surfaces */
860
864
  --doc-surface: #ffffff; /* panels, menus, dropdowns, cards */
865
+ --doc-popover-bg: var(--doc-surface); /* floating previews and contextual menus */
861
866
  --doc-card: #f8fbff; /* collapsed comment / suggestion cards (near-white) */
862
867
  --doc-bg: #f8f9fa; /* app background behind the page */
863
868
  --doc-bg-subtle: #f5f5f5; /* subtle section backgrounds */
@@ -884,13 +889,24 @@
884
889
 
885
890
  /* Inline comment/annotation marks. Resting highlights stay quiet on the
886
891
  * document canvas; focused sidebar items get the stronger active treatment. */
892
+ /* The open review card's wash. OPAQUE, and stated per theme rather than mixed from
893
+ `--doc-primary-light`: that token is translucent under `.dark`, so mixing it produced a
894
+ card the page showed through. A card is chrome and sits on its own ground. */
895
+ --doc-review-card-active-bg: color-mix(in srgb, #e8f0fe 45%, #fff);
896
+ /* The comment half of the highlight layer described beside the revision tokens below:
897
+ `-bg` and `-border` are the band every comment wears, and the `-active-` pair is the
898
+ one the reader has open. Comments carry no wash on the run itself, so unlike a tracked
899
+ change their pending state lives here. */
887
900
  --doc-comment-bg: rgba(255, 212, 0, 0.12);
888
901
  --doc-comment-border: rgba(245, 174, 0, 0.45);
889
902
  --doc-comment-active-bg: rgba(255, 212, 0, 0.35);
890
903
  --doc-comment-active-border: rgba(245, 174, 0, 0.9);
904
+ --doc-comment-resolved-active-bg: rgba(255, 212, 0, 0.18);
905
+ --doc-comment-resolved-active-border: rgba(245, 174, 0, 0.6);
891
906
 
892
907
  /* Text */
893
908
  --doc-text: #202124; /* primary text */
909
+ --doc-popover-fg: var(--doc-text); /* text inside floating previews and menus */
894
910
  --doc-text-muted: #5f6368; /* secondary text */
895
911
  --doc-text-subtle: #9aa0a6; /* tertiary/disabled text */
896
912
  --doc-text-placeholder: #999; /* placeholder text */
@@ -921,6 +937,29 @@
921
937
  --doc-revision-deletion: #c62828;
922
938
  --doc-revision-insertion-tint: rgba(46, 125, 50, 0.09);
923
939
  --doc-revision-deletion-tint: rgba(198, 40, 40, 0.09);
940
+ /* THE HIGHLIGHT LAYER, which reads the same for tracked changes and for comments:
941
+ `-bg` is the band's fill and `-border` the rule under it, and an `-active-` pair is
942
+ the same two for the one the reader has open. The comment family is below.
943
+
944
+ Only the OPEN state is a token here. A pending change already carries its colour on
945
+ the run itself (the `-wash` pair below), so its band is transparent by design —
946
+ painting both doubled the colour wherever the band happened to reach. A comment has
947
+ no run wash, so its pending state lives on the band and does take a token.
948
+
949
+ Deeper than the wash for the same reason the comment bands deepen: opening a card
950
+ does not select the text, so this band is the only thing on the page saying which
951
+ change the card is about. */
952
+ --doc-revision-insertion-active-bg: rgba(46, 125, 50, 0.24);
953
+ --doc-revision-insertion-active-border: var(--doc-revision-insertion);
954
+ --doc-revision-deletion-active-bg: rgba(198, 40, 40, 0.24);
955
+ --doc-revision-deletion-active-border: var(--doc-revision-deletion);
956
+ /* A format or structural change decorates no characters, so it takes a neutral fill
957
+ rather than one claiming text was added or removed. */
958
+ --doc-revision-other-active-bg: color-mix(
959
+ in srgb,
960
+ var(--doc-text-muted, #8a8f98) 14%,
961
+ transparent
962
+ );
924
963
  /* The wash a PENDING change wears. The painter puts this on the run itself, so it covers
925
964
  tracked text anywhere in the document rather than only where the band layer reaches; the
926
965
  band adds the full tint on top for the one the caret is in, and the two multiply into a
@@ -1110,19 +1149,19 @@
1110
1149
  --doc-on-primary: #1f1f1f; /* text/icon on a filled primary surface */
1111
1150
  --doc-toggle-active-bg: var(--doc-primary-light);
1112
1151
  --doc-toggle-active-fg: var(--doc-primary);
1152
+ /* Mixed from the OPAQUE accent, not from the translucent `--doc-primary-light` above. */
1153
+ --doc-review-card-active-bg: color-mix(in srgb, #4e9dff 12%, var(--doc-surface, #1b1d22));
1113
1154
  --doc-comment-bg: rgba(253, 214, 99, 0.16);
1114
1155
  --doc-comment-border: rgba(253, 214, 99, 0.5);
1115
1156
  --doc-comment-active-bg: rgba(253, 214, 99, 0.32);
1116
1157
  --doc-comment-active-border: rgba(253, 214, 99, 0.95);
1117
- /* Dark mode: the same ramp, lifted so it reads on a dark page. */
1118
- --doc-review-author-0: #ff8a80;
1119
- --doc-review-author-1: #82b1ff;
1120
- --doc-review-author-2: #d7a3ff;
1121
- --doc-review-author-3: #7fe3c5;
1122
- --doc-review-author-4: #ffd180;
1123
- --doc-review-author-5: #ff9e80;
1124
- --doc-review-author-6: #b0bec5;
1125
- --doc-review-author-7: #ce93d8;
1158
+ /* NOT the author ramp. It used to be lifted here, back when only the review cards read
1159
+ it — but the ramp now colours the painted DOCUMENT too, and the dark page is rendered
1160
+ through `invert(1) hue-rotate(180deg)` (see `.docx-page-content` below). A colour
1161
+ consumed inside that filter must be authored for the LIGHT page or it is corrected
1162
+ twice: the lifted `#ff8a80` inverted to `#b54a41` on a `#333` page, 2.4:1 and below
1163
+ AA. The same reason `--doc-revision-insertion` / `-deletion` are not overridden here.
1164
+ The CARDS sit outside the filter and lift the accent themselves, further down. */
1126
1165
  --doc-revision-format: #9fb3bf;
1127
1166
  --doc-review-change-bar: #9e9e9e;
1128
1167
  --doc-text: #e8e8e8; /* primary text */
@@ -1703,6 +1742,22 @@ a.docx-hyperlink:focus-visible {
1703
1742
  opacity: 1;
1704
1743
  }
1705
1744
 
1745
+ /* A document nobody may write has nothing to fill in, so the pointer must not light a
1746
+ * control as though it did. `data-active` and `data-boundary-visible` still show: those say
1747
+ * WHERE a control is, which a reader may want. Only the hover invitation goes. The painter
1748
+ * sets `data-read-only` from the same answer that disables the widget, so there is no second
1749
+ * definition of what read-only means. */
1750
+ .docx-content-control-chrome[data-read-only]:hover .docx-content-control-boundary {
1751
+ border-color: color-mix(in srgb, var(--doc-primary) 24%, var(--doc-page-bg-rendered));
1752
+ background: color-mix(in srgb, var(--doc-primary) 3%, var(--doc-page-bg-rendered));
1753
+ opacity: 0;
1754
+ }
1755
+
1756
+ .docx-content-control-chrome[data-read-only][data-active] .docx-content-control-boundary,
1757
+ .docx-content-control-chrome[data-read-only][data-boundary-visible] .docx-content-control-boundary {
1758
+ opacity: 1;
1759
+ }
1760
+
1706
1761
  /*
1707
1762
  * Populated TOC: nothing at rest — no border, no background — and never sticky from the
1708
1763
  * caret or a click. The surface sets `data-hover` on the painted chrome while the pointer
@@ -1760,6 +1815,12 @@ a.docx-hyperlink:focus-visible {
1760
1815
  border-color: color-mix(in srgb, var(--doc-primary) 55%, transparent) !important;
1761
1816
  }
1762
1817
 
1818
+ /* Same rule for the widget: a disabled button that lights under the pointer reads as live. */
1819
+ .docx-content-control-chrome[data-read-only]:hover .docx-content-control-widget {
1820
+ background: color-mix(in srgb, var(--doc-primary) 4%, var(--doc-page-bg-rendered));
1821
+ border-color: color-mix(in srgb, var(--doc-primary) 28%, var(--doc-page-bg-rendered)) !important;
1822
+ }
1823
+
1763
1824
  .docx-content-control-widget::after {
1764
1825
  position: absolute;
1765
1826
  inset: 0;
@@ -3132,6 +3193,36 @@ a.docx-hyperlink:focus-visible {
3132
3193
  pointer-events: auto;
3133
3194
  }
3134
3195
 
3196
+ .docx-image-selection-overlay {
3197
+ position: absolute;
3198
+ inset: 0;
3199
+ z-index: var(--doc-z-chrome);
3200
+ pointer-events: none;
3201
+ outline: none;
3202
+ }
3203
+
3204
+ .docx-image-selection-overlay__frame {
3205
+ position: absolute;
3206
+ box-sizing: border-box;
3207
+ border: 2px solid var(--doc-accent);
3208
+ pointer-events: none;
3209
+ }
3210
+
3211
+ .docx-image-selection-overlay__frame.docx-editor-one-surface__overlay-control {
3212
+ pointer-events: auto;
3213
+ }
3214
+
3215
+ .docx-image-selection-overlay__handle {
3216
+ position: absolute;
3217
+ box-sizing: border-box;
3218
+ width: 10px;
3219
+ height: 10px;
3220
+ padding: 0;
3221
+ border: 1px solid var(--doc-accent);
3222
+ background: var(--doc-bg);
3223
+ pointer-events: auto;
3224
+ }
3225
+
3135
3226
  /* The hidden ProseMirror input host. Position, size, clipping, and opacity are
3136
3227
  * owned imperatively by engine-binding's input-host module, which keeps the
3137
3228
  * host attached, non-`display:none`, and tracking the engine caret so browser
@@ -3235,18 +3326,24 @@ a.docx-hyperlink:focus-visible {
3235
3326
  }
3236
3327
 
3237
3328
  /* Sticky horizontal ruler: scrolls horizontally with the document, stays put
3238
- * vertically, and never covers the page content. */
3329
+ * vertically, and never covers the page content. Centred by auto margins on the
3330
+ * child, not justify-content, so an oversized ruler clamps to the start edge
3331
+ * like the page instead of overflowing both sides on narrow hosts. */
3239
3332
  .docx-editor-shell__ruler-h {
3240
3333
  position: sticky;
3241
3334
  top: 0;
3242
3335
  z-index: 2;
3243
3336
  flex: none;
3244
3337
  display: flex;
3245
- justify-content: center;
3246
3338
  padding: 4px 20px;
3247
3339
  background: var(--doc-bg);
3248
3340
  }
3249
3341
 
3342
+ .docx-editor-shell__ruler-h > * {
3343
+ flex-shrink: 0;
3344
+ margin-inline: auto;
3345
+ }
3346
+
3250
3347
  .docx-editor-shell__canvas {
3251
3348
  position: relative;
3252
3349
  flex: 1;
@@ -3434,16 +3531,21 @@ a.docx-hyperlink:focus-visible {
3434
3531
  height: 22px;
3435
3532
  }
3436
3533
 
3437
- /* The review pane's gutter reaches the ruler as a right MARGIN and the page as the scroller's
3438
- right PADDING. Both move by the same distance, so both have to move on the same curve —
3439
- without this the sheet glided left and the ruler above it snapped, and for the length of the
3440
- animation the ruler measured a page that was no longer under it. */
3441
- .docx-horizontal-ruler {
3442
- transition: margin 0.2s ease;
3534
+ /* The pane gutters reach the ruler as PADDING on its frame and the page as the scroller's
3535
+ padding. Both move by the same distance, so both have to move on the same curve —
3536
+ without this the sheet glided and the ruler above it snapped, and for the length of the
3537
+ animation the ruler measured a page that was no longer under it.
3538
+
3539
+ The INLINE-START edge only, because that is the only edge the scroller animates: the
3540
+ scroller's `padding-right` (the review column) deliberately snaps, so a ruler easing
3541
+ its right padding for 0.2s measured a page that had already jumped. One edge per curve,
3542
+ both elements on the same one. */
3543
+ .docx-ruler-frame {
3544
+ transition: padding-inline-start 0.2s ease;
3443
3545
  }
3444
3546
 
3445
3547
  @media (prefers-reduced-motion: reduce) {
3446
- .docx-horizontal-ruler {
3548
+ .docx-ruler-frame {
3447
3549
  transition: none;
3448
3550
  }
3449
3551
  }
@@ -4042,16 +4144,23 @@ a.docx-hyperlink:focus-visible {
4042
4144
  margin-bottom: 4px;
4043
4145
  }
4044
4146
 
4045
- /* No affordance while another furniture scope is open, in view mode, or in print. */
4147
+ /* No affordance while another furniture scope is open, in view mode, or in print.
4148
+ * Each selector MIRRORS the qualifiers of the rule it cancels: the existing-band tint
4149
+ * carries two `:not()`s and the footer hint carries an attribute selector, so a plainer
4150
+ * selector here LOST the specificity race and left the invitation on screen. */
4046
4151
  .docx-pages--hf-editing .docx-hf--placeholder:hover,
4047
4152
  .docx-paginated-surface--viewing .docx-hf--placeholder:hover,
4048
- .docx-pages--hf-editing .docx-hf:not([data-docx-hf-active]):hover,
4049
- .docx-paginated-surface--viewing .docx-hf:not([data-docx-hf-active]):hover {
4153
+ .docx-pages--hf-editing .docx-hf:not([data-docx-hf-active]):not(.docx-hf--placeholder):hover,
4154
+ .docx-paginated-surface--viewing
4155
+ .docx-hf:not([data-docx-hf-active]):not(.docx-hf--placeholder):hover {
4050
4156
  background: none;
4051
4157
  }
4052
4158
 
4053
- .docx-pages--hf-editing .docx-hf--placeholder:hover::after,
4054
- .docx-paginated-surface--viewing .docx-hf--placeholder:hover::after {
4159
+ /* The extra class here is STRUCTURE, not ballast: `docx-pages` is `docx-paginated-surface`'s
4160
+ * own child and carries `docx-pages--hf-editing` itself, so the weight that beats the
4161
+ * footer variant comes from a fact the painter cannot drift away from. */
4162
+ .docx-pages.docx-pages--hf-editing .docx-hf--placeholder:hover::after,
4163
+ .docx-paginated-surface--viewing .docx-pages .docx-hf--placeholder:hover::after {
4055
4164
  content: none;
4056
4165
  }
4057
4166
 
@@ -4060,6 +4169,13 @@ a.docx-hyperlink:focus-visible {
4060
4169
  display: none;
4061
4170
  }
4062
4171
 
4172
+ /* The last half of the affordance: an I-beam over a band nobody can enter reads as "put a
4173
+ * caret here", which viewing refuses. Furniture text never maps to a model position anyway
4174
+ * — see `dom-selection` — so the arrow is the honest cursor here. */
4175
+ .docx-paginated-surface--viewing .docx-hf:not([data-docx-hf-active]) {
4176
+ cursor: default;
4177
+ }
4178
+
4063
4179
  @media print {
4064
4180
  .docx-hf--placeholder,
4065
4181
  .docx-hf-edit-hint {
@@ -5385,6 +5501,35 @@ a.docx-hyperlink:focus-visible {
5385
5501
  font-size: 14px;
5386
5502
  }
5387
5503
 
5504
+ /* The overlay variant (`<DocxEditor.Loading overlay />`): pinned over the nearest
5505
+ positioned ancestor — the workspace row in the packaged frame — and opaque, so it
5506
+ covers the previous document while the next one opens. The 150ms appearance delay
5507
+ keeps an open that finishes inside a few frames from flashing a spinner.
5508
+
5509
+ The fade MUST be a real compositor animation. The engine paints exactly one frame
5510
+ (overlay committed, still in its delay) and then blocks the main thread with the
5511
+ mount — so only the compositor can bring the overlay in. A non-zero opacity
5512
+ animation on a `will-change: opacity` layer runs compositor-side through the block;
5513
+ a zero-duration delay trick would be a main-thread style jump and never show. */
5514
+ .docx-editor__loading--overlay {
5515
+ position: absolute;
5516
+ inset: 0;
5517
+ z-index: var(--doc-z-overlay);
5518
+ background: var(--doc-bg);
5519
+ will-change: opacity;
5520
+ animation: docx-editor-loading-appear 0.2s linear 0.15s backwards;
5521
+ }
5522
+
5523
+ @keyframes docx-editor-loading-appear {
5524
+ from {
5525
+ opacity: 0;
5526
+ }
5527
+
5528
+ to {
5529
+ opacity: 1;
5530
+ }
5531
+ }
5532
+
5388
5533
  /* The default screen when the host supplies no children.
5389
5534
  `display` and `box-sizing` are explicit rather than inherited from Tailwind's
5390
5535
  preflight: the part emits its own `docx-editor`, so it can be composed somewhere the
@@ -5398,6 +5543,9 @@ a.docx-hyperlink:focus-visible {
5398
5543
  border: 3px solid var(--doc-border);
5399
5544
  border-top-color: var(--doc-primary);
5400
5545
  border-radius: 50%;
5546
+ /* Layer-promoted so the rotation runs on the compositor: while a big document
5547
+ mounts, the main thread is blocked and only a composited animation still moves. */
5548
+ will-change: transform;
5401
5549
  animation: docx-editor-loading-spin 0.8s linear infinite;
5402
5550
  }
5403
5551
 
@@ -5563,13 +5711,22 @@ a.docx-hyperlink:focus-visible {
5563
5711
 
5564
5712
  /* Room for the review pane. The page centres inside the scroller's padding box, so
5565
5713
  * reserving the rail's width here shifts the sheet left by half of it and the document and
5566
- * its cards read as one centred pair. Closed, only the marker strip is reserved. */
5714
+ * its cards read as one centred pair.
5715
+ *
5716
+ * The reservation is a MEASUREMENT, not a constant: `DocxEditor.Viewport` publishes
5717
+ * `--docx-review-gutter` (this edge) and `--docx-review-gutter-start` (mirrored onto the
5718
+ * inline start, composed into the navigation rule below) from the viewport's width and the
5719
+ * page's entitled width. A viewport with room for both keeps the full column; one without
5720
+ * gets the marker strip on BOTH edges, so the sheet sits centred instead of parked beside
5721
+ * a mostly-empty band. The fallbacks — the full column while open, the strip while
5722
+ * closed — are what stood before the measurement existed, so an unmeasured host paints as
5723
+ * it always did. */
5567
5724
  .docx-editor__scroll-container[data-review-pane='open'] {
5568
- padding-right: 316px;
5725
+ padding-right: var(--docx-review-gutter, 316px);
5569
5726
  }
5570
5727
 
5571
5728
  .docx-editor__scroll-container[data-review-pane='closed'] {
5572
- padding-right: 44px;
5729
+ padding-right: var(--docx-review-gutter, 44px);
5573
5730
  }
5574
5731
 
5575
5732
  /* The review rail (`DocxEditor.Review` / the Vue equivalent): one card per pending decision,
@@ -5593,6 +5750,22 @@ a.docx-hyperlink:focus-visible {
5593
5750
  width: 32px;
5594
5751
  }
5595
5752
 
5753
+ /* Compact rail (`data-compact`: the pane is open but the viewport reserved only the
5754
+ * mirrored marker strip). The strip shows the markers, and the ONE active card floats at
5755
+ * column width, pinned inside the viewport's right edge — over the page, where a shadow
5756
+ * has to separate it from the ink underneath. Its slot is positioned inline by the rail. */
5757
+ .docx-review__slot--compact .docx-review__card {
5758
+ box-shadow: var(--doc-shadow-lg);
5759
+ }
5760
+
5761
+ /* The column's cards print BESIDE the sheet, which is harmless; the compact card floats
5762
+ * OVER it, which would print on top of the document's own ink. Screen chrome only. */
5763
+ @media print {
5764
+ .docx-review__slot--compact {
5765
+ display: none !important;
5766
+ }
5767
+ }
5768
+
5596
5769
  /* The "comment on this" button. Pulled OUT of the card column, onto the page's own edge:
5597
5770
  the column is where comments live, and a button standing in it lands on whichever card
5598
5771
  already annotates the text being re-selected. On the edge there is nothing to collide
@@ -5630,7 +5803,7 @@ a.docx-hyperlink:focus-visible {
5630
5803
 
5631
5804
  /* A card being composed reads as unfinished until it is committed. */
5632
5805
  .docx-review__card[data-draft] {
5633
- border-color: var(--doc-primary, #1a73e8);
5806
+ border-color: var(--doc-review-author-ink, var(--doc-primary, #1a73e8));
5634
5807
  }
5635
5808
 
5636
5809
  /* The Word-style decision balloon: clicking a format or structural change in the page
@@ -5700,7 +5873,12 @@ a.docx-hyperlink:focus-visible {
5700
5873
  * as scrollbar-gutter above. */
5701
5874
  .docx-editor .docx-editor__scroll-container,
5702
5875
  .docx-editor.docx-editor__scroll-container {
5703
- padding-inline-start: var(--docx-nav-shift, 0px);
5876
+ /* Two reservations compose on this edge: the navigation pane's displacement, and the
5877
+ * review gutter's mirrored strip (`--docx-review-gutter-start`, 0 whenever the full
5878
+ * column stands on the right). One declaration, because `padding-inline-start` and
5879
+ * `padding-left` are the same slot in LTR and a second rule would just lose the
5880
+ * specificity fight. */
5881
+ padding-inline-start: calc(var(--docx-nav-shift, 0px) + var(--docx-review-gutter-start, 0px));
5704
5882
  transition: padding-inline-start 0.2s ease;
5705
5883
  }
5706
5884
 
@@ -6070,6 +6248,34 @@ a.docx-hyperlink:focus-visible {
6070
6248
  display: none;
6071
6249
  }
6072
6250
 
6251
+ /* THE CHROME'S READING OF AN AUTHOR'S COLOUR.
6252
+ The review surface sets `--doc-review-author-current` inline on each card, balloon and marker,
6253
+ from the same ramp the painted document draws that author in. These two derive from it,
6254
+ and they are declared on the elements themselves because a custom property that
6255
+ references `--doc-review-author-current` has to be computed where that property is actually set —
6256
+ an ancestor rule would resolve the fallback and inherit it down.
6257
+ Light: the page and the chrome agree on the value. Dark: the PAGE is rendered through an
6258
+ inverting filter and the chrome is not, so only the chrome lifts. */
6259
+ .docx-review__card,
6260
+ .docx-review__marker {
6261
+ --doc-review-author-ink: var(--doc-review-author-current, #c0392b);
6262
+ --doc-review-author-disc: color-mix(
6263
+ in srgb,
6264
+ var(--doc-review-author-current, #c0392b) 82%,
6265
+ white
6266
+ );
6267
+ }
6268
+
6269
+ .docx-editor.dark .docx-review__card,
6270
+ .docx-editor.dark .docx-review__marker {
6271
+ --doc-review-author-ink: color-mix(in srgb, var(--doc-review-author-current, #c0392b) 55%, white);
6272
+ --doc-review-author-disc: color-mix(
6273
+ in srgb,
6274
+ var(--doc-review-author-current, #c0392b) 62%,
6275
+ white
6276
+ );
6277
+ }
6278
+
6073
6279
  .docx-review__card {
6074
6280
  display: flex;
6075
6281
  flex-direction: column;
@@ -6080,6 +6286,13 @@ a.docx-hyperlink:focus-visible {
6080
6286
  margin: 0 12px 0 0;
6081
6287
  padding: 12px 14px;
6082
6288
  border: 1px solid var(--doc-border, #e3e5e8);
6289
+ /* WHOSE CARD THIS IS, at a glance. The document colours each author's changes, so the
6290
+ card that annotates them carries the same colour on its leading edge — the eye pairs
6291
+ the two without reading either. An edge rather than a wash: the card is chrome and its
6292
+ text has to keep full contrast, and eight tinted slabs down a rail read as warnings.
6293
+ `--doc-review-author-current` is set per card by the review surface; `--doc-review-author-ink`
6294
+ is the chrome-side reading of it, lifted under `.dark` (see below). */
6295
+ border-left: 3px solid var(--doc-review-author-ink, var(--doc-border, #e3e5e8));
6083
6296
  /* The card is CHROME, so it is themed; the document canvas beside it never is. */
6084
6297
  border-radius: 12px;
6085
6298
  background: var(--doc-surface, #fff);
@@ -6103,11 +6316,128 @@ a.docx-hyperlink:focus-visible {
6103
6316
  the rail read as eight competing highlights. */
6104
6317
  .docx-review__card[data-active] {
6105
6318
  box-shadow: 0 4px 14px rgb(0 0 0 / 12%);
6106
- border-color: var(--doc-border-strong, #c8ccd2);
6319
+ /* THREE SIDES, not `border-color`. The leading edge carries the author's colour, and the
6320
+ shorthand overwrote it — the open card was the one place a reader could not tell whose
6321
+ change they were deciding on. */
6322
+ border-top-color: var(--doc-border-strong, #c8ccd2);
6323
+ border-right-color: var(--doc-border-strong, #c8ccd2);
6324
+ border-bottom-color: var(--doc-border-strong, #c8ccd2);
6325
+ /* The faintest wash of the chrome's own accent, the same one the toolbar uses for a
6326
+ pressed control, so "open" reads as selection rather than as a fourth author colour. */
6327
+ background: var(--doc-review-card-active-bg);
6328
+ }
6329
+
6330
+ .docx-review__card[data-resolved]:not([data-resolved-miniature]) {
6331
+ opacity: 0.55;
6107
6332
  }
6108
6333
 
6109
- .docx-review__card[data-resolved] {
6110
- opacity: 0.55;
6334
+ .docx-review__card[data-resolved-miniature]:not([open]) {
6335
+ box-sizing: border-box;
6336
+ width: 28px;
6337
+ height: 28px;
6338
+ padding: 0;
6339
+ align-items: center;
6340
+ justify-content: center;
6341
+ border: 0;
6342
+ border-radius: 6px;
6343
+ background: transparent;
6344
+ box-shadow: none;
6345
+ color: var(--doc-text-muted);
6346
+ font: inherit;
6347
+ opacity: 1;
6348
+ }
6349
+
6350
+ .docx-review__card[data-resolved-miniature]:not([open]):hover {
6351
+ background: var(--doc-surface-hover, rgb(0 0 0 / 6%));
6352
+ color: var(--doc-text);
6353
+ }
6354
+
6355
+ .docx-review__resolved-toggle {
6356
+ display: inline-flex;
6357
+ width: 28px;
6358
+ height: 28px;
6359
+ margin: -6px;
6360
+ align-items: center;
6361
+ justify-content: center;
6362
+ align-self: flex-end;
6363
+ border-radius: 50%;
6364
+ color: var(--doc-success, #34a853);
6365
+ cursor: pointer;
6366
+ list-style: none;
6367
+ }
6368
+
6369
+ .docx-review__resolved-toggle::-webkit-details-marker {
6370
+ display: none;
6371
+ }
6372
+
6373
+ .docx-review__resolved-status {
6374
+ display: none;
6375
+ color: var(--doc-text-muted);
6376
+ font-size: 11px;
6377
+ font-weight: 600;
6378
+ letter-spacing: 0.02em;
6379
+ text-transform: uppercase;
6380
+ }
6381
+
6382
+ .docx-review__card[data-resolved-miniature][open] > .docx-review__resolved-toggle {
6383
+ width: 100%;
6384
+ height: 28px;
6385
+ margin: -4px 0 4px;
6386
+ justify-content: space-between;
6387
+ align-self: stretch;
6388
+ border-radius: 4px;
6389
+ }
6390
+
6391
+ .docx-review__card[data-resolved-miniature][open]
6392
+ > .docx-review__resolved-toggle
6393
+ > .docx-review__resolved-status {
6394
+ display: inline;
6395
+ }
6396
+
6397
+ .docx-review__card[data-resolved-miniature]:not([open]) .docx-review__resolved-toggle {
6398
+ width: 28px;
6399
+ height: 28px;
6400
+ margin: 0;
6401
+ align-self: center;
6402
+ border-radius: 6px;
6403
+ }
6404
+
6405
+ .docx-review__resolved-toggle:focus-visible {
6406
+ outline: 2px solid var(--doc-focus-ring);
6407
+ outline-offset: 1px;
6408
+ }
6409
+
6410
+ .docx-review__resolved-icon {
6411
+ position: relative;
6412
+ display: inline-flex;
6413
+ width: 16px;
6414
+ height: 16px;
6415
+ align-items: center;
6416
+ justify-content: center;
6417
+ }
6418
+
6419
+ .docx-review__resolved-comment {
6420
+ display: inline-flex;
6421
+ color: var(--doc-text-muted);
6422
+ }
6423
+
6424
+ .docx-review__resolved-comment > svg {
6425
+ width: 16px;
6426
+ height: 16px;
6427
+ }
6428
+
6429
+ .docx-review__resolved-tick {
6430
+ position: absolute;
6431
+ inset: 2px 3px 4px;
6432
+ display: inline-flex;
6433
+ align-items: center;
6434
+ justify-content: center;
6435
+ color: var(--doc-success);
6436
+ }
6437
+
6438
+ .docx-review__resolved-tick > svg {
6439
+ width: 10px;
6440
+ height: 10px;
6111
6441
  }
6112
6442
 
6113
6443
  .docx-review__head {
@@ -6126,11 +6456,24 @@ a.docx-hyperlink:focus-visible {
6126
6456
  border-radius: 50%;
6127
6457
  /* Softened against white: the ramp is chosen to stay legible as TEXT on the page, and the
6128
6458
  same values as a 30px filled disc read as eight warning lights down the margin. */
6129
- background: color-mix(in srgb, var(--doc-review-author, #c0392b) 82%, white);
6459
+ background: var(--doc-review-author-disc, #c0392b);
6130
6460
  color: #fff;
6131
6461
  font-size: 11px;
6132
6462
  font-weight: 600;
6133
6463
  letter-spacing: 0.02em;
6464
+ /* An avatar image must not spill past the disc while it loads or if it fails. */
6465
+ overflow: hidden;
6466
+ }
6467
+
6468
+ /* A host-supplied avatar image (`RevisionAuthorStyle.avatarUrl`) fills the disc; the
6469
+ author-coloured background above shows through until it loads. */
6470
+ .docx-review__avatar-img {
6471
+ display: block;
6472
+ width: 100%;
6473
+ height: 100%;
6474
+ border-radius: inherit;
6475
+ -o-object-fit: cover;
6476
+ object-fit: cover;
6134
6477
  }
6135
6478
 
6136
6479
  .docx-review__meta {
@@ -6298,7 +6641,7 @@ a.docx-hyperlink:focus-visible {
6298
6641
  }
6299
6642
 
6300
6643
  .docx-review__input:focus-visible {
6301
- outline: 2px solid var(--doc-focus-ring, #3b82f6);
6644
+ outline: 1px solid var(--doc-border-strong, #c8ccd2);
6302
6645
  outline-offset: -1px;
6303
6646
  }
6304
6647
 
@@ -6382,6 +6725,32 @@ a.docx-hyperlink:focus-visible {
6382
6725
  box-shadow: inset 0 -1px 0 var(--doc-comment-active-border);
6383
6726
  }
6384
6727
 
6728
+ .docx-comment-band--resolved-active {
6729
+ background: var(--doc-comment-resolved-active-bg);
6730
+ box-shadow: inset 0 -1px 0 var(--doc-comment-resolved-active-border);
6731
+ }
6732
+
6733
+ /* WHOSE COMMENT THIS IS, for CSS only.
6734
+ *
6735
+ * Every band carries `data-review-author`, `data-review-author-slot` and `--doc-review-author-current` — the same
6736
+ * three hooks the review card carries, so one selector restyles a reviewer's card and the text
6737
+ * it annotates together. Nothing here paints them: Word keeps every comment the same yellow,
6738
+ * and eight highlighter colours down a page reads as eight meanings rather than eight people.
6739
+ * The author is a HANDLE, not a default.
6740
+ *
6741
+ * To tint by author, a host writes the one rule this deliberately does not:
6742
+ *
6743
+ * .docx-editor .docx-comment-band {
6744
+ * background: color-mix(in srgb, var(--doc-review-author-current) 22%, transparent);
6745
+ * }
6746
+ *
6747
+ * The band is CHROME, not page content: this layer is a sibling of the pages, so the page's
6748
+ * inverting filter never reaches it. It composites over the already-inverted sheet, and the
6749
+ * blend mode flips from `multiply` to `screen` under `.dark` for that reason. A colour used
6750
+ * here therefore needs its own dark value, the way `--doc-comment-bg` has one — nothing
6751
+ * corrects it downstream. `--doc-review-author-current` carries the light ramp value in both themes,
6752
+ * so a rule that tints by author should lift it under `.docx-editor.dark` itself. */
6753
+
6385
6754
  /* Tracked changes carry a band always, in the change's OWN colour, so it never contradicts
6386
6755
  * the decoration it sits behind — green where text is arriving, red where it is leaving. A
6387
6756
  * replacement gets both, red over the struck half and green over what replaced it.
@@ -6398,13 +6767,13 @@ a.docx-hyperlink:focus-visible {
6398
6767
  }
6399
6768
 
6400
6769
  .docx-revision-band--insert.docx-revision-band--active {
6401
- background: var(--doc-revision-insertion-tint);
6402
- box-shadow: inset 0 -1px 0 var(--doc-revision-insertion);
6770
+ background: var(--doc-revision-insertion-active-bg);
6771
+ box-shadow: inset 0 -1px 0 var(--doc-revision-insertion-active-border);
6403
6772
  }
6404
6773
 
6405
6774
  .docx-revision-band--delete.docx-revision-band--active {
6406
- background: var(--doc-revision-deletion-tint);
6407
- box-shadow: inset 0 -1px 0 var(--doc-revision-deletion);
6775
+ background: var(--doc-revision-deletion-active-bg);
6776
+ box-shadow: inset 0 -1px 0 var(--doc-revision-deletion-active-border);
6408
6777
  }
6409
6778
 
6410
6779
  /* A formatting or structural change decorates no characters of its own, so it gets the
@@ -6415,7 +6784,7 @@ a.docx-hyperlink:focus-visible {
6415
6784
  }
6416
6785
 
6417
6786
  .docx-revision-band--other.docx-revision-band--active {
6418
- background: color-mix(in srgb, var(--doc-text-muted, #8a8f98) 14%, transparent);
6787
+ background: var(--doc-revision-other-active-bg);
6419
6788
  }
6420
6789
 
6421
6790
  /* Dark paper inverts the arithmetic: multiplying a tint into a dark sheet drives it to