PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.6
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.6
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 / window-overview.css

window-overview.css in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 1.1.6, at assets/css/window-overview.css

761 lines 22.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * OpenStation — Overview.
3 *
4 * Zoom-out grid view: windows transform into thumbnails, floating
5 * labels sit above them, and a top bar lists every virtual desktop
6 * with one tile per space plus a "+" to add a new one. The dock
7 * collapses in parallel with the enter transition.
8 *
9 * Windows keep their `left/top/width/height` intact; only `transform`
10 * animates (translate + scale) so the layout change is a GPU
11 * composite, not a reflow. `transform-origin: top left` makes
12 * translate + scale compose cleanly — a target coordinate maps to
13 * the window's top-left corner pre-scale. Iframes go
14 * `pointer-events: none` inside overview so clicks hit the window
15 * wrapper (and bubble to the desktop-area click handler) instead of
16 * the iframe content, which would otherwise eat the click.
17 *
18 * Base chrome lives in window-chrome.css; non-overview state classes
19 * live in window-states.css.
20 *
21 * @since 6.9.0
22 */
23 .os-area--overview {
24 /* Darken the backdrop and tint it so windows feel like they're
25 * floating over a neutral canvas, not the wallpaper. */
26 background-color: var( --os-ui-scrim, rgba( 0, 0, 0, 0.45 ) );
27 transition: background-color 0.28s ease;
28 }
29
30 .os-window--overview {
31 transform-origin: top left;
32 transition:
33 transform 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
34 box-shadow 0.2s ease,
35 opacity 0.2s ease;
36 cursor: pointer;
37 /* Hover effects apply a thick outline rather than another
38 * transform (which would fight the layout's own transform).
39 * Box-shadow is composite-only, so it's cheap. */
40 box-shadow: 0 10px 30px rgba( 0, 0, 0, 0.35 );
41 /* Overview thumbnails are click targets, not reading surfaces —
42 * suppress text selection so a drag across a thumbnail doesn't
43 * highlight paragraphs inside the title bar / native body. */
44 user-select: none;
45 -webkit-user-select: none;
46 }
47
48 /*
49 * While in overview, treat each window as a single click target —
50 * every inner element (title bar, buttons, iframe, native body) goes
51 * transparent to pointer events so drags/taps never start a drag,
52 * trip a close button, or launch an in-iframe action. Only the
53 * window's root element receives pointer events; our desktop-level
54 * pointerdown/pointerup handlers drive selection from there.
55 */
56 .os-window--overview * {
57 pointer-events: none;
58 }
59
60 .os-window--overview {
61 pointer-events: auto;
62 }
63
64 .os-window--overview:hover {
65 box-shadow:
66 0 14px 38px rgba( 0, 0, 0, 0.45 ),
67 0 0 0 3px var( --wp-admin-theme-color, #2271b1 );
68 z-index: 1;
69 }
70
71 /*
72 * Minimized windows shown in overview are rendered slightly dimmed
73 * so the user can distinguish them from active windows at a glance.
74 */
75 .os-window--overview.os-window--minimized {
76 opacity: 0.6;
77 }
78
79 /*
80 * Mission-Control-style dimming: once ANY window is hovered, every
81 * OTHER window dims and desaturates slightly — creating a clear
82 * focal point without needing the hovered one to grow or lift.
83 * `:has()` lands in every evergreen browser we target (Chrome 105,
84 * Safari 15.4, Firefox 121+); older engines miss the dimming but
85 * keep the accent-ring affordance, so it degrades gracefully.
86 */
87 .os-area--overview:has( .os-window--overview:hover )
88 .os-window--overview:not( :hover ) {
89 opacity: 0.5;
90 filter: brightness( 0.75 );
91 transition:
92 transform 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
93 opacity 0.18s ease,
94 filter 0.18s ease;
95 }
96
97 /*
98 * Dock slides out smoothly during overview — width collapses (the
99 * flex row reflows so the area grows into the freed space) while
100 * the dock itself slides left and fades. `display: none` would have
101 * been abrupt in both directions; animating the flex width does the
102 * heavy lifting and the user sees a single continuous motion.
103 *
104 * `pointer-events: none` comes in immediately on overview enter so
105 * stray clicks mid-animation can't open a window behind the user's
106 * back. `overflow: hidden` is scoped to the collapsed state so the
107 * shrinking dock doesn't leak icons past its boundary — outside
108 * overview, the dock keeps `overflow: visible` from dock.css so
109 * per-tile "+ open another" chips can float past the edge.
110 */
111 .os-dock {
112 transition:
113 width 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
114 min-width 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
115 padding 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
116 transform 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
117 opacity 0.22s ease;
118 }
119
120 /*
121 * The escape hatch for the rule above, and the reason it lives here
122 * rather than in `dock.css`: this is the only place `.os-dock` is
123 * given a transition, so it is the only place worth looking when one
124 * fires where it should not.
125 *
126 * The properties above are geometry, and geometry also changes for a
127 * reason that is not a state change: moving the dock to another edge
128 * tears the rail down and builds a new one on the SAME element, which
129 * still carries the previous placement's padding and width. Animated,
130 * the new dock slides out of the old one's shape — it arrives a size
131 * too big and settles. `Dock`'s constructor wears this class while it
132 * commits the placement, so that change lands with nothing to tween
133 * from.
134 */
135 .os-dock--no-transition {
136 transition: none !important;
137 }
138
139 /*
140 * Collapse EVERY dock (bottom + side rails, Classic / Unified /
141 * Spatial layouts alike) when overview is active.
142 *
143 * The placement-specific width rules in dock.css —
144 * `.os-dock[ data-os-dock-placement="left" ]
145 * { width: var( --os-dock-width ); }` — share equal
146 * specificity with `.os-shell--overview .os-dock`
147 * (two classes / class+attr) and load LATER in the cascade, so
148 * without `!important` the side rail keeps its placement width
149 * and stays visible during overview. The bottom dock happens to
150 * lack a placement-attr-keyed width override so it collapsed
151 * fine; the side rail did not — caught by the regression
152 * screenshot.
153 *
154 * `!important` is the right tool here: this rule is a transient,
155 * mode-scoped override (overview screen only) of a layout-mode
156 * default, and we want it to win unconditionally.
157 */
158 .os-shell--overview .os-dock,
159 .os-shell--overview #os-side-dock {
160 width: 0 !important;
161 min-width: 0 !important;
162 padding-inline: 0 !important;
163 padding-block: 0 !important;
164 transform: translateX( -16px );
165 opacity: 0;
166 overflow: hidden;
167 pointer-events: none;
168 transition:
169 width 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
170 min-width 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
171 padding 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
172 transform 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
173 opacity 0.22s ease;
174 }
175
176 @media ( prefers-reduced-motion: reduce ) {
177 .os-dock {
178 transition-duration: 0.01ms;
179 }
180 }
181
182 /*
183 * Desktop shortcut icons & files-layer tiles —
184 * hidden during overview so they don't compete with window
185 * thumbnails or overlap them (especially noticeable with few
186 * windows or Spatial layout). Matches the fade-out pattern
187 * used by widgets and pinned notes. Scoped to DIRECT children
188 * of the desktop area only: folder windows mount their own
189 * files layer inside the window body, and that must stay
190 * visible in its thumbnail.
191 */
192 .os-area--overview > .os-icons,
193 .os-area--overview > .os-files-layer {
194 opacity: 0;
195 pointer-events: none;
196 transition: opacity 0.22s ease;
197 }
198
199 /* ---------------------------------------------------------------
200 * Overview thumbnail labels.
201 *
202 * Sit outside each window's transform (as absolute-positioned
203 * siblings in the desktop area) so they stay readable at any
204 * thumbnail scale — an icon-sized thumbnail still has its
205 * full-size caption hovering above it.
206 *
207 * Layout: one line, icon + title (+ optional meta). Horizontal
208 * center-of-thumbnail alignment is handled via the label's
209 * own flex + width set in JS to match the scaled thumbnail.
210 * --------------------------------------------------------------- */
211 .os-overview-label {
212 position: absolute;
213 height: 28px;
214 display: flex;
215 align-items: center;
216 justify-content: center;
217 gap: 6px;
218 padding: 0 10px;
219 color: var( --os-ui-fg-on-accent, #fff );
220 font-size: 13px;
221 font-weight: 500;
222 line-height: 1;
223 letter-spacing: 0.01em;
224 text-shadow: 0 1px 3px rgba( 0, 0, 0, 0.55 );
225 white-space: nowrap;
226 pointer-events: none;
227 opacity: 0;
228 transform: translateY( 4px );
229 transition:
230 opacity 0.22s ease 0.06s,
231 transform 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ) 0.06s;
232 z-index: 2;
233 }
234
235 /*
236 * Active labels fade/slide in once the area enters overview mode.
237 * The short delay on `transition-*` lets the thumbnails start
238 * moving first, so labels appear to "catch up" rather than race
239 * ahead of their windows.
240 */
241 .os-area--overview .os-overview-label {
242 opacity: 1;
243 transform: translateY( 0 );
244 }
245
246 /* On exit, flip the animation off. */
247 .os-overview-label--out {
248 opacity: 0 !important;
249 transform: translateY( -4px ) !important;
250 transition-delay: 0s !important;
251 }
252
253 .os-overview-label__icon {
254 font-size: 16px;
255 width: 16px;
256 height: 16px;
257 line-height: 1;
258 flex-shrink: 0;
259 opacity: 0.9;
260 }
261
262 .os-overview-label__title {
263 overflow: hidden;
264 text-overflow: ellipsis;
265 }
266
267 .os-overview-label__meta {
268 color: rgba( 255, 255, 255, 0.7 );
269 font-weight: 400;
270 flex-shrink: 0;
271 }
272
273 /*
274 * Dim labels when another window is hovered. DOM order places
275 * each label immediately after its window, so the adjacent-
276 * sibling selector picks out exactly the label belonging to the
277 * hovered window and keeps it bright; all other labels fall under
278 * the `:has()` rule and dim.
279 */
280 .os-area--overview:has( .os-window--overview:hover )
281 .os-overview-label {
282 opacity: 0.45;
283 transform: translateY( 0 );
284 }
285
286 .os-window--overview:hover + .os-overview-label {
287 opacity: 1 !important;
288 }
289
290 @media ( prefers-reduced-motion: reduce ) {
291 .os-overview-label {
292 transition-duration: 0.01ms;
293 transition-delay: 0s;
294 }
295 }
296
297 /*
298 * Focused-window label overlay is not strictly needed — the title
299 * bar stays visible in the scaled thumbnail. If we later want a
300 * cleaner label (to combat tiny text on 8+-window grids), slot it
301 * in here via a ::after pseudo-element.
302 */
303
304 @media ( prefers-reduced-motion: reduce ) {
305 .os-area--overview,
306 .os-window--overview {
307 transition-duration: 0.01ms;
308 }
309 .os-area--overview > .os-icons,
310 .os-area--overview > .os-files-layer {
311 transition-duration: 0.01ms;
312 }
313 }
314
315 /* ---------------------------------------------------------------
316 * Overview top bar — virtual desktops ("Spaces") strip.
317 *
318 * Lives at the top of the desktop area while overview is active,
319 * stacked above the dimmed backdrop and below the window
320 * thumbnails. Each tile represents one desktop; clicking switches
321 * to it (and exits overview), the trailing "+" tile creates a new
322 * one, and per-tile X buttons close.
323 * --------------------------------------------------------------- */
324
325 .os-overview-top-bar {
326 position: absolute;
327 top: 16px;
328 left: 50%;
329 transform: translateX( -50% );
330 z-index: 2;
331 display: flex;
332 flex-direction: column;
333 align-items: center;
334 gap: 10px;
335 opacity: 0;
336 pointer-events: none;
337 transition:
338 opacity 0.22s ease 0.06s,
339 transform 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ) 0.06s;
340 }
341
342 /* The row above the desktop tiles — the site switcher on a network,
343 * where every site is its own OpenStation with its own desks. Its own
344 * panel, so the switcher reads as the thing the tiles hang under, not
345 * as one more tile. `OVERVIEW_TOP_BAR_HEADER_RESERVE` in
346 * `overview-constants.ts` is this row's height plus the gap. */
347 .os-overview-top-bar__header {
348 display: flex;
349 align-items: center;
350 justify-content: center;
351 padding: 6px 8px;
352 border-radius: 14px;
353 background-color: var( --os-ui-scrim, rgba( 0, 0, 0, 0.32 ) );
354 backdrop-filter: blur( 18px ) saturate( 140% );
355 -webkit-backdrop-filter: blur( 18px ) saturate( 140% );
356 box-shadow:
357 0 8px 28px rgba( 0, 0, 0, 0.35 ),
358 inset 0 0 0 1px rgba( 255, 255, 255, 0.08 );
359 max-width: min( 92vw, 960px );
360 overflow-x: auto;
361 }
362
363 .os-area--overview .os-overview-top-bar {
364 opacity: 1;
365 pointer-events: auto;
366 }
367
368 .os-overview-top-bar--out {
369 opacity: 0 !important;
370 transform: translateX( -50% ) translateY( -6px ) !important;
371 transition-delay: 0s !important;
372 }
373
374 .os-overview-top-bar__list {
375 display: flex;
376 flex-direction: row;
377 align-items: stretch;
378 gap: 12px;
379 padding: 8px 12px;
380 border-radius: 14px;
381 background-color: var( --os-ui-scrim, rgba( 0, 0, 0, 0.32 ) );
382 backdrop-filter: blur( 18px ) saturate( 140% );
383 -webkit-backdrop-filter: blur( 18px ) saturate( 140% );
384 box-shadow:
385 0 8px 28px rgba( 0, 0, 0, 0.35 ),
386 inset 0 0 0 1px rgba( 255, 255, 255, 0.08 );
387 }
388
389 .os-overview-top-bar__tile {
390 position: relative;
391 display: flex;
392 flex-direction: column;
393 align-items: stretch;
394 justify-content: stretch;
395 width: 140px;
396 padding: 0;
397 margin: 0;
398 background: rgba( 255, 255, 255, 0.04 );
399 border: 2px solid rgba( 255, 255, 255, 0.18 );
400 border-radius: 10px;
401 color: var( --os-ui-fg-on-accent, #fff );
402 cursor: pointer;
403 overflow: hidden;
404 transition:
405 border-color 0.18s ease,
406 background-color 0.18s ease,
407 transform 0.18s ease;
408 font: inherit;
409 }
410
411 .os-overview-top-bar__tile:hover {
412 background: rgba( 255, 255, 255, 0.08 );
413 }
414
415 /*
416 * Excluded because `:hover` (0,2,0) outranks `--active` (0,1,0) — an
417 * unguarded hover border replaces the active tile's accent ring.
418 */
419 .os-overview-top-bar__tile:hover:not( .os-overview-top-bar__tile--active ) {
420 border-color: rgba( 255, 255, 255, 0.4 );
421 }
422
423 .os-overview-top-bar__tile:focus-visible {
424 outline: 2px solid var( --wp-admin-theme-color, #2271b1 );
425 outline-offset: 2px;
426 }
427
428 .os-overview-top-bar__tile--active {
429 border-color: var( --wp-admin-theme-color, #2271b1 );
430 box-shadow: 0 0 0 1px var( --wp-admin-theme-color, #2271b1 );
431 }
432
433 .os-overview-top-bar__tile-preview {
434 display: flex;
435 align-items: center;
436 justify-content: center;
437 height: 60px;
438 background: linear-gradient(
439 135deg,
440 rgba( 255, 255, 255, 0.04 ),
441 rgba( 255, 255, 255, 0.12 )
442 );
443 border-bottom: 1px solid rgba( 255, 255, 255, 0.08 );
444 }
445
446 .os-overview-top-bar__tile-count {
447 font-size: 18px;
448 font-weight: 600;
449 color: rgba( 255, 255, 255, 0.7 );
450 letter-spacing: 0.02em;
451 }
452
453 /*
454 * A workspace's identity on its overview tile — the glyph and the
455 * accent it wears on the switcher pill. Overview is where desks are
456 * compared, and a row of identical grey tiles is exactly where "which
457 * one was the shop?" gets asked. A plain Space carries neither, so
458 * these rules simply never match for one.
459 */
460 .os-overview-top-bar__tile-glyph {
461 width: 24px;
462 height: 24px;
463 margin-inline-end: 6px;
464 font-size: 24px;
465 line-height: 24px;
466 color: var( --os-workspace-accent, rgba( 255, 255, 255, 0.7 ) );
467 }
468
469 .os-overview-top-bar__tile--tinted {
470 border-color: color-mix(
471 in srgb,
472 var( --os-workspace-accent, #f252fc ) 60%,
473 transparent
474 );
475 }
476
477 /*
478 * The active ring still wins: a tinted tile says which workspace it
479 * is, the ring says which one you are on, and the second question is
480 * the one overview is open to answer.
481 */
482 .os-overview-top-bar__tile--tinted.os-overview-top-bar__tile--active {
483 border-color: var( --wp-admin-theme-color, #2271b1 );
484 }
485
486 .os-overview-top-bar__tile-label {
487 display: block;
488 padding: 6px 10px 8px;
489 text-align: center;
490 font-size: 12px;
491 font-weight: 500;
492 color: rgba( 255, 255, 255, 0.85 );
493 white-space: nowrap;
494 overflow: hidden;
495 text-overflow: ellipsis;
496 }
497
498 /*
499 * The tile, plus whatever hangs off it.
500 *
501 * A column so the Restore button can sit BELOW the tile rather than
502 * over its preview — the preview is the tile's picture of the desk,
503 * and a control laid across it covers the one thing the tile is for.
504 * `position: relative` stays for the rename / close corner buttons,
505 * which are still positioned against the wrapper.
506 *
507 * The tile keeps its content height (no `flex` on it), so when the
508 * list stretches every wrapper to the tallest, a desk with no Restore
509 * simply has empty space under its tile instead of a taller tile —
510 * every tile box stays the same size and on the same line.
511 */
512 .os-overview-top-bar__tile-wrapper {
513 position: relative;
514 display: inline-flex;
515 flex-direction: column;
516 gap: 6px;
517 }
518
519 /* Tile corner buttons: rename on the leading edge, close on the
520 * trailing one, otherwise identical. */
521 .os-overview-top-bar__tile-close,
522 .os-overview-top-bar__tile-rename {
523 position: absolute;
524 top: 4px;
525 width: 18px;
526 height: 18px;
527 display: flex;
528 align-items: center;
529 justify-content: center;
530 color: rgba( 255, 255, 255, 0.7 );
531 background: var( --os-ui-scrim, rgba( 0, 0, 0, 0.45 ) );
532 border-radius: 50%;
533 cursor: pointer;
534 opacity: 0;
535 transition:
536 opacity 0.15s ease,
537 background-color 0.15s ease,
538 color 0.15s ease;
539 border: none;
540 padding: 0;
541 }
542
543 .os-overview-top-bar__tile-rename {
544 inset-inline-start: 4px;
545 }
546
547 .os-overview-top-bar__tile-close {
548 inset-inline-end: 4px;
549 }
550
551 .os-overview-top-bar__tile-wrapper:is( :hover, :focus-within )
552 :is(
553 .os-overview-top-bar__tile-close,
554 .os-overview-top-bar__tile-rename
555 ),
556 .os-overview-top-bar__tile-close:focus-visible,
557 .os-overview-top-bar__tile-rename:focus-visible {
558 opacity: 1;
559 }
560
561 .os-overview-top-bar__tile-close:hover {
562 background: var( --os-ui-danger, #d63638 );
563 color: var( --os-ui-fg-on-accent, #fff );
564 }
565
566 /*
567 * The desk's actions — a column below the tile, separated by the
568 * wrapper's gap. Not over the preview: the preview is the tile's
569 * picture of the desk, and a bar laid across it covers the one thing
570 * the tile is there to show. Not the corners either — rename and
571 * close have those — and these two are the actions that need a word,
572 * because no glyph says "rebuild this desk" or "change what it is".
573 *
574 * Two rows. **Restore** is always visible, but only painted on a desk
575 * with something to restore, so its absence is information. **Edit**
576 * is revealed on hover and keyboard focus, like rename and close: it
577 * is a way to change the desk rather than a thing about it, and a row
578 * of Edit buttons at rest would make the bar read as a form. The
579 * column reserves both rows' height whether or not either is present,
580 * so every tile box stays on the same line.
581 */
582 .os-overview-top-bar__tile-actions {
583 display: flex;
584 flex-direction: column;
585 gap: 4px;
586 /*
587 * One 22px row: Edit, which every desk has. Reserving two here
588 * made every bar as tall as its most elaborate desk, so a user
589 * with no workspaces at all paid a row of empty space under every
590 * tile for a button none of their desks could show.
591 */
592 min-height: 22px;
593 }
594
595 /* Two 22px rows and the gap, once some desk on the bar can restore. */
596 .os-overview-top-bar__list--restorable .os-overview-top-bar__tile-actions {
597 min-height: 48px;
598 }
599
600 .os-overview-top-bar__tile-action {
601 display: flex;
602 align-items: center;
603 justify-content: center;
604 gap: 5px;
605 height: 22px;
606 padding: 0 8px;
607 border: 1px solid rgba( 255, 255, 255, 0.14 );
608 border-radius: 8px;
609 background: var( --os-ui-scrim, rgba( 0, 0, 0, 0.42 ) );
610 color: rgba( 255, 255, 255, 0.78 );
611 font: inherit;
612 font-size: 10px;
613 font-weight: 600;
614 letter-spacing: 0.04em;
615 text-transform: uppercase;
616 cursor: pointer;
617 transition:
618 opacity 0.15s ease,
619 background-color 0.15s ease,
620 border-color 0.15s ease,
621 color 0.15s ease;
622 }
623
624 .os-overview-top-bar__tile-action svg {
625 width: 12px;
626 height: 12px;
627 flex: 0 0 auto;
628 }
629
630 .os-overview-top-bar__tile-action:hover {
631 background: var( --os-ui-accent, #f252fc );
632 border-color: var( --os-ui-accent, #f252fc );
633 color: var( --os-ui-fg-on-accent, #fff );
634 }
635
636 .os-overview-top-bar__tile-action:focus-visible {
637 outline: 2px solid var( --wp-admin-theme-color, #2271b1 );
638 outline-offset: 2px;
639 }
640
641 /* Edit rests hidden; the wrapper's hover / focus brings it up. */
642 .os-overview-top-bar__tile-edit {
643 opacity: 0;
644 }
645
646 .os-overview-top-bar__tile-wrapper:is( :hover, :focus-within )
647 .os-overview-top-bar__tile-edit,
648 .os-overview-top-bar__tile-edit:focus-visible {
649 opacity: 1;
650 }
651
652 @media ( prefers-reduced-motion: reduce ) {
653 .os-overview-top-bar__tile-action {
654 transition: none;
655 }
656 }
657
658 .os-overview-top-bar__tile-rename:hover {
659 background: var( --os-ui-accent, #f252fc );
660 color: var( --os-ui-fg-on-accent, #fff );
661 }
662
663 /*
664 * The label while it is being edited. Neutral hairline, not the
665 * accent: the active tile already wears an accent ring, and a second
666 * one reads as a rendering fault. `outline: none` is safe — the
667 * element is only editable while focused, so its treatment IS the
668 * focus indicator.
669 */
670 .os-overview-top-bar__tile-label[contenteditable] {
671 outline: none;
672 cursor: text;
673 background: rgba( 0, 0, 0, 0.55 );
674 border-radius: 6px;
675 box-shadow: inset 0 0 0 1px rgba( 255, 255, 255, 0.28 );
676 }
677
678
679 /*
680 * Hide the close X when there's only one tile left — the tile
681 * list contains both desktop wrappers AND the trailing "+".
682 * So "only one desktop" means exactly one wrapper in the list.
683 */
684 .os-overview-top-bar__list:has(
685 .os-overview-top-bar__tile-wrapper:only-of-type
686 )
687 .os-overview-top-bar__tile-close {
688 display: none;
689 }
690
691 /*
692 * The "+" is the place another desk goes, so it is the size of one.
693 * It sits in the same wrapper a desk does, above an empty actions
694 * block, which is what keeps the dashed box level with the tiles
695 * instead of stretching over the buttons underneath them.
696 */
697 .os-overview-top-bar__tile--add {
698 width: 60px;
699 background: transparent;
700 border-style: dashed;
701 }
702
703 /*
704 * The slot's own preview band: no gradient and no rule under it, since
705 * there is nothing to preview. It keeps the band's height, which is
706 * half of what makes the dashed box a tile tall.
707 */
708 .os-overview-top-bar__tile--add .os-overview-top-bar__tile-preview {
709 background: none;
710 /* Transparent, not removed. The rule is 1px of the tile's height,
711 and dropping it left the slot a pixel short of its neighbours. */
712 border-bottom-color: transparent;
713 }
714
715 /*
716 * The glyph centres in the whole slot, not in the preview band it
717 * happens to sit in. The two rows are there to make the box a tile
718 * tall; a desk splits them into a picture and a name, and the slot has
719 * neither, so its one mark belongs in the middle of the box. Taking it
720 * out of flow is what lets the rows still do the measuring.
721 */
722 .os-overview-top-bar__tile--add .os-overview-top-bar__tile-plus {
723 position: absolute;
724 inset: 0;
725 }
726
727 .os-overview-top-bar__tile--add:hover {
728 background: rgba( 255, 255, 255, 0.08 );
729 }
730
731 /*
732 * Keyboard cursor parked on the "+" tile. Mirrors the visual weight
733 * of `--active` (solid accent border + halo) so the user sees at a
734 * glance "Enter will land here". The dashed border on the add tile
735 * flips to solid when the cursor lands, matching the desktop tiles'
736 * solid borders.
737 */
738 .os-overview-top-bar__tile--add.os-overview-top-bar__tile--cursor {
739 border-style: solid;
740 border-color: var( --wp-admin-theme-color, #2271b1 );
741 box-shadow: 0 0 0 1px var( --wp-admin-theme-color, #2271b1 );
742 background: rgba( 255, 255, 255, 0.08 );
743 }
744
745 .os-overview-top-bar__tile-plus {
746 display: flex;
747 align-items: center;
748 justify-content: center;
749 flex: 1;
750 font-size: 28px;
751 font-weight: 200;
752 color: rgba( 255, 255, 255, 0.7 );
753 line-height: 1;
754 }
755
756 @media ( prefers-reduced-motion: reduce ) {
757 .os-overview-top-bar {
758 transition-duration: 0.01ms;
759 }
760 }
761