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

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

1,041 lines 23.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Native Plugins window — shell + tab styles.
3 *
4 * Bundle iterates fast; this stylesheet is `filemtime`-cache-busted
5 * via `wp_register_style`. Heavy view-specific styles (gallery
6 * cards, detail-flyout hero) ship here too so a single CSS handle
7 * covers the whole window.
8 */
9
10 .desktop-mode-plugins {
11 display: flex;
12 flex-direction: column;
13 height: 100%;
14 width: 100%;
15 min-height: 0;
16 min-width: 0;
17 max-width: 100%;
18 /* Clip horizontal overflow at every level — `<os-flyout>` when
19 * closed sits at `transform: translateX(110%)` and would
20 * otherwise create a phantom scroll out to its off-screen
21 * resting position. We need `overflow-x` AND `position:
22 * relative` so the flyout's `position: absolute` containing
23 * block resolves to THIS element (not a higher ancestor). */
24 overflow-x: hidden;
25 overflow-y: hidden;
26 position: relative;
27 box-sizing: border-box;
28 }
29
30 .os-plugins__tabs {
31 border-block-end: 1px solid var( --os-ui-border, rgba( 0, 0, 0, 0.08 ) );
32 flex: 0 0 auto;
33 }
34
35 .os-plugins__panel {
36 flex: 1 1 auto;
37 min-height: 0;
38 min-width: 0;
39 max-width: 100%;
40 display: flex;
41 flex-direction: column;
42 box-sizing: border-box;
43 /* Belt + braces — never let a child stretch the panel past the
44 * window width. Earlier the right-hand side of the window would
45 * scroll into empty space because the os-table host was sized
46 * by content rather than container. */
47 overflow: hidden;
48 }
49
50 /* Honour the `hidden` attribute — `<os-tabs>` toggles it on inactive
51 * panels, but our explicit `display: flex` above wins by specificity.
52 * Without this rule every panel renders concurrently in the first
53 * panel slot. */
54 .os-plugins__panel[ hidden ] {
55 display: none;
56 }
57
58 .os-plugins__installed,
59 .os-plugins__browse {
60 flex: 1 1 auto;
61 min-height: 0;
62 display: flex;
63 flex-direction: column;
64 }
65
66 /* ─── Toolbar ───────────────────────────────────────────────────── */
67
68 .os-plugins__toolbar {
69 display: flex;
70 align-items: center;
71 gap: 12px;
72 padding: 12px 16px;
73 border-block-end: 1px solid var( --os-ui-border, rgba( 0, 0, 0, 0.08 ) );
74 flex-wrap: wrap;
75 }
76
77 .os-plugins__toolbar-left {
78 display: flex;
79 align-items: center;
80 gap: 12px;
81 flex: 1 1 auto;
82 min-width: 0;
83 }
84
85 .os-plugins__toolbar-left os-text-field {
86 flex: 1 1 240px;
87 min-width: 200px;
88 max-width: 360px;
89 }
90
91 .os-plugins__toolbar-right {
92 display: flex;
93 align-items: center;
94 gap: 8px;
95 }
96
97 .os-plugins__toolbar-trailing {
98 display: flex;
99 align-items: center;
100 gap: 6px;
101 }
102
103 .os-plugins__bulk {
104 display: flex;
105 align-items: center;
106 gap: 8px;
107 padding-inline: 8px;
108 }
109
110 .os-plugins__bulk-count {
111 font-size: 0.85em;
112 color: var( --os-ui-fg-muted, #555 );
113 }
114
115 /* ─── Body / table ──────────────────────────────────────────────── */
116
117 .os-plugins__body {
118 flex: 1 1 auto;
119 min-height: 0;
120 min-width: 0;
121 max-width: 100%;
122 overflow: hidden;
123 display: flex;
124 flex-direction: column;
125 box-sizing: border-box;
126 /* Inset matching the Posts/Pages/Users windows so the table
127 * doesn't kiss the window's left/right borders. */
128 padding: 8px 12px 12px;
129 }
130
131 .os-plugins__body os-table {
132 flex: 1 1 auto;
133 min-height: 0;
134 min-width: 0;
135 max-width: 100%;
136 width: 100%;
137 box-sizing: border-box;
138 /* The `<os-table>` ships with its own scroll container, but it
139 * needs a constrained height to know when to start scrolling.
140 * Without `--os-ui-table-max-height` set, sticky-header silently
141 * disables itself and the table grows to its full intrinsic
142 * height instead of scrolling inside the panel.
143 *
144 * NO `overflow` here — os-table's internal `.scroll` div
145 * handles scrolling. An outer `overflow: auto` here was
146 * causing a phantom horizontal scrollbar that revealed empty
147 * space to the right of the table because the host was sized
148 * by content (icon cell + actions cell) rather than container. */
149 --os-ui-table-max-height: 100%;
150 }
151
152 .os-plugins__empty {
153 text-align: center;
154 padding: 32px 16px;
155 color: var( --os-ui-fg-muted, #666 );
156 }
157
158 .os-plugins__empty .dashicons {
159 font-size: 32px;
160 width: 32px;
161 height: 32px;
162 display: inline-block;
163 margin-block-end: 8px;
164 opacity: 0.6;
165 }
166
167 /* ─── Cells ─────────────────────────────────────────────────────── */
168
169 .os-plugins__name-cell {
170 display: flex;
171 align-items: center;
172 gap: 12px;
173 min-width: 0;
174 padding-block: 4px;
175 }
176
177 .os-plugins__name-icon {
178 flex: 0 0 40px;
179 width: 40px;
180 height: 40px;
181 max-width: 40px;
182 max-height: 40px;
183 border-radius: 8px;
184 overflow: hidden;
185 display: inline-flex;
186 align-items: center;
187 justify-content: center;
188 background: var( --os-ui-surface-sunken, rgba( 0, 0, 0, 0.04 ) );
189 }
190
191 /* Hard-clamp the inner image too — wp.org SVG icons are unsized,
192 * which left the user agent stretching them to the document's full
193 * width when the parent ever became `auto`. */
194 .os-plugins__name-icon img,
195 .os-plugins__name-icon svg {
196 width: 100%;
197 height: 100%;
198 max-width: 100%;
199 max-height: 100%;
200 object-fit: contain;
201 display: block;
202 transition: opacity 180ms ease;
203 }
204
205 .os-plugins__name-icon-fallback {
206 font-size: 22px;
207 width: 22px;
208 height: 22px;
209 line-height: 22px;
210 color: var( --os-ui-fg-muted, #888 );
211 }
212
213 .os-plugins__name-text {
214 display: flex;
215 flex-direction: column;
216 gap: 2px;
217 min-width: 0;
218 flex: 1 1 auto;
219 }
220
221 /* Force the title + path to actually stack — `<strong>` and `<span>`
222 * are `display: inline` by default, and `display: flex` on the
223 * parent doesn't always force flex-item layout when the cell
224 * surrounding them comes from a third-party component (the user
225 * reported them rendering on the same line). */
226 .os-plugins__name-text > strong,
227 .os-plugins__name-text > span {
228 display: block;
229 }
230
231 .os-plugins__name-text > strong {
232 font-weight: 600;
233 white-space: nowrap;
234 overflow: hidden;
235 text-overflow: ellipsis;
236 }
237
238 .os-plugins__name-path {
239 font-size: 0.78em;
240 color: var( --os-ui-fg-muted, #888 );
241 font-family: var( --os-ui-font-mono, ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace );
242 white-space: nowrap;
243 overflow: hidden;
244 text-overflow: ellipsis;
245 }
246
247 .os-plugins__badge {
248 display: inline-flex;
249 align-items: center;
250 gap: 6px;
251 padding: 2px 10px 2px 8px;
252 border-radius: 999px;
253 font-size: 0.78em;
254 font-weight: 600;
255 letter-spacing: 0.01em;
256 text-transform: none;
257 line-height: 1.4;
258 white-space: nowrap;
259 }
260
261 /* Coloured dot prepended to the badge label — provides the
262 * status-at-a-glance signal without relying on text alone. */
263 .os-plugins__badge::before {
264 content: '';
265 width: 6px;
266 height: 6px;
267 border-radius: 50%;
268 background: currentColor;
269 flex: 0 0 auto;
270 display: inline-block;
271 }
272
273 .os-plugins__badge.is-active {
274 background: rgba( 35, 165, 90, 0.14 );
275 color: rgb( 22, 110, 55 );
276 }
277
278 .os-plugins__badge.is-inactive {
279 background: rgba( 120, 120, 120, 0.12 );
280 color: var( --os-ui-fg-muted, #555 );
281 }
282
283 .os-plugins__version-cell {
284 display: flex;
285 align-items: center;
286 gap: 6px;
287 flex-wrap: wrap;
288 }
289
290 .os-plugins__update-badge {
291 font-size: 0.78em;
292 background: var( --os-ui-notice-warning-bg, rgba( 250, 175, 0, 0.18 ) );
293 color: var( --os-ui-warning-fg, rgb( 145, 95, 0 ) );
294 padding: 1px 7px;
295 border-radius: 999px;
296 font-weight: 600;
297 }
298
299 .os-plugins__author-cell {
300 white-space: nowrap;
301 overflow: hidden;
302 text-overflow: ellipsis;
303 }
304
305 .os-plugins__row-actions {
306 display: inline-flex;
307 gap: 8px;
308 align-items: center;
309 justify-content: flex-end;
310 flex-wrap: nowrap;
311 }
312
313 .os-plugins__row-actions os-button {
314 flex: 0 0 auto;
315 }
316
317 /* ─── Browse — gallery ──────────────────────────────────────────── */
318
319 .os-plugins__gallery {
320 display: grid;
321 grid-template-columns: repeat( auto-fill, minmax( 280px, 1fr ) );
322 gap: 14px;
323 padding: 16px;
324 flex: 1 1 auto;
325 min-height: 0;
326 min-width: 0;
327 max-width: 100%;
328 /* Vertical scroll only — `auto-fill` with `1fr` already prevents
329 * children from exceeding the container width, but we still
330 * clamp `overflow-x` defensively so a misbehaving card can't
331 * stretch the gallery. */
332 overflow-x: hidden;
333 overflow-y: auto;
334 align-content: start;
335 box-sizing: border-box;
336 }
337
338 .os-plugins__gallery-sentinel {
339 height: 1px;
340 }
341
342 .os-plugins__gallery-status {
343 padding: 12px 16px;
344 color: var( --os-ui-fg-muted, #666 );
345 text-align: center;
346 margin: 0;
347 }
348
349 /* ─── Browse — card ─────────────────────────────────────────────── */
350
351 /* The card chrome (padding, gap, border, radius, hover lift, focus
352 * ring, reduced-motion fallback) all comes from `<os-card>` —
353 * `:host([interactive])` handles the hover transform, the kit's
354 * `prefers-reduced-motion` rule kills the transition. We layer
355 * gallery-specific tweaks here; nothing duplicates the kit. */
356
357 .os-plugins__card.os-plugins__card--skeleton {
358 gap: 8px;
359 }
360
361 .os-plugins__card-header {
362 display: flex;
363 gap: 12px;
364 align-items: center;
365 }
366
367 .os-plugins__card-icon {
368 flex: 0 0 auto;
369 width: 56px;
370 height: 56px;
371 border-radius: 10px;
372 overflow: hidden;
373 display: inline-flex;
374 align-items: center;
375 justify-content: center;
376 background: var( --os-ui-surface-sunken, rgba( 0, 0, 0, 0.04 ) );
377 }
378
379 .os-plugins__card-icon img {
380 width: 100%;
381 height: 100%;
382 object-fit: contain;
383 opacity: 0;
384 transition: opacity 180ms ease;
385 }
386
387 .os-plugins__card-icon img.is-loaded {
388 opacity: 1;
389 }
390
391 .os-plugins__card-icon-fallback {
392 font-size: 28px;
393 width: 28px;
394 height: 28px;
395 color: var( --os-ui-fg-muted, #888 );
396 }
397
398 .os-plugins__card-titleblock {
399 min-width: 0;
400 flex: 1 1 auto;
401 }
402
403 .os-plugins__card-title {
404 margin: 0 0 2px 0;
405 font-size: 1rem;
406 font-weight: 600;
407 white-space: nowrap;
408 overflow: hidden;
409 text-overflow: ellipsis;
410 }
411
412 .os-plugins__card-byline {
413 margin: 0;
414 color: var( --os-ui-fg-muted, #777 );
415 font-size: 0.82rem;
416 white-space: nowrap;
417 overflow: hidden;
418 text-overflow: ellipsis;
419 }
420
421 .os-plugins__card-desc {
422 margin: 0;
423 color: var( --os-ui-fg, #333 );
424 font-size: 0.88rem;
425 line-height: 1.45;
426 display: -webkit-box;
427 -webkit-line-clamp: 3;
428 line-clamp: 3;
429 -webkit-box-orient: vertical;
430 overflow: hidden;
431 }
432
433 .os-plugins__card-footer {
434 display: flex;
435 align-items: center;
436 justify-content: space-between;
437 gap: 8px;
438 margin-top: auto;
439 }
440
441 .os-plugins__card-meta {
442 display: flex;
443 flex-direction: column;
444 gap: 2px;
445 font-size: 0.78rem;
446 color: var( --os-ui-fg-muted, #666 );
447 }
448
449 /* ─── Stars ─────────────────────────────────────────────────────── */
450
451 .os-plugins__stars {
452 display: inline-flex;
453 align-items: center;
454 gap: 2px;
455 }
456
457 .os-plugins__star .dashicons {
458 font-size: 14px;
459 width: 14px;
460 height: 14px;
461 color: rgb( 245, 175, 0 );
462 }
463
464 .os-plugins__star .dashicons-star-empty {
465 color: var( --os-ui-fg-muted, rgba( 0, 0, 0, 0.25 ) );
466 }
467
468 .os-plugins__stars-count {
469 margin-inline-start: 4px;
470 color: var( --os-ui-fg-muted, #888 );
471 font-size: 0.78em;
472 }
473
474 .os-plugins__card-installs {
475 font-size: 0.78em;
476 color: var( --os-ui-fg-muted, #888 );
477 }
478
479 /* ─── Skeleton lines (gallery + flyout) ─────────────────────────── */
480
481 .os-plugins__skeleton {
482 display: flex;
483 flex-direction: column;
484 gap: 8px;
485 padding: 16px;
486 }
487
488 .os-plugins__skeleton-line {
489 display: block;
490 height: 12px;
491 border-radius: 4px;
492 background: linear-gradient(
493 90deg,
494 rgba( 0, 0, 0, 0.06 ) 0%,
495 rgba( 0, 0, 0, 0.10 ) 50%,
496 rgba( 0, 0, 0, 0.06 ) 100%
497 );
498 background-size: 200% 100%;
499 animation: dm-plugins-shimmer 1.4s linear infinite;
500 }
501
502 @keyframes dm-plugins-shimmer {
503 from {
504 background-position: 100% 0;
505 }
506 to {
507 background-position: -100% 0;
508 }
509 }
510
511 @media ( prefers-reduced-motion: reduce ) {
512 .os-plugins__skeleton-line {
513 animation: none;
514 }
515 }
516
517 /* ─── Flyout detail ─────────────────────────────────────────────── */
518
519 [data-os-plugins-flyout] {
520 width: min( 560px, calc( 100% - 28px ) );
521 }
522
523 .os-plugins__flyout {
524 display: flex;
525 flex-direction: column;
526 height: 100%;
527 min-height: 0;
528 }
529
530 .os-plugins__flyout-hero {
531 position: relative;
532 padding: 16px 56px 14px 18px;
533 border-block-end: 1px solid var( --os-ui-border, rgba( 0, 0, 0, 0.08 ) );
534 flex: 0 0 auto;
535 overflow: hidden;
536 /* Mirror the flyout shell's outer corner radius (`<os-flyout>`
537 * uses 14px) so a banner background-image stops at the rounded
538 * top edge instead of bleeding past it. */
539 border-start-start-radius: 14px;
540 border-start-end-radius: 14px;
541 }
542
543 /* ─── Flyout close — circular glass button ──────────────────────── */
544
545 .os-plugins__flyout-close {
546 position: absolute;
547 inset-block-start: 12px;
548 inset-inline-end: 12px;
549 width: 32px;
550 height: 32px;
551 padding: 0;
552 /* Glass close button. Tokenized so it follows the palette: a white
553 disc on a dark flyout is the one control you cannot miss, in the
554 wrong sense. Literals unchanged for the unthemed look. */
555 border: 1px solid var( --os-ui-border, rgba( 0, 0, 0, 0.08 ) );
556 border-radius: 50%;
557 background: var( --os-ui-surface, rgba( 255, 255, 255, 0.78 ) );
558 -webkit-backdrop-filter: blur( 12px ) saturate( 160% );
559 backdrop-filter: blur( 12px ) saturate( 160% );
560 box-shadow:
561 0 1px 4px rgba( 0, 0, 0, 0.10 ),
562 0 0 0 1px rgba( 255, 255, 255, 0.4 ) inset;
563 color: var( --os-ui-fg, #333 );
564 display: inline-flex;
565 align-items: center;
566 justify-content: center;
567 cursor: pointer;
568 z-index: 2;
569 transition:
570 transform 150ms ease,
571 background 150ms ease,
572 border-color 150ms ease,
573 box-shadow 150ms ease;
574 }
575
576 .os-plugins__flyout-close:hover {
577 background: var( --os-ui-surface-elevated, rgba( 255, 255, 255, 0.96 ) );
578 transform: scale( 1.06 );
579 border-color: var( --os-ui-border-strong, rgba( 0, 0, 0, 0.16 ) );
580 box-shadow:
581 0 4px 10px rgba( 0, 0, 0, 0.14 ),
582 0 0 0 1px rgba( 255, 255, 255, 0.5 ) inset;
583 }
584
585 .os-plugins__flyout-close:active {
586 transform: scale( 0.96 );
587 }
588
589 .os-plugins__flyout-close:focus-visible {
590 outline: 2px solid var( --wp-admin-theme-color, #2271b1 );
591 outline-offset: 2px;
592 }
593
594 @media ( prefers-reduced-motion: reduce ) {
595 .os-plugins__flyout-close {
596 transition: none;
597 }
598 .os-plugins__flyout-close:hover,
599 .os-plugins__flyout-close:active {
600 transform: none;
601 }
602 }
603
604 .os-plugins__flyout-banner {
605 position: absolute;
606 inset: 0;
607 background-size: cover;
608 background-position: center;
609 opacity: 0;
610 transition: opacity 220ms ease;
611 z-index: 0;
612 }
613
614 .os-plugins__flyout-banner.has-banner {
615 opacity: 0.18;
616 }
617
618 .os-plugins__flyout-hero-inner {
619 position: relative;
620 display: flex;
621 gap: 12px;
622 align-items: center;
623 z-index: 1;
624 }
625
626 .os-plugins__flyout-hero-icon {
627 width: 64px;
628 height: 64px;
629 border-radius: 12px;
630 overflow: hidden;
631 background: var( --os-ui-surface-sunken, rgba( 0, 0, 0, 0.04 ) );
632 flex: 0 0 auto;
633 display: inline-flex;
634 align-items: center;
635 justify-content: center;
636 }
637
638 .os-plugins__flyout-hero-icon img {
639 width: 100%;
640 height: 100%;
641 object-fit: contain;
642 }
643
644 .os-plugins__flyout-hero-text {
645 flex: 1 1 auto;
646 min-width: 0;
647 }
648
649 .os-plugins__flyout-hero-title {
650 margin: 0 0 4px;
651 font-size: 1.2rem;
652 font-weight: 600;
653 }
654
655 .os-plugins__flyout-hero-byline {
656 margin: 0 0 6px;
657 color: var( --os-ui-fg-muted, #666 );
658 }
659
660 .os-plugins__flyout-meta-row {
661 display: flex;
662 flex-wrap: wrap;
663 gap: 4px 16px;
664 font-size: 0.78rem;
665 color: var( --os-ui-fg-muted, #666 );
666 margin-top: 6px;
667 }
668
669 .os-plugins__flyout-tabs {
670 flex: 0 0 auto;
671 border-block-end: 1px solid var( --os-ui-border, rgba( 0, 0, 0, 0.08 ) );
672 }
673
674 .os-plugins__flyout-body {
675 padding: 16px 18px;
676 flex: 1 1 auto;
677 overflow: auto;
678 min-height: 0;
679 }
680
681 .os-plugins__flyout-footer {
682 display: flex;
683 align-items: center;
684 justify-content: space-between;
685 gap: 8px;
686 padding: 12px 16px;
687 border-block-start: 1px solid var( --os-ui-border, rgba( 0, 0, 0, 0.08 ) );
688 flex: 0 0 auto;
689 }
690
691 .os-plugins__flyout-footer-right {
692 display: inline-flex;
693 gap: 6px;
694 }
695
696 .os-plugins__flyout-wporg {
697 font-size: 0.86rem;
698 }
699
700 .os-plugins__flyout-error {
701 color: rgb( 184, 50, 50 );
702 padding: 16px;
703 }
704
705 /* ─── Histogram (Reviews tab) ───────────────────────────────────── */
706
707 .os-plugins__histogram {
708 display: flex;
709 flex-direction: column;
710 gap: 6px;
711 margin-block-end: 16px;
712 }
713
714 .os-plugins__histogram-row {
715 display: grid;
716 grid-template-columns: 32px 1fr 48px;
717 gap: 8px;
718 align-items: center;
719 font-size: 0.82rem;
720 }
721
722 .os-plugins__histogram-track {
723 background: var( --os-ui-surface-sunken, rgba( 0, 0, 0, 0.06 ) );
724 border-radius: 999px;
725 height: 6px;
726 overflow: hidden;
727 }
728
729 .os-plugins__histogram-fill {
730 display: block;
731 height: 100%;
732 background: rgb( 245, 175, 0 );
733 border-radius: 999px;
734 transition: width 220ms ease;
735 }
736
737 .os-plugins__histogram-count {
738 color: var( --os-ui-fg-muted, #777 );
739 text-align: end;
740 }
741
742 .os-plugins__reviews-list {
743 display: flex;
744 flex-direction: column;
745 gap: 12px;
746 }
747
748 .os-plugins__review {
749 border: 1px solid var( --os-ui-border, rgba( 0, 0, 0, 0.08 ) );
750 border-radius: 10px;
751 padding: 12px 14px;
752 background: var( --os-ui-card-bg, #fff );
753 }
754
755 .os-plugins__review-head {
756 display: flex;
757 align-items: center;
758 gap: 12px;
759 margin-block-end: 6px;
760 flex-wrap: wrap;
761 }
762
763 .os-plugins__review-author {
764 font-weight: 600;
765 }
766
767 .os-plugins__review-date {
768 margin-inline-start: auto;
769 font-size: 0.78em;
770 color: var( --os-ui-fg-muted, #888 );
771 }
772
773 .os-plugins__review-excerpt {
774 margin: 0;
775 font-size: 0.92em;
776 line-height: 1.5;
777 color: var( --os-ui-fg, #333 );
778 }
779
780 .os-plugins__review-link {
781 display: inline-block;
782 margin-block-start: 6px;
783 font-size: 0.82em;
784 }
785
786 .os-plugins__reviews-loading,
787 .os-plugins__reviews-fallback {
788 color: var( --os-ui-fg-muted, #888 );
789 font-size: 0.92em;
790 }
791
792 .os-plugins__html {
793 font-size: 0.92rem;
794 line-height: 1.5;
795 }
796
797 .os-plugins__html h3,
798 .os-plugins__html h4 {
799 margin-top: 1em;
800 }
801
802 .os-plugins__screenshots {
803 display: flex;
804 flex-direction: column;
805 gap: 14px;
806 }
807
808 .os-plugins__screenshot img {
809 max-width: 100%;
810 border-radius: 8px;
811 border: 1px solid var( --os-ui-border, rgba( 0, 0, 0, 0.08 ) );
812 }
813
814 .os-plugins__screenshot figcaption {
815 font-size: 0.84rem;
816 color: var( --os-ui-fg-muted, #666 );
817 margin-top: 6px;
818 }
819
820 /* ─── Upload dialog ─────────────────────────────────────────────── */
821
822 .os-plugins__upload-overlay {
823 position: absolute;
824 inset: 0;
825 background: var( --os-ui-scrim, rgba( 0, 0, 0, 0.32 ) );
826 display: flex;
827 align-items: center;
828 justify-content: center;
829 z-index: 20;
830 animation: dm-plugins-fade-in 180ms ease both;
831 }
832
833 .os-plugins__upload-card {
834 width: min( 480px, calc( 100% - 32px ) );
835 background: var( --os-ui-card-bg, #fff );
836 border-radius: 14px;
837 padding: 22px 22px 18px;
838 box-shadow: 0 16px 48px rgba( 0, 0, 0, 0.32 );
839 animation: dm-plugins-pop-in 220ms cubic-bezier( 0.22, 1, 0.36, 1 ) both;
840 }
841
842 @keyframes dm-plugins-fade-in {
843 from { opacity: 0; }
844 to { opacity: 1; }
845 }
846
847 @keyframes dm-plugins-pop-in {
848 from { transform: scale( 0.96 ); opacity: 0; }
849 to { transform: none; opacity: 1; }
850 }
851
852 @media ( prefers-reduced-motion: reduce ) {
853 .os-plugins__upload-overlay,
854 .os-plugins__upload-card {
855 animation: none;
856 }
857 }
858
859 .os-plugins__upload-heading {
860 margin: 0 0 4px;
861 font-size: 1.1rem;
862 }
863
864 .os-plugins__upload-lede {
865 margin: 0 0 16px;
866 color: var( --os-ui-fg-muted, #666 );
867 font-size: 0.9em;
868 }
869
870 .os-plugins__upload-dropzone {
871 border: 2px dashed var( --os-ui-border-strong, rgba( 0, 0, 0, 0.18 ) );
872 border-radius: 12px;
873 padding: 24px 16px;
874 text-align: center;
875 cursor: pointer;
876 transition: border-color 150ms ease, background 150ms ease;
877 }
878
879 .os-plugins__upload-dropzone.is-hovered,
880 .os-plugins__upload-dropzone.has-file {
881 border-color: var( --wp-admin-theme-color, #2271b1 );
882 background: rgba( 34, 113, 177, 0.05 );
883 }
884
885 .os-plugins__upload-icon {
886 font-size: 32px;
887 width: 32px;
888 height: 32px;
889 color: var( --os-ui-fg-muted, #888 );
890 margin-block-end: 6px;
891 }
892
893 .os-plugins__upload-hint {
894 margin: 0 0 4px;
895 }
896
897 .os-plugins__upload-filename {
898 margin: 0;
899 font-size: 0.86em;
900 color: var( --os-ui-fg, #333 );
901 font-family: var( --os-ui-font-mono, ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace );
902 }
903
904 .os-plugins__upload-status {
905 margin: 12px 0 0;
906 font-size: 0.86em;
907 }
908
909 .os-plugins__upload-status[ data-tone='error' ] {
910 color: rgb( 184, 50, 50 );
911 }
912
913 .os-plugins__upload-status[ data-tone='success' ] {
914 color: rgb( 25, 120, 65 );
915 }
916
917 .os-plugins__upload-actions {
918 display: flex;
919 justify-content: flex-end;
920 gap: 8px;
921 margin-block-start: 14px;
922 }
923
924 .os-plugins__upload-success-heading {
925 margin: 4px 0 6px;
926 font-size: 1rem;
927 color: rgb( 25, 120, 65 );
928 }
929
930 .os-plugins__upload-success-detail {
931 margin: 0 0 6px;
932 color: var( --os-ui-fg, #333 );
933 font-family: var( --os-ui-font-mono, ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace );
934 font-size: 0.9em;
935 }
936
937 /* ─── Window-level .zip drop overlay ────────────────────────────── */
938
939 .os-plugins__window-drop {
940 position: absolute;
941 inset: 12px;
942 border: 2px dashed var( --wp-admin-theme-color, #2271b1 );
943 border-radius: 14px;
944 background: rgba( 34, 113, 177, 0.08 );
945 color: var( --wp-admin-theme-color, #2271b1 );
946 display: flex;
947 align-items: center;
948 justify-content: center;
949 font-size: 1.05rem;
950 font-weight: 600;
951 pointer-events: none;
952 opacity: 0;
953 transition: opacity 180ms ease;
954 z-index: 9;
955 }
956
957 .has-zip-dragover .os-plugins__window-drop {
958 opacity: 1;
959 }
960
961 /* ─── Drag ghost ────────────────────────────────────────────────── */
962
963 .os-plugins__drag-ghost {
964 display: inline-flex;
965 align-items: center;
966 gap: 8px;
967 padding: 8px 14px;
968 background: var( --os-ui-card-bg, #fff );
969 border-radius: 999px;
970 box-shadow: 0 6px 20px rgba( 0, 0, 0, 0.18 );
971 font-size: 0.92rem;
972 font-weight: 600;
973 max-width: 240px;
974 white-space: nowrap;
975 overflow: hidden;
976 text-overflow: ellipsis;
977 }
978
979 .os-plugins__drag-ghost img {
980 width: 24px;
981 height: 24px;
982 border-radius: 6px;
983 }
984
985 .os-plugins__drag-ghost-fallback {
986 color: var( --os-ui-fg-muted, #888 );
987 font-size: 22px;
988 }
989
990 [ data-plugins-card-drop-active ] {
991 outline: 2px dashed var( --wp-admin-theme-color, #2271b1 );
992 outline-offset: 2px;
993 }
994 /* Row-click cue — pointer-cursor on Installed-tab body rows so users
995 * discover that clicking the plugin name expands the detail panel.
996 * `<os-table>` exposes each body `<tr>` as a `row` shadow part. */
997
998 os-table[ data-installed-rows ]::part( row ) {
999 cursor: pointer;
1000 }
1001
1002 /* ─── Featured tab ─────────────────────────────────────────────── */
1003
1004 .os-plugins__featured {
1005 display: flex;
1006 flex-direction: column;
1007 min-height: 0;
1008 flex: 1 1 auto;
1009 }
1010
1011 .os-plugins__featured-intro {
1012 padding: 20px 20px 4px;
1013 display: flex;
1014 flex-direction: column;
1015 gap: 4px;
1016 }
1017
1018 .os-plugins__featured-heading {
1019 margin: 0;
1020 font-size: 1.15em;
1021 font-weight: 600;
1022 }
1023
1024 .os-plugins__featured-blurb {
1025 margin: 0;
1026 color: var( --os-ui-fg-muted, #666 );
1027 font-size: 0.9em;
1028 line-height: 1.45;
1029 }
1030
1031 /* Curated cards get a soft inset border + a `<os-ribbon>` stamped
1032 * onto the top-end corner. The card host carries `position: relative`
1033 * so the ribbon's `position: absolute` anchors to the card itself,
1034 * not to whatever positioned ancestor lives further out. The ribbon
1035 * owns its own clipping geometry; nothing else here needs to know
1036 * about the diagonal. */
1037 .os-plugins__card--featured {
1038 position: relative;
1039 box-shadow: 0 0 0 1px var( --wp-admin-theme-color, #2271b1 ) inset;
1040 }
1041