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

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

1,435 lines 32.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * OpenStation — Native Posts window styles.
3 *
4 * Scoped to `.desktop-mode-posts` so the rules can't leak into other
5 * windows. Layout: a toolbar across the top, a flex-1 body that hosts
6 * a `<os-table>`, and a footer pager at the bottom. The table is
7 * told to size to the body via `--os-ui-table-max-height: 100%` so
8 * sticky-header engages without an outer scrollbar.
9 *
10 * Cell-content styles are NOT here — they're inlined in
11 * `src/posts-window/index.ts` because `<os-table>` renders into its
12 * own shadow DOM and document stylesheets do not cross that boundary.
13 *
14 * @since 0.8.0
15 */
16
17 .desktop-mode-posts {
18 display: flex;
19 flex-direction: column;
20 height: 100%;
21 width: 100%;
22 background: var( --os-ui-surface, #fff );
23 color: var( --os-ui-fg, #1d2327 );
24 }
25
26 /* --- Toolbar --------------------------------------------------------- */
27
28 .os-posts__toolbar {
29 display: flex;
30 flex-wrap: wrap;
31 align-items: center;
32 gap: 12px;
33 padding: 10px 14px;
34 border-bottom: 1px solid var( --os-ui-border, rgba( 0, 0, 0, 0.08 ) );
35 background: var( --os-ui-surface-elevated, #f6f7f7 );
36 }
37
38 .os-posts__toolbar-left,
39 .os-posts__toolbar-right,
40 .os-posts__toolbar-trailing {
41 display: flex;
42 align-items: center;
43 gap: 8px;
44 }
45
46 /*
47 * Honour the `hidden` attribute. UA stylesheet sets
48 * `[hidden] { display: none }` but our explicit `display: flex`
49 * above wins on specificity, so we restore the hide behaviour
50 * for `bulkBar.hidden = true` from JS.
51 */
52 .os-posts__toolbar-right[hidden] {
53 display: none;
54 }
55
56 .os-posts__toolbar-trailing {
57 margin-inline-start: auto;
58 }
59
60 .os-posts__count {
61 font-size: 12px;
62 font-weight: 600;
63 color: var( --os-ui-fg-muted, #50575e );
64 font-variant-numeric: tabular-nums;
65 padding-inline-end: 4px;
66 }
67
68 /* --- Body ------------------------------------------------------------ */
69
70 .os-posts__body {
71 flex: 1 1 auto;
72 /*
73 * `min-width: 0` is the load-bearing piece — without it, the
74 * flex item's intrinsic width (the table's column-sum) becomes
75 * its hard minimum, which pushes the table past the window's
76 * right edge and turns the WHOLE WINDOW into a horizontal
77 * scroller. With `min-width: 0`, the flex item shrinks to the
78 * available space and the table's own `.scroll` container
79 * picks up the horizontal overflow internally.
80 */
81 min-width: 0;
82 min-height: 0;
83 display: flex;
84 padding: 8px 12px;
85 }
86
87 .os-posts__body os-table {
88 flex: 1 1 auto;
89 min-width: 0;
90 --os-ui-table-max-height: 100%;
91 }
92
93 /* --- Empty state ----------------------------------------------------- */
94
95 .os-posts__empty {
96 display: flex;
97 flex-direction: column;
98 align-items: center;
99 justify-content: center;
100 gap: 12px;
101 padding: 48px 24px;
102 color: var( --os-ui-fg-muted, #50575e );
103 text-align: center;
104 }
105
106 .os-posts__empty .dashicons {
107 font-size: 40px;
108 width: 40px;
109 height: 40px;
110 color: var( --os-ui-fg-muted, #a7aaad );
111 }
112
113 .os-posts__empty p {
114 margin: 0;
115 }
116
117 .os-posts__empty-hint {
118 font-size: 13px;
119 color: var( --os-ui-fg-muted, #646970 );
120 }
121
122 /* --- Footer / pager -------------------------------------------------- */
123
124 .os-posts__pager {
125 display: flex;
126 align-items: center;
127 justify-content: space-between;
128 gap: 12px;
129 padding: 10px 14px;
130 border-top: 1px solid var( --os-ui-border, rgba( 0, 0, 0, 0.08 ) );
131 background: var( --os-ui-surface-elevated, #f6f7f7 );
132 font-size: 13px;
133 }
134
135 .os-posts__pager-meta {
136 color: var( --os-ui-fg-muted, #50575e );
137 font-variant-numeric: tabular-nums;
138 }
139
140 .os-posts__pager-nav {
141 display: flex;
142 align-items: center;
143 gap: 8px;
144 }
145
146 .os-posts__pager-perpage {
147 display: inline-flex;
148 align-items: center;
149 gap: 6px;
150 color: var( --os-ui-fg-muted, #50575e );
151 font-size: 12px;
152 margin-inline-start: 8px;
153 }
154
155 .os-posts__pager-perpage select {
156 padding: 4px 6px;
157 border: 1px solid var( --os-ui-border, #c3c4c7 );
158 border-radius: 4px;
159 background: var( --os-ui-surface, #fff );
160 color: var( --os-ui-fg, #1d2327 );
161 font: inherit;
162 }
163
164 /* Title-bar ⋯ menu — "Show columns" sub-section.
165 * Section label is a small caps separator above the column toggles.
166 * The toggles are real <os-menu-item role="menuitemcheckbox"> nodes,
167 * so they pick up the menu's existing styling automatically. */
168 .os-posts-window__menu-columns {
169 margin-top: 4px;
170 padding: 6px 12px 2px;
171 font-size: 11px;
172 font-weight: 600;
173 letter-spacing: 0.04em;
174 text-transform: uppercase;
175 color: var( --os-ui-fg-muted, #50575e );
176 border-top: 1px solid var( --os-ui-border, #dcdcde );
177 pointer-events: none;
178 }
179
180 /* Filter cell uses the framework's `<os-multiselect>` — no
181 * post-specific styles needed here. The component lives inside the
182 * <th> and renders its popover into <body> so the dropdown escapes
183 * the table's overflow chain. */
184
185 /* ---------------------------------------------------------------
186 * Categories + Tags tabs.
187 *
188 * Reimagined replacement for legacy `edit-tags.php`. Layout (top to
189 * bottom): horizontal stats strip → search + add-row toolbar →
190 * `<os-table>` → pager. The stats strip is the value-add over the
191 * legacy view — at-a-glance counts the user previously had to hunt
192 * for. */
193 /* Tabs strip — auto-height; only the active panel below grows. */
194 .os-posts__tabs {
195 flex: 0 0 auto;
196 }
197
198 /* Sibling panels under the same flex column. The hidden ones are
199 * UA-display:none via the `[hidden]` attribute; the visible one
200 * stretches to fill the remaining height. */
201 .os-posts__panel {
202 flex: 1 1 auto;
203 min-height: 0;
204 min-width: 0;
205 display: flex;
206 flex-direction: column;
207 }
208
209 .os-posts__panel[ hidden ] {
210 display: none;
211 }
212
213 .os-posts__terms-host,
214 .os-posts__terms {
215 display: flex;
216 flex-direction: column;
217 flex: 1 1 auto;
218 min-height: 0;
219 min-width: 0;
220 }
221
222 .os-posts__stats {
223 display: grid;
224 grid-template-columns: repeat( auto-fit, minmax( 140px, 1fr ) );
225 gap: 8px;
226 padding: 12px 14px 0;
227 }
228
229 .os-posts__stat {
230 display: flex;
231 flex-direction: column;
232 gap: 2px;
233 padding: 10px 14px;
234 background: var( --os-ui-surface-elevated, #f6f7f7 );
235 border: 1px solid var( --os-ui-border, rgba( 0, 0, 0, 0.08 ) );
236 border-radius: 8px;
237 }
238
239 .os-posts__stat[ data-tone='accent' ] {
240 border-color: color-mix(
241 in srgb,
242 var( --wp-admin-theme-color, #2271b1 ) 45%,
243 transparent
244 );
245 }
246
247 .os-posts__stat[ data-tone='warning' ] {
248 border-color: color-mix( in srgb, var( --os-ui-danger, #d63638 ) 45%, transparent );
249 }
250
251 .os-posts__stat-value {
252 font-size: 18px;
253 font-weight: 700;
254 color: var( --os-ui-fg, #1d2327 );
255 line-height: 1.2;
256 overflow: hidden;
257 text-overflow: ellipsis;
258 white-space: nowrap;
259 }
260
261 .os-posts__stat[ data-tone='accent' ] .os-posts__stat-value {
262 color: var( --wp-admin-theme-color, #2271b1 );
263 }
264
265 .os-posts__stat[ data-tone='warning' ] .os-posts__stat-value {
266 color: var( --os-ui-danger, #d63638 );
267 }
268
269 .os-posts__stat-label {
270 font-size: 11px;
271 font-weight: 500;
272 letter-spacing: 0.04em;
273 text-transform: uppercase;
274 color: var( --os-ui-fg-muted, #50575e );
275 overflow: hidden;
276 text-overflow: ellipsis;
277 white-space: nowrap;
278 }
279
280 .os-posts__terms-toolbar {
281 display: flex;
282 flex-wrap: wrap;
283 align-items: center;
284 gap: 12px;
285 padding: 12px 14px;
286 border-bottom: 1px solid var( --os-ui-border, rgba( 0, 0, 0, 0.08 ) );
287 }
288
289 .os-posts__terms-search {
290 flex: 1 1 220px;
291 min-width: 0;
292 }
293
294 .os-posts__terms-search os-text-field {
295 width: 100%;
296 }
297
298 .os-posts__terms-add {
299 display: flex;
300 align-items: center;
301 gap: 8px;
302 flex: 1 1 auto;
303 min-width: 0;
304 justify-content: flex-end;
305 }
306
307 .os-posts__terms-add os-text-field {
308 flex: 1 1 200px;
309 min-width: 0;
310 }
311
312 .os-posts__terms-parent {
313 padding: 6px 8px;
314 border: 1px solid var( --os-ui-border, #c3c4c7 );
315 border-radius: 4px;
316 background: var( --os-ui-surface, #fff );
317 color: var( --os-ui-fg, #1d2327 );
318 font: inherit;
319 font-size: 13px;
320 max-width: 180px;
321 }
322
323 .os-posts__terms os-table {
324 flex: 1 1 auto;
325 min-width: 0;
326 min-height: 0;
327 margin: 0 14px;
328 --os-ui-table-max-height: 100%;
329 }
330
331 .os-posts__term-name {
332 display: inline-flex;
333 align-items: center;
334 gap: 6px;
335 }
336
337 .os-posts__term-indent {
338 display: inline-block;
339 flex-shrink: 0;
340 }
341
342 .os-posts__term-tee {
343 color: var( --os-ui-fg-muted, #8c8f94 );
344 font-size: 13px;
345 flex-shrink: 0;
346 }
347
348 .os-posts__term-label {
349 font-weight: 500;
350 color: var( --os-ui-fg, #1d2327 );
351 overflow: hidden;
352 text-overflow: ellipsis;
353 white-space: nowrap;
354 }
355
356 .os-posts__term-slug {
357 display: inline-block;
358 padding: 2px 6px;
359 border-radius: 4px;
360 background: var( --os-ui-hover, rgba( 0, 0, 0, 0.05 ) );
361 color: var( --os-ui-fg-muted, #50575e );
362 font-family: var( --os-ui-font-mono, ui-monospace, "SF Mono", Menlo, monospace );
363 font-size: 11px;
364 }
365
366 .os-posts__term-count {
367 display: inline-flex;
368 align-items: center;
369 gap: 8px;
370 min-width: 0;
371 }
372
373 .os-posts__term-bar {
374 flex: 1 1 auto;
375 height: 4px;
376 min-width: 24px;
377 background: var( --os-ui-hover, rgba( 0, 0, 0, 0.06 ) );
378 border-radius: 999px;
379 position: relative;
380 overflow: hidden;
381 }
382
383 .os-posts__term-bar::before {
384 content: '';
385 position: absolute;
386 inset-inline-start: 0;
387 top: 0;
388 bottom: 0;
389 width: var( --os-ui-term-bar, 0% );
390 background: var( --wp-admin-theme-color, #2271b1 );
391 border-radius: 999px;
392 transition: width 0.2s ease;
393 }
394
395 .os-posts__term-count-num {
396 font-variant-numeric: tabular-nums;
397 font-weight: 600;
398 color: var( --os-ui-fg, #1d2327 );
399 min-width: 2ch;
400 text-align: end;
401 }
402
403 .os-posts__term-desc {
404 color: var( --os-ui-fg-muted, #50575e );
405 overflow: hidden;
406 text-overflow: ellipsis;
407 white-space: nowrap;
408 display: inline-block;
409 max-width: 100%;
410 }
411
412 .os-posts__term-desc.is-empty {
413 color: var( --os-ui-fg-faint, #c3c4c7 );
414 font-style: italic;
415 }
416
417 .os-posts__term-actions {
418 display: inline-flex;
419 gap: 4px;
420 }
421
422 .os-posts__term-action {
423 appearance: none;
424 padding: 3px 8px;
425 font: inherit;
426 font-size: 11px;
427 font-weight: 500;
428 border: 1px solid transparent;
429 border-radius: 4px;
430 background: transparent;
431 color: var( --wp-admin-theme-color, #2271b1 );
432 cursor: pointer;
433 transition: background-color 0.12s ease, border-color 0.12s ease;
434 }
435
436 .os-posts__term-action:hover {
437 background: color-mix(
438 in srgb,
439 var( --wp-admin-theme-color, #2271b1 ) 10%,
440 transparent
441 );
442 border-color: color-mix(
443 in srgb,
444 var( --wp-admin-theme-color, #2271b1 ) 35%,
445 transparent
446 );
447 }
448
449 .os-posts__term-action--danger {
450 color: var( --os-ui-danger, #d63638 );
451 }
452
453 .os-posts__term-action--danger:hover {
454 background: color-mix( in srgb, var( --os-ui-danger, #d63638 ) 10%, transparent );
455 border-color: color-mix( in srgb, var( --os-ui-danger, #d63638 ) 35%, transparent );
456 }
457
458 /* ---------------------------------------------------------------
459 * Categories tab — Pixi mindmap (the only Categories view).
460 *
461 * Hybrid render: Pixi canvas paints circles + edges, an HTML overlay
462 * paints labels + count badges + the inline editor + post mini-cards.
463 * The overlay keeps text crisp at any zoom; the canvas keeps the
464 * graph hardware-accelerated. */
465 .os-mindmap {
466 flex: 1 1 auto;
467 min-height: 0;
468 min-width: 0;
469 display: flex;
470 flex-direction: column;
471 /* Mindmap canvas — dot grid + theme-tinted vignettes. The dot
472 * grid is the canonical "infinite thinking surface" texture
473 * (Miro / Obsidian Canvas / Excalidraw all use it); pairs nicely
474 * with radial trees because the dots give the user a sense of
475 * pan/zoom motion without dominating the node colors. The two
476 * offset vignettes add light, atmospheric depth — a touch of
477 * ambient lighting in the admin theme hue. */
478 background:
479 radial-gradient(
480 circle,
481 rgba( 0, 0, 0, 0.06 ) 1px,
482 transparent 1.5px
483 ) 0 0 / 24px 24px,
484 radial-gradient(
485 ellipse at 28% 22%,
486 color-mix(
487 in srgb,
488 var( --wp-admin-theme-color, #2271b1 ) 8%,
489 transparent
490 ),
491 transparent 60%
492 ),
493 radial-gradient(
494 ellipse at 78% 80%,
495 color-mix(
496 in srgb,
497 var( --wp-admin-theme-color, #2271b1 ) 5%,
498 transparent
499 ),
500 transparent 58%
501 ),
502 var( --os-ui-surface, #fff );
503 }
504
505 .os-mindmap__toolbar {
506 display: flex;
507 align-items: center;
508 gap: 10px;
509 padding: 10px 14px;
510 border-bottom: 1px solid var( --os-ui-border, rgba( 0, 0, 0, 0.08 ) );
511 background: rgba( 255, 255, 255, 0.6 );
512 backdrop-filter: blur( 8px );
513 /* New stacking context so the search dropdown (z-index inside)
514 * paints above the pixi canvas in the layout sibling below. Without
515 * this, the canvas (later in DOM, no z-index) wins the paint order
516 * and the dropdown renders BEHIND the chips/nodes — clicks then land
517 * on the canvas instead of the dropdown items. */
518 position: relative;
519 z-index: 2;
520 }
521
522 .os-mindmap__btn {
523 appearance: none;
524 display: inline-flex;
525 align-items: center;
526 gap: 4px;
527 padding: 6px 10px;
528 font: inherit;
529 font-size: 12px;
530 font-weight: 500;
531 border: 1px solid var( --os-ui-border, #c3c4c7 );
532 border-radius: 6px;
533 background: transparent;
534 color: var( --os-ui-fg, #1d2327 );
535 cursor: pointer;
536 transition: background-color 0.12s ease, border-color 0.12s ease,
537 color 0.12s ease;
538 }
539
540 .os-mindmap__btn:hover {
541 background: var( --os-ui-hover, rgba( 0, 0, 0, 0.04 ) );
542 border-color: var( --wp-admin-theme-color, #2271b1 );
543 }
544
545 .os-mindmap__btn--primary {
546 background: var( --wp-admin-theme-color, #2271b1 );
547 color: var( --os-ui-fg-on-accent, #fff );
548 border-color: transparent;
549 }
550
551 .os-mindmap__btn--primary:hover {
552 filter: brightness( 1.05 );
553 background: var( --wp-admin-theme-color, #2271b1 );
554 color: var( --os-ui-fg-on-accent, #fff );
555 }
556
557 .os-mindmap__btn--secondary {
558 background: var( --os-ui-hover, rgba( 0, 0, 0, 0.04 ) );
559 }
560
561 .os-mindmap__btn--danger {
562 color: var( --os-ui-danger, #d63638 );
563 border-color: transparent;
564 }
565
566 .os-mindmap__btn--danger:hover {
567 background: color-mix( in srgb, var( --os-ui-danger, #d63638 ) 10%, transparent );
568 border-color: color-mix( in srgb, var( --os-ui-danger, #d63638 ) 35%, transparent );
569 }
570
571 .os-mindmap__btn--danger.is-armed {
572 background: var( --os-ui-danger, #d63638 );
573 color: var( --os-ui-fg-on-accent, #fff );
574 border-color: transparent;
575 }
576
577 .os-mindmap__hint {
578 flex: 1 1 auto;
579 font-size: 12px;
580 font-style: italic;
581 color: var( --os-ui-fg-muted, #50575e );
582 text-align: end;
583 overflow: hidden;
584 text-overflow: ellipsis;
585 white-space: nowrap;
586 }
587
588 .os-mindmap__search {
589 position: relative;
590 flex: 0 1 280px;
591 min-width: 180px;
592 }
593
594 .os-mindmap__search-input {
595 width: 100%;
596 padding: 6px 10px;
597 border: 1px solid var( --os-ui-border, #d8dde4 );
598 border-radius: 6px;
599 background: var( --os-ui-surface, #fff );
600 color: inherit;
601 font: inherit;
602 font-size: 13px;
603 }
604
605 .os-mindmap__search-input:focus {
606 outline: none;
607 border-color: var( --os-ui-accent, var( --wp-admin-theme-color, #2271b1 ) );
608 box-shadow: 0 0 0 3px
609 var( --os-ui-accent-soft, rgba( 34, 113, 177, 0.18 ) );
610 }
611
612 .os-mindmap__search-results {
613 position: absolute;
614 top: calc( 100% + 4px );
615 inset-inline-start: 0;
616 inset-inline-end: 0;
617 margin: 0;
618 padding: 4px;
619 list-style: none;
620 background: var( --os-ui-surface-elevated, #fff );
621 border: 1px solid var( --os-ui-border, #d8dde4 );
622 border-radius: 8px;
623 box-shadow: 0 6px 18px rgba( 17, 24, 39, 0.08 );
624 z-index: 100;
625 max-height: 300px;
626 overflow-y: auto;
627 }
628
629 .os-mindmap__search-result {
630 display: flex;
631 align-items: center;
632 justify-content: space-between;
633 gap: 8px;
634 width: 100%;
635 padding: 6px 10px;
636 background: transparent;
637 border: 0;
638 border-radius: 6px;
639 color: inherit;
640 cursor: pointer;
641 text-align: start;
642 font: inherit;
643 font-size: 13px;
644 }
645
646 .os-mindmap__search-result:hover,
647 .os-mindmap__search-result.is-active {
648 background: var( --os-ui-hover, rgba( 79, 139, 243, 0.08 ) );
649 }
650
651 .os-mindmap__search-title {
652 flex: 1;
653 overflow: hidden;
654 text-overflow: ellipsis;
655 white-space: nowrap;
656 }
657
658 .os-mindmap__search-meta {
659 font-size: 11px;
660 color: var( --os-ui-fg-muted, #6b7280 );
661 white-space: nowrap;
662 }
663
664 /* Two-column layout: Pixi stage on the left, fixed sidebar on the
665 * right. The sidebar always renders — empty-state copy when no node
666 * is focused, full editor form otherwise — so the editing surface
667 * never covers the post nodes. */
668 .os-mindmap__layout {
669 display: flex;
670 flex: 1 1 auto;
671 min-height: 0;
672 min-width: 0;
673 }
674
675 .os-mindmap__stage {
676 position: relative;
677 flex: 1 1 auto;
678 min-height: 0;
679 min-width: 0;
680 overflow: hidden;
681 /* Fade in once the very first `fitToView()` has run — without
682 * this the canvas briefly paints its tree at the unfitted
683 * default transform on the frame between mount and the first
684 * rAF, which the user saw as a flash. */
685 transition: opacity 200ms ease;
686 }
687
688 .os-mindmap__stage.is-loading {
689 opacity: 0;
690 }
691
692 .os-mindmap__sidebar {
693 flex: 0 0 320px;
694 display: flex;
695 flex-direction: column;
696 gap: 12px;
697 padding: 16px;
698 border-inline-start: 1px solid var( --os-ui-border, rgba( 0, 0, 0, 0.08 ) );
699 background: var( --os-ui-surface, #fff );
700 color: var( --os-ui-fg, #1d2327 );
701 overflow-y: auto;
702 min-height: 0;
703 }
704
705 .os-mindmap__sidebar-empty {
706 flex: 1 1 auto;
707 display: flex;
708 flex-direction: column;
709 align-items: center;
710 justify-content: center;
711 gap: 6px;
712 color: var( --os-ui-fg-muted, #50575e );
713 text-align: center;
714 padding: 24px 8px;
715 }
716
717 .os-mindmap__sidebar-empty .dashicons {
718 font-size: 36px;
719 width: 36px;
720 height: 36px;
721 opacity: 0.5;
722 }
723
724 .os-mindmap__sidebar-empty-title {
725 font-size: 13px;
726 font-weight: 600;
727 color: var( --os-ui-fg, #1d2327 );
728 }
729
730 .os-mindmap__sidebar-empty-hint {
731 font-size: 12px;
732 font-style: italic;
733 max-width: 220px;
734 }
735
736 .os-mindmap__sidebar-header {
737 display: flex;
738 align-items: center;
739 gap: 8px;
740 font-size: 11px;
741 font-weight: 600;
742 letter-spacing: 0.04em;
743 text-transform: uppercase;
744 color: var( --os-ui-fg-muted, #50575e );
745 }
746
747 .os-mindmap__sidebar-dot {
748 width: 10px;
749 height: 10px;
750 border-radius: 50%;
751 flex: 0 0 10px;
752 }
753
754 .os-mindmap__sidebar-slug {
755 overflow: hidden;
756 text-overflow: ellipsis;
757 white-space: nowrap;
758 }
759
760 .os-mindmap__sidebar-label {
761 font-size: 11px;
762 font-weight: 500;
763 color: var( --os-ui-fg-muted, #50575e );
764 margin-block-start: 4px;
765 }
766
767 .os-mindmap__sidebar-meta {
768 font-size: 12px;
769 color: var( --os-ui-fg-muted, #50575e );
770 padding-block: 4px;
771 }
772
773 .os-mindmap__canvas {
774 display: block;
775 position: absolute;
776 inset: 0;
777 width: 100%;
778 height: 100%;
779 touch-action: none;
780 }
781
782 /* Spotlight: dim the world container while a node is deployed so
783 * the focused branch reads as the foreground. Implemented as a
784 * filter on the canvas itself because category and post chips are
785 * Pixi nodes inside the canvas — there is no longer an HTML overlay
786 * we can selectively dim. The canvas keeps full alpha so the
787 * focused-node + post fan stay vivid; only the discs/chips outside
788 * the focus area look muted via the slight desaturation in JS
789 * (drawEdges + chip-color logic dim non-focused branches). */
790
791 /* Editor lives in the sidebar — no longer a floating popover, so no
792 * positioning, shadow or backdrop. Just a vertical stack of inputs +
793 * actions. (Kept the class so the form's children still hit the
794 * existing input/button styles below.) */
795 .os-mindmap__editor {
796 display: contents;
797 }
798
799 .os-mindmap__editor-name {
800 appearance: none;
801 font: inherit;
802 font-size: 14px;
803 font-weight: 600;
804 padding: 6px 8px;
805 border: 1px solid var( --os-ui-border, #c3c4c7 );
806 border-radius: 6px;
807 background: var( --os-ui-surface, #fff );
808 color: inherit;
809 }
810
811 .os-mindmap__editor-name:focus,
812 .os-mindmap__editor-desc:focus {
813 outline: none;
814 border-color: var( --wp-admin-theme-color, #2271b1 );
815 box-shadow: 0 0 0 2px
816 color-mix(
817 in srgb,
818 var( --wp-admin-theme-color, #2271b1 ) 25%,
819 transparent
820 );
821 }
822
823 .os-mindmap__editor-desc {
824 appearance: none;
825 font: inherit;
826 font-size: 12px;
827 padding: 6px 8px;
828 border: 1px solid var( --os-ui-border, #c3c4c7 );
829 border-radius: 6px;
830 background: var( --os-ui-surface, #fff );
831 color: inherit;
832 resize: vertical;
833 min-height: 46px;
834 }
835
836 .os-mindmap__editor-actions {
837 display: flex;
838 gap: 6px;
839 flex-wrap: wrap;
840 }
841
842 .os-mindmap__editor-actions .os-mindmap__btn {
843 flex: 1 1 auto;
844 justify-content: center;
845 }
846
847 .os-mindmap__empty {
848 position: absolute;
849 inset: 0;
850 display: flex;
851 align-items: center;
852 justify-content: center;
853 pointer-events: none;
854 color: var( --os-ui-fg-muted, #50575e );
855 font-size: 13px;
856 font-style: italic;
857 text-align: center;
858 padding: 0 24px;
859 }
860
861 /* ---------------------------------------------------------------------
862 * Tag cloud (Tags tab)
863 *
864 * Same surface shape as the Categories mindmap — toolbar across the
865 * top, Pixi stage on the left, fixed-width sidebar editor on the right
866 * — but with a hashtag-pill metaphor instead of circles. The Pixi-side
867 * code (`tags-cloud.ts`) paints chips, post satellites, and the pager
868 * directly into the canvas; this stylesheet only owns the chrome
869 * around the canvas (toolbar, sidebar form, empty states).
870 * ------------------------------------------------------------------ */
871 .os-tagcloud {
872 flex: 1 1 auto;
873 min-height: 0;
874 min-width: 0;
875 display: flex;
876 flex-direction: column;
877 background:
878 repeating-linear-gradient(
879 135deg,
880 transparent 0,
881 transparent 22px,
882 color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 4%, transparent ) 22px,
883 color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 4%, transparent ) 23px
884 ),
885 radial-gradient(
886 circle at 30% 20%,
887 color-mix(
888 in srgb,
889 var( --wp-admin-theme-color, #2271b1 ) 6%,
890 transparent
891 ),
892 transparent 65%
893 ),
894 var( --os-ui-surface, #fff );
895 }
896
897 .os-tagcloud__toolbar {
898 display: flex;
899 align-items: center;
900 gap: 10px;
901 padding: 10px 14px;
902 border-bottom: 1px solid var( --os-ui-border, rgba( 0, 0, 0, 0.08 ) );
903 background: rgba( 255, 255, 255, 0.6 );
904 backdrop-filter: blur( 8px );
905 /* Stacking context for the search dropdown — see the matching
906 * comment on `.os-mindmap__toolbar`. */
907 position: relative;
908 z-index: 2;
909 }
910
911 .os-tagcloud__btn {
912 appearance: none;
913 display: inline-flex;
914 align-items: center;
915 gap: 4px;
916 padding: 6px 10px;
917 font: inherit;
918 font-size: 12px;
919 font-weight: 500;
920 border: 1px solid var( --os-ui-border, #c3c4c7 );
921 border-radius: 6px;
922 background: transparent;
923 color: var( --os-ui-fg, #1d2327 );
924 cursor: pointer;
925 transition: background-color 0.12s ease, border-color 0.12s ease,
926 color 0.12s ease;
927 }
928
929 .os-tagcloud__btn:hover {
930 background: var( --os-ui-hover, rgba( 0, 0, 0, 0.04 ) );
931 border-color: var( --wp-admin-theme-color, #2271b1 );
932 }
933
934 .os-tagcloud__btn--primary {
935 background: var( --wp-admin-theme-color, #2271b1 );
936 color: var( --os-ui-fg-on-accent, #fff );
937 border-color: transparent;
938 }
939
940 .os-tagcloud__btn--primary:hover {
941 filter: brightness( 1.05 );
942 background: var( --wp-admin-theme-color, #2271b1 );
943 color: var( --os-ui-fg-on-accent, #fff );
944 }
945
946 .os-tagcloud__btn--danger {
947 color: var( --os-ui-danger, #d63638 );
948 border-color: transparent;
949 }
950
951 .os-tagcloud__btn--danger:hover {
952 background: color-mix( in srgb, var( --os-ui-danger, #d63638 ) 10%, transparent );
953 border-color: color-mix( in srgb, var( --os-ui-danger, #d63638 ) 35%, transparent );
954 }
955
956 .os-tagcloud__btn--danger.is-armed {
957 background: var( --os-ui-danger, #d63638 );
958 color: var( --os-ui-fg-on-accent, #fff );
959 border-color: transparent;
960 }
961
962 .os-tagcloud__hint {
963 flex: 1 1 auto;
964 font-size: 12px;
965 font-style: italic;
966 color: var( --os-ui-fg-muted, #50575e );
967 text-align: end;
968 overflow: hidden;
969 text-overflow: ellipsis;
970 white-space: nowrap;
971 }
972
973 .os-tagcloud__search {
974 position: relative;
975 flex: 0 1 280px;
976 min-width: 180px;
977 }
978
979 .os-tagcloud__search-input {
980 width: 100%;
981 padding: 6px 10px;
982 border: 1px solid var( --os-ui-border, #d8dde4 );
983 border-radius: 6px;
984 background: var( --os-ui-surface, #fff );
985 color: inherit;
986 font: inherit;
987 font-size: 13px;
988 }
989
990 .os-tagcloud__search-input:focus {
991 outline: none;
992 border-color: var( --os-ui-accent, var( --wp-admin-theme-color, #2271b1 ) );
993 box-shadow: 0 0 0 3px
994 var( --os-ui-accent-soft, rgba( 34, 113, 177, 0.18 ) );
995 }
996
997 .os-tagcloud__search-results {
998 position: absolute;
999 top: calc( 100% + 4px );
1000 inset-inline-start: 0;
1001 inset-inline-end: 0;
1002 margin: 0;
1003 padding: 4px;
1004 list-style: none;
1005 background: var( --os-ui-surface-elevated, #fff );
1006 border: 1px solid var( --os-ui-border, #d8dde4 );
1007 border-radius: 8px;
1008 box-shadow: 0 6px 18px rgba( 17, 24, 39, 0.08 );
1009 z-index: 100;
1010 max-height: 300px;
1011 overflow-y: auto;
1012 }
1013
1014 .os-tagcloud__search-result {
1015 display: flex;
1016 align-items: center;
1017 justify-content: space-between;
1018 gap: 8px;
1019 width: 100%;
1020 padding: 6px 10px;
1021 background: transparent;
1022 border: 0;
1023 border-radius: 6px;
1024 color: inherit;
1025 cursor: pointer;
1026 text-align: start;
1027 font: inherit;
1028 font-size: 13px;
1029 }
1030
1031 .os-tagcloud__search-result:hover,
1032 .os-tagcloud__search-result.is-active {
1033 background: var( --os-ui-hover, rgba( 79, 139, 243, 0.08 ) );
1034 }
1035
1036 .os-tagcloud__search-title {
1037 flex: 1;
1038 overflow: hidden;
1039 text-overflow: ellipsis;
1040 white-space: nowrap;
1041 }
1042
1043 .os-tagcloud__search-meta {
1044 font-size: 11px;
1045 color: var( --os-ui-fg-muted, #6b7280 );
1046 white-space: nowrap;
1047 }
1048
1049 .os-tagcloud__layout {
1050 display: flex;
1051 flex: 1 1 auto;
1052 min-height: 0;
1053 min-width: 0;
1054 }
1055
1056 .os-tagcloud__stage {
1057 position: relative;
1058 flex: 1 1 auto;
1059 min-height: 0;
1060 min-width: 0;
1061 overflow: hidden;
1062 transition: opacity 200ms ease;
1063 }
1064
1065 .os-tagcloud__stage.is-loading {
1066 opacity: 0;
1067 }
1068
1069 .os-tagcloud__sidebar {
1070 flex: 0 0 320px;
1071 display: flex;
1072 flex-direction: column;
1073 gap: 12px;
1074 padding: 16px;
1075 border-inline-start: 1px solid var( --os-ui-border, rgba( 0, 0, 0, 0.08 ) );
1076 background: var( --os-ui-surface, #fff );
1077 color: var( --os-ui-fg, #1d2327 );
1078 overflow-y: auto;
1079 min-height: 0;
1080 }
1081
1082 .os-tagcloud__sidebar-empty {
1083 flex: 1 1 auto;
1084 display: flex;
1085 flex-direction: column;
1086 align-items: center;
1087 justify-content: center;
1088 gap: 6px;
1089 color: var( --os-ui-fg-muted, #50575e );
1090 text-align: center;
1091 padding: 24px 8px;
1092 }
1093
1094 .os-tagcloud__sidebar-empty .dashicons {
1095 font-size: 36px;
1096 width: 36px;
1097 height: 36px;
1098 opacity: 0.5;
1099 }
1100
1101 .os-tagcloud__sidebar-empty-title {
1102 font-size: 13px;
1103 font-weight: 600;
1104 color: var( --os-ui-fg, #1d2327 );
1105 margin: 0;
1106 }
1107
1108 .os-tagcloud__sidebar-empty-hint {
1109 font-size: 12px;
1110 font-style: italic;
1111 max-width: 240px;
1112 margin: 0;
1113 }
1114
1115 .os-tagcloud__sidebar-header {
1116 display: flex;
1117 align-items: center;
1118 gap: 8px;
1119 font-size: 11px;
1120 font-weight: 600;
1121 letter-spacing: 0.04em;
1122 text-transform: uppercase;
1123 color: var( --os-ui-fg-muted, #50575e );
1124 }
1125
1126 .os-tagcloud__sidebar-dot {
1127 width: 10px;
1128 height: 10px;
1129 border-radius: 50%;
1130 flex: 0 0 10px;
1131 }
1132
1133 .os-tagcloud__sidebar-slug {
1134 overflow: hidden;
1135 text-overflow: ellipsis;
1136 white-space: nowrap;
1137 }
1138
1139 .os-tagcloud__sidebar-label {
1140 font-size: 11px;
1141 font-weight: 500;
1142 color: var( --os-ui-fg-muted, #50575e );
1143 margin-block-start: 4px;
1144 }
1145
1146 .os-tagcloud__sidebar-meta {
1147 font-size: 12px;
1148 color: var( --os-ui-fg-muted, #50575e );
1149 padding-block: 4px;
1150 }
1151
1152 .os-tagcloud__canvas {
1153 display: block;
1154 position: absolute;
1155 inset: 0;
1156 width: 100%;
1157 height: 100%;
1158 touch-action: none;
1159 }
1160
1161 .os-tagcloud__editor-name {
1162 appearance: none;
1163 font: inherit;
1164 font-size: 14px;
1165 font-weight: 600;
1166 padding: 6px 8px;
1167 border: 1px solid var( --os-ui-border, #c3c4c7 );
1168 border-radius: 6px;
1169 background: var( --os-ui-surface, #fff );
1170 color: inherit;
1171 }
1172
1173 .os-tagcloud__editor-name:focus,
1174 .os-tagcloud__editor-desc:focus {
1175 outline: none;
1176 border-color: var( --wp-admin-theme-color, #2271b1 );
1177 box-shadow: 0 0 0 2px
1178 color-mix(
1179 in srgb,
1180 var( --wp-admin-theme-color, #2271b1 ) 25%,
1181 transparent
1182 );
1183 }
1184
1185 .os-tagcloud__editor-desc {
1186 appearance: none;
1187 font: inherit;
1188 font-size: 12px;
1189 padding: 6px 8px;
1190 border: 1px solid var( --os-ui-border, #c3c4c7 );
1191 border-radius: 6px;
1192 background: var( --os-ui-surface, #fff );
1193 color: inherit;
1194 resize: vertical;
1195 min-height: 46px;
1196 }
1197
1198 .os-tagcloud__editor-actions {
1199 display: flex;
1200 gap: 6px;
1201 flex-wrap: wrap;
1202 }
1203
1204 .os-tagcloud__editor-actions .os-tagcloud__btn {
1205 flex: 1 1 auto;
1206 justify-content: center;
1207 }
1208
1209 .os-tagcloud__empty {
1210 position: absolute;
1211 inset: 0;
1212 display: flex;
1213 align-items: center;
1214 justify-content: center;
1215 pointer-events: none;
1216 color: var( --os-ui-fg-muted, #50575e );
1217 font-size: 13px;
1218 font-style: italic;
1219 text-align: center;
1220 padding: 0 24px;
1221 }
1222
1223 /* ─── Native Users window — tabs + Add User panel ────────────────── */
1224 /*
1225 * Lives in the shared posts-window stylesheet because the Users
1226 * window enqueues `os-posts-window` (single bundle, single
1227 * style handle covers both). Scoped to `.desktop-mode-users` so it
1228 * never bleeds into the Posts/Pages markup.
1229 */
1230 /*
1231 * Tab strip — keep it auto-height (matches the
1232 * `.os-posts__tabs` rule). Without the `flex: 0 0 auto`
1233 * the os-tabs element grows to fill the column and the panel
1234 * below collapses to zero height — exactly the "no table"
1235 * regression the first cut hit.
1236 */
1237 .os-users__tabs {
1238 flex: 0 0 auto;
1239 padding: 0 18px;
1240 border-bottom: 1px solid var( --os-ui-border, #dcdcde );
1241 }
1242
1243 /*
1244 * The Add User tab. The PHP template applies this class to the
1245 * `<os-tabpanel>`. Padding lives on the host so the form's own
1246 * footer separator sits flush with the panel edges. `flex: 1 1
1247 * auto` matches the All-users panel so the active tab fills the
1248 * remaining height and the inactive one is fully `hidden`.
1249 */
1250 .os-users__add-panel {
1251 flex: 1 1 auto;
1252 min-height: 0;
1253 display: block;
1254 padding: 32px 24px 28px;
1255 box-sizing: border-box;
1256 overflow-y: auto;
1257 }
1258 .os-users__add-panel[ hidden ] {
1259 display: none;
1260 }
1261
1262 /*
1263 * Center the form at a comfortable reading width. The os-form
1264 * itself does the column layout — we only do the OUTER centering
1265 * here. `min(760px, 100%)` keeps it from blowing past the panel's
1266 * edges on narrow windows where the max-width would be moot.
1267 */
1268 .os-users__add-panel > os-form {
1269 display: block;
1270 margin-inline: auto;
1271 width: min( 760px, 100% );
1272 }
1273
1274 .os-users__add-panel [ slot="header" ] {
1275 margin-bottom: 4px;
1276 }
1277 .os-users__add-panel [ slot="header" ] h2 {
1278 margin: 0 0 6px;
1279 font-size: 20px;
1280 font-weight: 600;
1281 letter-spacing: -0.01em;
1282 color: var( --os-ui-fg, #1d2327 );
1283 }
1284 .os-users__form-lede {
1285 margin: 0 0 8px;
1286 color: var( --os-ui-fg-muted, #50575e );
1287 font-size: 13px;
1288 line-height: 1.5;
1289 }
1290 .os-users__form-pwd-actions {
1291 display: flex;
1292 align-items: center;
1293 gap: 12px;
1294 flex-wrap: wrap;
1295 margin-top: -4px;
1296 }
1297 .os-users__form-hint {
1298 margin: 0;
1299 font-size: 12px;
1300 color: var( --os-ui-fg-muted, #50575e );
1301 }
1302 /*
1303 * Narrow-window trim — at < 540px the side padding gets in the way
1304 * more than it helps. Same breakpoint the form's own grid uses to
1305 * collapse to one column, so the visual cadence stays consistent.
1306 */
1307 @media ( max-width: 540px ) {
1308 .os-users__add-panel {
1309 padding: 20px 14px 16px;
1310 }
1311 .os-users__tabs {
1312 padding: 0 12px;
1313 }
1314 }
1315
1316 /*
1317 * Profile tab — third tab in the Users window. Same flex
1318 * stretch as the .os-posts__panel rule: the active
1319 * tabpanel fills the remaining height, scrolls its own content,
1320 * leaves the tab strip pinned at the top.
1321 */
1322 .os-users__edit-panel {
1323 flex: 1 1 auto;
1324 min-height: 0;
1325 display: flex;
1326 flex-direction: column;
1327 overflow: hidden;
1328 }
1329 .os-users__edit-panel[ hidden ] {
1330 display: none;
1331 }
1332 /*
1333 * `<os-user-profile>` slotted as a tabpanel child needs to fill
1334 * the height itself so its internal scroll container takes the
1335 * remaining space. Without this the layout grid lives at its
1336 * intrinsic height and the user can't reach the bottom of the
1337 * form on shorter windows.
1338 */
1339 .os-users__edit-panel > os-user-profile {
1340 flex: 1 1 auto;
1341 min-height: 0;
1342 display: flex;
1343 flex-direction: column;
1344 }
1345
1346 /*
1347 * Standalone `desktop-mode-user-edit` window. The native body is
1348 * a chromeless host; `<os-user-profile>` fills the whole space
1349 * and owns its own scroll. Without `min-height: 0` on the chain,
1350 * the inner `overflow-y: auto` on the layout grid never gets a
1351 * chance to clip and scroll.
1352 */
1353 .os-user-edit-window {
1354 display: flex;
1355 flex-direction: column;
1356 height: 100%;
1357 min-height: 0;
1358 }
1359 .os-user-edit-window > os-user-profile {
1360 flex: 1 1 auto;
1361 min-height: 0;
1362 display: flex;
1363 flex-direction: column;
1364 }
1365 /*
1366 * The component itself — light-DOM host of the layout. Same
1367 * flex semantics so the inner scroll container is the
1368 * .os-users__edit-layout div.
1369 */
1370 os-user-profile {
1371 display: flex;
1372 flex-direction: column;
1373 min-height: 0;
1374 }
1375 os-user-profile > .os-users__edit-layout {
1376 flex: 1 1 auto;
1377 min-height: 0;
1378 }
1379
1380 /*
1381 * Sidebar layout — at-a-glance summary on the left, editable
1382 * form + activity feed in the main column on the right. A
1383 * single CSS container query collapses the two columns to one
1384 * stack on narrow widths, where the aside moves above the form
1385 * (the user still sees their summary; just scrolls past it
1386 * before the form). The Profile form's own os-form container
1387 * query handles the inner 1↔2 column flip.
1388 */
1389 .os-users__edit-layout {
1390 flex: 1 1 auto;
1391 min-height: 0;
1392 overflow-y: auto;
1393 display: grid;
1394 grid-template-columns: 280px minmax( 0, 1fr );
1395 gap: 28px;
1396 padding: 28px 32px 32px;
1397 container-type: inline-size;
1398 container-name: desktop-mode-user-edit;
1399 }
1400 @container desktop-mode-user-edit ( max-width: 800px ) {
1401 .os-users__edit-layout {
1402 grid-template-columns: minmax( 0, 1fr );
1403 }
1404 }
1405 .os-users__edit-aside {
1406 display: flex;
1407 flex-direction: column;
1408 gap: 8px;
1409 min-width: 0;
1410 position: sticky;
1411 top: 0;
1412 align-self: start;
1413 }
1414 @container desktop-mode-user-edit ( max-width: 800px ) {
1415 .os-users__edit-aside {
1416 position: static;
1417 }
1418 }
1419 .os-users__edit-main {
1420 min-width: 0;
1421 width: 100%;
1422 max-width: 720px;
1423 /* Center within the `minmax(0, 1fr)` grid cell so the form
1424 * stays readable on wide windows instead of leaving a large
1425 * empty band on the right edge. The 720px max preserves the
1426 * intended line length; the auto inline margin pushes the
1427 * unused width equally to both sides. */
1428 margin-inline: auto;
1429 display: flex;
1430 flex-direction: column;
1431 }
1432 .os-users__edit-activity {
1433 min-width: 0;
1434 }
1435