PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.0.0
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.0.0
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 / my-wordpress.css

my-wordpress.css in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 1.0.0, at assets/css/my-wordpress.css

2,372 lines 58.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * My WordPress — window-local layout.
3 *
4 * Two-pane file-explorer for browsing WordPress entities. Mirrors the
5 * Recycle Bin and Posts window CSS conventions (`os-*`
6 * BEM-ish prefix, container-relative geometry, theming via the
7 * os-variables CSS custom properties).
8 *
9 */
10
11 .desktop-mode-my-wordpress {
12 display: flex;
13 flex-direction: column;
14 width: 100%;
15 height: 100%;
16 min-height: 0;
17 font-family: var(
18 --os-font,
19 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif
20 );
21 color: var( --os-my-wordpress-fg, var( --os-ui-fg, #1d2327 ) );
22 /* Window background — separate from the wallpaper bg so the
23 * folder window reads as a real OS window even when the desktop
24 * gradient is dark. Themes / plugins can override
25 * `--os-my-wordpress-bg` to repaint just this surface
26 * without touching every other window. */
27 background: var(
28 --os-my-wordpress-bg,
29 var( --os-window-bg, #fff )
30 );
31 /* Light-context tile color tokens — same recipe as the folder
32 * window. Tiles inside My WordPress paint dark-on-light. */
33 --os-tile-fg: var( --os-my-wordpress-fg, var( --os-ui-fg, #1d2327 ) );
34 --os-tile-fg-muted: rgba( 0, 0, 0, 0.55 );
35 --os-tile-hover-bg: var(
36 --os-hover,
37 rgba( 0, 0, 0, 0.06 )
38 );
39 /* Light-context label rendering — same recipe as the folder
40 * window. Defined as tokens in `variables.css`; the single
41 * `.os-file-tile__label` rule reads them for every
42 * surface. */
43 --os-tile-label-shadow: none;
44 --os-tile-label-weight: 500;
45 --os-tile-label-smoothing: antialiased;
46 --os-tile-label-color: var( --os-my-wordpress-fg, var( --os-ui-fg, #1d2327 ) );
47 }
48
49 /* Pinned-icon visual cue — used by `os-icon--pinned` (the
50 * generic flag added in 0.8.0). The icon-rail itself owns the
51 * non-draggable invariant; this rule just removes the grab affordance
52 * if the framework ever attaches one in a later phase.
53 */
54 .os-icon--pinned {
55 cursor: pointer;
56 }
57
58 /* Breadcrumb header chrome — owned by the shared
59 * `.os-breadcrumbs` rules in `desktop-files.css`. No
60 * per-surface duplication. */
61
62 /* ----- Body host ----- */
63
64 .os-my-wordpress__body {
65 flex: 1 1 auto;
66 min-height: 0;
67 overflow: hidden;
68 position: relative;
69 display: flex;
70 flex-direction: column;
71 }
72
73 /* List-view toolbar — sits between the breadcrumb header and the
74 * split pane in every entity list view (Posts, Pages, Users, Media).
75 * Holds the server-side search input today; reserved for future
76 * filter / sort controls. Visual treatment mirrors the Content
77 * Graph toolbar's search row so the two surfaces read as the same
78 * control. */
79 .os-my-wordpress__list-toolbar {
80 flex: 0 0 auto;
81 display: flex;
82 align-items: center;
83 gap: 8px;
84 padding: 8px 12px;
85 border-bottom: 1px solid var( --os-ui-border, #dcdcde );
86 /* Opaque and above the canvas: the tile canvas scrolls beneath
87 * this row, and a transparent toolbar let tiles read through it. */
88 position: relative;
89 z-index: 4;
90 background: var( --os-ui-bg, #fff );
91 }
92
93 .os-my-wordpress__list-toolbar-search {
94 position: relative;
95 flex: 1 1 auto;
96 min-width: 0;
97 max-width: 360px;
98 }
99
100 .os-my-wordpress__list-toolbar-search-input {
101 width: 100%;
102 padding: 6px 10px;
103 border: 1px solid var( --os-ui-border, #d8dde4 );
104 border-radius: 6px;
105 background: var( --os-ui-surface, #fff );
106 color: inherit;
107 font-size: 13px;
108 box-sizing: border-box;
109 }
110
111 .os-my-wordpress__list-toolbar-search-input:focus {
112 outline: none;
113 border-color: var( --os-ui-accent, #2c6be5 );
114 box-shadow: 0 0 0 3px var( --os-ui-accent-soft, rgba( 44, 107, 229, 0.18 ) );
115 }
116
117 /* When the list-toolbar mounts, the split pane needs to claim the
118 * remaining vertical space inside the flex column body — without
119 * this rule it would size to its content (which, for an empty list,
120 * is zero) and the tile canvas would collapse. */
121 .os-my-wordpress__body > .os-my-wordpress__split {
122 flex: 1 1 auto;
123 min-height: 0;
124 }
125
126 /* Search-in-progress dimming. The previous result set stays in place
127 * (no skeleton flash, no empty intermediate page) but reads as
128 * "stale" until the new page lands and the renderer atomically swaps
129 * the tiles. `pointer-events: none` blocks the user from clicking
130 * a tile that's about to disappear. */
131 .os-my-wordpress__tiles--searching,
132 .os-my-wordpress__media-grid--searching {
133 opacity: 0.45;
134 pointer-events: none;
135 transition: opacity 0.12s ease-out;
136 }
137
138 /* Reuse the file-system folder window's status-bar element
139 * (`.os-folder-status-bar`) so segments render with the
140 * exact same DOM the file-system uses — but retone it for the
141 * white window background. The dark default (white-on-dark) reads
142 * as invisible against `--os-window-bg`. */
143 .desktop-mode-my-wordpress > .os-folder-status-bar {
144 border-top: 1px solid var( --os-ui-border, #dcdcde );
145 background: transparent;
146 color: var( --os-ui-fg-muted, #50575e );
147 }
148
149 .desktop-mode-my-wordpress
150 > .os-folder-status-bar
151 button.os-folder-status-bar__segment:hover {
152 background: var( --os-hover, var( --os-ui-hover, rgba( 0, 0, 0, 0.06 ) ) );
153 }
154
155 /* ----- Tile canvas (root + entity list) -----
156 *
157 * Both views use the SAME tile element (`.os-file-tile`)
158 * the wallpaper uses, so visuals stay 1:1 with the desktop. The
159 * canvas is `position: relative`; tiles are absolute-positioned and
160 * draggable — same interaction pattern as the wallpaper, just
161 * scoped to the window. Positions persist per-window in
162 * `localStorage` (see `createTileLayout` in src/my-wordpress).
163 */
164
165 .os-my-wordpress__canvas {
166 position: relative;
167 min-height: 100%;
168 box-sizing: border-box;
169 /* Note — DO NOT add `overflow: auto` here. Scroll is owned by
170 * the surrounding pane (`__list` for entity views, `__body` for
171 * the root view via `__grid` below). A second scroller here
172 * would steal the wheel from the outer pane and break the
173 * IntersectionObserver-based infinite scroll. */
174 }
175
176 .os-my-wordpress__grid {
177 height: 100%;
178 overflow-y: scroll;
179 }
180
181 /* Override the wallpaper file-tile palette for in-window context.
182 * On the wallpaper the file tile sits on a dark gradient and uses
183 * white text + a 12% white hover — both of which would be invisible
184 * on a white window background. Inside My WordPress we re-tone the
185 * same element to read on light surfaces. The dimensions / tile
186 * structure are inherited from `.os-file-tile`.
187 */
188 .desktop-mode-my-wordpress .os-file-tile {
189 /* Color + hover come from `--os-tile-*` — see the
190 * scope-level variable overrides on `.desktop-mode-my-wordpress`
191 * above. We only override structural / animation bits here.
192 *
193 * Drop the wallpaper's `transition: transform` — it hints at
194 * GPU compositing in Chrome, and the moment the layer is
195 * composited the label rasterizes against fractional device
196 * pixels (sub-pixel blur on HiDPI). We don't animate transform
197 * here, so the transition is dead code anyway. */
198 transition: background-color 0.15s ease;
199 transform: none;
200 }
201
202 /* Selected state for every tile in My WordPress is rendered by
203 * the canonical `.os-file-tile--selected` rule in
204 * `desktop-files.css` — same accent border + tinted background
205 * the folder windows + wallpaper tiles use. No section-specific
206 * override here — visual parity across the whole shell.
207 */
208
209 /* Large tiles — sections that opt in with `tileSize: 'large'`.
210 *
211 * A section whose rows carry a photograph (a shop's products) reads
212 * as a catalogue, not a file list: the picture is what's being
213 * scanned, and at 48px it's a thumbnail of a thumbnail. Roughly
214 * doubling the icon well also gives a corner ribbon room to be a
215 * corner flash instead of covering the subject.
216 *
217 * The cell pitch lives in `TILE_METRICS_LARGE` (src/my-wordpress/
218 * index.ts) and the two MUST move together — a wider tile in a cell
219 * that didn't grow overlaps its neighbour. */
220 /*
221 * Image-led sections re-point the tile tokens for their whole
222 * subtree rather than overriding the tile's width directly. The base
223 * `.os-file-tile` rule then sizes itself from them, and so does
224 * everything derived from them (the label's max-width, the loading
225 * skeletons) — one declaration instead of a chain of overrides that
226 * have to be kept in step.
227 */
228 .os-my-wordpress__tiles--large {
229 --os-tile-w: var( --os-tile-w-large, 132px );
230 --os-tile-h: var( --os-tile-h-large, 160px );
231 }
232
233 .os-my-wordpress__tiles--large .os-file-tile__visual,
234 .os-my-wordpress__tiles--large .os-file-tile__icon {
235 width: 104px;
236 height: 104px;
237 font-size: 64px;
238 }
239
240 .os-my-wordpress__tiles--large .os-file-tile__preview {
241 width: 104px;
242 height: 104px;
243 border-radius: 8px;
244 }
245
246 /* Three lines of title at this width instead of two — a product name
247 * is long and the extra width earns the room. Matches the taller
248 * cell in `TILE_METRICS_LARGE`. */
249 .os-my-wordpress__tiles--large .os-file-tile__label {
250 -webkit-line-clamp: 3;
251 }
252
253 /* Featured-image tiles. Entries that have a featured image render it
254 * in the icon well instead of the section dashicon — decisive for
255 * image-led types like WooCommerce products. The base
256 * `.os-file-tile__preview` rule in `desktop-files.css`
257 * already sizes and crops it; all that's added here is a hairline
258 * border so a light-on-light photo still reads as a distinct object
259 * against the wallpaper, plus a neutral well behind it so a
260 * transparent PNG or a slow-loading image doesn't flash the
261 * wallpaper through. */
262 .os-my-wordpress__tile--entry .os-file-tile__preview {
263 background: var(
264 --os-media-tile-bg,
265 rgba( 0, 0, 0, 0.05 )
266 );
267 box-shadow: inset 0 0 0 1px rgba( 0, 0, 0, 0.12 );
268 }
269
270 /* Banded list views. A section can split its tiles into labelled
271 * bands (WooCommerce Orders groups by status, needs-attention first)
272 * instead of one flat canvas. The root container stops being a
273 * positioned canvas and becomes a plain stack; each band owns its
274 * own canvas below its heading. */
275 .os-my-wordpress__tiles--banded {
276 position: static;
277 min-height: 0;
278 }
279
280 .os-my-wordpress__band + .os-my-wordpress__band {
281 margin-block-start: 8px;
282 }
283
284 /* Bands are laid out in order before the first page arrives so none
285 * appears mid-scroll, but one that hasn't received a row yet stays
286 * out of the way rather than showing a heading over nothing. */
287 .os-my-wordpress__band--empty {
288 display: none;
289 }
290
291 .os-my-wordpress__band-title {
292 display: flex;
293 align-items: center;
294 gap: 8px;
295 position: sticky;
296 /* Keeps the band label visible while scrolling a long band —
297 * the whole point of banding is knowing what you're looking at. */
298 top: 0;
299 /* Above the absolutely-positioned tiles of every band, including
300 * the ones that come later in the DOM. */
301 z-index: 3;
302 margin: 0;
303 padding: 6px 12px;
304 font-size: 11px;
305 font-weight: 600;
306 letter-spacing: 0.06em;
307 text-transform: uppercase;
308 color: var( --os-ui-fg-muted, #787c82 );
309 /* Near-opaque on purpose. Tiles scrolling underneath are behind
310 * the bar, but at 85% they still read as ghostly blurred shapes
311 * through it, which looks like a rendering fault rather than
312 * frosted glass. The blur + saturate keeps the frosted feel while
313 * the alpha stops the content beneath resolving into shapes. */
314 background: color-mix(
315 in srgb,
316 var( --os-ui-bg, #fff ) 94%,
317 transparent
318 );
319 backdrop-filter: blur( 14px ) saturate( 180% );
320 border-block-end: 1px solid var( --os-ui-border, rgba( 0, 0, 0, 0.08 ) );
321 }
322
323 /* Browsers without `color-mix()` fall back to the flat surface —
324 * still opaque, just without the translucency. */
325 @supports not ( background: color-mix( in srgb, red 50%, transparent ) ) {
326 .os-my-wordpress__band-title {
327 background: var( --os-ui-bg, #fff );
328 }
329 }
330
331 /* Attention-carrying bands (WooCommerce's "Needs attention",
332 * "Problems") tint their bar so the eye lands there first instead of
333 * having to read every heading. */
334 .os-my-wordpress__band-title--warn {
335 color: var( --os-ui-warning, #8a6116 );
336 background: color-mix(
337 in srgb,
338 var( --os-ui-warning, #8a6116 ) 12%,
339 var( --os-ui-bg, #fff )
340 );
341 border-block-end-color: color-mix(
342 in srgb,
343 var( --os-ui-warning, #8a6116 ) 35%,
344 transparent
345 );
346 }
347
348 .os-my-wordpress__band-title--danger {
349 color: var( --os-ui-danger, #b32d2e );
350 background: color-mix(
351 in srgb,
352 var( --os-ui-danger, #b32d2e ) 12%,
353 var( --os-ui-bg, #fff )
354 );
355 border-block-end-color: color-mix(
356 in srgb,
357 var( --os-ui-danger, #b32d2e ) 35%,
358 transparent
359 );
360 }
361
362 .os-my-wordpress__band-count {
363 padding: 0 6px;
364 border-radius: 999px;
365 font-size: 11px;
366 line-height: 1.7;
367 background: color-mix( in srgb, currentColor 16%, transparent );
368 color: inherit;
369 }
370
371 /* Lock state — another user is currently editing this post. We dim
372 * the tile a touch and overlay a small dashicon-lock badge on the
373 * top-right of the icon. The whole tile stays clickable; the lock
374 * is just a visual heads-up so the user knows the takeover dialog
375 * is coming if they double-click. */
376 .os-my-wordpress__tile--locked {
377 opacity: 0.85;
378 }
379
380 .os-my-wordpress__tile-lock {
381 position: absolute;
382 top: 4px;
383 inset-inline-end: 14px;
384 width: 18px;
385 height: 18px;
386 font-size: 12px;
387 line-height: 18px;
388 text-align: center;
389 border-radius: 50%;
390 background: var( --os-danger, var( --os-ui-danger, #b32d2e ) );
391 color: var( --os-ui-fg-on-accent, #fff );
392 box-shadow:
393 0 0 0 1.5px rgba( 0, 0, 0, 0.4 ),
394 0 1px 3px rgba( 0, 0, 0, 0.35 );
395 pointer-events: none;
396 }
397
398 /* Tooltip lock banner — shown above the excerpt when present. */
399 .os-my-wordpress__tooltip-lock {
400 display: flex;
401 align-items: center;
402 gap: 6px;
403 margin: 0 0 8px;
404 padding: 6px 8px;
405 border-radius: 4px;
406 background: rgba( 179, 45, 46, 0.08 );
407 color: var( --os-danger, var( --os-ui-danger, #b32d2e ) );
408 font-size: 12px;
409 font-weight: 600;
410 }
411
412 .os-my-wordpress__tooltip-lock .dashicons {
413 font-size: 14px;
414 width: 14px;
415 height: 14px;
416 }
417
418 /* Plain two-line clamp without `-webkit-line-clamp`. The webkit
419 * variant promotes the label to its own composited layer, which on
420 * HiDPI screens snaps text to fractional device pixels and renders
421 * blurry. `max-height: 2 × line-height` + `overflow: hidden` looks
422 * the same and stays sharp.
423 */
424 .os-my-wordpress__tile .os-file-tile__label {
425 font-size: 12px;
426 line-height: 1.3;
427 max-height: calc( 1.3em * 2 );
428 text-align: center;
429 overflow: hidden;
430 max-width: 100%;
431 word-break: break-word;
432 }
433
434 /* ----- Entity list: two-pane split ----- */
435
436 .os-my-wordpress__split {
437 display: grid;
438 grid-template-columns: minmax( 240px, 60% ) minmax( 0, 1fr );
439 height: 100%;
440 min-height: 0;
441 }
442
443 .os-my-wordpress__list {
444 overflow-y: scroll;
445 border-inline-end: 1px solid var( --os-ui-border, #dcdcde );
446 min-width: 0;
447 }
448
449 /* Always-visible scrollbar styling for the icon canvases. macOS
450 * defaults to overlay scrollbars that hide until a wheel/scroll
451 * event — fine for documents but actively confusing on a tile
452 * canvas where the user can't tell whether more icons live below
453 * or to the right. We force the scrollbar to render at all times
454 * via `::-webkit-scrollbar` (works in WebKit / Blink / Edge), and
455 * the explicit `scrollbar-width: thin` covers Firefox. */
456 .os-my-wordpress__list,
457 .os-my-wordpress__grid {
458 scrollbar-width: thin;
459 scrollbar-color: rgba( 0, 0, 0, 0.25 ) transparent;
460 }
461
462 .os-my-wordpress__list::-webkit-scrollbar,
463 .os-my-wordpress__grid::-webkit-scrollbar {
464 width: 12px;
465 height: 12px;
466 }
467
468 .os-my-wordpress__list::-webkit-scrollbar-thumb,
469 .os-my-wordpress__grid::-webkit-scrollbar-thumb {
470 background: var( --os-ui-scrim, rgba( 0, 0, 0, 0.25 ) );
471 border-radius: 6px;
472 border: 3px solid transparent;
473 background-clip: padding-box;
474 }
475
476 .os-my-wordpress__list::-webkit-scrollbar-thumb:hover,
477 .os-my-wordpress__grid::-webkit-scrollbar-thumb:hover {
478 background: var( --os-ui-scrim, rgba( 0, 0, 0, 0.4 ) );
479 background-clip: padding-box;
480 }
481
482 .os-my-wordpress__list::-webkit-scrollbar-track,
483 .os-my-wordpress__grid::-webkit-scrollbar-track {
484 background: transparent;
485 }
486
487 .os-my-wordpress__sentinel {
488 height: 1px;
489 }
490
491 /* Tile-grid loading skeleton — placeholder tiles that mimic the
492 * icon + label shape of what's about to load. We dropped the
493 * spinning WordPress mark here because it read as an alien
494 * affordance inside the file-explorer surface; a skeleton signals
495 * "tiles are landing in these slots" instead of "the system is
496 * busy doing something opaque."
497 *
498 * Each placeholder is parented directly to the positioned canvas
499 * (`__canvas--positioned`) and `position: absolute` at the
500 * (left, top) the next real tile will occupy — see
501 * `layout.peekNextCells()` and `showLoadingSkeleton()` in
502 * `src/my-wordpress/index.ts`. Per-tile shimmer delay and label
503 * width are inlined so a row of placeholders reads as a cascade,
504 * not a uniform pulse.
505 *
506 * Tile dimensions mirror the real `.os-file-tile` width
507 * so a placeholder sits cleanly in the cell its successor will
508 * inherit.
509 */
510 .os-my-wordpress__skeleton-tile {
511 position: absolute;
512 display: flex;
513 flex-direction: column;
514 align-items: center;
515 gap: 6px;
516 /* Same box as the real tile it stands in for — a skeleton that
517 * doesn't match the grid makes the list jump when rows land. */
518 width: var( --os-tile-w, 88px );
519 height: var( --os-tile-h, 104px );
520 padding: 8px 4px;
521 box-sizing: border-box;
522 pointer-events: none;
523 }
524
525 .os-my-wordpress__skeleton-icon,
526 .os-my-wordpress__skeleton-label {
527 background: linear-gradient(
528 90deg,
529 var( --os-skeleton-low, var( --os-ui-hover, rgba( 0, 0, 0, 0.05 ) ) ) 0%,
530 var( --os-skeleton-high, var( --os-ui-hover, rgba( 0, 0, 0, 0.13 ) ) ) 50%,
531 var( --os-skeleton-low, var( --os-ui-hover, rgba( 0, 0, 0, 0.05 ) ) ) 100%
532 );
533 background-size: 200% 100%;
534 animation: os-my-wordpress-skeleton-shimmer 1.4s ease-in-out
535 var( --os-skeleton-delay, 0s ) infinite;
536 }
537
538 .os-my-wordpress__skeleton-icon {
539 width: 44px;
540 height: 44px;
541 border-radius: 10px;
542 }
543
544 .os-my-wordpress__skeleton-label {
545 width: 72%;
546 height: 10px;
547 border-radius: 4px;
548 }
549
550 @keyframes os-my-wordpress-skeleton-shimmer {
551 from {
552 background-position: 200% 0;
553 }
554 to {
555 background-position: -200% 0;
556 }
557 }
558
559 @media ( prefers-reduced-motion: reduce ) {
560 .os-my-wordpress__skeleton-icon,
561 .os-my-wordpress__skeleton-label {
562 animation: none;
563 }
564 }
565
566 /* ----- Right pane: preview ----- */
567
568 .os-my-wordpress__preview {
569 overflow: auto;
570 min-width: 0;
571 background: transparent;
572 }
573
574 .os-my-wordpress__preview-empty {
575 display: flex;
576 flex-direction: column;
577 gap: 6px;
578 align-items: center;
579 justify-content: center;
580 height: 100%;
581 color: var( --os-ui-fg-muted, #787c82 );
582 font-size: 13px;
583 padding: 24px;
584 text-align: center;
585 }
586
587 /* Type / status breakdown under a multi-selection's count. */
588 .os-my-wordpress__preview-selection-breakdown {
589 font-size: 12px;
590 opacity: 0.75;
591 }
592
593 /* One labelled control in the bulk-edit modal. Label above field,
594 * because the fields are wide (a category tree, a tag row) and a
595 * two-column grid would put a one-word label beside a control four
596 * times its height. */
597 .os-my-wordpress__bulk-row {
598 display: flex;
599 flex-direction: column;
600 gap: 6px;
601 margin-block-end: 16px;
602 }
603
604 .os-my-wordpress__bulk-label {
605 font-size: 12px;
606 font-weight: 600;
607 color: var( --os-ui-fg-muted, #787c82 );
608 }
609
610 .os-my-wordpress__preview-loading {
611 display: flex;
612 align-items: center;
613 justify-content: center;
614 height: 100%;
615 min-height: 320px;
616 padding: 32px;
617 box-sizing: border-box;
618 }
619
620 /* Preview-pane loader — same scale curve as the tile-grid first
621 * spinner and the window-loading overlay. The JS used to hard-code
622 * `size="128"`, which set an inline `--os-ui-spinner-size` that
623 * overrode any CSS knob; the size attribute is now omitted so this
624 * rule is the single source of truth for both the My WordPress
625 * preview and the wallpaper file-preview pane (which reuses this
626 * class deliberately).
627 */
628 .os-my-wordpress__preview-loading os-spinner {
629 --os-ui-spinner-size: clamp( 96px, 14vw, 192px );
630 }
631
632 .os-my-wordpress__article {
633 padding: 24px 32px;
634 max-width: 720px;
635 margin: 0 auto;
636 }
637
638 .os-my-wordpress__article-title {
639 font-size: 22px;
640 margin: 0 0 8px;
641 line-height: 1.3;
642 }
643
644 .os-my-wordpress__article-meta {
645 margin: 0 0 16px;
646 color: var( --os-ui-fg-muted, #50575e );
647 font-size: 12px;
648 }
649
650 .os-my-wordpress__article-hero {
651 width: 100%;
652 height: auto;
653 border-radius: 6px;
654 margin-bottom: 16px;
655 display: block;
656 }
657
658 .os-my-wordpress__article-content {
659 font-size: 14px;
660 line-height: 1.6;
661 }
662
663 .os-my-wordpress__article-content img {
664 max-width: 100%;
665 height: auto;
666 }
667
668 .os-my-wordpress__article-footer {
669 margin-top: 24px;
670 padding-top: 16px;
671 border-top: 1px solid var( --os-ui-border, #dcdcde );
672 display: flex;
673 justify-content: flex-end;
674 align-items: center;
675 gap: 8px;
676 flex-wrap: wrap;
677 }
678
679 /* ----- Empty / error states ----- */
680
681 .os-my-wordpress__empty,
682 .os-my-wordpress__error {
683 padding: 32px 24px;
684 text-align: center;
685 color: var( --os-ui-fg-muted, #787c82 );
686 font-size: 13px;
687 }
688
689 .os-my-wordpress__error {
690 color: var( --os-danger, var( --os-ui-danger, #b32d2e ) );
691 }
692
693 /* ----- Hover tooltip (floats over body) ----- */
694
695 .os-my-wordpress__tooltip {
696 position: fixed;
697 z-index: 100000;
698 max-width: 320px;
699 background: var(
700 --os-tooltip-bg,
701 var( --os-surface, var( --os-ui-surface, #fff ) )
702 );
703 color: var(
704 --os-tooltip-fg,
705 var( --os-fg, #1d2327 )
706 );
707 border: 1px solid var( --os-ui-border, #dcdcde );
708 border-radius: 6px;
709 padding: 12px;
710 box-shadow: 0 6px 24px rgba( 0, 0, 0, 0.18 );
711 font-size: 12px;
712 pointer-events: none;
713 }
714
715 .os-my-wordpress__tooltip-title {
716 font-weight: 600;
717 margin-bottom: 6px;
718 font-size: 13px;
719 }
720
721 .os-my-wordpress__tooltip-thumb {
722 display: block;
723 max-width: 100%;
724 height: auto;
725 border-radius: 4px;
726 margin: 6px 0;
727 }
728
729 .os-my-wordpress__tooltip-excerpt {
730 margin: 0;
731 color: var( --os-ui-fg-muted, #50575e );
732 line-height: 1.4;
733 }
734
735 /* ----- Context menu host ----- */
736
737 .os-my-wordpress__menu {
738 position: fixed;
739 z-index: 100001;
740 }
741
742 /* ---------------------------------------------------------------
743 * User dossier — right-pane preview when a person is selected.
744 * Header (avatar + name + roles + links), bio, stat cards row,
745 * 12-month activity sparkline, milestones, recent posts, top
746 * categories. Designed to fit comfortably on a 360px-wide pane
747 * but to stretch nicely up to ~720px before the line-length stops
748 * helping readability.
749 * --------------------------------------------------------------- */
750
751 .os-my-wordpress__user {
752 max-width: 720px;
753 }
754
755 .os-my-wordpress__user-header {
756 display: flex;
757 gap: 16px;
758 align-items: center;
759 margin-bottom: 16px;
760 }
761
762 .os-my-wordpress__user-avatar {
763 width: 96px;
764 height: 96px;
765 border-radius: 50%;
766 flex-shrink: 0;
767 box-shadow: 0 2px 8px rgba( 0, 0, 0, 0.12 );
768 }
769
770 .os-my-wordpress__user-headline {
771 flex: 1 1 auto;
772 min-width: 0;
773 }
774
775 .os-my-wordpress__user
776 .os-my-wordpress__article-title {
777 margin: 0 0 4px;
778 }
779
780 .os-my-wordpress__user-roles {
781 display: flex;
782 flex-wrap: wrap;
783 gap: 6px;
784 margin-bottom: 6px;
785 }
786
787 .os-my-wordpress__user-role {
788 display: inline-flex;
789 align-items: center;
790 padding: 2px 8px;
791 border-radius: 10px;
792 font-size: 11px;
793 font-weight: 600;
794 text-transform: uppercase;
795 letter-spacing: 0.04em;
796 background: rgba( 34, 113, 177, 0.12 );
797 color: var( --wp-admin-theme-color, #2271b1 );
798 }
799
800 .os-my-wordpress__user-links {
801 display: flex;
802 gap: 12px;
803 font-size: 12px;
804 }
805
806 .os-my-wordpress__user-links a {
807 color: var( --os-link, var( --os-ui-accent, #2271b1 ) );
808 text-decoration: none;
809 }
810
811 .os-my-wordpress__user-links a:hover {
812 text-decoration: underline;
813 }
814
815 .os-my-wordpress__user-bio {
816 font-size: 14px;
817 line-height: 1.5;
818 color: var( --os-fg, #1d2327 );
819 margin: 0 0 16px;
820 padding-left: 12px;
821 border-left: 3px solid var( --os-ui-border, #dcdcde );
822 }
823
824 /* ----- Stat cards row ----- */
825
826 .os-my-wordpress__user-stats {
827 display: grid;
828 grid-template-columns: repeat( auto-fit, minmax( 120px, 1fr ) );
829 gap: 8px;
830 margin-bottom: 20px;
831 }
832
833 .os-my-wordpress__user-stat {
834 display: flex;
835 flex-direction: column;
836 gap: 2px;
837 padding: 12px 14px;
838 border-radius: 8px;
839 background: var( --os-hover, var( --os-ui-hover, rgba( 0, 0, 0, 0.04 ) ) );
840 border: 1px solid var( --os-ui-border, #dcdcde );
841 }
842
843 .os-my-wordpress__user-stat-value {
844 font-size: 26px;
845 font-weight: 700;
846 line-height: 1.1;
847 color: var( --wp-admin-theme-color, #2271b1 );
848 font-variant-numeric: tabular-nums;
849 }
850
851 .os-my-wordpress__user-stat-label {
852 font-size: 12px;
853 color: var( --os-ui-fg-muted, #50575e );
854 text-transform: uppercase;
855 letter-spacing: 0.04em;
856 }
857
858 .os-my-wordpress__user-stat-caption {
859 font-size: 11px;
860 color: var( --os-ui-fg-muted, #787c82 );
861 }
862
863 /* ----- 12-month activity sparkline ----- */
864
865 .os-my-wordpress__user-section {
866 margin-bottom: 20px;
867 }
868
869 .os-my-wordpress__user-section h3 {
870 font-size: 13px;
871 font-weight: 600;
872 color: var( --os-ui-fg-muted, #50575e );
873 text-transform: uppercase;
874 letter-spacing: 0.04em;
875 margin: 0 0 8px;
876 }
877
878 .os-my-wordpress__user-spark-chart {
879 display: grid;
880 grid-template-columns: repeat( 12, 1fr );
881 gap: 4px;
882 height: 80px;
883 align-items: end;
884 padding: 6px 0;
885 }
886
887 .os-my-wordpress__user-spark-col {
888 display: flex;
889 flex-direction: column;
890 align-items: stretch;
891 justify-content: flex-end;
892 gap: 4px;
893 height: 100%;
894 min-height: 0;
895 }
896
897 .os-my-wordpress__user-spark-bar {
898 background: linear-gradient(
899 180deg,
900 var( --wp-admin-theme-color, #2271b1 ) 0%,
901 rgba( 34, 113, 177, 0.55 ) 100%
902 );
903 border-radius: 3px 3px 0 0;
904 min-height: 2px;
905 transition: height 0.3s ease;
906 }
907
908 .os-my-wordpress__user-spark-bar--empty {
909 background: var( --os-ui-border, #dcdcde );
910 min-height: 2px;
911 height: 2px !important;
912 }
913
914 .os-my-wordpress__user-spark-label {
915 font-size: 10px;
916 text-align: center;
917 color: var( --os-ui-fg-muted, #787c82 );
918 }
919
920 /* ----- Milestones ----- */
921
922 .os-my-wordpress__user-milestones {
923 display: grid;
924 grid-template-columns: repeat( auto-fit, minmax( 140px, 1fr ) );
925 gap: 12px;
926 margin: 0 0 20px;
927 }
928
929 .os-my-wordpress__user-milestones dt {
930 font-size: 11px;
931 color: var( --os-ui-fg-muted, #50575e );
932 text-transform: uppercase;
933 letter-spacing: 0.04em;
934 margin-bottom: 2px;
935 }
936
937 .os-my-wordpress__user-milestones dd {
938 font-size: 14px;
939 font-weight: 600;
940 margin: 0;
941 }
942
943 /* ----- Recent posts list ----- */
944
945 .os-my-wordpress__user-recent {
946 list-style: none;
947 margin: 0;
948 padding: 0;
949 display: flex;
950 flex-direction: column;
951 gap: 6px;
952 }
953
954 .os-my-wordpress__user-recent li {
955 display: flex;
956 flex-direction: column;
957 gap: 2px;
958 padding: 8px 10px;
959 border-radius: 6px;
960 background: var( --os-ui-hover, rgba( 0, 0, 0, 0.02 ) );
961 }
962
963 .os-my-wordpress__user-recent a {
964 font-weight: 600;
965 color: var( --os-link, var( --os-ui-accent, #2271b1 ) );
966 text-decoration: none;
967 }
968
969 .os-my-wordpress__user-recent a:hover {
970 text-decoration: underline;
971 }
972
973 .os-my-wordpress__user-recent-meta {
974 font-size: 11px;
975 color: var( --os-ui-fg-muted, #787c82 );
976 }
977
978 /* ----- Top categories chips ----- */
979
980 .os-my-wordpress__user-chips {
981 display: flex;
982 flex-wrap: wrap;
983 gap: 6px;
984 }
985
986 .os-my-wordpress__user-chip {
987 display: inline-flex;
988 align-items: center;
989 gap: 6px;
990 padding: 4px 10px;
991 border-radius: 999px;
992 font-size: 12px;
993 background: var( --os-ui-hover, rgba( 0, 0, 0, 0.05 ) );
994 border: 1px solid var( --os-ui-border, #dcdcde );
995 }
996
997 .os-my-wordpress__user-chip--tag {
998 background: rgba( 124, 58, 237, 0.08 );
999 border-color: rgba( 124, 58, 237, 0.25 );
1000 }
1001
1002 .os-my-wordpress__user-chip-count {
1003 font-weight: 700;
1004 color: var( --wp-admin-theme-color, #2271b1 );
1005 font-variant-numeric: tabular-nums;
1006 }
1007
1008 /* ---------------------------------------------------------------
1009 * Term dossier — same skeleton as the user dossier (header, stat
1010 * cards, sparkline, milestones, recent list, chips) plus a few
1011 * term-specific bits below: a colored taxonomy icon medallion in
1012 * the header, role badge variants for category vs tag, and a
1013 * "Top contributors" grid that pairs an author avatar with a
1014 * post count.
1015 * --------------------------------------------------------------- */
1016
1017 .os-my-wordpress__term-header {
1018 display: flex;
1019 align-items: center;
1020 gap: 16px;
1021 margin-bottom: 16px;
1022 }
1023
1024 .os-my-wordpress__term-icon {
1025 width: 64px;
1026 height: 64px;
1027 border-radius: 12px;
1028 display: inline-flex;
1029 align-items: center;
1030 justify-content: center;
1031 flex-shrink: 0;
1032 color: var( --os-ui-fg-on-accent, #fff );
1033 }
1034
1035 .os-my-wordpress__term-icon--category {
1036 background: linear-gradient( 135deg, var( --os-ui-accent, #2271b1 ) 0%, var( --os-ui-accent-strong, #135e96 ) 100% );
1037 box-shadow: 0 4px 12px rgba( 34, 113, 177, 0.32 );
1038 }
1039
1040 .os-my-wordpress__term-icon--tag {
1041 background: linear-gradient( 135deg, #7c3aed 0%, #5b21b6 100% );
1042 box-shadow: 0 4px 12px rgba( 124, 58, 237, 0.32 );
1043 }
1044
1045 .os-my-wordpress__user-role--category {
1046 background: rgba( 34, 113, 177, 0.12 );
1047 color: var( --os-ui-accent-strong, #135e96 );
1048 }
1049
1050 .os-my-wordpress__user-role--tag {
1051 background: rgba( 124, 58, 237, 0.12 );
1052 color: #6d28d9;
1053 }
1054
1055 /* Top contributors row — paired avatar + name + post count. */
1056 .os-my-wordpress__term-authors {
1057 display: grid;
1058 grid-template-columns: repeat( auto-fit, minmax( 180px, 1fr ) );
1059 gap: 8px;
1060 }
1061
1062 .os-my-wordpress__term-author {
1063 display: flex;
1064 align-items: center;
1065 gap: 10px;
1066 padding: 8px 12px;
1067 border-radius: 8px;
1068 background: var( --os-ui-hover, rgba( 0, 0, 0, 0.03 ) );
1069 border: 1px solid var( --os-ui-border, #dcdcde );
1070 }
1071
1072 .os-my-wordpress__term-author-avatar {
1073 width: 36px;
1074 height: 36px;
1075 border-radius: 50%;
1076 flex-shrink: 0;
1077 }
1078
1079 .os-my-wordpress__term-author-text {
1080 display: flex;
1081 flex-direction: column;
1082 gap: 2px;
1083 min-width: 0;
1084 }
1085
1086 .os-my-wordpress__term-author-name {
1087 font-weight: 600;
1088 font-size: 13px;
1089 overflow: hidden;
1090 text-overflow: ellipsis;
1091 white-space: nowrap;
1092 }
1093
1094 .os-my-wordpress__term-author-count {
1095 font-size: 11px;
1096 color: var( --os-ui-fg-muted, #50575e );
1097 }
1098
1099 /* ---------------------------------------------------------------
1100 * Comment dossier — header (avatar + name + status / date / count
1101 * badges + author archive / website / moderate links), optional
1102 * "in reply to" quote, the comment body, parent-post card,
1103 * direct-reply thread, and a moderation strip (IP + user agent)
1104 * for users with moderate_comments.
1105 * --------------------------------------------------------------- */
1106
1107 .os-my-wordpress__comment-status--approved {
1108 background: rgba( 34, 113, 177, 0.12 );
1109 color: var( --os-ui-accent-strong, #135e96 );
1110 }
1111
1112 .os-my-wordpress__comment-status--pending {
1113 background: rgba( 217, 119, 6, 0.16 );
1114 color: #b45309;
1115 }
1116
1117 .os-my-wordpress__comment-status--spam {
1118 background: rgba( 179, 45, 46, 0.14 );
1119 color: var( --os-ui-danger-hover, #b32d2e );
1120 }
1121
1122 .os-my-wordpress__comment-status--trash {
1123 background: var( --os-ui-hover, rgba( 0, 0, 0, 0.08 ) );
1124 color: var( --os-ui-fg-muted, #50575e );
1125 }
1126
1127 .os-my-wordpress__comment-date-badge {
1128 background: transparent;
1129 color: var( --os-ui-fg-muted, #50575e );
1130 border: 1px solid var( --os-ui-border, #dcdcde );
1131 text-transform: none;
1132 letter-spacing: normal;
1133 }
1134
1135 /* "In reply to ..." quote shown above the comment body when this
1136 * is a thread reply. */
1137 .os-my-wordpress__comment-quote {
1138 margin: 0 0 16px;
1139 padding: 10px 14px;
1140 border-left: 3px solid var( --wp-admin-theme-color, #2271b1 );
1141 background: rgba( 34, 113, 177, 0.06 );
1142 border-radius: 0 6px 6px 0;
1143 font-size: 13px;
1144 }
1145
1146 .os-my-wordpress__comment-quote-lead {
1147 font-size: 11px;
1148 font-weight: 600;
1149 color: var( --os-ui-fg-muted, #50575e );
1150 text-transform: uppercase;
1151 letter-spacing: 0.04em;
1152 margin-bottom: 4px;
1153 }
1154
1155 .os-my-wordpress__comment-quote p {
1156 margin: 0;
1157 color: var( --os-fg, #1d2327 );
1158 }
1159
1160 /* Comment body — same style as article-content but with a soft
1161 * card background so it reads as the focal element. */
1162 .os-my-wordpress__comment-body {
1163 padding: 14px 16px;
1164 background: var( --os-ui-hover, rgba( 0, 0, 0, 0.03 ) );
1165 border-radius: 8px;
1166 border: 1px solid var( --os-ui-border, #dcdcde );
1167 }
1168
1169 /* Parent-post card under the comment body. */
1170 .os-my-wordpress__comment-post {
1171 display: flex;
1172 flex-direction: column;
1173 gap: 4px;
1174 padding: 10px 14px;
1175 border-radius: 8px;
1176 background: var( --os-ui-hover, rgba( 0, 0, 0, 0.04 ) );
1177 border: 1px solid var( --os-ui-border, #dcdcde );
1178 }
1179
1180 .os-my-wordpress__comment-post-title {
1181 font-weight: 600;
1182 color: var( --os-link, var( --os-ui-accent, #2271b1 ) );
1183 text-decoration: none;
1184 }
1185
1186 .os-my-wordpress__comment-post-title:hover {
1187 text-decoration: underline;
1188 }
1189
1190 .os-my-wordpress__comment-post-meta {
1191 font-size: 11px;
1192 color: var( --os-ui-fg-muted, #787c82 );
1193 }
1194
1195 /* Replies list. */
1196 .os-my-wordpress__comment-replies {
1197 list-style: none;
1198 margin: 0;
1199 padding: 0;
1200 display: flex;
1201 flex-direction: column;
1202 gap: 10px;
1203 }
1204
1205 .os-my-wordpress__comment-reply {
1206 display: flex;
1207 gap: 10px;
1208 align-items: flex-start;
1209 padding: 10px 12px;
1210 border-radius: 8px;
1211 background: var( --os-ui-hover, rgba( 0, 0, 0, 0.02 ) );
1212 border: 1px solid var( --os-ui-border, #dcdcde );
1213 }
1214
1215 .os-my-wordpress__comment-reply-avatar {
1216 width: 32px;
1217 height: 32px;
1218 border-radius: 50%;
1219 flex-shrink: 0;
1220 }
1221
1222 .os-my-wordpress__comment-reply-text {
1223 display: flex;
1224 flex-direction: column;
1225 gap: 2px;
1226 min-width: 0;
1227 }
1228
1229 .os-my-wordpress__comment-reply-head {
1230 display: flex;
1231 align-items: baseline;
1232 gap: 8px;
1233 flex-wrap: wrap;
1234 }
1235
1236 .os-my-wordpress__comment-reply-name {
1237 font-weight: 600;
1238 font-size: 13px;
1239 }
1240
1241 .os-my-wordpress__comment-reply-when {
1242 font-size: 11px;
1243 color: var( --os-ui-fg-muted, #787c82 );
1244 }
1245
1246 .os-my-wordpress__comment-reply-excerpt {
1247 margin: 0;
1248 font-size: 13px;
1249 color: var( --os-fg, #1d2327 );
1250 line-height: 1.45;
1251 }
1252
1253 /* =================================================================== *
1254 * USERS — list tiles + activity footprint surface.
1255 *
1256 * The Users folder reuses the same canvas + 96×92 tile grid the
1257 * post tiles use; the user-tile content (avatar circle + label +
1258 * small sub-line) fits inside the cell. The "View activity
1259 * footprint" surface is a full-width body view (no split pane)
1260 * with hero / stats / heatmap / rhythm / timeline.
1261 *
1262 * Since 0.20.0.
1263 * =================================================================== */
1264
1265 /* User tile — replaces the dashicon glyph with a real avatar */
1266 .os-my-wordpress__tile--user {
1267 display: flex;
1268 flex-direction: column;
1269 align-items: center;
1270 justify-content: flex-start;
1271 gap: 4px;
1272 padding: 8px 4px 6px;
1273 box-sizing: border-box;
1274 }
1275
1276 .os-my-wordpress__user-tile-avatar {
1277 display: inline-flex;
1278 align-items: center;
1279 justify-content: center;
1280 width: 44px;
1281 height: 44px;
1282 border-radius: 50%;
1283 overflow: hidden;
1284 background: linear-gradient(
1285 135deg,
1286 rgba( 34, 113, 177, 0.18 ),
1287 rgba( 34, 113, 177, 0.04 )
1288 );
1289 box-shadow:
1290 inset 0 0 0 1px rgba( 0, 0, 0, 0.08 ),
1291 0 2px 6px rgba( 0, 0, 0, 0.08 );
1292 flex: 0 0 auto;
1293 }
1294
1295 .os-my-wordpress__user-tile-avatar img {
1296 width: 100%;
1297 height: 100%;
1298 object-fit: cover;
1299 display: block;
1300 }
1301
1302 .os-my-wordpress__user-tile-initials {
1303 font-weight: 600;
1304 font-size: 14px;
1305 letter-spacing: 0.02em;
1306 color: var( --wp-admin-theme-color, #2271b1 );
1307 text-transform: uppercase;
1308 }
1309
1310 /* Single-line label for user tiles — we already have a generic
1311 * label clamp, but the user variant gets only ONE line so the
1312 * sub-line ("Editor · 12 posts") can fit beneath it. */
1313 .os-my-wordpress__tile--user .os-file-tile__label {
1314 font-size: 11px;
1315 font-weight: 500;
1316 line-height: 1.25;
1317 max-height: 1.25em;
1318 white-space: nowrap;
1319 overflow: hidden;
1320 text-overflow: ellipsis;
1321 width: 100%;
1322 padding: 0 4px;
1323 box-sizing: border-box;
1324 }
1325
1326 .os-my-wordpress__user-tile-sub {
1327 font-size: 10px;
1328 line-height: 1.2;
1329 color: var( --os-tile-fg-muted, rgba( 0, 0, 0, 0.55 ) );
1330 max-height: 1.2em;
1331 white-space: nowrap;
1332 overflow: hidden;
1333 text-overflow: ellipsis;
1334 width: 100%;
1335 text-align: center;
1336 padding: 0 4px;
1337 box-sizing: border-box;
1338 }
1339
1340 /* Selected/hover user tiles inherit the same chrome the post tiles
1341 * use — see `.os-my-wordpress__tile--selected` above. */
1342
1343 /* ----- Activity footprint — full-width body surface -----
1344 *
1345 * Opens via the right-click context menu on a user tile (or the
1346 * dossier's "View activity footprint" button). Replaces the split
1347 * list/preview with a wide canvas so each section gets enough room
1348 * to read.
1349 */
1350
1351 .os-my-wordpress__footprint {
1352 display: flex;
1353 flex-direction: column;
1354 gap: 20px;
1355 padding: 24px 28px 32px;
1356 box-sizing: border-box;
1357 overflow-y: auto;
1358 height: 100%;
1359 /* Scroll container spans the full window width so wheel + touch
1360 * scroll work no matter where the pointer is — including in the
1361 * empty margins to the left / right of the content. The 1080px
1362 * cap is applied to each immediate child instead (below). */
1363 align-items: center;
1364 }
1365
1366 .os-my-wordpress__footprint > * {
1367 width: 100%;
1368 max-width: 1080px;
1369 }
1370
1371 .os-my-wordpress__footprint-section {
1372 border: 1px solid var( --os-ui-border, #dcdcde );
1373 border-radius: 12px;
1374 padding: 18px 20px;
1375 background: var(
1376 --os-my-wordpress-surface,
1377 var( --os-surface, var( --os-ui-surface, rgba( 255, 255, 255, 0.6 ) ) )
1378 );
1379 box-shadow: 0 1px 2px rgba( 0, 0, 0, 0.04 );
1380 /* The parent `.__footprint` is a flex column with `overflow-y:
1381 * auto`. Flex items default to `flex-shrink: 1`, so each section
1382 * would compress along the column axis when the combined natural
1383 * height exceeds the container — clipping the calendar heatmap
1384 * (the calendar section also sets `overflow-x: auto`, which
1385 * doesn't surface a vertical scrollbar). Lock the intrinsic
1386 * height so the parent scroller, not the children, handles the
1387 * overflow. */
1388 flex: 0 0 auto;
1389 }
1390
1391 .os-my-wordpress__footprint-section h3 {
1392 margin: 0 0 12px;
1393 font-size: 13px;
1394 font-weight: 600;
1395 letter-spacing: 0.04em;
1396 text-transform: uppercase;
1397 color: var( --os-ui-fg-muted, #50575e );
1398 }
1399
1400 /* ----- Hero ----- */
1401
1402 .os-my-wordpress__footprint-hero {
1403 display: flex;
1404 gap: 20px;
1405 align-items: center;
1406 padding: 24px;
1407 border-radius: 16px;
1408 background: linear-gradient(
1409 135deg,
1410 rgba( 34, 113, 177, 0.10 ) 0%,
1411 rgba( 34, 113, 177, 0.02 ) 60%,
1412 transparent 100%
1413 );
1414 border: 1px solid var( --os-ui-border, #dcdcde );
1415 }
1416
1417 .os-my-wordpress__footprint-avatar {
1418 width: 112px;
1419 height: 112px;
1420 border-radius: 50%;
1421 overflow: hidden;
1422 flex: 0 0 auto;
1423 box-shadow:
1424 inset 0 0 0 2px rgba( 255, 255, 255, 0.8 ),
1425 0 6px 24px rgba( 0, 0, 0, 0.14 );
1426 background: linear-gradient(
1427 135deg,
1428 rgba( 34, 113, 177, 0.18 ),
1429 rgba( 34, 113, 177, 0.04 )
1430 );
1431 display: inline-flex;
1432 align-items: center;
1433 justify-content: center;
1434 }
1435
1436 .os-my-wordpress__footprint-avatar img {
1437 width: 100%;
1438 height: 100%;
1439 object-fit: cover;
1440 display: block;
1441 }
1442
1443 .os-my-wordpress__footprint-avatar
1444 .os-my-wordpress__user-tile-initials {
1445 font-size: 36px;
1446 }
1447
1448 .os-my-wordpress__footprint-headline {
1449 min-width: 0;
1450 flex: 1 1 auto;
1451 display: flex;
1452 flex-direction: column;
1453 gap: 8px;
1454 }
1455
1456 .os-my-wordpress__footprint-title {
1457 margin: 0;
1458 font-size: 28px;
1459 line-height: 1.15;
1460 font-weight: 700;
1461 color: var( --os-fg, #1d2327 );
1462 }
1463
1464 .os-my-wordpress__footprint-meta {
1465 display: flex;
1466 flex-wrap: wrap;
1467 gap: 6px;
1468 align-items: center;
1469 }
1470
1471 .os-my-wordpress__footprint-since {
1472 background: var( --os-ui-hover, rgba( 0, 0, 0, 0.06 ) );
1473 color: var( --os-ui-fg-muted, #50575e );
1474 }
1475
1476 /* ----- Headline stats row (4 cards) ----- */
1477
1478 .os-my-wordpress__footprint-stats-row {
1479 display: grid;
1480 grid-template-columns: repeat( auto-fit, minmax( 160px, 1fr ) );
1481 gap: 12px;
1482 padding: 16px 18px;
1483 }
1484
1485 .os-my-wordpress__footprint-stats-row
1486 .os-my-wordpress__user-stat {
1487 background: var( --os-surface, var( --os-ui-surface, rgba( 255, 255, 255, 0.9 ) ) );
1488 box-shadow: 0 1px 4px rgba( 0, 0, 0, 0.04 );
1489 }
1490
1491 /* ----- Calendar heatmap (GitHub-style) ----- */
1492
1493 .os-my-wordpress__footprint-calendar-section {
1494 overflow-x: auto;
1495 }
1496
1497 .os-my-wordpress__footprint-calendar {
1498 display: flex;
1499 flex-direction: column;
1500 gap: 8px;
1501 /* Size to the grid itself so the legend (justify-content: flex-end
1502 * inside this same column) anchors to the grid's right edge instead
1503 * of the section's. Centered within the wider section by
1504 * `margin-inline: auto`. */
1505 width: max-content;
1506 max-width: 100%;
1507 margin-inline: auto;
1508 }
1509
1510 .os-my-wordpress__footprint-grid {
1511 display: grid;
1512 /* Row 1 holds month labels (auto height); rows 2–8 are the 7
1513 * weekdays at fixed 11px. Col 1 holds weekday labels (auto width);
1514 * subsequent cols are 11px-wide week tracks, set per-cell via
1515 * `grid-column` so the JS can place items explicitly. */
1516 grid-template-rows: auto repeat( 7, 11px );
1517 grid-template-columns: auto;
1518 grid-auto-columns: 11px;
1519 column-gap: 3px;
1520 row-gap: 3px;
1521 width: max-content;
1522 }
1523
1524 .os-my-wordpress__footprint-month,
1525 .os-my-wordpress__footprint-weekday {
1526 font-size: 10px;
1527 line-height: 11px;
1528 color: var( --os-ui-fg-muted, #50575e );
1529 white-space: nowrap;
1530 }
1531
1532 .os-my-wordpress__footprint-weekday {
1533 /* Sit flush to the right of the label gutter so each label reads
1534 * adjacent to its row. The 6px breathing room is in addition to
1535 * the grid's column-gap. */
1536 padding-inline-end: 6px;
1537 align-self: center;
1538 justify-self: end;
1539 }
1540
1541 .os-my-wordpress__footprint-month {
1542 padding-bottom: 2px;
1543 }
1544
1545 .os-my-wordpress__footprint-cell {
1546 width: 11px;
1547 height: 11px;
1548 border-radius: 2px;
1549 background: var( --os-ui-border, #ebedf0 );
1550 display: inline-block;
1551 transition: transform 0.12s ease;
1552 }
1553
1554 .os-my-wordpress__footprint-cell--pad {
1555 background: transparent;
1556 }
1557
1558 .os-my-wordpress__footprint-cell--l0 {
1559 background: var( --os-ui-hover, rgba( 0, 0, 0, 0.06 ) );
1560 }
1561
1562 .os-my-wordpress__footprint-cell--l1 {
1563 background: rgba( 34, 113, 177, 0.25 );
1564 }
1565
1566 .os-my-wordpress__footprint-cell--l2 {
1567 background: rgba( 34, 113, 177, 0.5 );
1568 }
1569
1570 .os-my-wordpress__footprint-cell--l3 {
1571 background: rgba( 34, 113, 177, 0.75 );
1572 }
1573
1574 .os-my-wordpress__footprint-cell--l4 {
1575 background: var( --wp-admin-theme-color, #2271b1 );
1576 }
1577
1578 .os-my-wordpress__footprint-cell:hover {
1579 transform: scale( 1.4 );
1580 z-index: 1;
1581 }
1582
1583 .os-my-wordpress__footprint-legend {
1584 display: flex;
1585 gap: 4px;
1586 align-items: center;
1587 justify-content: flex-end;
1588 font-size: 11px;
1589 color: var( --os-ui-fg-muted, #50575e );
1590 }
1591
1592 .os-my-wordpress__footprint-legend-label {
1593 font-size: 11px;
1594 color: var( --os-ui-fg-muted, #50575e );
1595 padding: 0 4px;
1596 }
1597
1598 /* ----- Rhythm (weekday + hour bar charts) ----- */
1599
1600 .os-my-wordpress__footprint-rhythm-grid {
1601 display: grid;
1602 grid-template-columns: minmax( 0, 1fr ) minmax( 0, 1.7fr );
1603 gap: 24px;
1604 }
1605
1606 @container ( max-width: 720px ) {
1607 .os-my-wordpress__footprint-rhythm-grid {
1608 grid-template-columns: 1fr;
1609 }
1610 }
1611
1612 .os-my-wordpress__footprint-chart-caption {
1613 font-size: 12px;
1614 color: var( --os-ui-fg-muted, #50575e );
1615 margin-bottom: 6px;
1616 }
1617
1618 .os-my-wordpress__footprint-bars {
1619 display: flex;
1620 align-items: end;
1621 gap: 4px;
1622 height: 100px;
1623 padding-bottom: 18px;
1624 position: relative;
1625 }
1626
1627 .os-my-wordpress__footprint-bar-col {
1628 flex: 1 1 0;
1629 min-width: 0;
1630 display: flex;
1631 flex-direction: column;
1632 align-items: stretch;
1633 justify-content: flex-end;
1634 gap: 4px;
1635 height: 100%;
1636 position: relative;
1637 }
1638
1639 .os-my-wordpress__footprint-bar {
1640 background: linear-gradient(
1641 180deg,
1642 var( --wp-admin-theme-color, #2271b1 ) 0%,
1643 rgba( 34, 113, 177, 0.55 ) 100%
1644 );
1645 border-radius: 3px 3px 0 0;
1646 min-height: 2px;
1647 transition: opacity 0.2s ease;
1648 }
1649
1650 .os-my-wordpress__footprint-bar--empty {
1651 background: var( --os-ui-border, #dcdcde );
1652 height: 2px !important;
1653 min-height: 2px;
1654 }
1655
1656 .os-my-wordpress__footprint-bar-label {
1657 position: absolute;
1658 bottom: -16px;
1659 left: 0;
1660 right: 0;
1661 text-align: center;
1662 font-size: 10px;
1663 color: var( --os-ui-fg-muted, #787c82 );
1664 }
1665
1666 /* ----- Most-prolific-month callout ----- */
1667
1668 .os-my-wordpress__footprint-callout {
1669 display: flex;
1670 flex-direction: column;
1671 gap: 4px;
1672 align-items: center;
1673 text-align: center;
1674 padding: 20px 24px;
1675 background: linear-gradient(
1676 135deg,
1677 rgba( 34, 113, 177, 0.10 ),
1678 rgba( 34, 113, 177, 0.02 )
1679 );
1680 }
1681
1682 .os-my-wordpress__footprint-callout-label {
1683 font-size: 11px;
1684 text-transform: uppercase;
1685 letter-spacing: 0.08em;
1686 color: var( --os-ui-fg-muted, #50575e );
1687 font-weight: 600;
1688 }
1689
1690 .os-my-wordpress__footprint-callout-value {
1691 margin: 2px 0;
1692 font-size: 24px;
1693 font-weight: 700;
1694 color: var( --os-fg, #1d2327 );
1695 }
1696
1697 .os-my-wordpress__footprint-callout-detail {
1698 margin: 0;
1699 font-size: 13px;
1700 color: var( --os-ui-fg-muted, #50575e );
1701 max-width: 480px;
1702 }
1703
1704 /* ----- Recent-activity timeline ----- */
1705
1706 .os-my-wordpress__footprint-timeline {
1707 list-style: none;
1708 margin: 0;
1709 padding: 0;
1710 position: relative;
1711 display: flex;
1712 flex-direction: column;
1713 gap: 12px;
1714 }
1715
1716 .os-my-wordpress__footprint-timeline::before {
1717 content: '';
1718 position: absolute;
1719 inset-inline-start: 13px;
1720 top: 4px;
1721 bottom: 4px;
1722 width: 2px;
1723 background: var( --os-ui-border, #dcdcde );
1724 border-radius: 1px;
1725 }
1726
1727 .os-my-wordpress__footprint-event {
1728 display: flex;
1729 gap: 12px;
1730 align-items: flex-start;
1731 position: relative;
1732 padding-inline-start: 36px;
1733 min-height: 28px;
1734 }
1735
1736 .os-my-wordpress__footprint-dot {
1737 position: absolute;
1738 inset-inline-start: 0;
1739 top: 0;
1740 width: 28px;
1741 height: 28px;
1742 border-radius: 50%;
1743 display: inline-flex;
1744 align-items: center;
1745 justify-content: center;
1746 background: var( --os-surface, var( --os-ui-surface, #fff ) );
1747 border: 2px solid var( --wp-admin-theme-color, #2271b1 );
1748 color: var( --wp-admin-theme-color, #2271b1 );
1749 }
1750
1751 .os-my-wordpress__footprint-event--comment
1752 .os-my-wordpress__footprint-dot {
1753 border-color: var( --os-ui-fg-muted, #787c82 );
1754 color: var( --os-ui-fg-muted, #787c82 );
1755 }
1756
1757 .os-my-wordpress__footprint-dot .dashicons {
1758 font-size: 14px;
1759 width: 14px;
1760 height: 14px;
1761 line-height: 1;
1762 }
1763
1764 .os-my-wordpress__footprint-event-body {
1765 display: flex;
1766 flex-direction: column;
1767 gap: 2px;
1768 min-width: 0;
1769 flex: 1 1 auto;
1770 }
1771
1772 .os-my-wordpress__footprint-event-title {
1773 font-weight: 600;
1774 font-size: 13px;
1775 color: var( --os-link, var( --os-ui-accent, #2271b1 ) );
1776 text-decoration: none;
1777 overflow: hidden;
1778 text-overflow: ellipsis;
1779 white-space: nowrap;
1780 }
1781
1782 a.os-my-wordpress__footprint-event-title:hover {
1783 text-decoration: underline;
1784 }
1785
1786 .os-my-wordpress__footprint-event-meta {
1787 font-size: 11px;
1788 color: var( --os-ui-fg-muted, #787c82 );
1789 }
1790
1791 /* ----- Footer actions ----- */
1792
1793 .os-my-wordpress__footprint-footer {
1794 display: flex;
1795 justify-content: flex-end;
1796 align-items: center;
1797 gap: 8px;
1798 flex-wrap: wrap;
1799 background: transparent;
1800 border-color: transparent;
1801 box-shadow: none;
1802 padding: 0;
1803 }
1804
1805 /* ============================================================ *
1806 * Status ribbon — diagonal corner banner for non-published tiles
1807 * (since 0.21.0)
1808 *
1809 * Classic 45° corner ribbon — same affordance as a stamp on a
1810 * document. Applied to every tile whose post status isn't
1811 * `publish` across every My WordPress section (Posts, Pages,
1812 * Media drill-in, plugin kinds).
1813 *
1814 * Implementation:
1815 * 1. Tiles with a status modifier get `overflow: hidden` so the
1816 * ribbon's overshoot clips to the tile bounds.
1817 * 2. Ribbon is a wide strip (`width: 110px`) anchored to the
1818 * top-right corner, rotated +45° so it forms a diagonal
1819 * banner across that corner. The strip extends past the
1820 * tile edges; `overflow: hidden` on the parent crops it
1821 * into a clean triangle.
1822 *
1823 * The status tiles need a positioning context. `.os-
1824 * file-tile` is `position: absolute` (canvas layout) on the
1825 * Posts/Pages browse views — that satisfies the positioning-
1826 * context requirement. For the Media drill-in usage tiles we
1827 * swap from `static` to `relative` via the per-status rule
1828 * below so the ribbon stays anchored to its own tile.
1829 * ============================================================ */
1830
1831 /* Status ribbon — the diagonal corner banner — is now drawn by
1832 * the `<os-ribbon>` web component slotted inside `<os-tile>`.
1833 * The component's own shadow-DOM styles own placement, rotation,
1834 * background, lettering, and the WP admin-theme tint. The only
1835 * surface-specific rule left here is dimming the icon on non-
1836 * published tiles so the unpublished signal carries even when
1837 * the ribbon is hidden via the OS-settings toggle. */
1838
1839 .os-my-wordpress__tile--draft,
1840 .os-my-wordpress__tile--pending,
1841 .os-my-wordpress__tile--private,
1842 .os-my-wordpress__tile--future {
1843 overflow: hidden;
1844 }
1845
1846 os-tile[ status='draft' ] .os-file-tile__icon,
1847 os-tile[ status='pending' ] .os-file-tile__icon,
1848 os-tile[ status='private' ] .os-file-tile__icon,
1849 os-tile[ status='future' ] .os-file-tile__icon {
1850 opacity: 0.7;
1851 }
1852
1853 /* ============================================================ *
1854 * Media section (since 0.21.0)
1855 * ============================================================ */
1856
1857 .os-my-wordpress__media-grid {
1858 display: grid;
1859 grid-template-columns: repeat( auto-fill, minmax( 120px, 1fr ) );
1860 /* A flow grid rather than the absolute canvas, but the air
1861 * between two icons should not depend on which window you are
1862 * looking at — so the gaps and the gutter come from the same
1863 * tokens the canvas pitch is built from. */
1864 gap: var( --os-grid-gap-y, 16px ) var( --os-grid-gap-x, 20px );
1865 padding: var( --os-grid-padding, 16px );
1866 overflow-y: auto;
1867 align-content: start;
1868 }
1869
1870 .os-my-wordpress__media-tile {
1871 /* Override the base `.os-file-tile` (position: absolute,
1872 * width: 88px) so media tiles flow inside the CSS Grid instead of
1873 * stacking at (0,0) like the absolute-positioned post/user tiles.
1874 *
1875 * `relative` (not `static`) so the tile remains a containing
1876 * block for absolutely-positioned descendants — the `::after`
1877 * shortcut-arrow badge on attachment tiles, and the
1878 * `<os-ribbon>` post-status corner ribbon — both of which
1879 * would otherwise escape to the nearest positioned ancestor
1880 * (the window, the desktop, the viewport) and render way off
1881 * the tile. */
1882 position: relative;
1883 width: auto;
1884 /* …and out of the fixed tile height for the same reason: a media
1885 * tile is a square thumbnail plus a caption, sized by the grid
1886 * column it lands in, not by the icon-canvas cell. */
1887 height: auto;
1888 display: flex;
1889 flex-direction: column;
1890 align-items: stretch;
1891 gap: 6px;
1892 padding: 8px;
1893 background: transparent;
1894 border: 1px solid transparent;
1895 border-radius: 8px;
1896 cursor: pointer;
1897 text-align: center;
1898 min-width: 0;
1899 }
1900
1901 .os-my-wordpress__media-tile:hover {
1902 background: var( --os-hover, var( --os-ui-hover, rgba( 0, 0, 0, 0.04 ) ) );
1903 }
1904
1905 /* Media tiles inherit the canonical `.os-file-tile--selected`
1906 * rule from `desktop-files.css` — accent inset border + tinted
1907 * background — same as every other tile in the shell. */
1908
1909 /* Override the canonical 48×48 visual/preview sizing — media tiles
1910 * want the visual to fill the full grid-cell width as a square
1911 * thumbnail (or icon-fallback square). Photos browser look, not
1912 * folder-icon look. Applies to BOTH the `<img>` (real thumbnail)
1913 * and the dashicon fallback (non-image MIME), so the two tile
1914 * shapes are visually consistent in the grid. */
1915 .os-my-wordpress__media-tile .os-file-tile__visual {
1916 display: flex;
1917 align-items: center;
1918 justify-content: center;
1919 width: 100%;
1920 height: auto;
1921 aspect-ratio: 1 / 1;
1922 overflow: hidden;
1923 border-radius: 6px;
1924 background: var(
1925 --os-media-tile-bg,
1926 rgba( 0, 0, 0, 0.05 )
1927 );
1928 /* Reset the base 32px font + 48px size since we're sizing the
1929 * inner img/icon explicitly below. */
1930 font-size: 0;
1931 line-height: 1;
1932 }
1933
1934 .os-my-wordpress__media-tile .os-file-tile__preview {
1935 width: 100%;
1936 height: 100%;
1937 object-fit: cover;
1938 border-radius: 0;
1939 }
1940
1941 .os-my-wordpress__media-tile .os-file-tile__icon {
1942 /* Centered dashicon fallback — proportional to the larger
1943 * thumbnail well so it doesn't look like a postage stamp. */
1944 width: auto;
1945 height: auto;
1946 font-size: 36px;
1947 color: var( --os-ui-fg-muted, #787c82 );
1948 }
1949
1950 .os-my-wordpress__media-tile .os-file-tile__label {
1951 font-size: 12px;
1952 line-height: 1.3;
1953 overflow: hidden;
1954 text-overflow: ellipsis;
1955 display: -webkit-box;
1956 -webkit-line-clamp: 2;
1957 -webkit-box-orient: vertical;
1958 }
1959
1960 /* ----- Media preview pane ----- */
1961
1962 .os-my-wordpress__media-pane {
1963 display: flex;
1964 flex-direction: column;
1965 gap: 16px;
1966 padding: 16px;
1967 }
1968
1969 .os-my-wordpress__media-title {
1970 font-size: 16px;
1971 font-weight: 600;
1972 margin: 0;
1973 }
1974
1975 .os-my-wordpress__media-visual {
1976 display: flex;
1977 align-items: center;
1978 justify-content: center;
1979 background: var( --os-media-visual-bg, var( --os-ui-hover, rgba( 0, 0, 0, 0.04 ) ) );
1980 border-radius: 8px;
1981 min-height: 200px;
1982 max-height: 480px;
1983 overflow: hidden;
1984 }
1985
1986 .os-my-wordpress__media-image,
1987 .os-my-wordpress__media-video {
1988 max-width: 100%;
1989 max-height: 480px;
1990 object-fit: contain;
1991 }
1992
1993 .os-my-wordpress__media-fallback-icon {
1994 font-size: 96px;
1995 width: 96px;
1996 height: 96px;
1997 color: var( --os-ui-fg-muted, #787c82 );
1998 }
1999
2000 .os-my-wordpress__media-doc-link {
2001 margin-inline-start: 16px;
2002 align-self: center;
2003 }
2004
2005 .os-my-wordpress__media-audio-stack {
2006 display: flex;
2007 flex-direction: column;
2008 align-items: center;
2009 gap: 12px;
2010 padding: 24px;
2011 }
2012
2013 .os-my-wordpress__media-meta {
2014 display: grid;
2015 grid-template-columns: max-content 1fr;
2016 gap: 4px 16px;
2017 font-size: 13px;
2018 margin: 0;
2019 }
2020
2021 .os-my-wordpress__media-meta-term {
2022 color: var( --os-ui-fg-muted, #787c82 );
2023 margin: 0;
2024 }
2025
2026 .os-my-wordpress__media-meta-value {
2027 color: var( --os-ui-fg, #1d2327 );
2028 word-break: break-word;
2029 margin: 0;
2030 }
2031
2032 .os-my-wordpress__media-actions {
2033 display: flex;
2034 flex-wrap: wrap;
2035 gap: 8px;
2036 padding-top: 8px;
2037 border-top: 1px solid var( --os-ui-border, #dcdcde );
2038 }
2039
2040 /* ----- Media drill-in ----- */
2041
2042 /* Drill-in: referencing-posts list. Visually identical to the
2043 * Posts / Pages tiles — same `os-file-tile` chrome (48px
2044 * dashicon + 88px-wide two-line label). We can't reuse the
2045 * absolute-positioning canvas layout from `renderEntityList` here
2046 * (those internals don't export), so this surface uses a flex-wrap
2047 * of fixed-width tiles to reproduce the look.
2048 *
2049 * NOTE: this rule INTENTIONALLY overrides the `__media-grid`
2050 * defaults (which target square thumbnails on 130px columns) so
2051 * usage tiles match the canvas-flowed post tiles instead.
2052 */
2053 .os-my-wordpress__usage-grid {
2054 display: flex;
2055 flex-wrap: wrap;
2056 gap: var( --os-grid-gap-y, 16px ) var( --os-grid-gap-x, 20px );
2057 padding: var( --os-grid-padding, 16px );
2058 align-content: flex-start;
2059 }
2060
2061 /* Reset the `__media-tile` overrides for usage tiles so they
2062 * inherit the unmodified `.os-file-tile` chrome the
2063 * canvas-positioned post tiles use — except for `position: static`
2064 * so they participate in the flex layout. */
2065 .os-my-wordpress__tile--usage {
2066 width: var( --os-tile-w, 88px );
2067 align-items: center;
2068 padding: 8px 4px;
2069 gap: 6px;
2070 }
2071
2072 /* Right-pane summary bar sits ABOVE the inline media preview. */
2073 .os-my-wordpress__media-detail-summary-bar {
2074 padding: 12px 16px;
2075 border-bottom: 1px solid var( --os-ui-border, #dcdcde );
2076 }
2077
2078 .os-my-wordpress__media-detail-summary {
2079 margin: 0;
2080 color: var( --os-ui-fg-muted, #787c82 );
2081 font-size: 13px;
2082 }
2083
2084 .os-my-wordpress__media-detail-preview {
2085 /* Lets the embedded `__media-pane` keep its own padding without
2086 * fighting the summary bar's spacing. */
2087 display: block;
2088 }
2089
2090 /* ------------------------------------------------------------------ */
2091 /* Agents section (`agent` entity kind — src/my-wordpress/agents-renderer.ts) */
2092 /* ------------------------------------------------------------------ */
2093
2094 .dm-agents {
2095 display: flex;
2096 flex-direction: column;
2097 height: 100%;
2098 min-height: 0;
2099 padding: 12px;
2100 gap: 10px;
2101 overflow: hidden;
2102 box-sizing: border-box;
2103 }
2104
2105 /* Section-level loading — same scale curve as the My WordPress
2106 preview loader and the window-loading overlay, instead of the bare
2107 48px component default. */
2108 .dm-agents__loading {
2109 display: flex;
2110 align-items: center;
2111 justify-content: center;
2112 height: 100%;
2113 min-height: 320px;
2114 }
2115
2116 .dm-agents__loading os-spinner {
2117 --os-ui-spinner-size: clamp( 96px, 14vw, 192px );
2118 }
2119
2120 .dm-agents__layout {
2121 display: flex;
2122 flex: 1;
2123 min-height: 0;
2124 gap: 12px;
2125 }
2126
2127 /* Sidebar column: a fixed "Create agent" header over the scrolling
2128 list. The button used to be the list's last child, which put it out
2129 of reach on any site with enough agents to need it. */
2130 .dm-agents__sidebar {
2131 display: flex;
2132 flex-direction: column;
2133 flex: 0 0 260px;
2134 /* `min-width: auto` on a flex item resolves to its min-content
2135 width, and the rows carry long `white-space: nowrap` descriptions
2136 — without this the column ignores its 260px basis and eats the
2137 detail pane. The scroll container used to be this item, whose
2138 non-visible overflow zeroed the minimum for free. */
2139 min-width: 0;
2140 min-height: 0;
2141 border-inline-end: 1px solid var( --os-border, rgba( 0, 0, 0, 0.08 ) );
2142 }
2143
2144 .dm-agents__list-toolbar {
2145 flex: none;
2146 display: flex;
2147 padding-block-end: 8px;
2148 padding-inline-end: 8px;
2149 }
2150
2151 .dm-agents__list-toolbar .dm-agents__create {
2152 flex: 1;
2153 }
2154
2155 .dm-agents__list {
2156 display: flex;
2157 flex-direction: column;
2158 gap: 4px;
2159 flex: 1;
2160 min-height: 0;
2161 overflow-y: auto;
2162 padding-inline-end: 4px;
2163 }
2164
2165 .dm-agents__row {
2166 display: flex;
2167 align-items: center;
2168 gap: 8px;
2169 padding: 8px;
2170 border-radius: 8px;
2171 cursor: pointer;
2172 }
2173
2174 .dm-agents__row:hover {
2175 background: var( --os-hover, rgba( 0, 0, 0, 0.06 ) );
2176 }
2177
2178 .dm-agents__row.is-selected {
2179 background: var( --os-selected, rgba( 0, 0, 0, 0.1 ) );
2180 }
2181
2182 .dm-agents__row-avatar {
2183 width: 32px;
2184 height: 32px;
2185 border-radius: 50%;
2186 /* Placeholder behind the avatar image while it loads — follows the
2187 palette so it isn't a white disc on a dark station. */
2188 background: var( --os-ui-surface-elevated, #fff );
2189 flex: none;
2190 }
2191
2192 .dm-agents__row-text {
2193 display: flex;
2194 flex-direction: column;
2195 min-width: 0;
2196 flex: 1;
2197 }
2198
2199 .dm-agents__row-name {
2200 font-weight: 600;
2201 white-space: nowrap;
2202 overflow: hidden;
2203 text-overflow: ellipsis;
2204 }
2205
2206 .dm-agents__row-desc {
2207 font-size: 12px;
2208 opacity: 0.65;
2209 white-space: nowrap;
2210 overflow: hidden;
2211 text-overflow: ellipsis;
2212 }
2213
2214
2215 .dm-agents__detail {
2216 flex: 1;
2217 min-width: 0;
2218 overflow-y: auto;
2219 display: flex;
2220 flex-direction: column;
2221 gap: 10px;
2222 }
2223
2224 .dm-agents__detail-head {
2225 display: flex;
2226 align-items: center;
2227 gap: 10px;
2228 }
2229
2230 .dm-agents__detail-avatar {
2231 width: 48px;
2232 height: 48px;
2233 border-radius: 50%;
2234 /* Placeholder behind the avatar image while it loads — follows the
2235 palette so it isn't a white disc on a dark station. */
2236 background: var( --os-ui-surface-elevated, #fff );
2237 flex: none;
2238 }
2239
2240 .dm-agents__detail-title {
2241 flex: 1;
2242 min-width: 0;
2243 }
2244
2245 .dm-agents__detail-title h3 {
2246 margin: 0;
2247 font-size: 16px;
2248 }
2249
2250 .dm-agents__detail-slug {
2251 font-size: 12px;
2252 opacity: 0.6;
2253 }
2254
2255 /* Verbs get their own row under the identity block: the set grows
2256 (profile, contributions, desktop, chat, delete) and squeezing them
2257 beside the name truncated it first. */
2258 .dm-agents__detail-actions {
2259 display: flex;
2260 flex-wrap: wrap;
2261 gap: 8px;
2262 }
2263
2264 .dm-agents__tabs {
2265 display: flex;
2266 gap: 4px;
2267 border-bottom: 1px solid var( --os-border, rgba( 0, 0, 0, 0.08 ) );
2268 }
2269
2270 .dm-agents__tab {
2271 appearance: none;
2272 background: none;
2273 border: none;
2274 border-bottom: 2px solid transparent;
2275 padding: 6px 10px;
2276 font: inherit;
2277 color: inherit;
2278 cursor: pointer;
2279 opacity: 0.7;
2280 }
2281
2282 .dm-agents__tab.is-active {
2283 border-bottom-color: var( --os-accent, #2271b1 );
2284 opacity: 1;
2285 font-weight: 600;
2286 }
2287
2288 .dm-agents__pane {
2289 display: flex;
2290 flex-direction: column;
2291 gap: 10px;
2292 padding-bottom: 12px;
2293 }
2294
2295 /* Pane-level loading: same big, centered WordPress mark the section
2296 loader uses, instead of a bare 48px spinner pinned to the top-left
2297 of the pane. */
2298 .dm-agents__pane--loading {
2299 align-items: center;
2300 justify-content: center;
2301 flex: 1;
2302 min-height: 260px;
2303 }
2304
2305 .dm-agents__pane--loading os-spinner {
2306 --os-ui-spinner-size: clamp( 96px, 12vw, 160px );
2307 }
2308
2309 .dm-agents__hint {
2310 margin: 0;
2311 font-size: 12px;
2312 opacity: 0.7;
2313 }
2314
2315 .dm-agents__category {
2316 margin: 8px 0 0;
2317 font-size: 12px;
2318 text-transform: uppercase;
2319 letter-spacing: 0.04em;
2320 opacity: 0.6;
2321 }
2322
2323 .dm-agents__ability {
2324 display: grid;
2325 grid-template-columns: 1fr auto;
2326 gap: 2px 8px;
2327 align-items: center;
2328 padding: 4px 0;
2329 }
2330
2331 .dm-agents__ability-desc {
2332 grid-column: 1 / -1;
2333 margin: 0;
2334 font-size: 12px;
2335 opacity: 0.6;
2336 }
2337
2338 .dm-agents__trigger {
2339 border: 1px solid var( --os-border, rgba( 0, 0, 0, 0.08 ) );
2340 border-radius: 8px;
2341 padding: 8px 10px;
2342 display: flex;
2343 flex-direction: column;
2344 gap: 6px;
2345 }
2346
2347 .dm-agents__trigger-head {
2348 display: flex;
2349 align-items: center;
2350 gap: 8px;
2351 }
2352
2353 .dm-agents__trigger-summary {
2354 flex: 1;
2355 font-size: 12px;
2356 opacity: 0.65;
2357 white-space: nowrap;
2358 overflow: hidden;
2359 text-overflow: ellipsis;
2360 }
2361
2362 .dm-agents__trigger-config {
2363 display: flex;
2364 flex-wrap: wrap;
2365 gap: 4px 14px;
2366 }
2367
2368 .dm-agents__actions {
2369 display: flex;
2370 gap: 8px;
2371 }
2372