PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 0.8.9
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v0.8.9
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 / dock.css

dock.css in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 0.8.9, at assets/css/dock.css

822 lines 26.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Desktop Mode — Dock.
3 *
4 * A rail that hosts admin menu tiles plus shell-level system tiles.
5 * Placement (left / right / bottom) is reflected on each dock element
6 * itself as `data-desktop-mode-dock-placement`; this stylesheet keys
7 * off that attribute for layout, tooltip anchor, and indicator
8 * position. Two instances can coexist (Classic layout: a left side
9 * bar with core menus + a bottom dock with plugin menus); each
10 * carries its own placement attribute, so the two rails are styled
11 * independently without leaking selector state to one another.
12 *
13 * @since 6.9.0
14 */
15
16 /* ------------------------------------------------------------------
17 * Shared dock chrome — applies to every placement.
18 * ------------------------------------------------------------------ */
19
20 .desktop-mode-dock {
21 display: flex;
22 align-items: center;
23 z-index: var( --desktop-mode-z-dock );
24 background: var( --desktop-mode-dock-bg );
25 backdrop-filter: blur( 20px );
26 -webkit-backdrop-filter: blur( 20px );
27 flex-shrink: 0;
28 /*
29 * overflow: visible so the per-tile "Open another" chip can float
30 * past the dock's outer edge. Real-world bottom-dock menus fit
31 * the viewport without a scrollbar; vertical placements route
32 * their overflow through the inner `__scroll` wrapper, leaving
33 * the dock itself non-scrolling.
34 */
35 overflow: visible;
36 }
37
38 /* A single dock tile — icon button (+ optional instance rail below). */
39 .desktop-mode-dock__item {
40 position: relative;
41 display: flex;
42 flex-direction: column;
43 align-items: center;
44 width: 40px;
45 flex-shrink: 0;
46 }
47
48 /* Primary icon button — opens or focuses the page. */
49 .desktop-mode-dock__item-primary {
50 position: relative;
51 display: flex;
52 align-items: center;
53 justify-content: center;
54 width: 40px;
55 height: 40px;
56 border: none;
57 border-radius: 10px;
58 cursor: pointer;
59 padding: 0;
60 background: transparent;
61 color: rgba( 255, 255, 255, 0.7 );
62 transition: background-color 0.15s ease, transform 0.15s ease, color 0.15s ease;
63 }
64
65 .desktop-mode-dock__item-primary:hover {
66 background: rgba( 255, 255, 255, 0.15 );
67 color: #fff;
68 transform: scale( 1.1 );
69 }
70
71 .desktop-mode-dock__item-primary:active {
72 transform: scale( 0.95 );
73 }
74
75 .desktop-mode-dock__item-primary:focus-visible {
76 outline: 2px solid rgba( 255, 255, 255, 0.7 );
77 outline-offset: 2px;
78 }
79
80 /* Dashicon inside dock item. */
81 .desktop-mode-dock__item .dashicons {
82 font-size: var( --desktop-mode-dock-icon-size, 20px );
83 width: var( --desktop-mode-dock-icon-size, 20px );
84 height: var( --desktop-mode-dock-icon-size, 20px );
85 line-height: 1;
86 }
87
88 /* SVG icon (for custom post types with data:image/svg+xml icons). */
89 .desktop-mode-dock__item-svg {
90 width: var( --desktop-mode-dock-icon-size, 20px );
91 height: var( --desktop-mode-dock-icon-size, 20px );
92 display: block;
93 fill: currentColor;
94 opacity: 0.7;
95 /* Some plugin SVGs ship hardcoded `fill="..."` attributes inside
96 the markup, which override `fill: currentColor` and make the
97 icon keep its brand color. Force the monochrome white palette
98 to match dashicons. */
99 filter: brightness(0) invert(1);
100 transition: opacity 0.15s ease;
101 }
102
103 .desktop-mode-dock__item-primary:hover .desktop-mode-dock__item-svg {
104 opacity: 1;
105 }
106
107 /*
108 * Letter-badge icon — rendered for items registered without a
109 * dashicon / SVG / image URL. Miniature "app placeholder": rounded
110 * square tinted with a title-derived hue, first letter centered.
111 */
112 .desktop-mode-dock__item-letter {
113 display: flex;
114 align-items: center;
115 justify-content: center;
116 width: 28px;
117 height: 28px;
118 border-radius: 8px;
119 color: #fff;
120 font-size: 15px;
121 font-weight: 700;
122 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
123 line-height: 1;
124 letter-spacing: 0;
125 text-shadow: 0 1px 1px rgba( 0, 0, 0, 0.22 );
126 box-shadow:
127 inset 0 1px 0 rgba( 255, 255, 255, 0.2 ),
128 inset 0 -1px 0 rgba( 0, 0, 0, 0.15 );
129 }
130
131 .desktop-mode-dock__item img.desktop-mode-dock__item-img {
132 width: var( --desktop-mode-dock-icon-size, 20px );
133 height: var( --desktop-mode-dock-icon-size, 20px );
134 display: block;
135 opacity: 0.7;
136 transition: opacity 0.15s ease;
137 }
138
139 .desktop-mode-dock__item-primary:hover img.desktop-mode-dock__item-img {
140 opacity: 1;
141 }
142
143 /* "Open another" floating chip — shown on multi-capable tiles that
144 * already have ≥1 open instance. Positioned inside each orientation
145 * block so the chip hugs the outward edge of the tile. */
146 .desktop-mode-dock__item-new {
147 position: absolute;
148 display: flex;
149 align-items: center;
150 justify-content: center;
151 width: 20px;
152 height: 20px;
153 padding: 0;
154 border: 2px solid var( --desktop-mode-dock-bg, rgba( 0, 0, 0, 0.4 ) );
155 border-radius: 50%;
156 background: var( --wp-admin-theme-color, #2271b1 );
157 color: #fff;
158 cursor: pointer;
159 transition: background-color 0.15s ease, transform 0.15s ease;
160 z-index: 1;
161 }
162
163 .desktop-mode-dock__item-new[hidden] {
164 display: none;
165 }
166
167 .desktop-mode-dock__item-new:hover {
168 background: #fff;
169 color: var( --wp-admin-theme-color, #2271b1 );
170 }
171
172 .desktop-mode-dock__item-new:focus-visible {
173 outline: 2px solid rgba( 255, 255, 255, 0.85 );
174 outline-offset: 2px;
175 }
176
177 /* Notification badge — iOS/macOS-style pill straddling the tile
178 * corner. Ring matches the dock bg so it reads as "punched out."
179 * Badge positioning is placement-aware via the blocks below. */
180 .desktop-mode-dock__badge {
181 position: absolute;
182 min-width: 16px;
183 height: 16px;
184 padding: 0 5px;
185 box-sizing: border-box;
186 border-radius: 999px;
187 background: linear-gradient( 180deg, #ff5a5a 0%, #d63638 100% );
188 color: #fff;
189 display: inline-flex;
190 align-items: center;
191 justify-content: center;
192 font-size: 10px;
193 font-weight: 700;
194 line-height: 1;
195 letter-spacing: 0.01em;
196 text-align: center;
197 font-variant-numeric: tabular-nums;
198 box-shadow:
199 0 0 0 1.5px var( --desktop-mode-dock-bg, rgba( 0, 0, 0, 0.4 ) ),
200 0 1px 3px rgba( 0, 0, 0, 0.35 );
201 pointer-events: none;
202 transition: transform 0.15s ease;
203 top: -3px;
204 inset-inline-end: -3px;
205 }
206
207 .desktop-mode-dock__item:hover .desktop-mode-dock__badge {
208 transform: scale( 1.05 );
209 top: -4px;
210 }
211
212 /* System tiles — same footprint as menu tiles, no badges, no rails. */
213 .desktop-mode-dock__item--system .desktop-mode-dock__item-primary {
214 color: rgba( 255, 255, 255, 0.8 );
215 }
216
217 /* -----------------------------------------------------------------------------
218 * Attention animations — driven by `Dock.setAttention()` /
219 * `Window.requestAttention()`. The class lands on the tile root,
220 * the animation runs on the primary icon button so the badge stays
221 * stable. Three modes (pulse / shake / bounce) and three intensities
222 * (subtle / normal / strong). All animations gated on
223 * `prefers-reduced-motion: no-preference`; the reduced-motion fallback
224 * shows a static accent ring for the same duration so the affordance
225 * still works.
226 * ------------------------------------------------------------------------- */
227
228 @keyframes wpd-dock-attention-pulse {
229 0%, 100% {
230 transform: scale( 1 );
231 box-shadow: 0 0 0 0 rgba( 255, 90, 90, 0.55 );
232 }
233 50% {
234 transform: scale( 1.06 );
235 box-shadow: 0 0 0 8px rgba( 255, 90, 90, 0 );
236 }
237 }
238
239 @keyframes wpd-dock-attention-shake {
240 0%, 100% {
241 transform: translateX( 0 );
242 }
243 20%, 60% {
244 transform: translateX( -3px );
245 }
246 40%, 80% {
247 transform: translateX( 3px );
248 }
249 }
250
251 @keyframes wpd-dock-attention-bounce {
252 0%, 100% {
253 transform: translateY( 0 );
254 }
255 30% {
256 transform: translateY( -6px );
257 }
258 60% {
259 transform: translateY( -2px );
260 }
261 }
262
263 .desktop-mode-dock__item--attention-pulse .desktop-mode-dock__item-primary {
264 animation: wpd-dock-attention-pulse 1.4s ease-in-out infinite;
265 }
266 .desktop-mode-dock__item--attention-shake .desktop-mode-dock__item-primary {
267 animation: wpd-dock-attention-shake 0.8s ease-in-out infinite;
268 }
269 .desktop-mode-dock__item--attention-bounce .desktop-mode-dock__item-primary {
270 animation: wpd-dock-attention-bounce 1.2s ease-in-out infinite;
271 }
272
273 /* Intensity modulates animation duration — strong = faster, more
274 urgent; subtle = slower, calmer. */
275 .desktop-mode-dock__item--intensity-strong.desktop-mode-dock__item--attention-pulse .desktop-mode-dock__item-primary {
276 animation-duration: 1s;
277 }
278 .desktop-mode-dock__item--intensity-strong.desktop-mode-dock__item--attention-shake .desktop-mode-dock__item-primary {
279 animation-duration: 0.6s;
280 }
281 .desktop-mode-dock__item--intensity-strong.desktop-mode-dock__item--attention-bounce .desktop-mode-dock__item-primary {
282 animation-duration: 0.9s;
283 }
284 .desktop-mode-dock__item--intensity-subtle.desktop-mode-dock__item--attention-pulse .desktop-mode-dock__item-primary {
285 animation-duration: 1.8s;
286 }
287 .desktop-mode-dock__item--intensity-subtle.desktop-mode-dock__item--attention-shake .desktop-mode-dock__item-primary {
288 animation-duration: 1s;
289 }
290 .desktop-mode-dock__item--intensity-subtle.desktop-mode-dock__item--attention-bounce .desktop-mode-dock__item-primary {
291 animation-duration: 1.6s;
292 }
293
294 /* Reduced-motion: kill the animation, replace with a static accent ring
295 for the same visual prominence without the movement. */
296 @media ( prefers-reduced-motion: reduce ) {
297 .desktop-mode-dock__item--attention-pulse .desktop-mode-dock__item-primary,
298 .desktop-mode-dock__item--attention-shake .desktop-mode-dock__item-primary,
299 .desktop-mode-dock__item--attention-bounce .desktop-mode-dock__item-primary {
300 animation: none;
301 outline: 2px solid var( --wp-admin-theme-color, #2271b1 );
302 outline-offset: 2px;
303 border-radius: 8px;
304 }
305 }
306
307 /* Shared tooltip — placement-specific anchor modifiers applied by JS. */
308 .desktop-mode-dock__tooltip {
309 position: fixed;
310 padding: 6px 12px;
311 background: rgba( 0, 0, 0, 0.85 );
312 color: #fff;
313 font-size: 12px;
314 font-weight: 400;
315 line-height: 1.4;
316 white-space: nowrap;
317 border-radius: 6px;
318 pointer-events: none;
319 z-index: calc( var( --desktop-mode-z-dock ) + 1 );
320 opacity: 0;
321 transition: opacity 0.15s ease, transform 0.15s ease;
322 }
323
324 .desktop-mode-dock__tooltip--visible {
325 opacity: 1;
326 }
327
328 /* ------------------------------------------------------------------
329 * Vertical placement (left + right) — dock runs the full shell body
330 * height along one edge, with items stacked vertically.
331 * ------------------------------------------------------------------ */
332
333 .desktop-mode-dock[ data-desktop-mode-dock-placement="left" ],
334 .desktop-mode-dock[ data-desktop-mode-dock-placement="right" ] {
335 width: var( --desktop-mode-dock-width );
336 flex-direction: column;
337 padding: 16px 0 12px;
338 gap: 6px;
339 /*
340 * Vertical docks split into two inner wrappers:
341 * - `__scroll` — flex: 1, scrollable, hosts menu tiles + the
342 * inline core/plugin separator. When the menu
343 * exceeds the dock's height, this is what
344 * scrolls; the outer dock stays a fixed pillar.
345 * - `__pinned` — sized to content, hosts system tiles
346 * (Recycle Bin, OS Settings, …) + their hairline
347 * separator. Always visible at the bottom edge
348 * regardless of scroll position.
349 *
350 * `min-height: 0` on the dock is defensive: even though `__scroll`
351 * absorbs the overflow, the dock is a flex item inside the shell
352 * body (a flex row), and the default `min-height: auto` would let
353 * a tall `__pinned` push the dock past the parent's height.
354 */
355 min-height: 0;
356 }
357
358 /*
359 * Scrollable menu-tile area inside vertical docks. `flex: 1 1 0` plus
360 * `min-height: 0` lets it shrink below its content's natural height so
361 * `overflow-y: auto` actually engages. `overflow-x: clip` keeps the
362 * active-dot / focused-pill indicators visible (they sit at x≈2px
363 * inside the wrapper's content box) while preventing `overflow-y: auto`
364 * from coercing horizontal scroll. Scrollbar is hidden visually —
365 * Firefox via `scrollbar-width: none`, WebKit via the pseudo-element
366 * rule below — so the rail keeps its clean macOS look. Mouse wheel,
367 * touchpad, touch, and keyboard focus-into-view all still work.
368 */
369 .desktop-mode-dock[ data-desktop-mode-dock-placement="left" ] .desktop-mode-dock__scroll,
370 .desktop-mode-dock[ data-desktop-mode-dock-placement="right" ] .desktop-mode-dock__scroll {
371 display: flex;
372 flex-direction: column;
373 align-items: center;
374 gap: 6px;
375 flex: 1 1 0;
376 min-height: 0;
377 width: 100%;
378 overflow-y: auto;
379 overflow-x: clip;
380 scrollbar-width: none;
381 }
382
383 .desktop-mode-dock[ data-desktop-mode-dock-placement="left" ] .desktop-mode-dock__scroll::-webkit-scrollbar,
384 .desktop-mode-dock[ data-desktop-mode-dock-placement="right" ] .desktop-mode-dock__scroll::-webkit-scrollbar {
385 display: none;
386 }
387
388 /*
389 * Pinned area below `__scroll` — system tiles stay reachable here
390 * regardless of how the menu list scrolls. `flex-shrink: 0` so it's
391 * never compressed; sized to its content's natural height.
392 */
393 .desktop-mode-dock[ data-desktop-mode-dock-placement="left" ] .desktop-mode-dock__pinned,
394 .desktop-mode-dock[ data-desktop-mode-dock-placement="right" ] .desktop-mode-dock__pinned {
395 display: flex;
396 flex-direction: column;
397 align-items: center;
398 gap: 6px;
399 flex-shrink: 0;
400 width: 100%;
401 }
402
403 /* Left: dock is the first flex item in __body (row layout). */
404 .desktop-mode-dock[ data-desktop-mode-dock-placement="left" ] {
405 border-inline-end: 1px solid var( --desktop-mode-dock-border );
406 order: -1;
407 }
408
409 /* Right: push the dock to the end of __body and flip the border edge. */
410 .desktop-mode-dock[ data-desktop-mode-dock-placement="right" ] {
411 border-inline-start: 1px solid var( --desktop-mode-dock-border );
412 order: 1;
413 }
414
415 /* Active-indicator dot — left dock: inside-edge vertical pill. */
416 .desktop-mode-dock[ data-desktop-mode-dock-placement="left" ]
417 .desktop-mode-dock__item--active::before {
418 content: "";
419 position: absolute;
420 inset-inline-start: -6px;
421 top: 50%;
422 transform: translateY( -50% );
423 width: 4px;
424 height: 4px;
425 border-radius: 50%;
426 background: #fff;
427 }
428
429 .desktop-mode-dock[ data-desktop-mode-dock-placement="left" ]
430 .desktop-mode-dock__item--focused::before {
431 width: 4px;
432 height: 16px;
433 border-radius: 2px;
434 }
435
436 /*
437 * "All instances minimized" — the tile still has windows, they're
438 * just hidden. Swap the solid dot for a hollow ring so the user sees
439 * "I have something here, currently tucked away" instead of "I have
440 * a focused / visible window here." `--all-minimized` is layered on
441 * top of `--active`; the rule below wins on selector specificity.
442 *
443 * Sized slightly larger than the solid dot so the ring is legible at
444 * dock size — a 4×4 outline reads as a dirty pixel.
445 */
446 .desktop-mode-dock[ data-desktop-mode-dock-placement="left" ]
447 .desktop-mode-dock__item--all-minimized::before {
448 width: 6px;
449 height: 6px;
450 border-radius: 50%;
451 background: transparent;
452 border: 1px solid rgba( 255, 255, 255, 0.85 );
453 }
454
455 /* Right dock: indicator on the opposite edge (inside-facing). */
456 .desktop-mode-dock[ data-desktop-mode-dock-placement="right" ]
457 .desktop-mode-dock__item--active::before {
458 content: "";
459 position: absolute;
460 inset-inline-end: -6px;
461 top: 50%;
462 transform: translateY( -50% );
463 width: 4px;
464 height: 4px;
465 border-radius: 50%;
466 background: #fff;
467 }
468
469 .desktop-mode-dock[ data-desktop-mode-dock-placement="right" ]
470 .desktop-mode-dock__item--focused::before {
471 width: 4px;
472 height: 16px;
473 border-radius: 2px;
474 }
475
476 .desktop-mode-dock[ data-desktop-mode-dock-placement="right" ]
477 .desktop-mode-dock__item--all-minimized::before {
478 width: 6px;
479 height: 6px;
480 border-radius: 50%;
481 background: transparent;
482 border: 1px solid rgba( 255, 255, 255, 0.85 );
483 }
484
485 /* "Open another" chip — left: right of tile; right: left of tile. */
486 .desktop-mode-dock[ data-desktop-mode-dock-placement="left" ]
487 .desktop-mode-dock__item-new {
488 top: 50%;
489 inset-inline-end: -13px;
490 transform: translateY( -50% );
491 }
492
493 .desktop-mode-dock[ data-desktop-mode-dock-placement="left" ]
494 .desktop-mode-dock__item-new:hover {
495 transform: translateY( -50% ) scale( 1.1 );
496 }
497
498 .desktop-mode-dock[ data-desktop-mode-dock-placement="right" ]
499 .desktop-mode-dock__item-new {
500 top: 50%;
501 inset-inline-start: -13px;
502 transform: translateY( -50% );
503 }
504
505 .desktop-mode-dock[ data-desktop-mode-dock-placement="right" ]
506 .desktop-mode-dock__item-new:hover {
507 transform: translateY( -50% ) scale( 1.1 );
508 }
509
510 /* Separator — horizontal hairline between menu tiles and system
511 * tiles. With the `__scroll` / `__pinned` split the system separator
512 * lives at the top of `__pinned`; flex-flow handles the "system
513 * tiles at the bottom" placement, no margin-top: auto needed. The
514 * `--group` variant is used inline between core and plugin menu
515 * tiles in `__scroll`; it keeps the hairline styling and sits
516 * exactly where it's inserted. */
517 .desktop-mode-dock[ data-desktop-mode-dock-placement="left" ]
518 .desktop-mode-dock__separator,
519 .desktop-mode-dock[ data-desktop-mode-dock-placement="right" ]
520 .desktop-mode-dock__separator {
521 width: 60%;
522 height: 1px;
523 margin: 8px auto 4px;
524 background: var( --desktop-mode-dock-border );
525 flex-shrink: 0;
526 }
527
528 .desktop-mode-dock[ data-desktop-mode-dock-placement="left" ]
529 .desktop-mode-dock__separator--group,
530 .desktop-mode-dock[ data-desktop-mode-dock-placement="right" ]
531 .desktop-mode-dock__separator--group {
532 margin: 10px auto;
533 background: rgba( 255, 255, 255, 0.22 );
534 }
535
536 /*
537 * Hide the system separator when nothing precedes it — on a clean
538 * install (or a low-cap user with zero menu items) the separator
539 * would render as a stray hairline with nothing to divide.
540 *
541 * Two cases:
542 * 1. Bottom dock — separator is a direct child of the dock; hide
543 * when it's the first such child.
544 * 2. Vertical docks — separator lives inside `__pinned`; hide when
545 * `__scroll` (its sibling above) is empty of menu tiles.
546 */
547 .desktop-mode-dock > .desktop-mode-dock__separator:first-child {
548 display: none;
549 }
550
551 .desktop-mode-dock__scroll:not(:has( .desktop-mode-dock__item ))
552 + .desktop-mode-dock__pinned
553 .desktop-mode-dock__separator {
554 display: none;
555 }
556
557 /* Tooltip — anchor modifiers are applied directly to the tooltip
558 * element (NOT via a descendant selector on `.desktop-mode-dock`)
559 * because the tooltip lives in `document.body`. JS writes the
560 * absolute `top` / `left` coords; CSS handles the slide-in
561 * animation direction per modifier.
562 *
563 * - `--after` : left-placed dock (tooltip to the RIGHT of tile)
564 * - `--before` : right-placed dock (tooltip to the LEFT of tile)
565 * - `--above` : bottom-placed dock (tooltip ABOVE the tile)
566 */
567
568 /* Left dock — tooltip slides in from the left by 4px. JS sets
569 * `left` to `tile.right + 8px`; the transform animates the entry. */
570 .desktop-mode-dock__tooltip--after {
571 transform: translateX( -4px );
572 }
573
574 .desktop-mode-dock__tooltip--after.desktop-mode-dock__tooltip--visible {
575 transform: translateX( 0 );
576 }
577
578 .desktop-mode-dock__tooltip--before {
579 /* Right-placed dock — tooltip sits to the left of the tile. JS
580 * writes the left coord to the tile's left edge; this translate
581 * pulls the tooltip further left by its own width. */
582 transform: translate( calc( -100% - 8px ), 0 );
583 }
584
585 .desktop-mode-dock__tooltip--before.desktop-mode-dock__tooltip--visible {
586 transform: translate( calc( -100% - 8px ), 0 );
587 opacity: 1;
588 }
589
590 /* ------------------------------------------------------------------
591 * Bottom placement — floating macOS-style pill centered above the
592 * viewport floor. Absolutely positioned so it floats as pure chrome
593 * rather than stealing vertical space from the shell body.
594 * ------------------------------------------------------------------ */
595
596 .desktop-mode-dock[ data-desktop-mode-dock-placement="bottom" ] {
597 position: absolute;
598 inset-inline-start: 0;
599 inset-inline-end: 0;
600 bottom: 12px;
601 margin: 0 auto;
602 width: fit-content;
603 max-width: calc( 100% - 32px );
604 flex-direction: row;
605 justify-content: center;
606 /* Top padding is 4px instead of 8px so that the inner `__scroll`
607 * wrapper can claim its own 4px padding-top for badge clearance
608 * (the tile's badge sits at top: -3px). Net vertical chrome stays
609 * symmetric: 4px pill padding + 4px wrapper padding above the
610 * tile, 8px pill padding below — tile is 8px from both edges. */
611 padding: 4px 12px 8px;
612 gap: 6px;
613 border-radius: 18px;
614
615 /* Warmer, more saturated glass tint than vertical placements so
616 * the floating pill reads as a distinct piece of chrome rather
617 * than a section of the sidebar. */
618 background: rgba( 22, 22, 26, 0.42 );
619 backdrop-filter: blur( 28px ) saturate( 170% );
620 -webkit-backdrop-filter: blur( 28px ) saturate( 170% );
621
622 border: 1px solid rgba( 255, 255, 255, 0.12 );
623 border-block-start: 1px solid rgba( 255, 255, 255, 0.18 );
624 box-shadow:
625 inset 0 1px 0 rgba( 255, 255, 255, 0.08 ),
626 0 10px 32px rgba( 0, 0, 0, 0.45 );
627 }
628
629 /* Active-indicator dot — below the tile, macOS-style. */
630 .desktop-mode-dock[ data-desktop-mode-dock-placement="bottom" ]
631 .desktop-mode-dock__item--active::before {
632 content: "";
633 position: absolute;
634 inset-inline-start: 50%;
635 top: auto;
636 bottom: -4px;
637 transform: translateX( -50% );
638 width: 4px;
639 height: 4px;
640 border-radius: 50%;
641 background: #fff;
642 }
643
644 .desktop-mode-dock[ data-desktop-mode-dock-placement="bottom" ]
645 .desktop-mode-dock__item--focused::before {
646 width: 16px;
647 height: 4px;
648 border-radius: 2px;
649 }
650
651 /*
652 * "All instances minimized" on the bottom dock — solid dot becomes
653 * a hollow ring. Matches the vertical-dock treatment so the cue is
654 * consistent across placements.
655 */
656 .desktop-mode-dock[ data-desktop-mode-dock-placement="bottom" ]
657 .desktop-mode-dock__item--all-minimized::before {
658 width: 6px;
659 height: 6px;
660 border-radius: 50%;
661 background: transparent;
662 border: 1px solid rgba( 255, 255, 255, 0.85 );
663 }
664
665 /*
666 * Global "Show Desktop" indicator — set on `<body>` by the dock when
667 * every live window on the active desktop is in the minimized state.
668 * The bottom-dock pill picks up a soft theme-color ring so the user
669 * has a global cue that the windows haven't disappeared, they're just
670 * minimized. ArrowUp / a wallpaper click / clicking any dock tile
671 * brings them back; without this the empty wallpaper looks identical
672 * to a freshly-loaded desktop with no windows open.
673 */
674 body.desktop-mode-show-desktop-active
675 .desktop-mode-dock[ data-desktop-mode-dock-placement="bottom" ] {
676 box-shadow:
677 inset 0 0 0 1px var( --wp-admin-theme-color, rgba( 255, 255, 255, 0.45 ) ),
678 inset 0 1px 0 rgba( 255, 255, 255, 0.08 ),
679 0 10px 32px rgba( 0, 0, 0, 0.45 );
680 }
681
682 /* Vertical docks get the same treatment along their inner edge. */
683 body.desktop-mode-show-desktop-active
684 .desktop-mode-dock[ data-desktop-mode-dock-placement="left" ],
685 body.desktop-mode-show-desktop-active
686 .desktop-mode-dock[ data-desktop-mode-dock-placement="right" ] {
687 box-shadow: inset 0 0 0 1px var( --wp-admin-theme-color, rgba( 255, 255, 255, 0.45 ) );
688 }
689
690 /* "Open another" chip — floats above the tile's top-right corner so
691 * it doesn't collide with neighbouring tiles in the horizontal row. */
692 .desktop-mode-dock[ data-desktop-mode-dock-placement="bottom" ]
693 .desktop-mode-dock__item-new {
694 top: -6px;
695 inset-inline-end: -6px;
696 transform: none;
697 }
698
699 .desktop-mode-dock[ data-desktop-mode-dock-placement="bottom" ]
700 .desktop-mode-dock__item-new:hover {
701 transform: scale( 1.1 );
702 }
703
704 /*
705 * Bottom-dock inner wrappers — `__scroll` carries the menu tiles and
706 * absorbs horizontal overflow; `__pinned` carries the system tiles and
707 * stays anchored to the trailing edge. Padding-top on `__scroll` gives
708 * the badge (top: -3px on the tile) room so `overflow-y: hidden`
709 * doesn't crop it. `min-width: 0` lets the wrapper shrink below its
710 * content's natural width, so the dock pill's `max-width` is what
711 * decides when scroll kicks in instead of the content forcing the
712 * pill wider. `justify-content: center` keeps tiles balanced inside
713 * the pill when content fits; when it overflows, scroll engages and
714 * items extend past the visible area.
715 */
716 .desktop-mode-dock[ data-desktop-mode-dock-placement="bottom" ] .desktop-mode-dock__scroll {
717 display: flex;
718 flex-direction: row;
719 align-items: center;
720 justify-content: center;
721 gap: 6px;
722 flex: 1 1 auto;
723 min-width: 0;
724 padding-top: 4px;
725 overflow-x: auto;
726 overflow-y: hidden;
727 scrollbar-width: none;
728 }
729
730 .desktop-mode-dock[ data-desktop-mode-dock-placement="bottom" ] .desktop-mode-dock__scroll::-webkit-scrollbar {
731 display: none;
732 }
733
734 .desktop-mode-dock[ data-desktop-mode-dock-placement="bottom" ] .desktop-mode-dock__pinned {
735 display: flex;
736 flex-direction: row;
737 align-items: center;
738 gap: 6px;
739 flex-shrink: 0;
740 /* Match the scroll wrapper's badge clearance so system tiles sit
741 * on the same vertical baseline as the menu tiles. */
742 padding-top: 4px;
743 }
744
745 /* Separator — vertical hairline between menu tiles and system tiles.
746 * Lives at the leading edge of `__pinned`; flex flow handles the
747 * "pinned at the trailing edge" placement, no margin-inline-start:
748 * auto needed. The `--group` variant keeps the hairline styling for
749 * the inline core→plugin boundary inside `__scroll` and sits where
750 * inserted. */
751 .desktop-mode-dock[ data-desktop-mode-dock-placement="bottom" ]
752 .desktop-mode-dock__separator {
753 width: 1px;
754 /* Fixed height — `60%` collapses against the floating pill's
755 intrinsic height, leaving the hairline effectively invisible.
756 28px matches the dock tile inner glyph area. */
757 height: 28px;
758 margin: auto 4px auto 8px;
759 background: var( --desktop-mode-dock-border );
760 flex-shrink: 0;
761 }
762
763 /*
764 * Group separator — sits inline between the core cluster and the
765 * plugin cluster. Brighter than the menu-vs-system separator because
766 * it carries user meaning ("this is where your installed apps
767 * begin"), and flanked by extra gap so the boundary reads at a
768 * glance rather than disappearing into the dock tint.
769 */
770 .desktop-mode-dock[ data-desktop-mode-dock-placement="bottom" ]
771 .desktop-mode-dock__separator--group {
772 width: 1px;
773 height: 60%;
774 margin: auto 10px;
775 margin-inline-start: 10px;
776 background: rgba( 255, 255, 255, 0.22 );
777 flex-shrink: 0;
778 }
779
780 /* Tooltip — above the hovered tile. JS writes the horizontal center
781 * + a top near the tile's top edge; CSS translates the tooltip up by
782 * its own height so it clears the tile. */
783 .desktop-mode-dock__tooltip--above {
784 inset-inline-start: auto;
785 transform: translate( -50%, calc( -100% - 4px ) );
786 }
787
788 .desktop-mode-dock__tooltip--above.desktop-mode-dock__tooltip--visible {
789 transform: translate( -50%, -100% );
790 }
791
792
793
794 /* Drag-to-reorder (since 0.25.0).
795 *
796 * The dragged tile follows the cursor via inline `transform:
797 * translate()` written from JS. It stays IN flow so flex doesn't
798 * collapse the row — the visual lift is a z-index bump and
799 * `pointer-events: none` so `elementFromPoint` finds siblings
800 * underneath the cursor. Sibling tiles animate via FLIP — the JS
801 * writes inline `transform` + `transition` per leg, so no CSS
802 * transition is declared here (it would race with the per-leg
803 * inline transition). */
804 .desktop-mode-dock__item--dragging {
805 pointer-events: none;
806 z-index: 50;
807 opacity: 0.92;
808 cursor: grabbing;
809 will-change: transform;
810 /* Subtle shadow so the dragged tile reads as "lifted" against
811 * the dock surface it floats above. */
812 filter: drop-shadow( 0 6px 12px rgba( 0, 0, 0, 0.35 ) );
813 }
814
815 .desktop-mode-dock__item:not( .desktop-mode-dock__item--system ) {
816 cursor: grab;
817 }
818
819 .desktop-mode-dock__item:not( .desktop-mode-dock__item--system ):active {
820 cursor: grabbing;
821 }
822