PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 0.9.8
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v0.9.8
1.1.10 1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.1 1.0.0 0.9.8 0.9.7 0.9.6 0.9.4 0.9.5 0.9.3 0.9.2 0.9.1 0.9.0 0.8.9 0.8.8 0.8.7 All 34 releases
desktop-mode / assets / css / os-settings.css

os-settings.css in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 0.9.8, at assets/css/os-settings.css

1,450 lines 38.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Desktop Mode — OS Settings native panel.
3 *
4 * The preferences panel rendered inside the OS Settings native
5 * window: wallpaper swatches + editor slot, accent colors, dock size,
6 * and the "Or use your own image" uploader + Media Library grid.
7 * Currently shipped alongside the window-chrome stylesheet because
8 * historically the rules lived there; marked for a future move to its
9 * own enqueue handle once the coupling to the shell CSS is removed.
10 *
11 * @since 0.5.0
12 */
13 .desktop-mode-os-settings {
14 font-size: 13px;
15 line-height: 1.5;
16 }
17
18 .desktop-mode-os-settings__intro {
19 margin: 0 0 16px;
20 color: var( --wpd-fg-muted, #50575e );
21 }
22
23 /*
24 * Card styling for each OS-Settings section. `<wpd-section>`'s
25 * shadow DOM handles the heading + description; the outer card
26 * (padding, background, border) lives here because it's a
27 * per-surface visual choice, not a property of the component
28 * itself. Targets the tag so shadow-DOM internals stay private.
29 */
30 .desktop-mode-os-settings wpd-section {
31 display: block;
32 margin: 0 0 20px;
33 padding: 16px 16px 18px;
34 background: var( --wpd-surface-elevated, #f6f7f7 );
35 border: 1px solid var( --wpd-border, #dcdcde );
36 border-radius: 8px;
37 }
38
39 /*
40 * Generic grid. Auto-fill + minmax gives us a truly responsive
41 * layout — the panel reflows columns as OS Settings is resized,
42 * rather than locking to a fixed 3-across.
43 */
44 .desktop-mode-os-settings__grid {
45 display: grid;
46 grid-template-columns: repeat( auto-fill, minmax( 140px, 1fr ) );
47 gap: 10px;
48 }
49
50 /*
51 * Wallpaper swatches — each is a `<wpd-swatch variant="wallpaper">`
52 * with its own shadow-DOM button + aspect ratio + selected state.
53 * The only outer knobs we need are: wider minmax for wallpapers
54 * (so each tile shows meaningful preview area), and the 16:9
55 * aspect ratio override. Everything else lives in the component.
56 */
57 .desktop-mode-os-settings__grid--wallpapers {
58 grid-template-columns: repeat( auto-fill, minmax( 160px, 1fr ) );
59 }
60
61 /*
62 * Wallpaper preset label — sits above the gradient/image preview.
63 * Presets span the full tonal range (graphite dark, mono near-
64 * black, aurora blue, sunset hot pink) so neither pure white nor
65 * pure black text is universally readable. A frosted glass chip
66 * behind the text gives the label its own local contrast that's
67 * legible on every preset and respects the tile's visual language
68 * (rounded pill shape matches the selected-state corners).
69 */
70 .desktop-mode-os-settings__swatch-label {
71 display: inline-block;
72 /* Sit above the live-preview overlay (z-index 0) — the caption
73 * must stay readable over a moving canvas. */
74 position: relative;
75 z-index: 1;
76 padding: 3px 10px;
77 font-size: 11px;
78 font-weight: 600;
79 color: var( --wpd-fg-on-accent, #fff );
80 background: var( --wpd-scrim, rgba(0, 0, 0, 0.45) );
81 backdrop-filter: blur(8px) saturate(160%);
82 -webkit-backdrop-filter: blur(8px) saturate(160%);
83 border-radius: 999px;
84 text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
85 letter-spacing: 0.01em;
86 /* Stop the chip from hugging the swatch edge — the 6 8 padding
87 * on the parent already gives a gap, but this keeps things
88 * consistent if the parent padding is ever tuned. */
89 pointer-events: none;
90 }
91
92 /*
93 * Live wallpaper preview — an overlay div slotted into a wallpaper
94 * `<wpd-swatch>` by the preview manager (see
95 * settings/sections/wallpaper-previews.ts). Fills the tile button
96 * (which is position: relative in the component's shadow styles) and
97 * paints between the CSS `preview` background and the label chip.
98 * pointer-events: none so the tile button keeps receiving the click.
99 */
100 .desktop-mode-os-settings__wallpaper-live-preview {
101 position: absolute;
102 inset: 0;
103 z-index: 0;
104 overflow: hidden;
105 pointer-events: none;
106 /* Match the swatch button's rounding so canvas corners don't
107 * poke out of the tile. */
108 border-radius: 8px;
109 }
110
111 .desktop-mode-os-settings__wallpaper-live-preview canvas {
112 display: block;
113 width: 100%;
114 height: 100%;
115 }
116
117 /* Accent swatches now render as `<wpd-swatch>` via `<wpd-swatch-grid>`.
118 * The old `__swatch--accent` / `__swatch-label` / `__segmented` /
119 * `__segment` rules moved into those component shadow-DOM
120 * stylesheets; nothing at host level needs to override them. */
121
122 .desktop-mode-os-settings__footer {
123 display: flex;
124 justify-content: flex-end;
125 margin-top: 12px;
126 }
127
128 /* Top-level tab strip separating Appearance from AI Settings.
129 * Don't add a `display` rule for `wpd-tabpanel` here — the component's
130 * shadow-DOM `:host([hidden]) { display: none }` has lower specificity
131 * than any outer descendant selector, and overriding it from outside
132 * breaks the auto-swap (hidden panels stay visible). The component's
133 * own `:host { display: block }` already handles the shown state. */
134 .desktop-mode-os-settings wpd-tabs {
135 display: block;
136 }
137
138 /* `__reset` now renders as `<wpd-button variant="ghost">`. */
139
140 /* ---------------------------------------------------------------
141 * Custom gradient editor — color inputs + angle slider.
142 *
143 * Toggled by `data-expanded` on the outer wrapper. Uses the modern
144 * grid-template-rows 0fr ↔ 1fr trick so we can animate to natural
145 * content height without hard-coding a max-height. The inner wrapper
146 * owns the visible chrome (padding, border, background) and is
147 * clipped during the transition by overflow: hidden; the outer
148 * wrapper animates the row track + spacing + opacity.
149 *
150 * Supported in all evergreen browsers (Chrome 117+, Safari 17.2+,
151 * Firefox 128+). On older engines the transition is simply skipped —
152 * the editor still appears, just without the glide.
153 * --------------------------------------------------------------- */
154 /*
155 * Editor slot — the per-wallpaper panel that slides in below the
156 * swatch grid when a wallpaper with `renderEditor` is selected.
157 * Collapses via the grid-template-rows 0fr → 1fr trick; TS drives
158 * the `[data-expanded]` attribute on the slot wrapper.
159 */
160 .desktop-mode-os-settings__editor-slot {
161 display: grid;
162 grid-template-rows: 0fr;
163 margin-top: 0;
164 opacity: 0;
165 transition:
166 grid-template-rows 0.25s cubic-bezier(0.2, 0, 0.2, 1),
167 margin-top 0.25s cubic-bezier(0.2, 0, 0.2, 1),
168 opacity 0.2s ease;
169 }
170
171 .desktop-mode-os-settings__editor-slot[data-expanded="true"] {
172 grid-template-rows: 1fr;
173 margin-top: 12px;
174 opacity: 1;
175 }
176
177 .desktop-mode-os-settings__editor-slot-inner {
178 overflow: hidden;
179 min-height: 0;
180 padding: 12px;
181 background: var( --wpd-surface, #fff );
182 border: 1px solid var( --wpd-border, #dcdcde );
183 border-radius: 6px;
184 }
185
186 /*
187 * Wallpaper description slot — a card that slides in below the swatch
188 * grid describing the ACTIVE wallpaper (its story, where its data comes
189 * from). Same 0fr → 1fr collapse as the editor slot; TS drives
190 * `[data-expanded]` from `syncWallpaperDescription()`.
191 */
192 .desktop-mode-os-settings__wallpaper-description-slot {
193 display: grid;
194 grid-template-rows: 0fr;
195 margin-top: 0;
196 opacity: 0;
197 transition:
198 grid-template-rows 0.25s cubic-bezier(0.2, 0, 0.2, 1),
199 margin-top 0.25s cubic-bezier(0.2, 0, 0.2, 1),
200 opacity 0.2s ease;
201 }
202
203 .desktop-mode-os-settings__wallpaper-description-slot[data-expanded="true"] {
204 grid-template-rows: 1fr;
205 margin-top: 12px;
206 opacity: 1;
207 }
208
209 .desktop-mode-os-settings__wallpaper-description-slot-inner {
210 overflow: hidden;
211 min-height: 0;
212 }
213
214 .desktop-mode-os-settings__wallpaper-description {
215 padding: 12px 14px;
216 background: color-mix(in srgb, var(--wpd-accent, #2271b1) 6%, var( --wpd-surface, #fff ));
217 border: 1px solid var( --wpd-border, #dcdcde );
218 border-inline-start: 3px solid var(--wpd-accent, #2271b1);
219 border-radius: 6px;
220 }
221
222 /* Glyph sits inline, right before the wallpaper's name. */
223 .desktop-mode-os-settings__wallpaper-description-header {
224 display: flex;
225 align-items: center;
226 gap: 7px;
227 margin-bottom: 4px;
228 }
229
230 .desktop-mode-os-settings__wallpaper-description-icon {
231 color: var(--wpd-accent, #2271b1);
232 flex-shrink: 0;
233 }
234
235 .desktop-mode-os-settings__wallpaper-description-header strong {
236 font-size: 13px;
237 color: var( --wpd-fg, #1d2327 );
238 }
239
240 .desktop-mode-os-settings__wallpaper-description p {
241 margin: 0;
242 font-size: 12px;
243 line-height: 1.55;
244 color: var( --wpd-fg-muted, #50575e );
245 }
246
247 /*
248 * Wallpaper config slot — hosts the "Wallpaper settings" button when
249 * the ACTIVE wallpaper ships a `renderConfig` dialog. Same 0fr → 1fr
250 * collapse as the slots above; TS drives `[data-expanded]` from
251 * `syncWallpaperConfigButton()`.
252 */
253 .desktop-mode-os-settings__wallpaper-config-slot {
254 display: grid;
255 grid-template-rows: 0fr;
256 margin-top: 0;
257 opacity: 0;
258 transition:
259 grid-template-rows 0.25s cubic-bezier(0.2, 0, 0.2, 1),
260 margin-top 0.25s cubic-bezier(0.2, 0, 0.2, 1),
261 opacity 0.2s ease;
262 }
263
264 .desktop-mode-os-settings__wallpaper-config-slot[data-expanded="true"] {
265 grid-template-rows: 1fr;
266 margin-top: 12px;
267 opacity: 1;
268 }
269
270 .desktop-mode-os-settings__wallpaper-config-slot-inner {
271 overflow: hidden;
272 min-height: 0;
273 }
274
275 .desktop-mode-os-settings__wallpaper-config wpd-icon {
276 margin-inline-end: 4px;
277 }
278
279 /*
280 * Wallpaper config dialog body — the container `renderConfig` renders
281 * into inside the `<wpd-modal>`. A simple vertical rhythm; each
282 * `<wpd-*>` field owns its own label / control styling. The critical
283 * column rules are ALSO inlined by the dialog opener (long-lived
284 * sessions can lazy-load the dialog with a stylesheet that predates
285 * this block); keep the two in sync.
286 */
287 .desktop-mode-os-settings__wallpaper-config-form {
288 display: flex;
289 flex-direction: column;
290 gap: 14px;
291 min-width: 0;
292 }
293
294 /* Bare buttons in a config form (Reset to defaults and friends) are
295 * actions, not fields — don't stretch them to the column width. */
296 .desktop-mode-os-settings__wallpaper-config-form > wpd-button {
297 align-self: flex-start;
298 }
299
300 /*
301 * Custom-gradient editor fills the inner slot. Kept as a separate
302 * class (vs. scoping to __editor-slot-inner) so a future plugin
303 * renderEditor can opt out of these per-control rules.
304 */
305 .desktop-mode-os-settings__gradient-editor-inner {
306 display: flex;
307 flex-direction: column;
308 gap: 12px;
309 }
310
311 /*
312 * Gradient editor row — laid out as a flex of `<wpd-color-field>` +
313 * `<wpd-range-field>`. Each field owns its own label / control /
314 * readout styling internally; only spacing between fields lives here.
315 */
316 .desktop-mode-os-settings__gradient-row {
317 display: flex;
318 gap: 16px;
319 }
320
321 .desktop-mode-os-settings__gradient-row wpd-color-field {
322 flex: 1;
323 }
324
325 .desktop-mode-os-settings__gradient-editor-inner wpd-range-field {
326 margin-top: 12px;
327 }
328
329 /* ---------------------------------------------------------------
330 * Image uploader tile.
331 *
332 * Empty state: dashed border, "+" glyph, drop-and-click zone.
333 * Filled state: thumbnail preview that doubles as a wallpaper swatch.
334 * --------------------------------------------------------------- */
335 .desktop-mode-os-settings__uploader {
336 margin-top: 16px;
337 }
338
339 .desktop-mode-os-settings__uploader-heading {
340 margin: 0 0 6px;
341 font-size: 12px;
342 font-weight: 600;
343 color: var( --wpd-fg-muted, #50575e );
344 text-transform: uppercase;
345 letter-spacing: 0.04em;
346 }
347
348 .desktop-mode-os-settings__file-input {
349 display: none;
350 }
351
352 .desktop-mode-os-settings__upload-tile {
353 position: relative;
354 display: flex;
355 align-items: center;
356 justify-content: center;
357 min-height: 120px;
358 padding: 16px;
359 background: var( --wpd-surface, #fff );
360 background-size: cover;
361 background-position: center;
362 border: 2px dashed var( --wpd-border, #c3c4c7 );
363 border-radius: 8px;
364 color: var( --wpd-fg-muted, #50575e );
365 cursor: pointer;
366 text-align: center;
367 transition: border-color 0.15s ease, background-color 0.15s ease, transform 0.15s ease;
368 }
369
370 .desktop-mode-os-settings__upload-tile:hover {
371 border-color: var(--wp-admin-theme-color, #2271b1);
372 color: var(--wp-admin-theme-color, #2271b1);
373 }
374
375 .desktop-mode-os-settings__upload-tile:focus-within,
376 .desktop-mode-os-settings__upload-tile:focus-visible {
377 outline: 2px solid var(--wp-admin-theme-color, #2271b1);
378 outline-offset: 2px;
379 }
380
381 .desktop-mode-os-settings__upload-tile--dragover {
382 border-style: solid;
383 border-color: var(--wp-admin-theme-color, #2271b1);
384 background-color: rgba(34, 113, 177, 0.06);
385 transform: scale(1.01);
386 }
387
388 .desktop-mode-os-settings__upload-tile--busy {
389 cursor: progress;
390 opacity: 0.8;
391 }
392
393 /* Filled state — thumbnail is the whole tile; selection uses the same
394 * aria-pressed pattern as the other swatches. */
395 .desktop-mode-os-settings__upload-tile--filled {
396 border-style: solid;
397 border-color: transparent;
398 padding: 0;
399 min-height: 140px;
400 color: transparent;
401 }
402
403 .desktop-mode-os-settings__upload-tile--filled:hover {
404 color: transparent;
405 }
406
407 .desktop-mode-os-settings__upload-tile[aria-pressed="true"] {
408 border-color: var(--wp-admin-theme-color, #2271b1);
409 box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.9) inset;
410 }
411
412 .desktop-mode-os-settings__upload-inner {
413 display: flex;
414 flex-direction: column;
415 align-items: center;
416 gap: 6px;
417 pointer-events: none;
418 }
419
420 .desktop-mode-os-settings__upload-plus {
421 display: inline-flex;
422 align-items: center;
423 justify-content: center;
424 width: 32px;
425 height: 32px;
426 border-radius: 50%;
427 background: var( --wpd-hover, rgba(0, 0, 0, 0.05) );
428 font-size: 22px;
429 font-weight: 300;
430 line-height: 1;
431 color: inherit;
432 }
433
434 .desktop-mode-os-settings__upload-tile:hover .desktop-mode-os-settings__upload-plus {
435 background: rgba(34, 113, 177, 0.12);
436 }
437
438 .desktop-mode-os-settings__upload-prompt {
439 font-size: 13px;
440 font-weight: 500;
441 }
442
443 .desktop-mode-os-settings__upload-hint {
444 font-size: 11px;
445 color: var( --wpd-fg-muted, #8c8f94 );
446 }
447
448 .desktop-mode-os-settings__upload-status {
449 font-size: 13px;
450 font-weight: 500;
451 color: var( --wpd-fg-muted, #50575e );
452 }
453
454 .desktop-mode-os-settings__upload-error {
455 position: absolute;
456 inset-inline: 10px;
457 bottom: 10px;
458 padding: 6px 10px;
459 background: var( --wpd-danger, #d63638 );
460 color: var( --wpd-fg-on-accent, #fff );
461 border-radius: 4px;
462 font-size: 11px;
463 line-height: 1.3;
464 text-align: start;
465 box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
466 }
467
468 /*
469 * `__upload-remove` renders as `<wpd-button variant="danger">`
470 * with component-owned styling. Only the positioning on the
471 * filled tile is caller-specific — stays here.
472 */
473 .desktop-mode-os-settings__upload-remove {
474 position: absolute;
475 top: 8px;
476 inset-inline-end: 8px;
477 }
478
479 /* Tab strip moved into `<wpd-tabs>` + `<wpd-tab>`
480 * (src/ui/components/wpd-tabs/). Only the surrounding pane keeps
481 * a host-level rule — it's an OS-Settings layout choice, not
482 * component-intrinsic. */
483 .desktop-mode-os-settings__tab-pane {
484 min-height: 140px;
485 }
486
487 /* ---------------------------------------------------------------
488 * Media Library picker.
489 *
490 * Toolbar (search + HD toggle), responsive thumbnail grid, footer
491 * with count + Load more button.
492 * --------------------------------------------------------------- */
493 .desktop-mode-os-settings__library-toolbar {
494 display: flex;
495 align-items: center;
496 gap: 12px;
497 margin-bottom: 10px;
498 flex-wrap: wrap;
499 }
500
501 .desktop-mode-os-settings__library-search {
502 flex: 1;
503 min-width: 180px;
504 padding: 6px 10px;
505 border: 1px solid var( --wpd-border, #dcdcde );
506 border-radius: 4px;
507 background: var( --wpd-surface, #fff );
508 font: inherit;
509 font-size: 12px;
510 color: var( --wpd-fg, #1d2327 );
511 }
512
513 .desktop-mode-os-settings__library-search:focus {
514 border-color: var(--wp-admin-theme-color, #2271b1);
515 box-shadow: 0 0 0 1px var(--wp-admin-theme-color, #2271b1);
516 outline: none;
517 }
518
519 /* `__library-hd` now renders as `<wpd-checkbox-label>`. */
520
521 .desktop-mode-os-settings__library-grid {
522 display: grid;
523 grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
524 gap: 8px;
525 min-height: 140px;
526 }
527
528 .desktop-mode-os-settings__library-tile {
529 position: relative;
530 aspect-ratio: 16 / 10;
531 padding: 0;
532 border: 2px solid transparent;
533 border-radius: 6px;
534 background-color: var( --wpd-surface-sunken, #eef0f1 );
535 background-size: cover;
536 background-position: center;
537 background-repeat: no-repeat;
538 cursor: pointer;
539 overflow: hidden;
540 transition: border-color 0.15s ease, transform 0.15s ease;
541 }
542
543 .desktop-mode-os-settings__library-tile:hover {
544 transform: translateY(-1px);
545 border-color: rgba(34, 113, 177, 0.4);
546 }
547
548 .desktop-mode-os-settings__library-tile:focus-visible {
549 outline: 2px solid var(--wp-admin-theme-color, #2271b1);
550 outline-offset: 2px;
551 }
552
553 .desktop-mode-os-settings__library-tile--selected,
554 .desktop-mode-os-settings__library-tile[aria-pressed="true"] {
555 border-color: var(--wp-admin-theme-color, #2271b1);
556 box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.9) inset;
557 }
558
559 /* Dimension badge in the corner — readable over any thumbnail. */
560 .desktop-mode-os-settings__library-tile-dims {
561 position: absolute;
562 bottom: 4px;
563 inset-inline-end: 4px;
564 padding: 2px 6px;
565 background: var( --wpd-scrim, rgba(0, 0, 0, 0.6) );
566 color: var( --wpd-fg-on-accent, #fff );
567 font-size: 10px;
568 font-weight: 500;
569 line-height: 1.3;
570 border-radius: 3px;
571 letter-spacing: 0.02em;
572 font-variant-numeric: tabular-nums;
573 pointer-events: none;
574 }
575
576 /* Skeleton tiles during the first-page fetch. Animated subtle pulse
577 * so the user perceives progress without us needing a spinner. */
578 .desktop-mode-os-settings__library-tile--skeleton {
579 cursor: default;
580 background: linear-gradient(
581 90deg,
582 var( --wpd-surface-sunken, #eef0f1 ) 0%,
583 #dcdcde 50%,
584 var( --wpd-surface-sunken, #eef0f1 ) 100%
585 );
586 background-size: 200% 100%;
587 animation: desktop-mode-library-shimmer 1.1s ease-in-out infinite;
588 }
589
590 .desktop-mode-os-settings__library-tile--skeleton:hover {
591 transform: none;
592 border-color: transparent;
593 }
594
595 @keyframes desktop-mode-library-shimmer {
596 from {
597 background-position: 200% 0;
598 }
599 to {
600 background-position: -200% 0;
601 }
602 }
603
604 .desktop-mode-os-settings__library-empty,
605 .desktop-mode-os-settings__library-error {
606 grid-column: 1 / -1;
607 margin: 0;
608 padding: 24px 16px;
609 text-align: center;
610 color: var( --wpd-fg-muted, #646970 );
611 font-size: 12px;
612 }
613
614 .desktop-mode-os-settings__library-error {
615 color: var( --wpd-danger-hover, #b32d2e );
616 }
617
618 .desktop-mode-os-settings__library-footer {
619 display: flex;
620 align-items: center;
621 justify-content: space-between;
622 margin-top: 10px;
623 gap: 10px;
624 min-height: 24px;
625 }
626
627 .desktop-mode-os-settings__library-meta {
628 color: var( --wpd-fg-muted, #8c8f94 );
629 font-size: 11px;
630 }
631
632 /* `__library-load-more` now renders as `<wpd-button variant="ghost">`. */
633
634 /* ---------------------------------------------------------------
635 * Reduced-motion: collapse every OS-Settings animation/transition to
636 * near-zero so motion-sensitive users still get the layout changes
637 * (hover feedback, expanded editor, tile highlights) but without the
638 * glide. Kept as a single scoped block so the intent is readable at
639 * a glance rather than spread across each rule.
640 * --------------------------------------------------------------- */
641 @media (prefers-reduced-motion: reduce) {
642 .desktop-mode-os-settings__editor-slot,
643 .desktop-mode-os-settings__wallpaper-config-slot,
644 .desktop-mode-os-settings__upload-tile,
645 .desktop-mode-os-settings__library-tile,
646 wpd-swatch {
647 transition-duration: 0.01ms !important;
648 }
649
650 .desktop-mode-os-settings__library-tile--skeleton {
651 animation: none;
652 }
653 }
654
655 /* AI settings section — error and saving feedback */
656 .desktop-mode-ai-settings__error {
657 margin: 6px 0 0;
658 font-size: 12px;
659 color: var( --wpd-danger, #d63638 );
660 }
661
662 .desktop-mode-ai-settings__saving {
663 margin: 6px 0 0;
664 font-size: 12px;
665 color: var( --wpd-fg-muted, #646970 );
666 font-style: italic;
667 }
668
669 /* Extended options section — hint paragraph + error/saving states */
670 .desktop-mode-ext__hint {
671 margin: 6px 0 0;
672 font-size: 12px;
673 color: var( --wpd-fg-muted, #646970 );
674 line-height: 1.5;
675 }
676
677 .desktop-mode-ext__error {
678 margin: 6px 0 0;
679 font-size: 12px;
680 color: var( --wpd-danger, #d63638 );
681 }
682
683 .desktop-mode-ext__saving {
684 margin: 6px 0 0;
685 font-size: 12px;
686 color: var( --wpd-fg-muted, #646970 );
687 font-style: italic;
688 }
689
690 /*
691 * Help tab — developer-facing component reference. Two-column layout
692 * (nav + detail) on desktop, stacks naturally on narrow windows via
693 * the same container the OS Settings panel lives in.
694 */
695 .desktop-mode-os-settings__help-count {
696 margin: 4px 0 0;
697 font-size: 12px;
698 color: var( --wpd-fg-muted, #646970 );
699 }
700
701 .desktop-mode-os-settings__help-layout {
702 display: grid;
703 grid-template-columns: 200px 1fr;
704 gap: 20px;
705 }
706
707 @container (max-width: 640px) {
708 .desktop-mode-os-settings__help-layout {
709 grid-template-columns: 1fr;
710 }
711 }
712
713 /*
714 * Search box + nav share one column so the field stays pinned while
715 * the component list below it scrolls.
716 */
717 .desktop-mode-os-settings__help-sidebar {
718 display: flex;
719 flex-direction: column;
720 gap: 8px;
721 min-height: 0;
722 }
723
724 .desktop-mode-os-settings__help-nav {
725 display: flex;
726 flex-direction: column;
727 gap: 2px;
728 align-self: stretch;
729 min-height: 0;
730 overflow-y: auto;
731 padding: 4px;
732 background: var( --wpd-surface-elevated, #f6f7f7 );
733 border: 1px solid var( --wpd-border, #dcdcde );
734 border-radius: 8px;
735 }
736
737 .desktop-mode-os-settings__help-nav-empty {
738 margin: 0;
739 padding: 8px 10px;
740 font-size: 12px;
741 color: var( --wpd-fg-muted, #646970 );
742 }
743
744 .desktop-mode-os-settings__help-nav-item {
745 display: flex;
746 flex-direction: column;
747 gap: 2px;
748 align-items: flex-start;
749 width: 100%;
750 padding: 6px 10px;
751 background: transparent;
752 border: 1px solid transparent;
753 border-radius: 6px;
754 text-align: start;
755 cursor: pointer;
756 font: inherit;
757 color: inherit;
758 }
759
760 .desktop-mode-os-settings__help-nav-item:hover {
761 background: var( --wpd-surface, #fff );
762 border-color: var( --wpd-border, #dcdcde );
763 }
764
765 .desktop-mode-os-settings__help-nav-item.is-active {
766 background: var( --wpd-surface, #fff );
767 border-color: var( --wp-admin-theme-color, #2271b1 );
768 }
769
770 .desktop-mode-os-settings__help-nav-title {
771 font-weight: 600;
772 font-size: 13px;
773 }
774
775 .desktop-mode-os-settings__help-nav-tag {
776 font-family: var( --wpd-font-mono, Menlo, Consolas, monospace );
777 font-size: 11px;
778 color: var( --wpd-fg-muted, #646970 );
779 }
780
781 .desktop-mode-os-settings__help-detail {
782 min-width: 0;
783 padding: 16px 18px 18px;
784 background: var( --wpd-surface-elevated, #f6f7f7 );
785 border: 1px solid var( --wpd-border, #dcdcde );
786 border-radius: 8px;
787 }
788
789 .desktop-mode-os-settings__help-head {
790 display: flex;
791 flex-wrap: wrap;
792 align-items: baseline;
793 gap: 8px;
794 margin: 0 0 8px;
795 }
796
797 .desktop-mode-os-settings__help-title {
798 margin: 0;
799 font-size: 16px;
800 font-weight: 600;
801 }
802
803 .desktop-mode-os-settings__help-code {
804 font-family: var( --wpd-font-mono, Menlo, Consolas, monospace );
805 font-size: 12px;
806 color: var( --wpd-fg-muted, #646970 );
807 }
808
809 .desktop-mode-os-settings__help-badge {
810 padding: 1px 8px;
811 border-radius: 999px;
812 font-size: 11px;
813 font-weight: 600;
814 text-transform: uppercase;
815 letter-spacing: 0.04em;
816 background: var( --wpd-surface-sunken, #e4e7eb );
817 color: var( --wpd-fg, #1d2327 );
818 }
819
820 .desktop-mode-os-settings__help-badge.is-experimental {
821 background: var( --wpd-warning-bg, #fcf9e8 );
822 color: var( --wpd-warning-fg, #996800 );
823 }
824
825 .desktop-mode-os-settings__help-badge.is-planned {
826 background: var( --wpd-info-bg, #e1e8ff );
827 color: var( --wpd-info-fg, #123fb3 );
828 }
829
830 .desktop-mode-os-settings__help-since {
831 font-size: 11px;
832 color: var( --wpd-fg-muted, #646970 );
833 }
834
835 .desktop-mode-os-settings__help-summary {
836 margin: 0 0 16px;
837 color: var( --wpd-fg, #1d2327 );
838 }
839
840 .desktop-mode-os-settings__help-group {
841 margin: 0 0 16px;
842 }
843
844 .desktop-mode-os-settings__help-group h4 {
845 margin: 0 0 8px;
846 font-size: 12px;
847 font-weight: 600;
848 text-transform: uppercase;
849 letter-spacing: 0.04em;
850 color: var( --wpd-fg-muted, #646970 );
851 }
852
853 .desktop-mode-os-settings__help-example {
854 padding: 16px;
855 background: var( --wpd-surface, #fff );
856 border: 1px dashed var( --wpd-border, #c3c4c7 );
857 border-radius: 6px;
858 }
859
860 .desktop-mode-os-settings__help-table {
861 width: 100%;
862 border-collapse: collapse;
863 font-size: 12px;
864 }
865
866 .desktop-mode-os-settings__help-table th,
867 .desktop-mode-os-settings__help-table td {
868 padding: 6px 8px;
869 border-bottom: 1px solid var( --wpd-border, #dcdcde );
870 text-align: start;
871 vertical-align: top;
872 }
873
874 .desktop-mode-os-settings__help-table th {
875 font-weight: 600;
876 color: var( --wpd-fg-muted, #646970 );
877 background: var( --wpd-surface, #fff );
878 }
879
880 .desktop-mode-os-settings__help-table code,
881 .desktop-mode-os-settings__help-list code {
882 font-family: var( --wpd-font-mono, Menlo, Consolas, monospace );
883 font-size: 11px;
884 padding: 1px 4px;
885 background: var( --wpd-surface, #fff );
886 border: 1px solid var( --wpd-border, #dcdcde );
887 border-radius: 3px;
888 }
889
890 .desktop-mode-os-settings__help-list {
891 margin: 0;
892 padding: 0;
893 list-style: none;
894 }
895
896 .desktop-mode-os-settings__help-list li {
897 padding: 4px 0;
898 border-bottom: 1px solid var( --wpd-border, #ececee );
899 font-size: 12px;
900 }
901
902 .desktop-mode-os-settings__help-list li:last-child {
903 border-bottom: 0;
904 }
905
906 .desktop-mode-os-settings__help-note {
907 margin: 12px 0 0;
908 padding: 10px 12px;
909 background: var( --wpd-warning-bg, #fcf9e8 );
910 border: 1px solid var( --wpd-warning-border, #f5e6a5 );
911 border-radius: 6px;
912 font-size: 12px;
913 color: var( --wpd-warning-fg, #996800 );
914 }
915
916 /* ---------------------------------------------------------------
917 * Window-fit scrolling.
918 *
919 * Without this block the OS Settings panel grows past the native
920 * window's viewport and the whole body scrolls — fine for short tabs
921 * but actively wrong for the Components tab, where a 200px nav rail
922 * and a tall detail pane should each scroll inside their own column,
923 * not in lockstep down a giant single-column page.
924 *
925 * Strategy:
926 * 1. The native window body normally has overflow:auto. Override it
927 * to `hidden` ONLY when the OS Settings root is mounted (via
928 * :has()) so other native windows keep their default page-scroll.
929 * 2. Make the OS Settings root a flex column that fills the body.
930 * The tab strip + footer hug the top/bottom; the active
931 * tabpanel takes the remaining height.
932 * 3. Each tabpanel scrolls itself (overflow:auto) — replaces the
933 * whole-body scroll, visually identical for the simple tabs
934 * (Appearance, AI, Extended) but pins the reset footer.
935 * 4. The Components tab opts OUT of overflow:auto so its inner
936 * grid (nav + detail) can scroll independently per pane.
937 *
938 * `:has()` is supported in every evergreen engine (Chrome 105+,
939 * Safari 15.4+, Firefox 121+); fine for an admin-context shell.
940 * --------------------------------------------------------------- */
941 .desktop-mode-window__body--native:has( .desktop-mode-os-settings ) {
942 overflow: hidden;
943 display: flex;
944 flex-direction: column;
945 }
946
947 .desktop-mode-os-settings {
948 flex: 1;
949 min-height: 0;
950 display: flex;
951 flex-direction: column;
952 }
953
954 /* The tab strip + footer must NOT shrink when the active panel
955 wants more height. Marking them flex-shrink:0 also keeps them
956 pinned visually as the panel below scrolls. */
957 .desktop-mode-os-settings > wpd-tabs,
958 .desktop-mode-os-settings > .desktop-mode-os-settings__footer {
959 flex: 0 0 auto;
960 }
961
962 .desktop-mode-os-settings > wpd-tabpanel {
963 flex: 1;
964 min-height: 0;
965 overflow: auto;
966 }
967
968 /* Components tab — split-pane layout. Don't scroll the whole panel;
969 let the inner grid distribute height to nav + detail, each with
970 their own overflow.
971 *
972 * The `:not([hidden])` guard is load-bearing: a bare
973 * `wpd-tabpanel[for='help'] { display: flex }` rule has specificity
974 * (0,0,2,1) which outranks the shadow-DOM `:host([hidden]) {
975 * display: none }` rule (specificity 0,0,1,0), so the panel would
976 * keep rendering when it should be hidden — bleeding the Components
977 * UI into every other tab. Pinning the rule to the visible state
978 * leaves the hidden state to the shadow-DOM default. */
979 .desktop-mode-os-settings > wpd-tabpanel[ for='help' ]:not( [ hidden ] ) {
980 overflow: hidden;
981 display: flex;
982 flex-direction: column;
983 }
984 .desktop-mode-os-settings
985 > wpd-tabpanel[ for='help' ]:not( [ hidden ] )
986 > wpd-panel {
987 flex: 1;
988 min-height: 0;
989 display: flex;
990 flex-direction: column;
991 }
992
993 .desktop-mode-os-settings__help {
994 flex: 1;
995 min-height: 0;
996 display: flex;
997 flex-direction: column;
998 gap: 12px;
999 }
1000 /* The intro card (Component library description) shouldn't grow —
1001 it's content-sized so the grid below gets the remaining height. */
1002 .desktop-mode-os-settings__help > wpd-section {
1003 flex: 0 0 auto;
1004 }
1005 .desktop-mode-os-settings__help-layout {
1006 flex: 1;
1007 min-height: 0;
1008 }
1009
1010 /* Each split pane is its own scroll container. min-height:0 unlocks
1011 shrinking in a grid item (default is `auto` which equals content
1012 height — would defeat the overflow). max-height:100% pins the
1013 pane to the grid track. */
1014 .desktop-mode-os-settings__help-nav,
1015 .desktop-mode-os-settings__help-detail {
1016 min-height: 0;
1017 max-height: 100%;
1018 overflow-y: auto;
1019 }
1020
1021 /*
1022 * Features section — per-user opt-in toggles.
1023 *
1024 * Save status pill renders the live OS-settings save lifecycle
1025 * (`pending` → `saving` → `saved` / `failed`) so toggling a
1026 * per-user feature flag gets immediate, honest feedback instead
1027 * of an optimistic flicker.
1028 */
1029 .desktop-mode-features__status-row {
1030 min-height: 22px;
1031 }
1032
1033 /* One toggle + hint pair. Stacking these without separators reads as
1034 * a wall of checkboxes; a hairline above each item (after the first)
1035 * groups the label with its description and gives the eye a stopping
1036 * point between unrelated settings. The first item sits flush so the
1037 * section heading already serves as its top boundary. */
1038 .desktop-mode-features__item {
1039 display: flex;
1040 flex-direction: column;
1041 gap: 6px;
1042 }
1043
1044 .desktop-mode-features__item + .desktop-mode-features__item {
1045 margin-top: 16px;
1046 padding-top: 16px;
1047 border-top: 1px solid var( --wpd-border, rgba( 0, 0, 0, 0.08 ) );
1048 }
1049
1050 /* "Reset what's-new dialogs" row — separates the action from the
1051 * native-Posts toggle above and gives breathing room around the
1052 * button. `align-items: flex-start` keeps the inline-flex
1053 * `<wpd-button>` from stretching full-width inside the column,
1054 * and the explicit margin on the button below works around the
1055 * fact that flex `gap` doesn't always render visibly when one
1056 * neighbour is an inline-flex custom element with zero outer
1057 * margin. */
1058 .desktop-mode-features__row {
1059 display: flex;
1060 flex-direction: column;
1061 align-items: flex-start;
1062 gap: 12px;
1063 margin-top: 20px;
1064 padding-top: 20px;
1065 border-top: 1px solid var( --wpd-border, rgba( 0, 0, 0, 0.08 ) );
1066 }
1067
1068 .desktop-mode-features__row > wpd-button {
1069 display: inline-flex;
1070 margin-block: 4px 8px;
1071 }
1072
1073 .desktop-mode-features__row > .desktop-mode-features__hint {
1074 margin: 0;
1075 }
1076
1077 .desktop-mode-features__hint {
1078 margin: 0;
1079 font-size: 12px;
1080 color: var( --wpd-fg-muted, #50575e );
1081 line-height: 1.5;
1082 }
1083
1084 .desktop-mode-features__status {
1085 display: inline-flex;
1086 align-items: center;
1087 gap: 6px;
1088 font-size: 12px;
1089 font-weight: 500;
1090 padding: 2px 10px;
1091 border-radius: 999px;
1092 white-space: nowrap;
1093 transition: opacity 200ms ease;
1094 }
1095
1096 .desktop-mode-features__status--saving {
1097 background: var( --wpd-surface-elevated, #f0f0f1 );
1098 color: var( --wpd-fg-muted, #50575e );
1099 }
1100
1101 .desktop-mode-features__status--saved {
1102 background: rgba( 30, 132, 73, 0.12 );
1103 color: var( --wpd-success-fg, #1d6f42 );
1104 }
1105
1106 .desktop-mode-features__status--saved .dashicons {
1107 font-size: 14px;
1108 width: 14px;
1109 height: 14px;
1110 }
1111
1112 .desktop-mode-features__status--failed {
1113 background: rgba( 214, 54, 56, 0.12 );
1114 color: var( --wpd-danger-hover, #a02622 );
1115 }
1116
1117 .desktop-mode-features__status--failed .dashicons {
1118 font-size: 14px;
1119 width: 14px;
1120 height: 14px;
1121 }
1122
1123 .desktop-mode-features__status-dot {
1124 display: inline-block;
1125 width: 8px;
1126 height: 8px;
1127 border-radius: 50%;
1128 background: currentColor;
1129 animation: desktop-mode-features-pulse 1.2s ease-in-out infinite;
1130 }
1131
1132 @keyframes desktop-mode-features-pulse {
1133 0%, 100% { opacity: 0.35; transform: scale( 0.85 ); }
1134 50% { opacity: 1; transform: scale( 1 ); }
1135 }
1136
1137 /*
1138 * OS Settings panel header — hosts the global tabs strip and a single
1139 * `<wpd-save-status>` indicator that auto-listens to the save
1140 * lifecycle. The save status sits on the trailing edge of the header
1141 * so it's visible across every tab without competing with section
1142 * content.
1143 */
1144 .desktop-mode-os-settings__header {
1145 display: flex;
1146 align-items: center;
1147 justify-content: space-between;
1148 gap: 16px;
1149 margin-bottom: 12px;
1150 }
1151
1152 .desktop-mode-os-settings__header wpd-tabs {
1153 flex: 1 1 auto;
1154 min-width: 0;
1155 }
1156
1157 .desktop-mode-os-settings__header wpd-save-status {
1158 flex: 0 0 auto;
1159 margin-inline-start: auto;
1160 }
1161
1162 /*
1163 * About tab — full-tabpanel PixiJS canvas. Every credit string and
1164 * the AUTOMATTIC logotype (formed by particles) render inside Pixi
1165 * itself; this stylesheet only sizes the host so the canvas fills
1166 * the available height + width without any HTML chrome around it.
1167 *
1168 * The chain is: tabpanel → wpd-panel → .about (flex column) →
1169 * .about-stage-host (the canvas mounts here). Each link sets
1170 * `flex: 1; min-height: 0;` so the canvas inherits the tabpanel's
1171 * full inner height instead of hugging an intrinsic minimum.
1172 *
1173 * @since 0.8.0
1174 */
1175 .desktop-mode-os-settings
1176 > wpd-tabpanel[ for='about' ]:not( [ hidden ] ) {
1177 display: flex;
1178 flex-direction: column;
1179 overflow: hidden;
1180 }
1181
1182 .desktop-mode-os-settings
1183 > wpd-tabpanel[ for='about' ]:not( [ hidden ] )
1184 > wpd-panel {
1185 flex: 1;
1186 min-height: 0;
1187 display: flex;
1188 flex-direction: column;
1189 }
1190
1191 .desktop-mode-os-settings__about {
1192 flex: 1;
1193 min-height: 0;
1194 display: flex;
1195 flex-direction: column;
1196 margin: 0;
1197 /* Edge-to-edge — no border-radius / box-shadow framing — so the
1198 * canvas (and the logotype centred inside it) consume the entire
1199 * tabpanel surface. The gradient is just the colour-of-last-resort
1200 * underneath while Pixi initialises; once the canvas is rendering
1201 * it covers every pixel of this element anyway. */
1202 background: linear-gradient( 180deg, #060a1c 0%, #0c1733 100% );
1203 overflow: hidden;
1204 }
1205
1206 .desktop-mode-os-settings__about-stage-host {
1207 flex: 1;
1208 min-height: 0;
1209 width: 100%;
1210 overflow: hidden;
1211 cursor: crosshair;
1212 }
1213
1214 .desktop-mode-os-settings__about-stage-host canvas {
1215 display: block;
1216 width: 100%;
1217 height: 100%;
1218 }
1219
1220
1221 /* Apps & Icons section (since 0.25.0) — per-item placement chooser. */
1222 .desktop-mode-apps-icons__list {
1223 display: flex;
1224 flex-direction: column;
1225 gap: 4px;
1226 }
1227
1228 .desktop-mode-apps-icons__row {
1229 display: flex;
1230 align-items: center;
1231 gap: 12px;
1232 padding: 8px 4px;
1233 border-bottom: 1px solid var( --wpd-border, rgba( 0, 0, 0, 0.08 ) );
1234 }
1235
1236 .desktop-mode-apps-icons__row:last-child {
1237 border-bottom: 0;
1238 }
1239
1240 .desktop-mode-apps-icons__identity {
1241 display: flex;
1242 align-items: center;
1243 gap: 10px;
1244 flex: 1;
1245 min-width: 0;
1246 }
1247
1248 .desktop-mode-apps-icons__icon {
1249 width: 24px;
1250 height: 24px;
1251 flex-shrink: 0;
1252 display: inline-flex;
1253 align-items: center;
1254 justify-content: center;
1255 }
1256
1257 .desktop-mode-apps-icons__icon.dashicons {
1258 font-size: 20px;
1259 }
1260
1261 .desktop-mode-apps-icons__title {
1262 overflow: hidden;
1263 text-overflow: ellipsis;
1264 white-space: nowrap;
1265 }
1266
1267 .desktop-mode-apps-icons__row wpd-select {
1268 min-width: 180px;
1269 }
1270
1271 /* ------------------------------------------------------------------
1272 * OS Settings → Themes.
1273 *
1274 * Card grid of the site's desktop-theme library. Deliberately styled
1275 * with the SAME neutral palette as the rest of the panel rather than
1276 * with themed tokens: the picker has to stay legible while the user
1277 * is trying on themes, including ones with hostile contrast.
1278 * ------------------------------------------------------------------ */
1279
1280 .desktop-mode-os-settings__theme-grid {
1281 display: grid;
1282 grid-template-columns: repeat( auto-fill, minmax( 160px, 1fr ) );
1283 gap: 12px;
1284 margin: 12px 0 16px;
1285 }
1286
1287 .desktop-mode-os-settings__theme-card-wrap {
1288 position: relative;
1289 }
1290
1291 .desktop-mode-os-settings__theme-card {
1292 display: flex;
1293 flex-direction: column;
1294 gap: 6px;
1295 width: 100%;
1296 padding: 8px;
1297 background: var( --wpd-surface, #fff );
1298 border: 2px solid var( --wpd-border, #dcdcde );
1299 border-radius: 10px;
1300 cursor: pointer;
1301 text-align: start;
1302 font: inherit;
1303 color: var( --wpd-fg, #1d2327 );
1304 transition: border-color 0.15s ease, box-shadow 0.15s ease;
1305 }
1306
1307 .desktop-mode-os-settings__theme-card:hover {
1308 border-color: var( --wp-admin-theme-color, #2271b1 );
1309 }
1310
1311 .desktop-mode-os-settings__theme-card:focus-visible {
1312 outline: 2px solid var( --wp-admin-theme-color, #2271b1 );
1313 outline-offset: 2px;
1314 }
1315
1316 .desktop-mode-os-settings__theme-card[ aria-pressed="true" ] {
1317 border-color: var( --wp-admin-theme-color, #2271b1 );
1318 box-shadow: 0 0 0 3px rgba( 34, 113, 177, 0.18 );
1319 }
1320
1321 .desktop-mode-os-settings__theme-preview {
1322 display: flex;
1323 align-items: center;
1324 justify-content: center;
1325 aspect-ratio: 16 / 10;
1326 overflow: hidden;
1327 border-radius: 6px;
1328 background: var( --wpd-surface-elevated, #f0f0f1 );
1329 }
1330
1331 .desktop-mode-os-settings__theme-preview img {
1332 width: 100%;
1333 height: 100%;
1334 object-fit: cover;
1335 display: block;
1336 }
1337
1338 /* Stand-in preview for "System default" — a miniature of the shipped
1339 * graphite desktop, so the card reads as a real option rather than an
1340 * absence. */
1341 .desktop-mode-os-settings__theme-preview--system {
1342 background: linear-gradient( 135deg, #1d2327 0%, #2c3338 50%, #1d2327 100% );
1343 }
1344
1345 .desktop-mode-os-settings__theme-initials {
1346 font-size: 24px;
1347 font-weight: 700;
1348 letter-spacing: 1px;
1349 color: var( --wpd-fg-muted, #787c82 );
1350 }
1351
1352 .desktop-mode-os-settings__theme-name {
1353 font-weight: 600;
1354 line-height: 1.3;
1355 overflow-wrap: anywhere;
1356 }
1357
1358 .desktop-mode-os-settings__theme-meta {
1359 font-size: 11px;
1360 color: var( --wpd-fg-muted, #646970 );
1361 line-height: 1.3;
1362 min-height: 1.3em;
1363 }
1364
1365 /* Delete overlay — outside the card button, because nesting a button
1366 * inside a button is invalid HTML and breaks keyboard traversal. */
1367 .desktop-mode-os-settings__theme-delete {
1368 position: absolute;
1369 inset-block-start: 4px;
1370 inset-inline-end: 4px;
1371 display: flex;
1372 align-items: center;
1373 justify-content: center;
1374 width: 22px;
1375 height: 22px;
1376 padding: 0;
1377 border: none;
1378 border-radius: 50%;
1379 background: var( --wpd-scrim, rgba( 0, 0, 0, 0.55 ) );
1380 color: var( --wpd-fg-on-accent, #fff );
1381 font-size: 15px;
1382 line-height: 1;
1383 cursor: pointer;
1384 opacity: 0;
1385 transition: opacity 0.15s ease, background-color 0.15s ease;
1386 }
1387
1388 .desktop-mode-os-settings__theme-card-wrap:hover
1389 .desktop-mode-os-settings__theme-delete,
1390 .desktop-mode-os-settings__theme-delete:focus-visible {
1391 opacity: 1;
1392 }
1393
1394 .desktop-mode-os-settings__theme-delete:hover {
1395 background: var( --wpd-danger, #d63638 );
1396 }
1397
1398 /*
1399 * "Apply <theme>'s recommended layout" — sits between the theme grid
1400 * and the upload tile, and only for a theme that recommends
1401 * something. Just the button: the dock resizing and the layout
1402 * moving is the feedback.
1403 */
1404 .desktop-mode-os-settings__theme-recommendation {
1405 display: flex;
1406 margin-block: 16px;
1407 }
1408
1409 .desktop-mode-os-settings__theme-upload {
1410 display: block;
1411 border: 2px dashed var( --wpd-border, #c3c4c7 );
1412 border-radius: 8px;
1413 background: var( --wpd-surface, #fff );
1414 transition: border-color 0.15s ease, background-color 0.15s ease;
1415 }
1416
1417 .desktop-mode-os-settings__theme-upload-label {
1418 display: flex;
1419 flex-direction: column;
1420 align-items: center;
1421 justify-content: center;
1422 gap: 6px;
1423 min-height: 96px;
1424 padding: 16px;
1425 color: var( --wpd-fg-muted, #50575e );
1426 cursor: pointer;
1427 text-align: center;
1428 }
1429
1430 .desktop-mode-os-settings__theme-upload:hover,
1431 .desktop-mode-os-settings__theme-upload--dragover {
1432 border-color: var( --wp-admin-theme-color, #2271b1 );
1433 background-color: rgba( 34, 113, 177, 0.06 );
1434 }
1435
1436 .desktop-mode-os-settings__theme-upload--dragover {
1437 border-style: solid;
1438 }
1439
1440 .desktop-mode-os-settings__theme-upload--busy
1441 .desktop-mode-os-settings__theme-upload-label {
1442 cursor: progress;
1443 opacity: 0.7;
1444 }
1445
1446 .desktop-mode-os-settings__theme-upload-plus {
1447 font-size: 22px;
1448 line-height: 1;
1449 }
1450