PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.10
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.10
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
← All changes | assets/css/window-overview.css +343 -65 0.9.81.1.10 View file →
@@ -1,6 +1,6 @@
1 1 /**
2 - * Desktop Mode — Overview.
2 + * OpenStation — Overview.
3 3 *
4 4 * Zoom-out grid view: windows transform into thumbnails, floating
5 5 * labels sit above them, and a top bar lists every virtual desktop
6 6 * with one tile per space plus a "+" to add a new one. The dock
@@ -19,16 +19,16 @@
19 19 * live in window-states.css.
20 20 *
21 21 * @since 6.9.0
22 22 */
23 -.desktop-mode-area--overview {
23 +.os-area--overview {
24 24 /* Darken the backdrop and tint it so windows feel like they're
25 25 * floating over a neutral canvas, not the wallpaper. */
26 - background-color: var( --wpd-scrim, rgba( 0, 0, 0, 0.45 ) );
26 + background-color: var( --os-ui-scrim, rgba( 0, 0, 0, 0.45 ) );
27 27 transition: background-color 0.28s ease;
28 28 }
29 29
30 -.desktop-mode-window--overview {
30 +.os-window--overview {
31 31 transform-origin: top left;
32 32 transition:
33 33 transform 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
34 34 box-shadow 0.2s ease,
@@ -52,17 +52,17 @@
52 52 * trip a close button, or launch an in-iframe action. Only the
53 53 * window's root element receives pointer events; our desktop-level
54 54 * pointerdown/pointerup handlers drive selection from there.
55 55 */
56 -.desktop-mode-window--overview * {
56 +.os-window--overview * {
57 57 pointer-events: none;
58 58 }
59 59
60 -.desktop-mode-window--overview {
60 +.os-window--overview {
61 61 pointer-events: auto;
62 62 }
63 63
64 -.desktop-mode-window--overview:hover {
64 +.os-window--overview:hover {
65 65 box-shadow:
66 66 0 14px 38px rgba( 0, 0, 0, 0.45 ),
67 67 0 0 0 3px var( --wp-admin-theme-color, #2271b1 );
68 68 z-index: 1;
@@ -71,9 +71,9 @@
71 71 /*
72 72 * Minimized windows shown in overview are rendered slightly dimmed
73 73 * so the user can distinguish them from active windows at a glance.
74 74 */
75 -.desktop-mode-window--overview.desktop-mode-window--minimized {
75 +.os-window--overview.os-window--minimized {
76 76 opacity: 0.6;
77 77 }
78 78
79 79 /*
@@ -83,10 +83,10 @@
83 83 * `:has()` lands in every evergreen browser we target (Chrome 105,
84 84 * Safari 15.4, Firefox 121+); older engines miss the dimming but
85 85 * keep the accent-ring affordance, so it degrades gracefully.
86 86 */
87 -.desktop-mode-area--overview:has( .desktop-mode-window--overview:hover )
88 - .desktop-mode-window--overview:not( :hover ) {
87 +.os-area--overview:has( .os-window--overview:hover )
88 + .os-window--overview:not( :hover ) {
89 89 opacity: 0.5;
90 90 filter: brightness( 0.75 );
91 91 transition:
92 92 transform 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
@@ -107,9 +107,9 @@
107 107 * shrinking dock doesn't leak icons past its boundary — outside
108 108 * overview, the dock keeps `overflow: visible` from dock.css so
109 109 * per-tile "+ open another" chips can float past the edge.
110 110 */
111 -.desktop-mode-dock {
111 +.os-dock {
112 112 transition:
113 113 width 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
114 114 min-width 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
115 115 padding 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ),
@@ -117,15 +117,34 @@
117 117 opacity 0.22s ease;
118 118 }
119 119
120 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 +/*
121 140 * Collapse EVERY dock (bottom + side rails, Classic / Unified /
122 141 * Spatial layouts alike) when overview is active.
123 142 *
124 143 * The placement-specific width rules in dock.css —
125 - * `.desktop-mode-dock[ data-desktop-mode-dock-placement="left" ]
126 - * { width: var( --desktop-mode-dock-width ); }` — share equal
127 - * specificity with `.desktop-mode-shell--overview .desktop-mode-dock`
144 + * `.os-dock[ data-os-dock-placement="left" ]
145 + * { width: var( --os-dock-width ); }` — share equal
146 + * specificity with `.os-shell--overview .os-dock`
128 147 * (two classes / class+attr) and load LATER in the cascade, so
129 148 * without `!important` the side rail keeps its placement width
130 149 * and stays visible during overview. The bottom dock happens to
131 150 * lack a placement-attr-keyed width override so it collapsed
@@ -135,10 +154,10 @@
135 154 * `!important` is the right tool here: this rule is a transient,
136 155 * mode-scoped override (overview screen only) of a layout-mode
137 156 * default, and we want it to win unconditionally.
138 157 */
139 -.desktop-mode-shell--overview .desktop-mode-dock,
140 -.desktop-mode-shell--overview #desktop-mode-side-dock {
158 +.os-shell--overview .os-dock,
159 +.os-shell--overview #os-side-dock {
141 160 width: 0 !important;
142 161 min-width: 0 !important;
143 162 padding-inline: 0 !important;
144 163 padding-block: 0 !important;
@@ -154,13 +173,30 @@
154 173 opacity 0.22s ease;
155 174 }
156 175
157 176 @media ( prefers-reduced-motion: reduce ) {
158 - .desktop-mode-dock {
177 + .os-dock {
159 178 transition-duration: 0.01ms;
160 179 }
161 180 }
162 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 +
163 199 /* ---------------------------------------------------------------
164 200 * Overview thumbnail labels.
165 201 *
166 202 * Sit outside each window's transform (as absolute-positioned
@@ -171,9 +207,9 @@
171 207 * Layout: one line, icon + title (+ optional meta). Horizontal
172 208 * center-of-thumbnail alignment is handled via the label's
173 209 * own flex + width set in JS to match the scaled thumbnail.
174 210 * --------------------------------------------------------------- */
175 -.desktop-mode-overview-label {
211 +.os-overview-label {
176 212 position: absolute;
177 213 height: 28px;
178 214 display: flex;
179 215 align-items: center;
@@ -179,9 +215,9 @@
179 215 align-items: center;
180 216 justify-content: center;
181 217 gap: 6px;
182 218 padding: 0 10px;
183 - color: var( --wpd-fg-on-accent, #fff );
219 + color: var( --os-ui-fg-on-accent, #fff );
184 220 font-size: 13px;
185 221 font-weight: 500;
186 222 line-height: 1;
187 223 letter-spacing: 0.01em;
@@ -201,21 +237,21 @@
201 237 * The short delay on `transition-*` lets the thumbnails start
202 238 * moving first, so labels appear to "catch up" rather than race
203 239 * ahead of their windows.
204 240 */
205 -.desktop-mode-area--overview .desktop-mode-overview-label {
241 +.os-area--overview .os-overview-label {
206 242 opacity: 1;
207 243 transform: translateY( 0 );
208 244 }
209 245
210 246 /* On exit, flip the animation off. */
211 -.desktop-mode-overview-label--out {
247 +.os-overview-label--out {
212 248 opacity: 0 !important;
213 249 transform: translateY( -4px ) !important;
214 250 transition-delay: 0s !important;
215 251 }
216 252
217 -.desktop-mode-overview-label__icon {
253 +.os-overview-label__icon {
218 254 font-size: 16px;
219 255 width: 16px;
220 256 height: 16px;
221 257 line-height: 1;
@@ -222,14 +258,14 @@
222 258 flex-shrink: 0;
223 259 opacity: 0.9;
224 260 }
225 261
226 -.desktop-mode-overview-label__title {
262 +.os-overview-label__title {
227 263 overflow: hidden;
228 264 text-overflow: ellipsis;
229 265 }
230 266
231 -.desktop-mode-overview-label__meta {
267 +.os-overview-label__meta {
232 268 color: rgba( 255, 255, 255, 0.7 );
233 269 font-weight: 400;
234 270 flex-shrink: 0;
235 271 }
@@ -240,20 +276,20 @@
240 276 * sibling selector picks out exactly the label belonging to the
241 277 * hovered window and keeps it bright; all other labels fall under
242 278 * the `:has()` rule and dim.
243 279 */
244 -.desktop-mode-area--overview:has( .desktop-mode-window--overview:hover )
245 - .desktop-mode-overview-label {
280 +.os-area--overview:has( .os-window--overview:hover )
281 + .os-overview-label {
246 282 opacity: 0.45;
247 283 transform: translateY( 0 );
248 284 }
249 285
250 -.desktop-mode-window--overview:hover + .desktop-mode-overview-label {
286 +.os-window--overview:hover + .os-overview-label {
251 287 opacity: 1 !important;
252 288 }
253 289
254 290 @media ( prefers-reduced-motion: reduce ) {
255 - .desktop-mode-overview-label {
291 + .os-overview-label {
256 292 transition-duration: 0.01ms;
257 293 transition-delay: 0s;
258 294 }
259 295 }
@@ -265,12 +301,16 @@
265 301 * in here via a ::after pseudo-element.
266 302 */
267 303
268 304 @media ( prefers-reduced-motion: reduce ) {
269 - .desktop-mode-area--overview,
270 - .desktop-mode-window--overview {
305 + .os-area--overview,
306 + .os-window--overview {
271 307 transition-duration: 0.01ms;
272 308 }
309 + .os-area--overview > .os-icons,
310 + .os-area--overview > .os-files-layer {
311 + transition-duration: 0.01ms;
312 + }
273 313 }
274 314
275 315 /* ---------------------------------------------------------------
276 316 * Overview top bar — virtual desktops ("Spaces") strip.
@@ -281,14 +321,18 @@
281 321 * to it (and exits overview), the trailing "+" tile creates a new
282 322 * one, and per-tile X buttons close.
283 323 * --------------------------------------------------------------- */
284 324
285 -.desktop-mode-overview-top-bar {
325 +.os-overview-top-bar {
286 326 position: absolute;
287 327 top: 16px;
288 328 left: 50%;
289 329 transform: translateX( -50% );
290 330 z-index: 2;
331 + display: flex;
332 + flex-direction: column;
333 + align-items: center;
334 + gap: 10px;
291 335 opacity: 0;
292 336 pointer-events: none;
293 337 transition:
294 338 opacity 0.22s ease 0.06s,
@@ -294,20 +338,64 @@
294 338 opacity 0.22s ease 0.06s,
295 339 transform 0.28s cubic-bezier( 0.2, 0, 0.2, 1 ) 0.06s;
296 340 }
297 341
298 -.desktop-mode-area--overview .desktop-mode-overview-top-bar {
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 +/* An install that joined from elsewhere wears a mark before its name,
364 + * and one line stands before the first of them, so the row says which
365 + * sites are this network's own and which are external. Both are light
366 + * DOM the switcher writes into the segment; its button is out of
367 + * reach behind the shadow root. */
368 +.os-site-switcher__divider {
369 + flex: none;
370 + align-self: stretch;
371 + width: 1px;
372 + margin: 5px 3px;
373 + background-color: var( --os-ui-border-strong, #c3c4c7 );
374 +}
375 +
376 +.os-site-switcher__mark.dashicons {
377 + font-size: 14px;
378 + width: 14px;
379 + height: 14px;
380 + line-height: 14px;
381 + margin-right: 5px;
382 + vertical-align: -2px;
383 + opacity: 0.75;
384 +}
385 +
386 +.os-area--overview .os-overview-top-bar {
299 387 opacity: 1;
300 388 pointer-events: auto;
301 389 }
302 390
303 -.desktop-mode-overview-top-bar--out {
391 +.os-overview-top-bar--out {
304 392 opacity: 0 !important;
305 393 transform: translateX( -50% ) translateY( -6px ) !important;
306 394 transition-delay: 0s !important;
307 395 }
308 396
309 -.desktop-mode-overview-top-bar__list {
397 +.os-overview-top-bar__list {
310 398 display: flex;
311 399 flex-direction: row;
312 400 align-items: stretch;
313 401 gap: 12px;
@@ -312,9 +400,9 @@
312 400 align-items: stretch;
313 401 gap: 12px;
314 402 padding: 8px 12px;
315 403 border-radius: 14px;
316 - background-color: var( --wpd-scrim, rgba( 0, 0, 0, 0.32 ) );
404 + background-color: var( --os-ui-scrim, rgba( 0, 0, 0, 0.32 ) );
317 405 backdrop-filter: blur( 18px ) saturate( 140% );
318 406 -webkit-backdrop-filter: blur( 18px ) saturate( 140% );
319 407 box-shadow:
320 408 0 8px 28px rgba( 0, 0, 0, 0.35 ),
@@ -320,9 +408,9 @@
320 408 0 8px 28px rgba( 0, 0, 0, 0.35 ),
321 409 inset 0 0 0 1px rgba( 255, 255, 255, 0.08 );
322 410 }
323 411
324 -.desktop-mode-overview-top-bar__tile {
412 +.os-overview-top-bar__tile {
325 413 position: relative;
326 414 display: flex;
327 415 flex-direction: column;
328 416 align-items: stretch;
@@ -332,9 +420,9 @@
332 420 margin: 0;
333 421 background: rgba( 255, 255, 255, 0.04 );
334 422 border: 2px solid rgba( 255, 255, 255, 0.18 );
335 423 border-radius: 10px;
336 - color: var( --wpd-fg-on-accent, #fff );
424 + color: var( --os-ui-fg-on-accent, #fff );
337 425 cursor: pointer;
338 426 overflow: hidden;
339 427 transition:
340 428 border-color 0.18s ease,
@@ -342,24 +430,31 @@
342 430 transform 0.18s ease;
343 431 font: inherit;
344 432 }
345 433
346 -.desktop-mode-overview-top-bar__tile:hover {
434 +.os-overview-top-bar__tile:hover {
435 + background: rgba( 255, 255, 255, 0.08 );
436 +}
437 +
438 +/*
439 + * Excluded because `:hover` (0,2,0) outranks `--active` (0,1,0) — an
440 + * unguarded hover border replaces the active tile's accent ring.
441 + */
442 +.os-overview-top-bar__tile:hover:not( .os-overview-top-bar__tile--active ) {
347 443 border-color: rgba( 255, 255, 255, 0.4 );
348 - background: rgba( 255, 255, 255, 0.08 );
349 444 }
350 445
351 -.desktop-mode-overview-top-bar__tile:focus-visible {
446 +.os-overview-top-bar__tile:focus-visible {
352 447 outline: 2px solid var( --wp-admin-theme-color, #2271b1 );
353 448 outline-offset: 2px;
354 449 }
355 450
356 -.desktop-mode-overview-top-bar__tile--active {
451 +.os-overview-top-bar__tile--active {
357 452 border-color: var( --wp-admin-theme-color, #2271b1 );
358 453 box-shadow: 0 0 0 1px var( --wp-admin-theme-color, #2271b1 );
359 454 }
360 455
361 -.desktop-mode-overview-top-bar__tile-preview {
456 +.os-overview-top-bar__tile-preview {
362 457 display: flex;
363 458 align-items: center;
364 459 justify-content: center;
365 460 height: 60px;
@@ -370,9 +465,9 @@
370 465 );
371 466 border-bottom: 1px solid rgba( 255, 255, 255, 0.08 );
372 467 }
373 468
374 -.desktop-mode-overview-top-bar__tile-count {
469 +.os-overview-top-bar__tile-count {
375 470 font-size: 18px;
376 471 font-weight: 600;
377 472 color: rgba( 255, 255, 255, 0.7 );
378 473 letter-spacing: 0.02em;
@@ -377,9 +472,42 @@
377 472 color: rgba( 255, 255, 255, 0.7 );
378 473 letter-spacing: 0.02em;
379 474 }
380 475
381 -.desktop-mode-overview-top-bar__tile-label {
476 +/*
477 + * A workspace's identity on its overview tile — the glyph and the
478 + * accent it wears on the switcher pill. Overview is where desks are
479 + * compared, and a row of identical grey tiles is exactly where "which
480 + * one was the shop?" gets asked. A plain Space carries neither, so
481 + * these rules simply never match for one.
482 + */
483 +.os-overview-top-bar__tile-glyph {
484 + width: 24px;
485 + height: 24px;
486 + margin-inline-end: 6px;
487 + font-size: 24px;
488 + line-height: 24px;
489 + color: var( --os-workspace-accent, rgba( 255, 255, 255, 0.7 ) );
490 +}
491 +
492 +.os-overview-top-bar__tile--tinted {
493 + border-color: color-mix(
494 + in srgb,
495 + var( --os-workspace-accent, #f252fc ) 60%,
496 + transparent
497 + );
498 +}
499 +
500 +/*
501 + * The active ring still wins: a tinted tile says which workspace it
502 + * is, the ring says which one you are on, and the second question is
503 + * the one overview is open to answer.
504 + */
505 +.os-overview-top-bar__tile--tinted.os-overview-top-bar__tile--active {
506 + border-color: var( --wp-admin-theme-color, #2271b1 );
507 +}
508 +
509 +.os-overview-top-bar__tile-label {
382 510 display: block;
383 511 padding: 6px 10px 8px;
384 512 text-align: center;
385 513 font-size: 12px;
@@ -389,17 +517,35 @@
389 517 overflow: hidden;
390 518 text-overflow: ellipsis;
391 519 }
392 520
393 -.desktop-mode-overview-top-bar__tile-wrapper {
521 +/*
522 + * The tile, plus whatever hangs off it.
523 + *
524 + * A column so the Restore button can sit BELOW the tile rather than
525 + * over its preview — the preview is the tile's picture of the desk,
526 + * and a control laid across it covers the one thing the tile is for.
527 + * `position: relative` stays for the rename / close corner buttons,
528 + * which are still positioned against the wrapper.
529 + *
530 + * The tile keeps its content height (no `flex` on it), so when the
531 + * list stretches every wrapper to the tallest, a desk with no Restore
532 + * simply has empty space under its tile instead of a taller tile —
533 + * every tile box stays the same size and on the same line.
534 + */
535 +.os-overview-top-bar__tile-wrapper {
394 536 position: relative;
395 - display: inline-block;
537 + display: inline-flex;
538 + flex-direction: column;
539 + gap: 6px;
396 540 }
397 541
398 -.desktop-mode-overview-top-bar__tile-close {
542 +/* Tile corner buttons: edit on the leading edge, close on the
543 + * trailing one, otherwise identical. */
544 +.os-overview-top-bar__tile-close,
545 +.os-overview-top-bar__tile-edit {
399 546 position: absolute;
400 547 top: 4px;
401 - inset-inline-end: 4px;
402 548 width: 18px;
403 549 height: 18px;
404 550 display: flex;
405 551 align-items: center;
@@ -404,9 +550,9 @@
404 550 display: flex;
405 551 align-items: center;
406 552 justify-content: center;
407 553 color: rgba( 255, 255, 255, 0.7 );
408 - background: var( --wpd-scrim, rgba( 0, 0, 0, 0.45 ) );
554 + background: var( --os-ui-scrim, rgba( 0, 0, 0, 0.45 ) );
409 555 border-radius: 50%;
410 556 cursor: pointer;
411 557 opacity: 0;
412 558 transition:
@@ -416,40 +562,172 @@
416 562 border: none;
417 563 padding: 0;
418 564 }
419 565
420 -.desktop-mode-overview-top-bar__tile-wrapper:hover
421 - .desktop-mode-overview-top-bar__tile-close,
422 -.desktop-mode-overview-top-bar__tile-wrapper:focus-within
423 - .desktop-mode-overview-top-bar__tile-close,
424 -.desktop-mode-overview-top-bar__tile-close:focus-visible {
566 +.os-overview-top-bar__tile-edit {
567 + inset-inline-start: 4px;
568 +}
569 +
570 +.os-overview-top-bar__tile-close {
571 + inset-inline-end: 4px;
572 +}
573 +
574 +.os-overview-top-bar__tile-wrapper:is( :hover, :focus-within )
575 + :is(
576 + .os-overview-top-bar__tile-close,
577 + .os-overview-top-bar__tile-edit
578 + ),
579 +.os-overview-top-bar__tile-close:focus-visible,
580 +.os-overview-top-bar__tile-edit:focus-visible {
425 581 opacity: 1;
426 582 }
427 583
428 -.desktop-mode-overview-top-bar__tile-close:hover {
429 - background: var( --wpd-danger, #d63638 );
430 - color: var( --wpd-fg-on-accent, #fff );
584 +.os-overview-top-bar__tile-close:hover {
585 + background: var( --os-ui-danger, #d63638 );
586 + color: var( --os-ui-fg-on-accent, #fff );
431 587 }
432 588
433 589 /*
590 + * The desk's actions — a column below the tile, separated by the
591 + * wrapper's gap. Not over the preview: the preview is the tile's
592 + * picture of the desk, and a bar laid across it covers the one thing
593 + * the tile is there to show. Not the corners either — edit and close
594 + * have those — and Restore needs a word, because no glyph says
595 + * "rebuild this desk".
596 + *
597 + * **Restore** is always visible, but only painted on a desk with
598 + * something to restore, so its absence is information. Once any desk
599 + * on the bar can restore, every column reserves the row, so every
600 + * tile box stays on the same line.
601 + */
602 +.os-overview-top-bar__tile-actions {
603 + display: flex;
604 + flex-direction: column;
605 + gap: 4px;
606 +}
607 +
608 +/* One 22px row, once some desk on the bar can restore. */
609 +.os-overview-top-bar__list--restorable .os-overview-top-bar__tile-actions {
610 + min-height: 22px;
611 +}
612 +
613 +.os-overview-top-bar__tile-action {
614 + display: flex;
615 + align-items: center;
616 + justify-content: center;
617 + gap: 5px;
618 + height: 22px;
619 + padding: 0 8px;
620 + border: 1px solid rgba( 255, 255, 255, 0.14 );
621 + border-radius: 8px;
622 + background: var( --os-ui-scrim, rgba( 0, 0, 0, 0.42 ) );
623 + color: rgba( 255, 255, 255, 0.78 );
624 + font: inherit;
625 + font-size: 10px;
626 + font-weight: 600;
627 + letter-spacing: 0.04em;
628 + text-transform: uppercase;
629 + cursor: pointer;
630 + transition:
631 + opacity 0.15s ease,
632 + background-color 0.15s ease,
633 + border-color 0.15s ease,
634 + color 0.15s ease;
635 +}
636 +
637 +.os-overview-top-bar__tile-action svg {
638 + width: 12px;
639 + height: 12px;
640 + flex: 0 0 auto;
641 +}
642 +
643 +.os-overview-top-bar__tile-action:hover {
644 + background: var( --os-ui-accent, #f252fc );
645 + border-color: var( --os-ui-accent, #f252fc );
646 + color: var( --os-ui-accent-ink, var( --os-ui-fg-on-accent, #fff ) );
647 +}
648 +
649 +.os-overview-top-bar__tile-action:focus-visible {
650 + outline: 2px solid var( --wp-admin-theme-color, #2271b1 );
651 + outline-offset: 2px;
652 +}
653 +
654 +@media ( prefers-reduced-motion: reduce ) {
655 + .os-overview-top-bar__tile-action {
656 + transition: none;
657 + }
658 +}
659 +
660 +.os-overview-top-bar__tile-edit:hover {
661 + background: var( --os-ui-accent, #f252fc );
662 + color: var( --os-ui-accent-ink, var( --os-ui-fg-on-accent, #fff ) );
663 +}
664 +
665 +/*
666 + * The label while it is being edited. Neutral hairline, not the
667 + * accent: the active tile already wears an accent ring, and a second
668 + * one reads as a rendering fault. `outline: none` is safe — the
669 + * element is only editable while focused, so its treatment IS the
670 + * focus indicator.
671 + */
672 +.os-overview-top-bar__tile-label[contenteditable] {
673 + outline: none;
674 + cursor: text;
675 + background: rgba( 0, 0, 0, 0.55 );
676 + border-radius: 6px;
677 + box-shadow: inset 0 0 0 1px rgba( 255, 255, 255, 0.28 );
678 +}
679 +
680 +
681 +/*
434 682 * Hide the close X when there's only one tile left — the tile
435 683 * list contains both desktop wrappers AND the trailing "+".
436 684 * So "only one desktop" means exactly one wrapper in the list.
437 685 */
438 -.desktop-mode-overview-top-bar__list:has(
439 - .desktop-mode-overview-top-bar__tile-wrapper:only-of-type
686 +.os-overview-top-bar__list:has(
687 + .os-overview-top-bar__tile-wrapper:only-of-type
440 688 )
441 - .desktop-mode-overview-top-bar__tile-close {
689 + .os-overview-top-bar__tile-close {
442 690 display: none;
443 691 }
444 692
445 -.desktop-mode-overview-top-bar__tile--add {
693 +/*
694 + * The "+" is the place another desk goes, so it is the size of one.
695 + * It sits in the same wrapper a desk does, above an empty actions
696 + * block, which is what keeps the dashed box level with the tiles
697 + * instead of stretching over the buttons underneath them.
698 + */
699 +.os-overview-top-bar__tile--add {
446 700 width: 60px;
447 701 background: transparent;
448 702 border-style: dashed;
449 703 }
450 704
451 -.desktop-mode-overview-top-bar__tile--add:hover {
705 +/*
706 + * The slot's own preview band: no gradient and no rule under it, since
707 + * there is nothing to preview. It keeps the band's height, which is
708 + * half of what makes the dashed box a tile tall.
709 + */
710 +.os-overview-top-bar__tile--add .os-overview-top-bar__tile-preview {
711 + background: none;
712 + /* Transparent, not removed. The rule is 1px of the tile's height,
713 + and dropping it left the slot a pixel short of its neighbours. */
714 + border-bottom-color: transparent;
715 +}
716 +
717 +/*
718 + * The glyph centres in the whole slot, not in the preview band it
719 + * happens to sit in. The two rows are there to make the box a tile
720 + * tall; a desk splits them into a picture and a name, and the slot has
721 + * neither, so its one mark belongs in the middle of the box. Taking it
722 + * out of flow is what lets the rows still do the measuring.
723 + */
724 +.os-overview-top-bar__tile--add .os-overview-top-bar__tile-plus {
725 + position: absolute;
726 + inset: 0;
727 +}
728 +
729 +.os-overview-top-bar__tile--add:hover {
452 730 background: rgba( 255, 255, 255, 0.08 );
453 731 }
454 732
455 733 /*
@@ -458,9 +736,9 @@
458 736 * glance "Enter will land here". The dashed border on the add tile
459 737 * flips to solid when the cursor lands, matching the desktop tiles'
460 738 * solid borders.
461 739 */
462 -.desktop-mode-overview-top-bar__tile--add.desktop-mode-overview-top-bar__tile--cursor {
740 +.os-overview-top-bar__tile--add.os-overview-top-bar__tile--cursor {
463 741 border-style: solid;
464 742 border-color: var( --wp-admin-theme-color, #2271b1 );
465 743 box-shadow: 0 0 0 1px var( --wp-admin-theme-color, #2271b1 );
466 744 background: rgba( 255, 255, 255, 0.08 );
@@ -465,9 +743,9 @@
465 743 box-shadow: 0 0 0 1px var( --wp-admin-theme-color, #2271b1 );
466 744 background: rgba( 255, 255, 255, 0.08 );
467 745 }
468 746
469 -.desktop-mode-overview-top-bar__tile-plus {
747 +.os-overview-top-bar__tile-plus {
470 748 display: flex;
471 749 align-items: center;
472 750 justify-content: center;
473 751 flex: 1;
@@ -477,8 +755,8 @@
477 755 line-height: 1;
478 756 }
479 757
480 758 @media ( prefers-reduced-motion: reduce ) {
481 - .desktop-mode-overview-top-bar {
759 + .os-overview-top-bar {
482 760 transition-duration: 0.01ms;
483 761 }
484 762 }