@linxin666/dsh-remote-web-ui 0.1.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 (118) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +346 -0
  3. package/cordis.patch.yml +10 -0
  4. package/lib/client.js +2817 -0
  5. package/lib/index.js +1455 -0
  6. package/lib/invariant.js +21 -0
  7. package/lib/types/client/PairFailedNotice.d.ts +12 -0
  8. package/lib/types/client/PairFailedNotice.d.ts.map +1 -0
  9. package/lib/types/client/PhoneIcon.d.ts +19 -0
  10. package/lib/types/client/PhoneIcon.d.ts.map +1 -0
  11. package/lib/types/client/PluginSettingsCard.d.ts +78 -0
  12. package/lib/types/client/PluginSettingsCard.d.ts.map +1 -0
  13. package/lib/types/client/RemoteEntry.d.ts +10 -0
  14. package/lib/types/client/RemoteEntry.d.ts.map +1 -0
  15. package/lib/types/client/RemotePanel.d.ts +50 -0
  16. package/lib/types/client/RemotePanel.d.ts.map +1 -0
  17. package/lib/types/client/RemoteSettingsCard.d.ts +75 -0
  18. package/lib/types/client/RemoteSettingsCard.d.ts.map +1 -0
  19. package/lib/types/client/deep-link.d.ts +40 -0
  20. package/lib/types/client/deep-link.d.ts.map +1 -0
  21. package/lib/types/client/index.d.ts +54 -0
  22. package/lib/types/client/index.d.ts.map +1 -0
  23. package/lib/types/client/locales.d.ts +144 -0
  24. package/lib/types/client/locales.d.ts.map +1 -0
  25. package/lib/types/client/pair-api.d.ts +100 -0
  26. package/lib/types/client/pair-api.d.ts.map +1 -0
  27. package/lib/types/client/settings-form.d.ts +119 -0
  28. package/lib/types/client/settings-form.d.ts.map +1 -0
  29. package/lib/types/gate.d.ts +58 -0
  30. package/lib/types/gate.d.ts.map +1 -0
  31. package/lib/types/index.d.ts +78 -0
  32. package/lib/types/index.d.ts.map +1 -0
  33. package/lib/types/invariant.d.ts +16 -0
  34. package/lib/types/invariant.d.ts.map +1 -0
  35. package/lib/types/lan.d.ts +15 -0
  36. package/lib/types/lan.d.ts.map +1 -0
  37. package/lib/types/mobile/api.d.ts +64 -0
  38. package/lib/types/mobile/api.d.ts.map +1 -0
  39. package/lib/types/mobile/index.d.ts +10 -0
  40. package/lib/types/mobile/index.d.ts.map +1 -0
  41. package/lib/types/mobile/messages.d.ts +103 -0
  42. package/lib/types/mobile/messages.d.ts.map +1 -0
  43. package/lib/types/mobile/messages.test.d.ts +2 -0
  44. package/lib/types/mobile/messages.test.d.ts.map +1 -0
  45. package/lib/types/mobile/mobile-styles.d.ts +6 -0
  46. package/lib/types/mobile/mobile-styles.d.ts.map +1 -0
  47. package/lib/types/mobile/mobile-theme.d.ts +22 -0
  48. package/lib/types/mobile/mobile-theme.d.ts.map +1 -0
  49. package/lib/types/mobile/mobile-theme.test.d.ts +2 -0
  50. package/lib/types/mobile/mobile-theme.test.d.ts.map +1 -0
  51. package/lib/types/mobile/mux.d.ts +52 -0
  52. package/lib/types/mobile/mux.d.ts.map +1 -0
  53. package/lib/types/mobile/rpc.d.ts +38 -0
  54. package/lib/types/mobile/rpc.d.ts.map +1 -0
  55. package/lib/types/mobile/theme-toggle.d.ts +12 -0
  56. package/lib/types/mobile/theme-toggle.d.ts.map +1 -0
  57. package/lib/types/mobile/views/App.d.ts +59 -0
  58. package/lib/types/mobile/views/App.d.ts.map +1 -0
  59. package/lib/types/mobile/views/ChatView.d.ts +39 -0
  60. package/lib/types/mobile/views/ChatView.d.ts.map +1 -0
  61. package/lib/types/mobile/views/ChatView.test.d.ts +2 -0
  62. package/lib/types/mobile/views/ChatView.test.d.ts.map +1 -0
  63. package/lib/types/mobile/views/SessionListView.d.ts +27 -0
  64. package/lib/types/mobile/views/SessionListView.d.ts.map +1 -0
  65. package/lib/types/mobile/views/SessionListView.test.d.ts +2 -0
  66. package/lib/types/mobile/views/SessionListView.test.d.ts.map +1 -0
  67. package/lib/types/mobile/views/WorkspaceView.d.ts +19 -0
  68. package/lib/types/mobile/views/WorkspaceView.d.ts.map +1 -0
  69. package/lib/types/mobile-api.d.ts +41 -0
  70. package/lib/types/mobile-api.d.ts.map +1 -0
  71. package/lib/types/mobile-routes.d.ts +16 -0
  72. package/lib/types/mobile-routes.d.ts.map +1 -0
  73. package/lib/types/pairing.d.ts +215 -0
  74. package/lib/types/pairing.d.ts.map +1 -0
  75. package/lib/types/routes.d.ts +58 -0
  76. package/lib/types/routes.d.ts.map +1 -0
  77. package/lib/types/tunnel.d.ts +99 -0
  78. package/lib/types/tunnel.d.ts.map +1 -0
  79. package/package.json +104 -0
  80. package/src/client/PairFailedNotice.tsx +33 -0
  81. package/src/client/PhoneIcon.tsx +31 -0
  82. package/src/client/PluginSettingsCard.tsx +207 -0
  83. package/src/client/RemoteEntry.tsx +202 -0
  84. package/src/client/RemotePanel.tsx +186 -0
  85. package/src/client/RemoteSettingsCard.tsx +220 -0
  86. package/src/client/deep-link.ts +137 -0
  87. package/src/client/index.ts +167 -0
  88. package/src/client/locales.ts +149 -0
  89. package/src/client/pair-api.ts +176 -0
  90. package/src/client/remote.module.css +422 -0
  91. package/src/client/settings-card.module.css +296 -0
  92. package/src/client/settings-form.ts +294 -0
  93. package/src/css-modules.d.ts +6 -0
  94. package/src/gate.ts +121 -0
  95. package/src/index.ts +299 -0
  96. package/src/invariant.ts +32 -0
  97. package/src/lan.ts +21 -0
  98. package/src/mobile/api.ts +106 -0
  99. package/src/mobile/index.tsx +27 -0
  100. package/src/mobile/messages.test.ts +222 -0
  101. package/src/mobile/messages.ts +555 -0
  102. package/src/mobile/mobile-styles.ts +853 -0
  103. package/src/mobile/mobile-theme.test.ts +84 -0
  104. package/src/mobile/mobile-theme.ts +76 -0
  105. package/src/mobile/mux.ts +126 -0
  106. package/src/mobile/rpc.ts +90 -0
  107. package/src/mobile/theme-toggle.tsx +47 -0
  108. package/src/mobile/views/App.tsx +152 -0
  109. package/src/mobile/views/ChatView.test.tsx +243 -0
  110. package/src/mobile/views/ChatView.tsx +650 -0
  111. package/src/mobile/views/SessionListView.test.tsx +139 -0
  112. package/src/mobile/views/SessionListView.tsx +186 -0
  113. package/src/mobile/views/WorkspaceView.tsx +108 -0
  114. package/src/mobile-api.ts +271 -0
  115. package/src/mobile-routes.ts +77 -0
  116. package/src/pairing.ts +390 -0
  117. package/src/routes.ts +346 -0
  118. package/src/tunnel.ts +264 -0
@@ -0,0 +1,422 @@
1
+ /* Mobile remote-control seat + panel (design tokens only — no literal
2
+ colors). The trigger matches the settings row/rail geometry; the panel is
3
+ a centered modal (mask + 560px card) like the settings panel. */
4
+
5
+ .overlay {
6
+ position: fixed;
7
+ inset: 0;
8
+ z-index: 1000;
9
+ display: flex;
10
+ align-items: center;
11
+ justify-content: center;
12
+ }
13
+
14
+ .mask {
15
+ position: absolute;
16
+ inset: 0;
17
+ background: var(--dsw-alias-bg-mask-1);
18
+ backdrop-filter: var(--dsw-mask-blur);
19
+ }
20
+
21
+ /* Trigger: settings row height beside the trigger row (wide), or the 36px
22
+ rail circle; the seat's owner (ui-sidebar) lays out the geometry. */
23
+ .trigger {
24
+ flex: none;
25
+ display: inline-flex;
26
+ align-items: center;
27
+ justify-content: center;
28
+ width: 36px;
29
+ height: 36px;
30
+ border: none;
31
+ border-radius: 50%;
32
+ padding: 0;
33
+ background: transparent;
34
+ color: var(--dsw-alias-label-secondary);
35
+ cursor: pointer;
36
+ /* Transition + focus ring consent (box-shadow from :focus-visible). */
37
+ transition: background-color 120ms ease, color 120ms ease, box-shadow 120ms ease;
38
+ }
39
+
40
+ .trigger:hover:not(:disabled) {
41
+ background: var(--dsw-alias-interactive-bg-hover);
42
+ color: var(--dsw-alias-label-primary);
43
+ }
44
+
45
+ .trigger:active:not(:disabled) {
46
+ background: var(--dsw-alias-interactive-bg-active);
47
+ }
48
+
49
+ .trigger:focus-visible {
50
+ outline: none;
51
+ box-shadow: 0 0 0 2px var(--dsw-alias-bg-layer-2), 0 0 0 4px var(--dsw-alias-brand-primary);
52
+ }
53
+
54
+ .trigger:disabled {
55
+ opacity: 0.5;
56
+ cursor: default;
57
+ }
58
+
59
+ .panel {
60
+ position: relative;
61
+ z-index: 1;
62
+ display: flex;
63
+ flex-direction: column;
64
+ gap: 14px;
65
+ width: 560px;
66
+ max-width: calc(100vw - 48px);
67
+ max-height: calc(100vh - 48px);
68
+ overflow: auto;
69
+ box-sizing: border-box;
70
+ padding: 24px;
71
+ border-radius: 24px;
72
+ background: var(--dsw-alias-bg-layer-2);
73
+ box-shadow: var(--dsw-shadow-lv3);
74
+ color: var(--dsw-alias-label-primary);
75
+ font-size: 14px;
76
+ line-height: 22px;
77
+ }
78
+
79
+ .header {
80
+ display: flex;
81
+ align-items: flex-start;
82
+ gap: 12px;
83
+ }
84
+
85
+ .heading {
86
+ flex: 1;
87
+ min-width: 0;
88
+ }
89
+
90
+ .title {
91
+ margin: 0;
92
+ font-size: 18px;
93
+ font-weight: 600;
94
+ line-height: 26px;
95
+ }
96
+
97
+ .subtitle {
98
+ margin: 4px 0 0;
99
+ color: var(--dsw-alias-label-secondary);
100
+ font-size: 13px;
101
+ }
102
+
103
+ .close {
104
+ flex: none;
105
+ display: inline-flex;
106
+ align-items: center;
107
+ justify-content: center;
108
+ width: 28px;
109
+ height: 28px;
110
+ border: none;
111
+ border-radius: 50%;
112
+ padding: 0;
113
+ background: transparent;
114
+ color: var(--dsw-alias-label-secondary);
115
+ cursor: pointer;
116
+ transition: background-color 120ms ease, color 120ms ease, box-shadow 120ms ease;
117
+ }
118
+
119
+ .close:hover:not(:disabled) {
120
+ background: var(--dsw-alias-interactive-bg-hover);
121
+ }
122
+
123
+ .close:active:not(:disabled) {
124
+ background: var(--dsw-alias-interactive-bg-active);
125
+ }
126
+
127
+ .close:focus-visible {
128
+ outline: none;
129
+ box-shadow: 0 0 0 2px var(--dsw-alias-bg-layer-2), 0 0 0 4px var(--dsw-alias-brand-primary);
130
+ }
131
+
132
+ .close:disabled {
133
+ opacity: 0.5;
134
+ cursor: default;
135
+ }
136
+
137
+ .card {
138
+ display: flex;
139
+ flex-direction: column;
140
+ align-items: center;
141
+ gap: 12px;
142
+ padding: 16px;
143
+ border: 1px solid var(--dsw-alias-border-l2);
144
+ border-radius: 16px;
145
+ background: var(--dsw-alias-bg-layer-1);
146
+ }
147
+
148
+ .cardHeader {
149
+ display: flex;
150
+ align-items: center;
151
+ justify-content: space-between;
152
+ width: 100%;
153
+ gap: 12px;
154
+ }
155
+
156
+ .cardTitle {
157
+ font-weight: 500;
158
+ }
159
+
160
+ .badge {
161
+ display: inline-flex;
162
+ flex: none;
163
+ align-items: center;
164
+ gap: 6px;
165
+ min-width: 0;
166
+ padding: 2px 10px;
167
+ border-radius: 999px;
168
+ font-size: 12px;
169
+ line-height: 18px;
170
+ white-space: nowrap;
171
+ }
172
+
173
+ .badge::before {
174
+ content: '';
175
+ width: 8px;
176
+ height: 8px;
177
+ border-radius: 50%;
178
+ background: currentColor;
179
+ }
180
+
181
+ .badge-waiting {
182
+ color: var(--dsw-alias-label-secondary);
183
+ background: var(--dsw-alias-interactive-bg-hover);
184
+ }
185
+
186
+ .badge-connected {
187
+ color: var(--dsw-alias-state-success-primary);
188
+ background: var(--dsw-alias-interactive-bg-hover);
189
+ }
190
+
191
+ .badge-disconnected {
192
+ color: var(--dsw-alias-state-warn-primary);
193
+ background: var(--dsw-alias-interactive-bg-hover);
194
+ }
195
+
196
+ .badge-stopped {
197
+ color: var(--dsw-alias-state-error-primary);
198
+ background: var(--dsw-alias-interactive-bg-hover);
199
+ }
200
+
201
+ .badgePublic {
202
+ color: var(--dsw-alias-brand-primary);
203
+ background: var(--dsw-alias-interactive-bg-hover);
204
+ }
205
+
206
+ .badges {
207
+ display: inline-flex;
208
+ align-items: center;
209
+ gap: 6px;
210
+ flex: none;
211
+ }
212
+
213
+ .qrWrap {
214
+ display: flex;
215
+ align-items: center;
216
+ justify-content: center;
217
+ padding: 12px;
218
+ border-radius: 12px;
219
+ background: var(--dsw-alias-bg-base);
220
+ }
221
+
222
+ .qr {
223
+ display: block;
224
+ }
225
+
226
+ .expired {
227
+ margin: 0;
228
+ color: var(--dsw-alias-state-error-primary);
229
+ font-size: 13px;
230
+ }
231
+
232
+ .expiry {
233
+ margin: 0;
234
+ color: var(--dsw-alias-label-secondary);
235
+ font-size: 12px;
236
+ }
237
+
238
+ .hint {
239
+ margin: 0;
240
+ color: var(--dsw-alias-label-secondary);
241
+ font-size: 13px;
242
+ }
243
+
244
+ .link {
245
+ margin: 0;
246
+ overflow: hidden;
247
+ text-overflow: ellipsis;
248
+ white-space: nowrap;
249
+ color: var(--dsw-alias-label-caption);
250
+ font-family: var(--dsw-font-mono, ui-monospace, monospace);
251
+ font-size: 12px;
252
+ }
253
+
254
+ .stoppedHint {
255
+ margin: 0;
256
+ color: var(--dsw-alias-state-error-primary);
257
+ font-size: 13px;
258
+ }
259
+
260
+ .tunnelNote {
261
+ margin: 0;
262
+ color: var(--dsw-alias-label-secondary);
263
+ font-size: 13px;
264
+ }
265
+
266
+ .tunnelFailed {
267
+ margin: 0;
268
+ color: var(--dsw-alias-state-error-primary);
269
+ font-size: 13px;
270
+ }
271
+
272
+ .actions {
273
+ display: flex;
274
+ gap: 8px;
275
+ }
276
+
277
+ .action {
278
+ display: inline-flex;
279
+ align-items: center;
280
+ justify-content: center;
281
+ gap: 6px;
282
+ height: 34px;
283
+ padding: 0 14px;
284
+ border: 1px solid var(--dsw-alias-border-l2);
285
+ border-radius: 10px;
286
+ background: var(--dsw-alias-button-elevated-fill);
287
+ color: var(--dsw-alias-label-primary);
288
+ font-size: 13px;
289
+ cursor: pointer;
290
+ white-space: nowrap;
291
+ transition: background-color 120ms ease, border-color 120ms ease, box-shadow 120ms ease;
292
+ }
293
+
294
+ .action:hover:not(:disabled) {
295
+ background: var(--dsw-alias-button-floating-hover);
296
+ }
297
+
298
+ .action:active:not(:disabled) {
299
+ background: var(--dsw-alias-interactive-bg-active);
300
+ }
301
+
302
+ .action:focus-visible {
303
+ outline: none;
304
+ box-shadow: 0 0 0 2px var(--dsw-alias-bg-layer-2), 0 0 0 4px var(--dsw-alias-brand-primary);
305
+ }
306
+
307
+ .action:disabled {
308
+ opacity: 0.5;
309
+ cursor: default;
310
+ }
311
+
312
+ .banner {
313
+ padding: 16px;
314
+ border: 1px solid var(--dsw-alias-border-l2);
315
+ border-radius: 16px;
316
+ background: var(--dsw-alias-bg-layer-1);
317
+ }
318
+
319
+ .bannerTitle {
320
+ margin: 0;
321
+ color: var(--dsw-alias-state-warn-primary);
322
+ font-weight: 500;
323
+ }
324
+
325
+ .bannerHint {
326
+ margin: 6px 0 0;
327
+ color: var(--dsw-alias-label-secondary);
328
+ font-size: 13px;
329
+ }
330
+
331
+ /* Failed-pair toast: fixed top-center diagnostic on the phone. */
332
+ .notice {
333
+ position: fixed;
334
+ top: 16px;
335
+ left: 50%;
336
+ transform: translateX(-50%);
337
+ z-index: 2000;
338
+ max-width: min(420px, calc(100vw - 32px));
339
+ box-sizing: border-box;
340
+ padding: 12px 16px;
341
+ border: 1px solid var(--dsw-alias-border-l2);
342
+ border-radius: 12px;
343
+ background: var(--dsw-alias-bg-layer-2);
344
+ box-shadow: var(--dsw-shadow-lv3);
345
+ }
346
+
347
+ .noticeTitle {
348
+ margin: 0;
349
+ color: var(--dsw-alias-state-error-primary);
350
+ font-weight: 500;
351
+ }
352
+
353
+ .noticeDetail {
354
+ margin: 4px 0 0;
355
+ color: var(--dsw-alias-label-secondary);
356
+ font-size: 13px;
357
+ }
358
+
359
+ /* Multi-homed address picker: one radio per constructible LAN literal. */
360
+ .addresses {
361
+ margin: 12px 0 0;
362
+ padding: 0;
363
+ border: none;
364
+ }
365
+
366
+ .addresses legend {
367
+ padding: 0;
368
+ color: var(--dsw-alias-label-secondary);
369
+ font-size: 13px;
370
+ }
371
+
372
+ .address {
373
+ display: flex;
374
+ align-items: center;
375
+ gap: 8px;
376
+ margin-top: 6px;
377
+ padding: 4px 6px;
378
+ border-radius: 6px;
379
+ color: var(--dsw-alias-label-primary);
380
+ font-size: 13px;
381
+ font-variant-numeric: tabular-nums;
382
+ cursor: pointer;
383
+ transition: background-color 120ms ease;
384
+ }
385
+
386
+ .address:hover {
387
+ background: var(--dsw-alias-interactive-bg-hover);
388
+ }
389
+
390
+ .address input:focus-visible {
391
+ outline: none;
392
+ box-shadow: 0 0 0 2px var(--dsw-alias-bg-layer-2), 0 0 0 4px var(--dsw-alias-brand-primary);
393
+ border-radius: 50%;
394
+ }
395
+
396
+ .addressValue {
397
+ flex: 1;
398
+ min-width: 0;
399
+ overflow: hidden;
400
+ text-overflow: ellipsis;
401
+ white-space: nowrap;
402
+ color: var(--dsw-alias-label-secondary);
403
+ font-size: 12px;
404
+ }
405
+
406
+ .addressHint {
407
+ margin: 6px 0 0;
408
+ color: var(--dsw-alias-label-tertiary);
409
+ font-size: 12px;
410
+ }
411
+
412
+ /* Accessibility: collapse the interaction transitions for reduced-motion
413
+ users. The panel chrome is already static; this just disables the
414
+ hover/active/focus cross-fades added above. */
415
+ @media (prefers-reduced-motion: reduce) {
416
+ .trigger,
417
+ .close,
418
+ .action,
419
+ .address {
420
+ transition: none;
421
+ }
422
+ }
@@ -0,0 +1,296 @@
1
+ .card {
2
+ list-style: none;
3
+ border: 1px solid var(--dsw-alias-border-l2);
4
+ border-radius: 8px;
5
+ background: var(--dsw-alias-bg-layer-3);
6
+ overflow: hidden;
7
+ transition: border-color 0.16s, background 0.16s;
8
+ }
9
+
10
+ .cardOpen {
11
+ background: var(--dsw-alias-bg-layer-2);
12
+ border-color: var(--dsw-alias-label-dimmed);
13
+ }
14
+
15
+ .header {
16
+ display: flex;
17
+ align-items: center;
18
+ gap: 8px;
19
+ width: 100%;
20
+ padding: 10px 14px;
21
+ border: 0;
22
+ background: transparent;
23
+ cursor: pointer;
24
+ text-align: left;
25
+ font: inherit;
26
+ border-radius: 8px;
27
+ transition: background-color 120ms ease, box-shadow 120ms ease;
28
+ }
29
+
30
+ .header:hover:not(:disabled) {
31
+ background: var(--dsw-alias-interactive-bg-hover);
32
+ }
33
+
34
+ .header:active:not(:disabled) {
35
+ background: var(--dsw-alias-interactive-bg-active);
36
+ }
37
+
38
+ .header:focus-visible {
39
+ outline: none;
40
+ box-shadow: 0 0 0 2px var(--dsw-alias-bg-layer-3), 0 0 0 4px var(--dsw-alias-brand-primary);
41
+ }
42
+
43
+ .header:disabled {
44
+ opacity: 0.5;
45
+ cursor: default;
46
+ }
47
+
48
+ .headText {
49
+ display: flex;
50
+ flex-direction: column;
51
+ gap: 2px;
52
+ flex: 1;
53
+ min-width: 0;
54
+ }
55
+
56
+ .name {
57
+ font-weight: 600;
58
+ color: var(--dsw-alias-label-primary);
59
+ }
60
+
61
+ .description {
62
+ font-size: 12px;
63
+ color: var(--dsw-alias-label-tertiary);
64
+ }
65
+
66
+ .pending {
67
+ font-size: 12px;
68
+ color: var(--dsw-alias-state-warn-primary);
69
+ }
70
+
71
+ .chevron {
72
+ transition: transform 120ms ease;
73
+ color: var(--dsw-alias-label-tertiary);
74
+ }
75
+
76
+ .chevronOpen {
77
+ transform: rotate(180deg);
78
+ }
79
+
80
+ .body {
81
+ padding: 0 14px 14px;
82
+ display: flex;
83
+ flex-direction: column;
84
+ gap: 14px;
85
+ }
86
+
87
+ .readOnly {
88
+ margin: 0;
89
+ font-size: 12px;
90
+ color: var(--dsw-alias-label-tertiary);
91
+ }
92
+
93
+ .footer {
94
+ display: flex;
95
+ align-items: center;
96
+ justify-content: flex-end;
97
+ gap: 8px;
98
+ }
99
+
100
+ .failed {
101
+ margin: 0 auto 0 0;
102
+ font-size: 12px;
103
+ color: var(--dsw-alias-state-error-primary);
104
+ }
105
+
106
+ .discard,
107
+ .save {
108
+ padding: 5px 12px;
109
+ border-radius: 6px;
110
+ font: inherit;
111
+ font-size: 13px;
112
+ cursor: pointer;
113
+ transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease, box-shadow 120ms ease;
114
+ }
115
+
116
+ .discard {
117
+ border: 1px solid var(--dsw-alias-border-l2);
118
+ background: transparent;
119
+ color: var(--dsw-alias-label-secondary);
120
+ }
121
+
122
+ .discard:hover:not(:disabled) {
123
+ color: var(--dsw-alias-label-primary);
124
+ border-color: var(--dsw-alias-label-dimmed);
125
+ }
126
+
127
+ .discard:active:not(:disabled) {
128
+ background: var(--dsw-alias-interactive-bg-active);
129
+ }
130
+
131
+ .discard:focus-visible {
132
+ outline: none;
133
+ box-shadow: 0 0 0 2px var(--dsw-alias-bg-layer-3), 0 0 0 4px var(--dsw-alias-brand-primary);
134
+ }
135
+
136
+ .save {
137
+ border: 1px solid var(--dsw-alias-button-info-fill);
138
+ background: var(--dsw-alias-button-info-fill);
139
+ color: var(--dsw-alias-label-primary-foreground);
140
+ }
141
+
142
+ .save:hover:not(:disabled) {
143
+ border-color: var(--dsw-alias-button-info-hover);
144
+ background: var(--dsw-alias-button-info-hover);
145
+ }
146
+
147
+ .save:active:not(:disabled) {
148
+ border-color: var(--dsw-alias-button-info-hover);
149
+ background: var(--dsw-alias-button-info-hover);
150
+ filter: brightness(0.96);
151
+ }
152
+
153
+ .save:focus-visible {
154
+ outline: none;
155
+ box-shadow: 0 0 0 2px var(--dsw-alias-bg-layer-3), 0 0 0 4px var(--dsw-alias-brand-primary);
156
+ }
157
+
158
+ .discard:disabled,
159
+ .save:disabled {
160
+ opacity: 0.5;
161
+ cursor: default;
162
+ }
163
+
164
+ .field {
165
+ display: flex;
166
+ flex-direction: column;
167
+ gap: 4px;
168
+ }
169
+
170
+ .head {
171
+ display: flex;
172
+ align-items: center;
173
+ gap: 8px;
174
+ }
175
+
176
+ .label {
177
+ font-size: 13px;
178
+ font-weight: 500;
179
+ color: var(--dsw-alias-label-primary);
180
+ }
181
+
182
+ .badges {
183
+ display: flex;
184
+ align-items: center;
185
+ gap: 6px;
186
+ }
187
+
188
+ .badge {
189
+ flex: none;
190
+ min-width: 0;
191
+ font-size: 11px;
192
+ padding: 1px 6px;
193
+ border-radius: 999px;
194
+ background: var(--dsw-alias-interactive-bg-hover-accent);
195
+ color: var(--dsw-alias-state-business-primary);
196
+ white-space: nowrap;
197
+ }
198
+
199
+ .reset {
200
+ flex: none;
201
+ font-size: 11px;
202
+ border: 0;
203
+ border-radius: 4px;
204
+ background: transparent;
205
+ color: var(--dsw-alias-state-business-primary);
206
+ cursor: pointer;
207
+ padding: 1px 2px;
208
+ transition: background-color 120ms ease, color 120ms ease, box-shadow 120ms ease;
209
+ }
210
+
211
+ .reset:hover:not(:disabled) {
212
+ color: var(--dsw-alias-label-primary);
213
+ background: var(--dsw-alias-interactive-bg-hover);
214
+ }
215
+
216
+ .reset:active:not(:disabled) {
217
+ background: var(--dsw-alias-interactive-bg-active);
218
+ }
219
+
220
+ .reset:focus-visible {
221
+ outline: none;
222
+ box-shadow: 0 0 0 2px var(--dsw-alias-bg-layer-3), 0 0 0 4px var(--dsw-alias-brand-primary);
223
+ }
224
+
225
+ .reset:disabled {
226
+ opacity: 0.5;
227
+ cursor: default;
228
+ }
229
+
230
+ .input,
231
+ .select {
232
+ padding: 6px 8px;
233
+ border: 1px solid var(--dsw-alias-border-l2);
234
+ border-radius: 6px;
235
+ font: inherit;
236
+ font-size: 13px;
237
+ color: var(--dsw-alias-label-primary);
238
+ background: var(--dsw-specific-input-major);
239
+ transition: border-color 120ms ease, box-shadow 120ms ease;
240
+ }
241
+
242
+ .input:focus-visible,
243
+ .select:focus-visible {
244
+ outline: none;
245
+ border-color: var(--dsw-alias-brand-primary);
246
+ box-shadow: 0 0 0 2px var(--dsw-alias-bg-layer-3), 0 0 0 4px var(--dsw-alias-brand-primary);
247
+ }
248
+
249
+ .inputInvalid {
250
+ padding: 6px 8px;
251
+ border: 1px solid var(--dsw-alias-state-error-primary);
252
+ border-radius: 6px;
253
+ font: inherit;
254
+ font-size: 13px;
255
+ color: var(--dsw-alias-label-primary);
256
+ transition: border-color 120ms ease, box-shadow 120ms ease;
257
+ }
258
+
259
+ .inputInvalid:focus-visible {
260
+ outline: none;
261
+ border-color: var(--dsw-alias-state-error-primary);
262
+ box-shadow: 0 0 0 2px var(--dsw-alias-bg-layer-3), 0 0 0 4px var(--dsw-alias-state-error-primary);
263
+ }
264
+
265
+ .input:disabled,
266
+ .select:disabled {
267
+ opacity: 0.6;
268
+ }
269
+
270
+ .hint {
271
+ margin: 0;
272
+ font-size: 12px;
273
+ color: var(--dsw-alias-label-secondary);
274
+ }
275
+
276
+ .invalid {
277
+ margin: 0;
278
+ font-size: 12px;
279
+ color: var(--dsw-alias-state-error-primary);
280
+ }
281
+
282
+ /* Accessibility: collapse the interaction transitions for reduced-motion
283
+ users; the card chrome itself stays static. */
284
+ @media (prefers-reduced-motion: reduce) {
285
+ .card,
286
+ .header,
287
+ .chevron,
288
+ .discard,
289
+ .save,
290
+ .reset,
291
+ .input,
292
+ .select,
293
+ .inputInvalid {
294
+ transition: none;
295
+ }
296
+ }