@einfach-excel/spreadsheet-ui-styles 0.0.0-stage → 0.2.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 (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +37 -2
  3. package/features/comment-thread.css +169 -0
  4. package/features/comment-thread.css.d.ts +2 -0
  5. package/features/conditional-format-dialog.css +254 -0
  6. package/features/conditional-format-dialog.css.d.ts +7 -0
  7. package/features/conditional-format-fields.css +10 -0
  8. package/features/conditional-format-fields.css.d.ts +2 -0
  9. package/features/data-validation-dialog.css +197 -0
  10. package/features/data-validation-dialog.css.d.ts +7 -0
  11. package/features/filter-dropdown.css +177 -0
  12. package/features/filter-dropdown.css.d.ts +2 -0
  13. package/features/find-replace-actions.css +13 -0
  14. package/features/find-replace-actions.css.d.ts +2 -0
  15. package/features/find-replace-dialog.css +147 -0
  16. package/features/find-replace-dialog.css.d.ts +2 -0
  17. package/features/find-replace-status-messages.css +19 -0
  18. package/features/find-replace-status-messages.css.d.ts +2 -0
  19. package/features/format-cells-dialog.css +296 -0
  20. package/features/format-cells-dialog.css.d.ts +2 -0
  21. package/features/format-cells-panels.css +154 -0
  22. package/features/format-cells-panels.css.d.ts +2 -0
  23. package/features/go-to-dialog.css +205 -0
  24. package/features/go-to-dialog.css.d.ts +2 -0
  25. package/features/menu-help-dialog.css +82 -0
  26. package/features/name-manager-dialog.css +276 -0
  27. package/features/number-format-dialog.css +147 -0
  28. package/features/number-format-dialog.css.d.ts +2 -0
  29. package/features/page-setup-dialog.css +167 -0
  30. package/features/page-setup-dialog.css.d.ts +3 -0
  31. package/features/paste-special-dialog.css +126 -0
  32. package/features/paste-special-dialog.css.d.ts +7 -0
  33. package/features/print-preview-dialog.css +197 -0
  34. package/features/print-preview-dialog.css.d.ts +3 -0
  35. package/features/protection-unlock-dialog.css +127 -0
  36. package/features/remove-duplicates-dialog.css +165 -0
  37. package/features/remove-duplicates-dialog.css.d.ts +7 -0
  38. package/features/sheet-tab-delete-dialog.css +64 -0
  39. package/features/sheet-tab-delete-dialog.css.d.ts +3 -0
  40. package/features/sort-confirmation-dialog.css +157 -0
  41. package/features/sort-confirmation-dialog.css.d.ts +2 -0
  42. package/features/text-to-columns-dialog.css +246 -0
  43. package/features/text-to-columns-dialog.css.d.ts +2 -0
  44. package/features/toolbar-shell.css +46 -0
  45. package/features/toolbar-shell.css.d.ts +2 -0
  46. package/package.json +40 -3
  47. package/styles/button-states.css +45 -0
  48. package/styles/chrome-tokens.css +124 -0
  49. package/styles/demo-header.css +23 -0
  50. package/styles/demo-two-column.css +115 -0
  51. package/styles/diagnostics.css +127 -0
  52. package/styles/dialog-skin.css +143 -0
  53. package/styles/formula-autocomplete.css +87 -0
  54. package/styles/formula-bar-row.css +51 -0
  55. package/styles/grid-cells.css +254 -0
  56. package/styles/grid-frame.css +268 -0
  57. package/styles/grid-headers.css +99 -0
  58. package/styles/grid-overlays.css +160 -0
  59. package/styles/help-overlay.css +67 -0
  60. package/styles/history-panel.css +127 -0
  61. package/styles/index.css +26 -0
  62. package/styles/locked-edit-feedback.css +45 -0
  63. package/styles/marching-ants.css +18 -0
  64. package/styles/menu-bar.css +97 -0
  65. package/styles/name-box.css +89 -0
  66. package/styles/presence-overlay.css +36 -0
  67. package/styles/shared-context-menu.css +50 -0
  68. package/styles/shared-format-toolbar.css +82 -0
  69. package/styles/shared-sheet-tabs.css +138 -0
  70. package/styles/sheet-tabs.css +98 -0
  71. package/styles/status-bar.css +161 -0
  72. package/styles/toolbar-popovers.css +278 -0
  73. package/styles/toolbar.css +213 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) dol
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,38 @@
1
- # Temporary Holding Version
1
+ # @einfach-excel/spreadsheet-ui-styles
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Framework-neutral CSS for Einfach spreadsheet surfaces. This package has no
4
+ runtime JavaScript and no framework dependency.
5
+
6
+ ## Use
7
+
8
+ Load the shared surface layer once for a spreadsheet implementation:
9
+
10
+ ```ts
11
+ import '@einfach-excel/spreadsheet-ui-styles/styles.css'
12
+ ```
13
+
14
+ Feature styles are exported individually so adapters can preserve their own
15
+ lazy-loading lifecycle:
16
+
17
+ ```ts
18
+ import '@einfach-excel/spreadsheet-ui-styles/features/find-replace-dialog.css'
19
+ ```
20
+
21
+ The selectors describe a DOM contract rather than a component API. Consumers
22
+ must render the matching markup and may provide the documented CSS custom
23
+ properties from the shared style layer.
24
+
25
+ ## Theming(vnext chrome)
26
+
27
+ `styles/chrome-tokens.css` 是 vnext 皮肤唯一的取色/尺寸来源(Excel for web
28
+ 口径)。规则:
29
+
30
+ - chrome 样式文件里**禁止裸色值** —— 缺 token 就先在 chrome-tokens.css 里加;
31
+ - 每个 chrome 面板必须铺**不透明**底色 token,不许透出宿主背景
32
+ (透明拼缝在暗色宿主下会漏光);
33
+ - `*-text` 变体是文本安全色(AA ≥4.5:1),同名非 text 色只用于边框/填充。
34
+
35
+ **暗色皮肤**:宿主在组件任意祖先上放 `data-spreadsheet-theme="dark"` 即
36
+ 整体换肤(变量继承,零组件配合)。excel-site 的 demo 岛把
37
+ `<html data-theme>` 镜像到岛根;solid-excel 的 e2e demo 壳吃 `?theme=dark`。
38
+ 对齐/对比度的回归门禁在 `excel/solid-excel/e2e/visual-chrome/`。
@@ -0,0 +1,169 @@
1
+ /* Anchored comment surface. dialog-skin.css owns modal shells, so this file
2
+ * deliberately restores the cell-adjacent geometry for the comment workflow. */
3
+
4
+ :is(.vnext-demo, .demo-page) [role='dialog'].spreadsheet-comment-thread.spreadsheet-comment-thread {
5
+ position: fixed;
6
+ z-index: 80;
7
+ box-sizing: border-box;
8
+ width: min(360px, calc(100vw - 24px));
9
+ min-width: 0;
10
+ max-height: calc(100vh - 24px);
11
+ padding: 0;
12
+ transform: none;
13
+ overflow: hidden;
14
+ border: 1px solid var(--border);
15
+ border-radius: var(--radius);
16
+ background: var(--bg-surface);
17
+ box-shadow: var(--shadow-popover);
18
+ color: var(--text-default);
19
+ font: 13px/1.4 var(--excel-font);
20
+ }
21
+
22
+ .comment-thread-header,
23
+ .comment-thread-actions {
24
+ display: flex;
25
+ align-items: center;
26
+ gap: 8px;
27
+ }
28
+
29
+ .comment-thread-header {
30
+ position: relative;
31
+ justify-content: space-between;
32
+ }
33
+
34
+ .comment-thread-header h2 {
35
+ margin: 0;
36
+ font-size: 16px;
37
+ }
38
+
39
+ .comment-thread-cell {
40
+ color: var(--text-muted);
41
+ font-size: 12px;
42
+ }
43
+
44
+ .comment-thread-body {
45
+ display: flex;
46
+ flex: 1 1 auto;
47
+ flex-direction: column;
48
+ gap: 6px;
49
+ padding: 14px 16px 16px;
50
+ overflow: auto;
51
+ background: var(--bg-surface);
52
+ }
53
+
54
+ .comment-thread-compose-label {
55
+ display: block;
56
+ color: var(--text-default);
57
+ font-size: 13px;
58
+ font-weight: 600;
59
+ }
60
+
61
+ .spreadsheet-comment-thread-textarea {
62
+ box-sizing: border-box;
63
+ width: 100%;
64
+ min-height: 96px;
65
+ resize: vertical;
66
+ padding: 8px;
67
+ border: 1px solid var(--border-strong);
68
+ border-radius: var(--control-radius);
69
+ background: var(--bg-surface);
70
+ color: var(--text-default);
71
+ font: inherit;
72
+ }
73
+
74
+ .spreadsheet-comment-thread-textarea:focus-visible {
75
+ border-color: var(--office-blue);
76
+ outline: 2px solid var(--office-blue);
77
+ outline-offset: 1px;
78
+ }
79
+
80
+ .spreadsheet-comment-thread-textarea:disabled {
81
+ border-color: var(--border);
82
+ background: var(--bg-chrome);
83
+ color: var(--text-disabled);
84
+ cursor: not-allowed;
85
+ }
86
+
87
+ .comment-thread-status {
88
+ margin-top: 4px;
89
+ padding: 8px 10px;
90
+ border: 1px solid var(--error-text);
91
+ border-radius: var(--control-radius);
92
+ background: var(--error-bg);
93
+ color: var(--error-text);
94
+ font-size: 12px;
95
+ }
96
+
97
+ .comment-thread-status p {
98
+ margin: 0;
99
+ }
100
+
101
+ .comment-thread-status p + p {
102
+ margin-top: 4px;
103
+ }
104
+
105
+ .comment-thread-actions {
106
+ justify-content: flex-end;
107
+ flex-wrap: wrap;
108
+ }
109
+
110
+ .comment-thread-actions button,
111
+ .comment-thread-header button {
112
+ box-sizing: border-box;
113
+ min-width: 72px;
114
+ height: var(--control-h);
115
+ padding: 0 12px;
116
+ cursor: pointer;
117
+ }
118
+
119
+ .comment-thread-header .dialog-close-x {
120
+ min-width: var(--control-h);
121
+ padding: 0;
122
+ }
123
+
124
+ .comment-thread-actions button:hover:not(:disabled) {
125
+ border-color: var(--border-strong);
126
+ background: var(--hover);
127
+ }
128
+
129
+ .comment-thread-actions .comment-post-button:hover:not(:disabled) {
130
+ border-color: var(--dialog-primary-hover);
131
+ background: var(--dialog-primary-hover);
132
+ }
133
+
134
+ .comment-thread-actions .comment-post-button:active:not(:disabled) {
135
+ border-color: var(--dialog-primary-active);
136
+ background: var(--dialog-primary-active);
137
+ }
138
+
139
+ .comment-thread-actions button:disabled {
140
+ border-color: var(--border);
141
+ background: var(--bg-chrome);
142
+ color: var(--text-disabled);
143
+ cursor: not-allowed;
144
+ }
145
+
146
+ .spreadsheet-comment-thread[data-status='PendingPublished'] .comment-post-button::before {
147
+ display: inline-block;
148
+ width: 10px;
149
+ height: 10px;
150
+ margin-right: 6px;
151
+ animation: comment-thread-spin 800ms linear infinite;
152
+ border: 1px solid var(--text-on-accent-soft);
153
+ border-top-color: var(--text-on-accent);
154
+ border-radius: 50%;
155
+ content: '';
156
+ vertical-align: -1px;
157
+ }
158
+
159
+ @keyframes comment-thread-spin {
160
+ to {
161
+ transform: rotate(1turn);
162
+ }
163
+ }
164
+
165
+ @media (prefers-reduced-motion: reduce) {
166
+ .spreadsheet-comment-thread[data-status='PendingPublished'] .comment-post-button::before {
167
+ animation: none;
168
+ }
169
+ }
@@ -0,0 +1,2 @@
1
+ declare const stylesheet: string
2
+ export default stylesheet
@@ -0,0 +1,254 @@
1
+ /* Conditional Formatting owns this interior; dialog-skin.css owns the modal shell. */
2
+
3
+ .conditional-format-dialog {
4
+ width: min(560px, calc(100vw - 32px));
5
+ min-height: 440px;
6
+ }
7
+
8
+ .conditional-format-dialog .cf-dialog-header {
9
+ justify-content: space-between;
10
+ }
11
+
12
+ .conditional-format-dialog .cf-dialog-title {
13
+ font-size: 14px;
14
+ font-weight: 600;
15
+ user-select: none;
16
+ }
17
+
18
+ .conditional-format-dialog .cf-dialog-body {
19
+ display: grid;
20
+ flex: 1 1 auto;
21
+ grid-template-rows: auto minmax(0, 1fr);
22
+ gap: 16px;
23
+ min-height: 0;
24
+ padding: 16px;
25
+ overflow-y: auto;
26
+ background: var(--bg-surface);
27
+ }
28
+
29
+ .conditional-format-dialog[aria-busy='true'] .cf-dialog-body {
30
+ cursor: progress;
31
+ }
32
+
33
+ .conditional-format-dialog[aria-busy='true'] .cf-form {
34
+ opacity: 0.72;
35
+ }
36
+
37
+ .conditional-format-dialog .cf-rules-section {
38
+ display: flex;
39
+ flex-direction: column;
40
+ gap: 6px;
41
+ min-width: 0;
42
+ }
43
+
44
+ .conditional-format-dialog .cf-section-label,
45
+ .conditional-format-dialog .cf-form-label {
46
+ color: var(--text-muted);
47
+ font-size: 12px;
48
+ font-weight: 600;
49
+ }
50
+
51
+ .conditional-format-dialog .cf-rule-list {
52
+ min-height: 64px;
53
+ max-height: 112px;
54
+ margin: 0;
55
+ padding: 3px;
56
+ overflow-y: auto;
57
+ border: 1px solid var(--border);
58
+ border-radius: var(--control-radius);
59
+ background: var(--bg-chrome-light);
60
+ list-style: none;
61
+ }
62
+
63
+ .conditional-format-dialog .cf-rule-list[aria-busy='true'] {
64
+ border-color: var(--office-blue);
65
+ }
66
+
67
+ [role='dialog'].conditional-format-dialog .cf-rules-section .cf-rule-select {
68
+ position: relative;
69
+ display: flex;
70
+ align-items: center;
71
+ width: 100%;
72
+ padding: 0 8px 0 22px;
73
+ overflow: hidden;
74
+ border: 0;
75
+ background: transparent;
76
+ color: var(--text-default);
77
+ cursor: pointer;
78
+ font: inherit;
79
+ font-size: 12px;
80
+ text-align: left;
81
+ text-overflow: ellipsis;
82
+ white-space: nowrap;
83
+ }
84
+
85
+ [role='dialog'].conditional-format-dialog .cf-rules-section .cf-rule-select::before {
86
+ position: absolute;
87
+ left: 8px;
88
+ width: 8px;
89
+ height: 8px;
90
+ border-radius: var(--control-radius);
91
+ background: var(--excel-green);
92
+ content: '';
93
+ }
94
+
95
+ [role='dialog'].conditional-format-dialog .cf-rules-section .cf-rule-select:hover:not(:disabled) {
96
+ background: var(--hover);
97
+ }
98
+
99
+ [role='dialog'].conditional-format-dialog .cf-rules-section .cf-rule-select[aria-current='true'] {
100
+ background: var(--select-bg);
101
+ color: var(--excel-green-text);
102
+ font-weight: 600;
103
+ }
104
+
105
+ [role='dialog'].conditional-format-dialog .cf-rules-section .cf-rule-select:disabled {
106
+ color: var(--text-disabled);
107
+ cursor: default;
108
+ }
109
+
110
+ .conditional-format-dialog .cf-form {
111
+ display: flex;
112
+ flex-direction: column;
113
+ gap: 10px;
114
+ min-width: 0;
115
+ padding-top: 14px;
116
+ border-top: 1px solid var(--border);
117
+ transition: opacity 120ms ease;
118
+ }
119
+
120
+ .conditional-format-dialog .cf-form-row {
121
+ display: grid;
122
+ grid-template-columns: 96px minmax(0, 1fr) auto;
123
+ align-items: center;
124
+ gap: 8px;
125
+ min-width: 0;
126
+ }
127
+
128
+ [role='dialog'].conditional-format-dialog .cf-form .cf-form-row > :is(input, select) {
129
+ width: 100%;
130
+ min-width: 0;
131
+ padding: 0 8px;
132
+ }
133
+
134
+ [role='dialog'].conditional-format-dialog .cf-form .cf-form-row > input[type='checkbox'] {
135
+ width: auto;
136
+ accent-color: var(--excel-green);
137
+ }
138
+
139
+ [role='dialog'].conditional-format-dialog .cf-form .cf-form-row > button {
140
+ min-width: 96px;
141
+ padding: 0 10px;
142
+ cursor: pointer;
143
+ }
144
+
145
+ [role='dialog'].conditional-format-dialog .cf-form .cf-form-row > button:hover:not(:disabled) {
146
+ border-color: var(--border-strong);
147
+ background: var(--hover);
148
+ }
149
+
150
+ [role='dialog'].conditional-format-dialog .cf-form :is(input, select, button):disabled {
151
+ color: var(--text-disabled);
152
+ cursor: default;
153
+ }
154
+
155
+ [role='dialog'].conditional-format-dialog .cf-form :is(input, select):disabled {
156
+ background: var(--bg-chrome);
157
+ }
158
+
159
+ .conditional-format-dialog .cf-rule-preview {
160
+ display: flex;
161
+ align-items: center;
162
+ gap: 10px;
163
+ min-height: 42px;
164
+ padding: 8px 10px;
165
+ border: 1px solid var(--border);
166
+ border-radius: var(--radius);
167
+ background: var(--bg-chrome-light);
168
+ }
169
+
170
+ .conditional-format-dialog .cf-rule-preview-swatch {
171
+ flex: 0 0 auto;
172
+ width: 44px;
173
+ height: 20px;
174
+ border: 1px solid var(--border-strong);
175
+ border-radius: var(--control-radius);
176
+ background: var(--select-bg);
177
+ }
178
+
179
+ .conditional-format-dialog .cf-rule-preview[data-rule-kind='formula'] .cf-rule-preview-swatch {
180
+ background: var(--error-bg);
181
+ }
182
+
183
+ .conditional-format-dialog
184
+ .cf-rule-preview:is([data-rule-kind='data-bar'], [data-rule-kind='top-bottom'])
185
+ .cf-rule-preview-swatch {
186
+ background: linear-gradient(to right, var(--bg-surface), var(--office-blue));
187
+ }
188
+
189
+ .conditional-format-dialog .cf-rule-preview[data-rule-kind='color-scale'] .cf-rule-preview-swatch {
190
+ background: linear-gradient(to right, var(--error-text), var(--office-blue), var(--excel-green));
191
+ }
192
+
193
+ .conditional-format-dialog .cf-rule-preview-text {
194
+ color: var(--text-muted);
195
+ font-size: 12px;
196
+ }
197
+
198
+ .conditional-format-dialog .cf-error {
199
+ margin: 0;
200
+ padding: 8px 16px;
201
+ border-top: 1px solid var(--error-text);
202
+ background: var(--error-bg);
203
+ color: var(--error-text);
204
+ font-size: 12px;
205
+ }
206
+
207
+ .conditional-format-dialog .cf-dialog-footer {
208
+ min-height: 48px;
209
+ }
210
+
211
+ .conditional-format-dialog .cf-error-spacer {
212
+ flex: 1 1 auto;
213
+ }
214
+
215
+ [role='dialog'].conditional-format-dialog .cf-dialog-footer button {
216
+ min-width: 72px;
217
+ padding: 0 14px;
218
+ cursor: pointer;
219
+ }
220
+
221
+ [role='dialog'].conditional-format-dialog .cf-dialog-footer button:hover:not(:disabled) {
222
+ border-color: var(--border-strong);
223
+ background: var(--hover);
224
+ }
225
+
226
+ [role='dialog'].conditional-format-dialog .cf-dialog-footer button[data-variant='danger'] {
227
+ border-color: var(--error-text);
228
+ background: var(--bg-surface);
229
+ color: var(--error-text);
230
+ }
231
+
232
+ [role='dialog'].conditional-format-dialog
233
+ .cf-dialog-footer
234
+ button[data-variant='danger']:hover:not(:disabled) {
235
+ background: var(--error-bg);
236
+ }
237
+
238
+ [role='dialog'].conditional-format-dialog .cf-dialog-footer button:disabled {
239
+ border-color: var(--border);
240
+ background: var(--bg-chrome);
241
+ color: var(--text-disabled);
242
+ cursor: default;
243
+ }
244
+
245
+ @media (max-width: 600px) {
246
+ .conditional-format-dialog .cf-form-row {
247
+ grid-template-columns: 80px minmax(0, 1fr);
248
+ }
249
+
250
+ .conditional-format-dialog .cf-form-row > button {
251
+ grid-column: 2;
252
+ justify-self: start;
253
+ }
254
+ }
@@ -0,0 +1,7 @@
1
+ // Side-effect CSS module — the dialog `.tsx` pulls this in for its styles.
2
+ // Declaration is co-located so tsc is happy when the runtime-guarded
3
+ // `import('./conditional-format-dialog.css')` is type-checked. The default
4
+ // export is `unknown` because nothing consumes the returned namespace; we
5
+ // only want the load side-effect.
6
+ declare const css: unknown
7
+ export default css
@@ -0,0 +1,10 @@
1
+ .cf-range-fields {
2
+ flex: 1 1 auto;
3
+ display: grid;
4
+ grid-template-columns: repeat(2, minmax(0, 1fr));
5
+ gap: 6px;
6
+ }
7
+
8
+ [role='dialog'].conditional-format-dialog .cf-range-fields input {
9
+ min-width: 0;
10
+ }
@@ -0,0 +1,2 @@
1
+ declare const css: unknown
2
+ export default css
@@ -0,0 +1,197 @@
1
+ /* Data Validation owns its rule editor interior; dialog-skin.css owns the modal shell. */
2
+
3
+ .validation-dialog {
4
+ width: min(520px, calc(100vw - 32px));
5
+ min-height: 360px;
6
+ }
7
+
8
+ .validation-dialog .dv-dialog-header {
9
+ justify-content: space-between;
10
+ }
11
+
12
+ .validation-dialog .dv-dialog-title {
13
+ margin: 0;
14
+ color: var(--text-default);
15
+ }
16
+
17
+ .validation-dialog .dv-dialog-body {
18
+ display: flex;
19
+ min-height: 0;
20
+ flex: 1 1 auto;
21
+ flex-direction: column;
22
+ gap: 14px;
23
+ padding: 16px;
24
+ overflow-y: auto;
25
+ background: var(--bg-surface);
26
+ }
27
+
28
+ .validation-dialog[aria-busy='true'] .dv-dialog-body {
29
+ cursor: progress;
30
+ }
31
+
32
+ .validation-dialog[aria-busy='true'] .dv-rule-form {
33
+ opacity: 0.72;
34
+ }
35
+
36
+ .validation-dialog .dv-range-row {
37
+ display: grid;
38
+ grid-template-columns: 88px minmax(0, 1fr);
39
+ align-items: center;
40
+ gap: 8px;
41
+ min-width: 0;
42
+ }
43
+
44
+ .validation-dialog .dv-range-label,
45
+ .validation-dialog .dv-form-row > label {
46
+ color: var(--text-muted);
47
+ font-size: 12px;
48
+ font-weight: 600;
49
+ }
50
+
51
+ .validation-dialog .validation-range {
52
+ display: flex;
53
+ min-width: 0;
54
+ align-items: center;
55
+ gap: 7px;
56
+ padding: 6px 9px;
57
+ overflow: hidden;
58
+ border: 1px solid var(--excel-green);
59
+ border-radius: var(--control-radius);
60
+ background: var(--select-bg);
61
+ color: var(--excel-green-text);
62
+ font-size: 12px;
63
+ font-weight: 600;
64
+ text-overflow: ellipsis;
65
+ white-space: nowrap;
66
+ }
67
+
68
+ .validation-dialog .validation-range::before {
69
+ width: 7px;
70
+ height: 7px;
71
+ flex: 0 0 auto;
72
+ border-radius: var(--radius);
73
+ background: var(--excel-green);
74
+ content: '';
75
+ }
76
+
77
+ .validation-dialog .dv-rule-form {
78
+ display: flex;
79
+ flex-direction: column;
80
+ gap: 10px;
81
+ min-width: 0;
82
+ padding-top: 14px;
83
+ border-top: 1px solid var(--border);
84
+ transition: opacity 120ms ease;
85
+ }
86
+
87
+ .validation-dialog .dv-form-row {
88
+ display: grid;
89
+ grid-template-columns: 88px minmax(0, 1fr);
90
+ align-items: center;
91
+ gap: 8px;
92
+ min-width: 0;
93
+ }
94
+
95
+ [role='dialog'].validation-dialog .dv-dialog-body :is(select, input) {
96
+ width: 100%;
97
+ min-width: 0;
98
+ padding: 0 8px;
99
+ }
100
+
101
+ [role='dialog'].validation-dialog .dv-dialog-body :is(select, input):hover:not(:disabled) {
102
+ border-color: var(--border-strong);
103
+ }
104
+
105
+ [role='dialog'].validation-dialog .dv-dialog-body :is(select, input):disabled {
106
+ background: var(--bg-chrome);
107
+ color: var(--text-disabled);
108
+ cursor: default;
109
+ }
110
+
111
+ .validation-dialog .dv-range-pair {
112
+ display: grid;
113
+ grid-template-columns: repeat(2, minmax(0, 1fr));
114
+ gap: 8px;
115
+ min-width: 0;
116
+ }
117
+
118
+ .validation-dialog .dv-error {
119
+ margin: 0;
120
+ padding: 8px 16px;
121
+ border-top: 1px solid var(--error-text);
122
+ background: var(--error-bg);
123
+ color: var(--error-text);
124
+ font-size: 12px;
125
+ }
126
+
127
+ .validation-dialog .dv-dialog-footer {
128
+ min-height: 48px;
129
+ }
130
+
131
+ [role='dialog'].validation-dialog .dv-dialog-footer button {
132
+ min-width: 72px;
133
+ padding: 0 12px;
134
+ cursor: pointer;
135
+ }
136
+
137
+ [role='dialog'].validation-dialog .dv-dialog-footer button:hover:not(:disabled) {
138
+ border-color: var(--border-strong);
139
+ background: var(--hover);
140
+ }
141
+
142
+ [role='dialog'].validation-dialog .dv-dialog-footer button[data-variant='danger'] {
143
+ border-color: var(--error-text);
144
+ background: var(--bg-surface);
145
+ color: var(--error-text);
146
+ }
147
+
148
+ [role='dialog'].validation-dialog
149
+ .dv-dialog-footer
150
+ button[data-variant='danger']:hover:not(:disabled) {
151
+ background: var(--error-bg);
152
+ }
153
+
154
+ [role='dialog'].validation-dialog .dv-dialog-footer button:disabled {
155
+ border-color: var(--border);
156
+ background: var(--bg-chrome);
157
+ color: var(--text-disabled);
158
+ cursor: default;
159
+ }
160
+
161
+ .validation-dialog .dv-footer-status {
162
+ display: inline-flex;
163
+ flex: 1 1 auto;
164
+ align-items: center;
165
+ gap: 6px;
166
+ color: var(--text-muted);
167
+ font-size: 12px;
168
+ }
169
+
170
+ .validation-dialog .dv-pending-indicator {
171
+ width: 10px;
172
+ height: 10px;
173
+ border: 2px solid var(--border);
174
+ border-top-color: var(--office-blue);
175
+ border-radius: 50%;
176
+ animation: dv-pending-spin 800ms linear infinite;
177
+ }
178
+
179
+ @keyframes dv-pending-spin {
180
+ to {
181
+ transform: rotate(360deg);
182
+ }
183
+ }
184
+
185
+ @media (max-width: 520px) {
186
+ .validation-dialog .dv-range-row,
187
+ .validation-dialog .dv-form-row {
188
+ grid-template-columns: minmax(0, 1fr);
189
+ gap: 5px;
190
+ }
191
+ }
192
+
193
+ @media (prefers-reduced-motion: reduce) {
194
+ .validation-dialog .dv-pending-indicator {
195
+ animation: none;
196
+ }
197
+ }