@beyondwork/docx-react-component 1.0.53 → 1.0.55

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 (99) hide show
  1. package/package.json +1 -1
  2. package/src/api/public-types.ts +125 -7
  3. package/src/index.ts +5 -0
  4. package/src/io/docx-session.ts +27 -3
  5. package/src/io/normalize/normalize-text.ts +1 -0
  6. package/src/io/ooxml/parse-field-switches.ts +134 -0
  7. package/src/io/ooxml/parse-fields.ts +28 -2
  8. package/src/model/canonical-document.ts +13 -2
  9. package/src/runtime/chart/chart-model-store.ts +88 -0
  10. package/src/runtime/chart/chart-snapshot.ts +239 -0
  11. package/src/runtime/collab/checkpoint-store.ts +1 -1
  12. package/src/runtime/collab/event-types.ts +4 -0
  13. package/src/runtime/collab/runtime-collab-sync.ts +1 -2
  14. package/src/runtime/document-runtime.ts +115 -13
  15. package/src/runtime/layout/inert-layout-facet.ts +1 -0
  16. package/src/runtime/layout/layout-engine-version.ts +58 -1
  17. package/src/runtime/layout/layout-invalidation.ts +150 -30
  18. package/src/runtime/layout/page-graph.ts +19 -0
  19. package/src/runtime/layout/paginated-layout-engine.ts +128 -19
  20. package/src/runtime/layout/project-block-fragments.ts +27 -0
  21. package/src/runtime/layout/public-facet.ts +27 -0
  22. package/src/runtime/page-number-format.ts +207 -0
  23. package/src/runtime/render/render-frame-diff.ts +38 -2
  24. package/src/runtime/surface-projection.ts +32 -3
  25. package/src/ui/WordReviewEditor.tsx +57 -3
  26. package/src/ui/headless/comment-decoration-model.ts +60 -5
  27. package/src/ui/headless/revision-decoration-model.ts +94 -6
  28. package/src/ui/shared/revision-filters.ts +16 -6
  29. package/src/ui-tailwind/chart/ChartSurface.tsx +236 -0
  30. package/src/ui-tailwind/chart/layout/axis-layout.ts +17 -9
  31. package/src/ui-tailwind/chart/layout/legend-layout.ts +231 -0
  32. package/src/ui-tailwind/chart/layout/plot-area.ts +152 -59
  33. package/src/ui-tailwind/chart/layout/title-layout.ts +184 -0
  34. package/src/ui-tailwind/chart/render/area.tsx +277 -0
  35. package/src/ui-tailwind/chart/render/bar-column.tsx +356 -0
  36. package/src/ui-tailwind/chart/render/bubble.tsx +134 -0
  37. package/src/ui-tailwind/chart/render/combo.tsx +85 -0
  38. package/src/ui-tailwind/chart/render/data-labels.tsx +513 -0
  39. package/src/ui-tailwind/chart/render/font-metrics.ts +298 -0
  40. package/src/ui-tailwind/chart/render/gridlines.ts +228 -0
  41. package/src/ui-tailwind/chart/render/line.tsx +363 -0
  42. package/src/ui-tailwind/chart/render/number-format.ts +120 -16
  43. package/src/ui-tailwind/chart/render/pie.tsx +275 -0
  44. package/src/ui-tailwind/chart/render/progressive-render.ts +103 -0
  45. package/src/ui-tailwind/chart/render/scatter.tsx +228 -0
  46. package/src/ui-tailwind/chart/render/smooth-curve.ts +101 -0
  47. package/src/ui-tailwind/chart/render/svg-primitives.ts +378 -0
  48. package/src/ui-tailwind/chart/render/unsupported.tsx +126 -0
  49. package/src/ui-tailwind/chrome/collab-audience-chip.tsx +11 -0
  50. package/src/ui-tailwind/chrome/collab-negotiation-action-bar.tsx +44 -18
  51. package/src/ui-tailwind/chrome/collab-presence-strip.tsx +68 -7
  52. package/src/ui-tailwind/chrome/collab-role-chip.tsx +21 -2
  53. package/src/ui-tailwind/chrome/collab-tamper-banner.tsx +20 -3
  54. package/src/ui-tailwind/chrome/tw-alert-banner.tsx +102 -37
  55. package/src/ui-tailwind/chrome/tw-command-palette.tsx +358 -0
  56. package/src/ui-tailwind/chrome/tw-comment-preview.tsx +108 -0
  57. package/src/ui-tailwind/chrome/tw-context-menu.tsx +227 -0
  58. package/src/ui-tailwind/chrome/tw-display-mode-selector.tsx +136 -0
  59. package/src/ui-tailwind/chrome/tw-empty-state.tsx +76 -0
  60. package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +30 -16
  61. package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +23 -4
  62. package/src/ui-tailwind/chrome/tw-paste-drop-toast.tsx +113 -0
  63. package/src/ui-tailwind/chrome/tw-revision-hover-preview.tsx +150 -0
  64. package/src/ui-tailwind/chrome/tw-selection-tool-formatting.tsx +2 -0
  65. package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +38 -2
  66. package/src/ui-tailwind/chrome/tw-selection-tool-placement.ts +15 -3
  67. package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +32 -20
  68. package/src/ui-tailwind/chrome/tw-shortcut-hint.tsx +68 -0
  69. package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +10 -10
  70. package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +26 -5
  71. package/src/ui-tailwind/chrome/tw-table-grip-layer.tsx +29 -22
  72. package/src/ui-tailwind/chrome/tw-unsaved-modal.tsx +72 -10
  73. package/src/ui-tailwind/chrome-overlay/tw-scope-card.tsx +33 -18
  74. package/src/ui-tailwind/chrome-overlay/tw-table-continuation-header.tsx +94 -0
  75. package/src/ui-tailwind/editor-surface/chart-node-view.tsx +90 -0
  76. package/src/ui-tailwind/editor-surface/pm-page-break-decorations.ts +20 -7
  77. package/src/ui-tailwind/editor-surface/pm-schema.ts +4 -0
  78. package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +14 -0
  79. package/src/ui-tailwind/editor-surface/scroll-anchor.ts +93 -0
  80. package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +2 -1
  81. package/src/ui-tailwind/index.ts +11 -0
  82. package/src/ui-tailwind/page-stack/tw-page-chrome-entry.tsx +52 -2
  83. package/src/ui-tailwind/page-stack/tw-page-footer-band.tsx +13 -0
  84. package/src/ui-tailwind/page-stack/tw-page-header-band.tsx +13 -0
  85. package/src/ui-tailwind/page-stack/tw-page-stack-chrome-layer.tsx +8 -0
  86. package/src/ui-tailwind/review/tw-comment-sidebar.tsx +83 -32
  87. package/src/ui-tailwind/review/tw-health-panel.tsx +174 -109
  88. package/src/ui-tailwind/review/tw-rail-card.tsx +9 -1
  89. package/src/ui-tailwind/review/tw-review-rail.tsx +36 -42
  90. package/src/ui-tailwind/review/tw-revision-sidebar.tsx +189 -101
  91. package/src/ui-tailwind/review/tw-workflow-tab.tsx +11 -1
  92. package/src/ui-tailwind/status/tw-status-bar.tsx +114 -46
  93. package/src/ui-tailwind/theme/editor-theme.css +249 -22
  94. package/src/ui-tailwind/toolbar/tw-role-action-region.tsx +14 -1
  95. package/src/ui-tailwind/toolbar/tw-shell-header.tsx +73 -32
  96. package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +49 -9
  97. package/src/ui-tailwind/toolbar/tw-toolbar.tsx +178 -14
  98. package/src/ui-tailwind/tw-review-workspace.tsx +39 -6
  99. package/src/ui-tailwind/chrome/review-queue-bar.tsx +0 -85
@@ -33,8 +33,34 @@ export interface TwStatusBarProps {
33
33
  * canvas backend is live vs. the empirical fallback. Absent = skip.
34
34
  */
35
35
  measurementFidelity?: PublicMeasurementFidelity;
36
+ /**
37
+ * Lane 6b §6b.S4: opt-in diagnostics flag. When `true`, the status
38
+ * bar reveals the measurement-fidelity badge on the right zone.
39
+ * Hosts must pair this with `debugMode` in production — the fidelity
40
+ * badge is a maintainer affordance, not a user-facing surface.
41
+ */
42
+ debugMode?: boolean;
43
+ /**
44
+ * Lane 6b §6b.S4: explicit opt-in to render the fidelity badge when
45
+ * `debugMode` is on. Defaults to `false` so even a debug harness
46
+ * keeps the badge hidden unless a human asks for it.
47
+ */
48
+ showFidelityBadge?: boolean;
36
49
  }
37
50
 
51
+ /**
52
+ * TwStatusBar — bottom chrome strip, 28-px tall (designsystem §6.16).
53
+ *
54
+ * Three-zone CSS grid (Lane 6b §6b.S4):
55
+ * LEFT — save state dot + export state dot + comment / change counts
56
+ * CENTER — Page N of M indicator
57
+ * RIGHT — measurement fidelity badge (opt-in) + session-active label
58
+ *
59
+ * Status dots bind `--color-status-*` tokens (Lane 6a §3 semantic family)
60
+ * so the review / draft / paused / blocked colour ladder stays consistent
61
+ * with the workflow card grammar. The fidelity badge is diagnostic-only:
62
+ * hidden unless `debugMode && showFidelityBadge` are both `true`.
63
+ */
38
64
  export function TwStatusBar(props: TwStatusBarProps) {
39
65
  const saveState = props.isExportBlocked
40
66
  ? "Read-only"
@@ -46,58 +72,100 @@ export function TwStatusBar(props: TwStatusBarProps) {
46
72
  : props.preserveOnlyCount > 0
47
73
  ? "Warnings"
48
74
  : "Ready";
75
+
76
+ const saveDotColor = props.isExportBlocked
77
+ ? "bg-[var(--color-status-blocked)]"
78
+ : props.isDirty
79
+ ? "bg-[var(--color-status-in-progress)]"
80
+ : "bg-[var(--color-status-ready)]";
81
+ const exportDotColor = props.isExportBlocked
82
+ ? "bg-[var(--color-status-blocked)]"
83
+ : props.preserveOnlyCount > 0
84
+ ? "bg-[var(--color-semantic-warning)]"
85
+ : "bg-[var(--color-status-ready)]";
86
+
87
+ const showFidelity =
88
+ props.measurementFidelity != null &&
89
+ props.debugMode === true &&
90
+ props.showFidelityBadge === true;
91
+
49
92
  return (
50
93
  <footer
51
94
  data-testid="status-bar"
52
- className="flex h-7 shrink-0 items-center gap-3 border-t border-border/60 bg-surface/72 px-3 text-[11px] text-tertiary"
95
+ style={{
96
+ // Lane 6b §6b.U5 — density opt-in. Scales the 28 px base by the
97
+ // root `--space-density-multiplier` (compact 0.85 / standard 1 /
98
+ // comfortable 1.15). Hosts toggle via the `useDensity` hook
99
+ // from Lane 6a.
100
+ height:
101
+ "calc(28px * var(--space-density-multiplier, 1))",
102
+ }}
103
+ className={[
104
+ "grid shrink-0 grid-cols-[1fr_auto_1fr] items-center gap-3",
105
+ "border-t border-[var(--color-border-subtle)]",
106
+ "bg-[var(--color-bg-chrome)]/72",
107
+ "px-3 text-[11px] text-[var(--color-text-tertiary)]",
108
+ ].join(" ")}
53
109
  >
54
- <span className="flex items-center gap-1.5">
55
- <span
56
- className={`inline-block h-1.5 w-1.5 rounded-full ${
57
- props.isExportBlocked
58
- ? "bg-danger"
59
- : props.isDirty
60
- ? "bg-comment"
61
- : "bg-accent"
62
- }`}
63
- />
64
- {saveState}
65
- </span>
66
- <span className="flex items-center gap-1.5">
67
- <span
68
- className={`inline-block h-1.5 w-1.5 rounded-full ${
69
- props.isExportBlocked
70
- ? "bg-danger"
71
- : props.preserveOnlyCount > 0
72
- ? "bg-warning"
73
- : "bg-accent"
74
- }`}
75
- />
76
- Export {exportState.toLowerCase()}
77
- </span>
78
- <span>
79
- {props.commentCount} comment{props.commentCount !== 1 ? "s" : ""} ·{" "}
80
- {props.changeCount} change{props.changeCount !== 1 ? "s" : ""}
81
- </span>
82
- {props.displayPageNumber != null && props.pageCount != null ? (
83
- <span data-testid="status-bar-page-count">
84
- Page {props.displayPageNumber} of {props.pageCount}
110
+ {/* LEFT zone — save + export + counts */}
111
+ <div
112
+ className="flex items-center gap-3"
113
+ data-region="left"
114
+ data-testid="status-bar__region-left"
115
+ >
116
+ <span className="flex items-center gap-1.5">
117
+ <span
118
+ className={`inline-block h-1.5 w-1.5 rounded-[var(--radius-pill)] ${saveDotColor}`}
119
+ data-testid="status-bar__save-dot"
120
+ />
121
+ {saveState}
122
+ </span>
123
+ <span className="flex items-center gap-1.5">
124
+ <span
125
+ className={`inline-block h-1.5 w-1.5 rounded-[var(--radius-pill)] ${exportDotColor}`}
126
+ data-testid="status-bar__export-dot"
127
+ />
128
+ Export {exportState.toLowerCase()}
85
129
  </span>
86
- ) : null}
87
- <span className="flex-1" />
88
- {props.measurementFidelity ? (
89
- <span
90
- data-testid="status-bar-measurement-fidelity"
91
- data-fidelity={props.measurementFidelity}
92
- className="uppercase tracking-[0.12em] text-tertiary/70"
93
- title={`Measurement fidelity: ${props.measurementFidelity}`}
94
- >
95
- {formatFidelityBadge(props.measurementFidelity)}
130
+ <span>
131
+ {props.commentCount} comment{props.commentCount !== 1 ? "s" : ""} ·{" "}
132
+ {props.changeCount} change{props.changeCount !== 1 ? "s" : ""}
133
+ </span>
134
+ </div>
135
+
136
+ {/* CENTER zone — page indicator */}
137
+ <div
138
+ className="flex items-center justify-center"
139
+ data-region="center"
140
+ data-testid="status-bar__region-center"
141
+ >
142
+ {props.displayPageNumber != null && props.pageCount != null ? (
143
+ <span data-testid="status-bar-page-count">
144
+ Page {props.displayPageNumber} of {props.pageCount}
145
+ </span>
146
+ ) : null}
147
+ </div>
148
+
149
+ {/* RIGHT zone — fidelity badge (opt-in) + session */}
150
+ <div
151
+ className="flex items-center justify-end gap-2"
152
+ data-region="right"
153
+ data-testid="status-bar__region-right"
154
+ >
155
+ {showFidelity ? (
156
+ <span
157
+ data-testid="status-bar-measurement-fidelity"
158
+ data-fidelity={props.measurementFidelity}
159
+ className="uppercase tracking-[0.12em] text-[var(--color-text-tertiary)]/70"
160
+ title={`Measurement fidelity: ${props.measurementFidelity}`}
161
+ >
162
+ {formatFidelityBadge(props.measurementFidelity!)}
163
+ </span>
164
+ ) : null}
165
+ <span className="truncate text-[10px] uppercase tracking-[0.12em] text-[var(--color-text-tertiary)]/80">
166
+ Session active
96
167
  </span>
97
- ) : null}
98
- <span className="truncate text-[10px] uppercase tracking-[0.12em] text-tertiary/80">
99
- Session active
100
- </span>
168
+ </div>
101
169
  </footer>
102
170
  );
103
171
  }
@@ -587,6 +587,14 @@
587
587
  .wre-scope-rail-stripe.wre-scope-rail-label-secondary { color: var(--color-secondary); }
588
588
  .wre-scope-rail-stripe.wre-scope-rail-label-danger { color: var(--color-danger); }
589
589
 
590
+ /* §3.7 canonical scope families — stripe color */
591
+ .wre-scope-rail-stripe.wre-scope-rail-tint-blocked { background: var(--color-scope-tint-blocked); }
592
+ .wre-scope-rail-stripe.wre-scope-rail-tint-in-scope { background: var(--color-scope-tint-in-scope); }
593
+ .wre-scope-rail-stripe.wre-scope-rail-tint-suggest { background: var(--color-scope-tint-suggest); }
594
+ .wre-scope-rail-stripe.wre-scope-rail-tint-comment { background: var(--color-scope-tint-comment); }
595
+ .wre-scope-rail-stripe.wre-scope-rail-tint-scheduled { background: var(--color-scope-tint-scheduled); }
596
+ .wre-scope-rail-stripe.wre-scope-rail-tint-proposed { background: var(--color-scope-tint-proposed); }
597
+
590
598
  /*
591
599
  * ─── Scope rail label pill ───
592
600
  *
@@ -652,6 +660,38 @@
652
660
  background: color-mix(in srgb, var(--color-danger) 8%, var(--color-canvas, #fff));
653
661
  }
654
662
 
663
+ /* §3.7 canonical scope families — label pill */
664
+ .wre-scope-rail-label-blocked {
665
+ color: var(--color-semantic-error);
666
+ border-color: color-mix(in srgb, var(--color-semantic-error) 40%, transparent);
667
+ background: color-mix(in srgb, var(--color-semantic-error) 8%, var(--color-canvas, #fff));
668
+ }
669
+ .wre-scope-rail-label-suggest {
670
+ color: var(--color-semantic-warning);
671
+ border-color: color-mix(in srgb, var(--color-semantic-warning) 42%, transparent);
672
+ background: color-mix(in srgb, var(--color-semantic-warning) 8%, var(--color-canvas, #fff));
673
+ }
674
+ .wre-scope-rail-label-scheduled {
675
+ color: var(--color-semantic-info);
676
+ border-color: color-mix(in srgb, var(--color-semantic-info) 40%, transparent);
677
+ background: color-mix(in srgb, var(--color-semantic-info) 8%, var(--color-canvas, #fff));
678
+ }
679
+ .wre-scope-rail-label-comment {
680
+ color: var(--color-accent-primary);
681
+ border-color: color-mix(in srgb, var(--color-accent-primary) 40%, transparent);
682
+ background: color-mix(in srgb, var(--color-accent-primary) 8%, var(--color-canvas, #fff));
683
+ }
684
+ .wre-scope-rail-label-in-scope {
685
+ color: var(--color-accent-primary);
686
+ border-color: color-mix(in srgb, var(--color-accent-primary) 40%, transparent);
687
+ background: color-mix(in srgb, var(--color-accent-primary) 8%, var(--color-canvas, #fff));
688
+ }
689
+ .wre-scope-rail-label-proposed {
690
+ color: var(--color-accent-primary);
691
+ border-color: color-mix(in srgb, var(--color-accent-primary) 40%, transparent);
692
+ background: color-mix(in srgb, var(--color-accent-primary) 8%, var(--color-canvas, #fff));
693
+ }
694
+
655
695
  .wre-scope-rail-label-active {
656
696
  box-shadow: 0 0 0 1px color-mix(in srgb, currentColor 30%, transparent);
657
697
  }
@@ -784,10 +824,14 @@
784
824
  * — consumers pick whichever matches their payload shape.
785
825
  */
786
826
  .wre-rail-card {
827
+ --wre-rail-card-edge: var(--color-border-default);
828
+ --wre-rail-card-eyebrow: var(--color-text-tertiary);
787
829
  position: relative;
788
- border-radius: var(--radius-card);
789
- background: var(--color-surface);
790
- border: 1px solid color-mix(in srgb, var(--color-border) 80%, transparent);
830
+ border-radius: var(--radius-lg);
831
+ background: var(--color-bg-elevated);
832
+ border: 1px solid var(--color-border-subtle);
833
+ border-left: 3px solid var(--wre-rail-card-edge);
834
+ box-shadow: var(--shadow-soft);
791
835
  padding: 14px 16px 16px;
792
836
  overflow: hidden;
793
837
  transition: background-color var(--motion-fast) ease-out,
@@ -812,34 +856,23 @@
812
856
  }
813
857
 
814
858
  .wre-rail-card[data-tone="inReview"] {
815
- --wre-rail-card-edge: var(--color-accent);
816
- --wre-rail-card-eyebrow: var(--color-accent);
817
- --wre-rail-card-progress-fill: var(--color-accent);
859
+ --wre-rail-card-edge: var(--color-semantic-warning);
860
+ --wre-rail-card-eyebrow: var(--color-semantic-warning);
818
861
  }
819
862
 
820
863
  .wre-rail-card[data-tone="blocked"] {
821
- --wre-rail-card-edge: var(--color-danger);
822
- --wre-rail-card-eyebrow: var(--color-danger);
823
- --wre-rail-card-progress-fill: var(--color-danger);
824
- background: color-mix(in srgb, var(--color-danger-soft) 75%, var(--color-surface));
864
+ --wre-rail-card-edge: var(--color-semantic-error);
865
+ --wre-rail-card-eyebrow: var(--color-semantic-error);
825
866
  }
826
867
 
827
868
  .wre-rail-card[data-tone="scheduled"] {
828
- --wre-rail-card-edge: var(--color-tertiary);
829
- --wre-rail-card-eyebrow: var(--color-tertiary);
830
- --wre-rail-card-progress-fill: var(--color-tertiary);
869
+ --wre-rail-card-edge: var(--color-semantic-info);
870
+ --wre-rail-card-eyebrow: var(--color-semantic-info);
831
871
  }
832
872
 
833
873
  .wre-rail-card[data-tone="resolved"] {
834
- --wre-rail-card-edge: var(--color-success);
835
- --wre-rail-card-eyebrow: var(--color-success);
836
- --wre-rail-card-progress-fill: var(--color-success);
837
- }
838
-
839
- .wre-rail-card[data-tone="neutral"] {
840
- --wre-rail-card-edge: var(--color-border-strong);
841
- --wre-rail-card-eyebrow: var(--color-tertiary);
842
- --wre-rail-card-progress-fill: var(--color-secondary);
874
+ --wre-rail-card-edge: var(--color-semantic-success);
875
+ --wre-rail-card-eyebrow: var(--color-semantic-success);
843
876
  }
844
877
 
845
878
  .wre-rail-card__eyebrow {
@@ -1009,3 +1042,197 @@
1009
1042
  color: var(--color-primary);
1010
1043
  background: color-mix(in srgb, var(--color-accent-soft) 80%, var(--color-subtle));
1011
1044
  }
1045
+
1046
+ /*
1047
+ * Lane 6d — Slice U1 (L8 Phase E): active H/F band chrome.
1048
+ *
1049
+ * Idle bands sit at 0.6 opacity so the header/footer content is
1050
+ * visible but doesn't compete with the body; hover bumps to 0.85; the
1051
+ * active band goes to full opacity and gains a 3 px accent ribbon
1052
+ * across its top edge plus a floating "Header — Section N" label in
1053
+ * the top-left corner so reviewers always know which band they are
1054
+ * editing when a section break changes the chrome.
1055
+ *
1056
+ * When any H/F story is active the chrome layer's root carries
1057
+ * `data-story-active="header|footer"` and the body PM surface dims to
1058
+ * 0.65 so the active band reads as the focal surface.
1059
+ */
1060
+ .wre-page-band {
1061
+ opacity: 0.6;
1062
+ transition: opacity var(--motion-fast, 120ms) ease-out;
1063
+ pointer-events: auto;
1064
+ }
1065
+
1066
+ .wre-page-band:hover {
1067
+ opacity: 0.85;
1068
+ }
1069
+
1070
+ .wre-page-band[data-active="true"] {
1071
+ opacity: 1;
1072
+ }
1073
+
1074
+ .wre-page-band[data-active="true"]::before {
1075
+ content: "";
1076
+ position: absolute;
1077
+ top: 0;
1078
+ left: 0;
1079
+ right: 0;
1080
+ height: 3px;
1081
+ background: var(--color-accent);
1082
+ border-radius: 0 0 var(--radius-pill) var(--radius-pill);
1083
+ pointer-events: none;
1084
+ }
1085
+
1086
+ .wre-page-band__label {
1087
+ position: absolute;
1088
+ top: 6px;
1089
+ left: 10px;
1090
+ font-size: 10px;
1091
+ letter-spacing: 0.08em;
1092
+ text-transform: uppercase;
1093
+ color: var(--color-accent);
1094
+ background: var(--color-surface);
1095
+ padding: 2px 8px;
1096
+ border-radius: var(--radius-pill);
1097
+ box-shadow: var(--shadow-soft);
1098
+ pointer-events: none;
1099
+ z-index: 1;
1100
+ }
1101
+
1102
+ [data-page-stack-chrome-layer][data-story-active="header"]
1103
+ ~ [data-pm-body-slot],
1104
+ [data-page-stack-chrome-layer][data-story-active="footer"]
1105
+ ~ [data-pm-body-slot] {
1106
+ opacity: 0.65;
1107
+ transition: opacity var(--motion-fast, 120ms) ease-out;
1108
+ }
1109
+
1110
+ /*
1111
+ * Lane 6d — Slice S2: print variant.
1112
+ *
1113
+ * At print time, collapse all editor chrome (toolbar, rails, overlays,
1114
+ * page-break spacers, dock chrome) and let the browser paginate the
1115
+ * paper cards one per physical sheet. Intentionally no `@page` rule —
1116
+ * the browser's print dialog owns paper size / margins so the host
1117
+ * application doesn't need to fight it.
1118
+ */
1119
+ @media print {
1120
+ .wre-toolbar,
1121
+ .wre-status-bar,
1122
+ .wre-review-rail,
1123
+ .wre-scope-rail-layer,
1124
+ .wre-page-chrome-widget,
1125
+ .wre-workspace-dock,
1126
+ .wre-mode-dock,
1127
+ [data-chrome-overlay],
1128
+ [data-pin-surface] {
1129
+ display: none !important;
1130
+ }
1131
+
1132
+ [data-paper-frame] {
1133
+ box-shadow: none !important;
1134
+ border: none !important;
1135
+ border-radius: 0 !important;
1136
+ margin: 0 !important;
1137
+ zoom: 1 !important;
1138
+ page-break-after: always;
1139
+ }
1140
+
1141
+ [data-paper-frame]:last-child {
1142
+ page-break-after: auto;
1143
+ }
1144
+
1145
+ .wre-page-surface {
1146
+ color: #000;
1147
+ background: #fff;
1148
+ }
1149
+ }
1150
+
1151
+ /*
1152
+ * §6.23 — Scrollbar grammar (Lane 6c.S10)
1153
+ * Thin track, thumb low-contrast until hover. Consistent across
1154
+ * rail, long popovers, and the health panel.
1155
+ * Scoped to the editor root class to avoid leaking into host chrome.
1156
+ */
1157
+ .wre-editor ::-webkit-scrollbar,
1158
+ .wre-editor *::-webkit-scrollbar {
1159
+ width: 6px;
1160
+ height: 6px;
1161
+ }
1162
+ .wre-editor ::-webkit-scrollbar-track,
1163
+ .wre-editor *::-webkit-scrollbar-track {
1164
+ background: transparent;
1165
+ }
1166
+ .wre-editor ::-webkit-scrollbar-thumb,
1167
+ .wre-editor *::-webkit-scrollbar-thumb {
1168
+ background: var(--color-border-default);
1169
+ border-radius: 9999px;
1170
+ }
1171
+ .wre-editor ::-webkit-scrollbar-thumb:hover,
1172
+ .wre-editor *::-webkit-scrollbar-thumb:hover {
1173
+ background: var(--color-border-strong);
1174
+ }
1175
+ .wre-editor,
1176
+ .wre-editor * {
1177
+ scrollbar-width: thin;
1178
+ scrollbar-color: var(--color-border-default) transparent;
1179
+ }
1180
+
1181
+ /*
1182
+ * §6.9 — Table grip hit area + affordance (Lane 6c.U8 / Commit C18)
1183
+ *
1184
+ * Visual stripe is 2 px; hit area is extended to 8 px via ::before pseudo-
1185
+ * element (3 px pad each side). On coarse-pointer devices the ::before extends
1186
+ * to 44 px total for WCAG 2.5.5 touch-target compliance.
1187
+ *
1188
+ * State cascade:
1189
+ * default → transparent background (invisible, pointer affordance only)
1190
+ * hover → --color-border-default (subtle stripe appears)
1191
+ * active → --color-accent-primary (vivid stripe during drag)
1192
+ */
1193
+ .wre-table-grip-col {
1194
+ position: absolute;
1195
+ width: 2px;
1196
+ background: transparent;
1197
+ cursor: col-resize;
1198
+ transition: background 75ms ease;
1199
+ }
1200
+ .wre-table-grip-col::before {
1201
+ content: "";
1202
+ position: absolute;
1203
+ inset: 0 -3px;
1204
+ }
1205
+ .wre-table-grip-col:hover {
1206
+ background: var(--color-border-default);
1207
+ }
1208
+ .wre-table-grip-col[data-active="true"] {
1209
+ background: var(--color-accent-primary);
1210
+ }
1211
+
1212
+ .wre-table-grip-row {
1213
+ position: absolute;
1214
+ height: 2px;
1215
+ background: transparent;
1216
+ cursor: row-resize;
1217
+ transition: background 75ms ease;
1218
+ }
1219
+ .wre-table-grip-row::before {
1220
+ content: "";
1221
+ position: absolute;
1222
+ inset: -3px 0;
1223
+ }
1224
+ .wre-table-grip-row:hover {
1225
+ background: var(--color-border-default);
1226
+ }
1227
+ .wre-table-grip-row[data-active="true"] {
1228
+ background: var(--color-accent-primary);
1229
+ }
1230
+
1231
+ @media (pointer: coarse) {
1232
+ .wre-table-grip-col::before {
1233
+ inset: 0 -21px; /* 44 px total touch hit area */
1234
+ }
1235
+ .wre-table-grip-row::before {
1236
+ inset: -21px 0; /* 44 px total touch hit area */
1237
+ }
1238
+ }
@@ -52,7 +52,20 @@ import { preserveEditorSelectionMouseDown } from "../../ui/headless/preserve-edi
52
52
  import { ROLE_ACTION_SETS } from "../chrome/role-action-sets";
53
53
  import { TwScopePostureMenu } from "./tw-scope-posture-menu";
54
54
 
55
- export type MarkupDisplayMode = "clean" | "simple" | "all";
55
+ /**
56
+ * Toolbar-local alias for the markup-display union. L6d.N2 widens
57
+ * this to match the `MarkupDisplay` surface in
58
+ * `comment-decoration-model.ts`, which now accepts Word's 4-mode
59
+ * grammar plus the legacy triple.
60
+ */
61
+ export type MarkupDisplayMode =
62
+ | "all-markup"
63
+ | "simple-markup"
64
+ | "no-markup"
65
+ | "original"
66
+ | "clean"
67
+ | "simple"
68
+ | "all";
56
69
 
57
70
  export interface WorkflowWorkItemSnapshot {
58
71
  workItemId: string;