PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.13
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.13
1.1.13 1.1.12 1.1.11 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 All 37 releases
← All changes | assets/css/my-wordpress.css +1479 -396 0.9.6 → 1.1.13 View file →
@@ -1,13 +1,12 @@
1 1 /**
2 2 * My WordPress — window-local layout.
3 3 *
4 4 * Two-pane file-explorer for browsing WordPress entities. Mirrors the
5 - * Recycle Bin and Posts window CSS conventions (`desktop-mode-*`
5 + * Recycle Bin and Posts window CSS conventions (`os-*`
6 6 * BEM-ish prefix, container-relative geometry, theming via the
7 - * desktop-mode-variables CSS custom properties).
7 + * os-variables CSS custom properties).
8 8 *
9 - * @since 0.8.0
10 9 */
11 10
12 11 .desktop-mode-my-wordpress {
13 12 display: flex;
@@ -15,55 +14,67 @@
15 14 width: 100%;
16 15 height: 100%;
17 16 min-height: 0;
18 17 font-family: var(
19 - --desktop-mode-font,
18 + --os-font,
20 19 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif
21 20 );
22 - color: var( --desktop-mode-my-wordpress-fg, #1d2327 );
21 + color: var( --os-my-wordpress-fg, var( --os-ui-fg, #1d2327 ) );
23 22 /* Window background — separate from the wallpaper bg so the
24 23 * folder window reads as a real OS window even when the desktop
25 24 * gradient is dark. Themes / plugins can override
26 - * `--desktop-mode-my-wordpress-bg` to repaint just this surface
25 + * `--os-my-wordpress-bg` to repaint just this surface
27 26 * without touching every other window. */
28 27 background: var(
29 - --desktop-mode-my-wordpress-bg,
30 - var( --desktop-mode-window-bg, #fff )
28 + --os-my-wordpress-bg,
29 + var( --os-window-bg, #fff )
31 30 );
32 - /* Light-context tile color tokens — same recipe as the folder
33 - * window. Tiles inside My WordPress paint dark-on-light. */
34 - --desktop-mode-tile-fg: var( --desktop-mode-my-wordpress-fg, #1d2327 );
35 - --desktop-mode-tile-fg-muted: rgba( 0, 0, 0, 0.55 );
36 - --desktop-mode-tile-hover-bg: var(
37 - --desktop-mode-hover,
31 + /* Tile color tokens — same recipe as the folder window. Both
32 + * chain through the palette so the surface follows the active
33 + * desktop theme, with the pre-brand WordPress-admin literal as
34 + * the floor if no stylesheet declares one.
35 + *
36 + * `--os-tile-fg-muted` used to be the bare literal below, which
37 + * outranked the palette's own value and painted every tile's
38 + * secondary line near-black — invisible on a dark station, while
39 + * the label right beside it followed the theme correctly. A
40 + * colour declared next to the thing it paints is out of reach of
41 + * the palette AND of every desktop theme. */
42 + --os-tile-fg: var( --os-my-wordpress-fg, var( --os-ui-fg, #1d2327 ) );
43 + --os-tile-fg-muted: var(
44 + --os-my-wordpress-fg-muted,
45 + var( --os-ui-fg-muted, rgba( 0, 0, 0, 0.55 ) )
46 + );
47 + --os-tile-hover-bg: var(
48 + --os-hover,
38 49 rgba( 0, 0, 0, 0.06 )
39 50 );
40 51 /* Light-context label rendering — same recipe as the folder
41 52 * window. Defined as tokens in `variables.css`; the single
42 - * `.desktop-mode-file-tile__label` rule reads them for every
53 + * `.os-file-tile__label` rule reads them for every
43 54 * surface. */
44 - --desktop-mode-tile-label-shadow: none;
45 - --desktop-mode-tile-label-weight: 500;
46 - --desktop-mode-tile-label-smoothing: antialiased;
47 - --desktop-mode-tile-label-color: var( --desktop-mode-my-wordpress-fg, #1d2327 );
55 + --os-tile-label-shadow: none;
56 + --os-tile-label-weight: 500;
57 + --os-tile-label-smoothing: antialiased;
58 + --os-tile-label-color: var( --os-my-wordpress-fg, var( --os-ui-fg, #1d2327 ) );
48 59 }
49 60
50 -/* Pinned-icon visual cue — used by `desktop-mode-icon--pinned` (the
61 +/* Pinned-icon visual cue — used by `os-icon--pinned` (the
51 62 * generic flag added in 0.8.0). The icon-rail itself owns the
52 63 * non-draggable invariant; this rule just removes the grab affordance
53 64 * if the framework ever attaches one in a later phase.
54 65 */
55 -.desktop-mode-icon--pinned {
66 +.os-icon--pinned {
56 67 cursor: pointer;
57 68 }
58 69
59 70 /* Breadcrumb header chrome — owned by the shared
60 - * `.desktop-mode-breadcrumbs` rules in `desktop-files.css`. No
71 + * `.os-breadcrumbs` rules in `desktop-files.css`. No
61 72 * per-surface duplication. */
62 73
63 74 /* ----- Body host ----- */
64 75
65 -.desktop-mode-my-wordpress__body {
76 +.os-my-wordpress__body {
66 77 flex: 1 1 auto;
67 78 min-height: 0;
68 79 overflow: hidden;
69 80 position: relative;
@@ -76,19 +87,23 @@
76 87 * Holds the server-side search input today; reserved for future
77 88 * filter / sort controls. Visual treatment mirrors the Content
78 89 * Graph toolbar's search row so the two surfaces read as the same
79 90 * control. */
80 -.desktop-mode-my-wordpress__list-toolbar {
91 +.os-my-wordpress__list-toolbar {
81 92 flex: 0 0 auto;
82 93 display: flex;
83 94 align-items: center;
84 95 gap: 8px;
85 96 padding: 8px 12px;
86 - border-bottom: 1px solid var( --desktop-mode-border, #dcdcde );
87 - background: transparent;
97 + border-bottom: 1px solid var( --os-ui-border, #dcdcde );
98 + /* Opaque and above the canvas: the tile canvas scrolls beneath
99 + * this row, and a transparent toolbar let tiles read through it. */
100 + position: relative;
101 + z-index: 4;
102 + background: var( --os-ui-bg, #fff );
88 103 }
89 104
90 -.desktop-mode-my-wordpress__list-toolbar-search {
105 +.os-my-wordpress__list-toolbar-search {
91 106 position: relative;
92 107 flex: 1 1 auto;
93 108 min-width: 0;
94 109 max-width: 360px;
@@ -93,23 +108,23 @@
93 108 min-width: 0;
94 109 max-width: 360px;
95 110 }
96 111
97 -.desktop-mode-my-wordpress__list-toolbar-search-input {
112 +.os-my-wordpress__list-toolbar-search-input {
98 113 width: 100%;
99 114 padding: 6px 10px;
100 - border: 1px solid var( --wpd-border, #d8dde4 );
115 + border: 1px solid var( --os-ui-border, #d8dde4 );
101 116 border-radius: 6px;
102 - background: var( --wpd-surface, #fff );
117 + background: var( --os-ui-surface, #fff );
103 118 color: inherit;
104 119 font-size: 13px;
105 120 box-sizing: border-box;
106 121 }
107 122
108 -.desktop-mode-my-wordpress__list-toolbar-search-input:focus {
123 +.os-my-wordpress__list-toolbar-search-input:focus {
109 124 outline: none;
110 - border-color: var( --wpd-accent, #2c6be5 );
111 - box-shadow: 0 0 0 3px var( --wpd-accent-soft, rgba( 44, 107, 229, 0.18 ) );
125 + border-color: var( --os-ui-accent, #2c6be5 );
126 + box-shadow: 0 0 0 3px var( --os-ui-accent-soft, rgba( 44, 107, 229, 0.18 ) );
112 127 }
113 128
114 129 /* When the list-toolbar mounts, the split pane needs to claim the
115 130 * remaining vertical space inside the flex column body — without
@@ -114,9 +129,9 @@
114 129 /* When the list-toolbar mounts, the split pane needs to claim the
115 130 * remaining vertical space inside the flex column body — without
116 131 * this rule it would size to its content (which, for an empty list,
117 132 * is zero) and the tile canvas would collapse. */
118 -.desktop-mode-my-wordpress__body > .desktop-mode-my-wordpress__split {
133 +.os-my-wordpress__body > .os-my-wordpress__split {
119 134 flex: 1 1 auto;
120 135 min-height: 0;
121 136 }
122 137
@@ -124,10 +139,10 @@
124 139 * (no skeleton flash, no empty intermediate page) but reads as
125 140 * "stale" until the new page lands and the renderer atomically swaps
126 141 * the tiles. `pointer-events: none` blocks the user from clicking
127 142 * a tile that's about to disappear. */
128 -.desktop-mode-my-wordpress__tiles--searching,
129 -.desktop-mode-my-wordpress__media-grid--searching {
143 +.os-my-wordpress__tiles--searching,
144 +.os-my-wordpress__media-grid--searching {
130 145 opacity: 0.45;
131 146 pointer-events: none;
132 147 transition: opacity 0.12s ease-out;
133 148 }
@@ -132,27 +147,27 @@
132 147 transition: opacity 0.12s ease-out;
133 148 }
134 149
135 150 /* Reuse the file-system folder window's status-bar element
136 - * (`.desktop-mode-folder-status-bar`) so segments render with the
151 + * (`.os-folder-status-bar`) so segments render with the
137 152 * exact same DOM the file-system uses — but retone it for the
138 153 * white window background. The dark default (white-on-dark) reads
139 - * as invisible against `--desktop-mode-window-bg`. */
140 -.desktop-mode-my-wordpress > .desktop-mode-folder-status-bar {
141 - border-top: 1px solid var( --desktop-mode-border, #dcdcde );
154 + * as invisible against `--os-window-bg`. */
155 +.desktop-mode-my-wordpress > .os-folder-status-bar {
156 + border-top: 1px solid var( --os-ui-border, #dcdcde );
142 157 background: transparent;
143 - color: var( --desktop-mode-muted, #50575e );
158 + color: var( --os-ui-fg-muted, #50575e );
144 159 }
145 160
146 161 .desktop-mode-my-wordpress
147 - > .desktop-mode-folder-status-bar
148 - button.desktop-mode-folder-status-bar__segment:hover {
149 - background: var( --desktop-mode-hover, rgba( 0, 0, 0, 0.06 ) );
162 + > .os-folder-status-bar
163 + button.os-folder-status-bar__segment:hover {
164 + background: var( --os-hover, var( --os-ui-hover, rgba( 0, 0, 0, 0.06 ) ) );
150 165 }
151 166
152 167 /* ----- Tile canvas (root + entity list) -----
153 168 *
154 - * Both views use the SAME tile element (`.desktop-mode-file-tile`)
169 + * Both views use the SAME tile element (`.os-file-tile`)
155 170 * the wallpaper uses, so visuals stay 1:1 with the desktop. The
156 171 * canvas is `position: relative`; tiles are absolute-positioned and
157 172 * draggable — same interaction pattern as the wallpaper, just
158 173 * scoped to the window. Positions persist per-window in
@@ -158,9 +173,9 @@
158 173 * scoped to the window. Positions persist per-window in
159 174 * `localStorage` (see `createTileLayout` in src/my-wordpress).
160 175 */
161 176
162 -.desktop-mode-my-wordpress__canvas {
177 +.os-my-wordpress__canvas {
163 178 position: relative;
164 179 min-height: 100%;
165 180 box-sizing: border-box;
166 181 /* Note — DO NOT add `overflow: auto` here. Scroll is owned by
@@ -169,9 +184,9 @@
169 184 * would steal the wheel from the outer pane and break the
170 185 * IntersectionObserver-based infinite scroll. */
171 186 }
172 187
173 -.desktop-mode-my-wordpress__grid {
188 +.os-my-wordpress__grid {
174 189 height: 100%;
175 190 overflow-y: scroll;
176 191 }
177 192
@@ -179,12 +194,12 @@
179 194 * On the wallpaper the file tile sits on a dark gradient and uses
180 195 * white text + a 12% white hover — both of which would be invisible
181 196 * on a white window background. Inside My WordPress we re-tone the
182 197 * same element to read on light surfaces. The dimensions / tile
183 - * structure are inherited from `.desktop-mode-file-tile`.
198 + * structure are inherited from `.os-file-tile`.
184 199 */
185 -.desktop-mode-my-wordpress .desktop-mode-file-tile {
186 - /* Color + hover come from `--desktop-mode-tile-*` — see the
200 +.desktop-mode-my-wordpress .os-file-tile {
201 + /* Color + hover come from `--os-tile-*` — see the
187 202 * scope-level variable overrides on `.desktop-mode-my-wordpress`
188 203 * above. We only override structural / animation bits here.
189 204 *
190 205 * Drop the wallpaper's `transition: transform` — it hints at
@@ -196,24 +211,190 @@
196 211 transform: none;
197 212 }
198 213
199 214 /* Selected state for every tile in My WordPress is rendered by
200 - * the canonical `.desktop-mode-file-tile--selected` rule in
215 + * the canonical `.os-file-tile--selected` rule in
201 216 * `desktop-files.css` — same accent border + tinted background
202 217 * the folder windows + wallpaper tiles use. No section-specific
203 218 * override here — visual parity across the whole shell.
204 219 */
205 220
221 +/* Large tiles — sections that opt in with `tileSize: 'large'`.
222 + *
223 + * A section whose rows carry a photograph (a shop's products) reads
224 + * as a catalogue, not a file list: the picture is what's being
225 + * scanned, and at 48px it's a thumbnail of a thumbnail. Roughly
226 + * doubling the icon well also gives a corner ribbon room to be a
227 + * corner flash instead of covering the subject.
228 + *
229 + * The cell pitch lives in `TILE_METRICS_LARGE` (src/my-wordpress/
230 + * index.ts) and the two MUST move together — a wider tile in a cell
231 + * that didn't grow overlaps its neighbour. */
232 +/*
233 + * Image-led sections re-point the tile tokens for their whole
234 + * subtree rather than overriding the tile's width directly. The base
235 + * `.os-file-tile` rule then sizes itself from them, and so does
236 + * everything derived from them (the label's max-width, the loading
237 + * skeletons) — one declaration instead of a chain of overrides that
238 + * have to be kept in step.
239 + */
240 +.os-my-wordpress__tiles--large {
241 + --os-tile-w: var( --os-tile-w-large, 132px );
242 + --os-tile-h: var( --os-tile-h-large, 160px );
243 +}
244 +
245 +.os-my-wordpress__tiles--large .os-file-tile__visual,
246 +.os-my-wordpress__tiles--large .os-file-tile__icon {
247 + width: 104px;
248 + height: 104px;
249 + font-size: 64px;
250 +}
251 +
252 +.os-my-wordpress__tiles--large .os-file-tile__preview {
253 + width: 104px;
254 + height: 104px;
255 + border-radius: 8px;
256 +}
257 +
258 +/* Three lines of title at this width instead of two — a product name
259 + * is long and the extra width earns the room. Matches the taller
260 + * cell in `TILE_METRICS_LARGE`. */
261 +.os-my-wordpress__tiles--large .os-file-tile__label {
262 + -webkit-line-clamp: 3;
263 +}
264 +
265 +/* Featured-image tiles. Entries that have a featured image render it
266 + * in the icon well instead of the section dashicon — decisive for
267 + * image-led types like WooCommerce products. The base
268 + * `.os-file-tile__preview` rule in `desktop-files.css`
269 + * already sizes and crops it; all that's added here is a hairline
270 + * border so a light-on-light photo still reads as a distinct object
271 + * against the wallpaper, plus a neutral well behind it so a
272 + * transparent PNG or a slow-loading image doesn't flash the
273 + * wallpaper through. */
274 +.os-my-wordpress__tile--entry .os-file-tile__preview {
275 + background: var(
276 + --os-media-tile-bg,
277 + rgba( 0, 0, 0, 0.05 )
278 + );
279 + /* The hairline was a flat 12%-alpha black — right on the pre-brand
280 + * white canvas, and nothing at all on a dark one, where a black
281 + * line over a near-black surface leaves the photo edgeless. It
282 + * follows the border token now, so it inverts with the theme. */
283 + box-shadow: inset 0 0 0 1px var( --os-ui-border, rgba( 0, 0, 0, 0.12 ) );
284 +}
285 +
286 +/* Banded list views. A section can split its tiles into labelled
287 + * bands (WooCommerce Orders groups by status, needs-attention first)
288 + * instead of one flat canvas. The root container stops being a
289 + * positioned canvas and becomes a plain stack; each band owns its
290 + * own canvas below its heading. */
291 +.os-my-wordpress__tiles--banded {
292 + position: static;
293 + min-height: 0;
294 +}
295 +
296 +.os-my-wordpress__band + .os-my-wordpress__band {
297 + margin-block-start: 8px;
298 +}
299 +
300 +/* Bands are laid out in order before the first page arrives so none
301 + * appears mid-scroll, but one that hasn't received a row yet stays
302 + * out of the way rather than showing a heading over nothing. */
303 +.os-my-wordpress__band--empty {
304 + display: none;
305 +}
306 +
307 +.os-my-wordpress__band-title {
308 + display: flex;
309 + align-items: center;
310 + gap: 8px;
311 + position: sticky;
312 + /* Keeps the band label visible while scrolling a long band —
313 + * the whole point of banding is knowing what you're looking at. */
314 + top: 0;
315 + /* Above the absolutely-positioned tiles of every band, including
316 + * the ones that come later in the DOM. */
317 + z-index: 3;
318 + margin: 0;
319 + padding: 6px 12px;
320 + font-size: 11px;
321 + font-weight: 600;
322 + letter-spacing: 0.06em;
323 + text-transform: uppercase;
324 + color: var( --os-ui-fg-muted, #787c82 );
325 + /* Near-opaque on purpose. Tiles scrolling underneath are behind
326 + * the bar, but at 85% they still read as ghostly blurred shapes
327 + * through it, which looks like a rendering fault rather than
328 + * frosted glass. The blur + saturate keeps the frosted feel while
329 + * the alpha stops the content beneath resolving into shapes. */
330 + background: color-mix(
331 + in srgb,
332 + var( --os-ui-bg, #fff ) 94%,
333 + transparent
334 + );
335 + backdrop-filter: blur( 14px ) saturate( 180% );
336 + border-block-end: 1px solid var( --os-ui-border, rgba( 0, 0, 0, 0.08 ) );
337 +}
338 +
339 +/* Browsers without `color-mix()` fall back to the flat surface —
340 + * still opaque, just without the translucency. */
341 +@supports not ( background: color-mix( in srgb, red 50%, transparent ) ) {
342 + .os-my-wordpress__band-title {
343 + background: var( --os-ui-bg, #fff );
344 + }
345 +}
346 +
347 +/* Attention-carrying bands (WooCommerce's "Needs attention",
348 + * "Problems") tint their bar so the eye lands there first instead of
349 + * having to read every heading. */
350 +.os-my-wordpress__band-title--warn {
351 + color: var( --os-ui-warning, #8a6116 );
352 + background: color-mix(
353 + in srgb,
354 + var( --os-ui-warning, #8a6116 ) 12%,
355 + var( --os-ui-bg, #fff )
356 + );
357 + border-block-end-color: color-mix(
358 + in srgb,
359 + var( --os-ui-warning, #8a6116 ) 35%,
360 + transparent
361 + );
362 +}
363 +
364 +.os-my-wordpress__band-title--danger {
365 + color: var( --os-ui-danger, #b32d2e );
366 + background: color-mix(
367 + in srgb,
368 + var( --os-ui-danger, #b32d2e ) 12%,
369 + var( --os-ui-bg, #fff )
370 + );
371 + border-block-end-color: color-mix(
372 + in srgb,
373 + var( --os-ui-danger, #b32d2e ) 35%,
374 + transparent
375 + );
376 +}
377 +
378 +.os-my-wordpress__band-count {
379 + padding: 0 6px;
380 + border-radius: 999px;
381 + font-size: 11px;
382 + line-height: 1.7;
383 + background: color-mix( in srgb, currentColor 16%, transparent );
384 + color: inherit;
385 +}
386 +
206 387 /* Lock state — another user is currently editing this post. We dim
207 388 * the tile a touch and overlay a small dashicon-lock badge on the
208 389 * top-right of the icon. The whole tile stays clickable; the lock
209 390 * is just a visual heads-up so the user knows the takeover dialog
210 391 * is coming if they double-click. */
211 -.desktop-mode-my-wordpress__tile--locked {
392 +.os-my-wordpress__tile--locked {
212 393 opacity: 0.85;
213 394 }
214 395
215 -.desktop-mode-my-wordpress__tile-lock {
396 +.os-my-wordpress__tile-lock {
216 397 position: absolute;
217 398 top: 4px;
218 399 inset-inline-end: 14px;
219 400 width: 18px;
@@ -221,10 +402,10 @@
221 402 font-size: 12px;
222 403 line-height: 18px;
223 404 text-align: center;
224 405 border-radius: 50%;
225 - background: var( --desktop-mode-danger, #b32d2e );
226 - color: #fff;
406 + background: var( --os-danger, var( --os-ui-danger, #b32d2e ) );
407 + color: var( --os-ui-fg-on-accent, #fff );
227 408 box-shadow:
228 409 0 0 0 1.5px rgba( 0, 0, 0, 0.4 ),
229 410 0 1px 3px rgba( 0, 0, 0, 0.35 );
230 411 pointer-events: none;
@@ -229,10 +410,13 @@
229 410 0 1px 3px rgba( 0, 0, 0, 0.35 );
230 411 pointer-events: none;
231 412 }
232 413
233 -/* Tooltip lock banner — shown above the excerpt when present. */
234 -.desktop-mode-my-wordpress__tooltip-lock {
414 +/* Hover-card lock banner — shown above the excerpt when present. The
415 + * wash was a fixed 8%-alpha red, which on a dark card was a smear too
416 + * faint to read as a banner at all; it follows the badge-danger token
417 + * now, so it lands at the alpha the active theme picked. */
418 +.os-my-wordpress__tooltip-lock {
235 419 display: flex;
236 420 align-items: center;
237 421 gap: 6px;
238 422 margin: 0 0 8px;
@@ -237,15 +421,18 @@
237 421 gap: 6px;
238 422 margin: 0 0 8px;
239 423 padding: 6px 8px;
240 424 border-radius: 4px;
241 - background: rgba( 179, 45, 46, 0.08 );
242 - color: var( --desktop-mode-danger, #b32d2e );
425 + background: var(
426 + --os-my-wordpress-card-lock-bg,
427 + rgba( 179, 45, 46, 0.08 )
428 + );
429 + color: var( --os-danger, var( --os-ui-danger, #b32d2e ) );
243 430 font-size: 12px;
244 431 font-weight: 600;
245 432 }
246 433
247 -.desktop-mode-my-wordpress__tooltip-lock .dashicons {
434 +.os-my-wordpress__tooltip-lock .dashicons {
248 435 font-size: 14px;
249 436 width: 14px;
250 437 height: 14px;
251 438 }
@@ -255,9 +442,9 @@
255 442 * HiDPI screens snaps text to fractional device pixels and renders
256 443 * blurry. `max-height: 2 × line-height` + `overflow: hidden` looks
257 444 * the same and stays sharp.
258 445 */
259 -.desktop-mode-my-wordpress__tile .desktop-mode-file-tile__label {
446 +.os-my-wordpress__tile .os-file-tile__label {
260 447 font-size: 12px;
261 448 line-height: 1.3;
262 449 max-height: calc( 1.3em * 2 );
263 450 text-align: center;
@@ -267,9 +454,9 @@
267 454 }
268 455
269 456 /* ----- Entity list: two-pane split ----- */
270 457
271 -.desktop-mode-my-wordpress__split {
458 +.os-my-wordpress__split {
272 459 display: grid;
273 460 grid-template-columns: minmax( 240px, 60% ) minmax( 0, 1fr );
274 461 height: 100%;
275 462 min-height: 0;
@@ -274,11 +461,11 @@
274 461 height: 100%;
275 462 min-height: 0;
276 463 }
277 464
278 -.desktop-mode-my-wordpress__list {
465 +.os-my-wordpress__list {
279 466 overflow-y: scroll;
280 - border-inline-end: 1px solid var( --desktop-mode-border, #dcdcde );
467 + border-inline-end: 1px solid var( --os-ui-border, #dcdcde );
281 468 min-width: 0;
282 469 }
283 470
284 471 /* Always-visible scrollbar styling for the icon canvases. macOS
@@ -287,40 +474,40 @@
287 474 * canvas where the user can't tell whether more icons live below
288 475 * or to the right. We force the scrollbar to render at all times
289 476 * via `::-webkit-scrollbar` (works in WebKit / Blink / Edge), and
290 477 * the explicit `scrollbar-width: thin` covers Firefox. */
291 -.desktop-mode-my-wordpress__list,
292 -.desktop-mode-my-wordpress__grid {
478 +.os-my-wordpress__list,
479 +.os-my-wordpress__grid {
293 480 scrollbar-width: thin;
294 481 scrollbar-color: rgba( 0, 0, 0, 0.25 ) transparent;
295 482 }
296 483
297 -.desktop-mode-my-wordpress__list::-webkit-scrollbar,
298 -.desktop-mode-my-wordpress__grid::-webkit-scrollbar {
484 +.os-my-wordpress__list::-webkit-scrollbar,
485 +.os-my-wordpress__grid::-webkit-scrollbar {
299 486 width: 12px;
300 487 height: 12px;
301 488 }
302 489
303 -.desktop-mode-my-wordpress__list::-webkit-scrollbar-thumb,
304 -.desktop-mode-my-wordpress__grid::-webkit-scrollbar-thumb {
305 - background: rgba( 0, 0, 0, 0.25 );
490 +.os-my-wordpress__list::-webkit-scrollbar-thumb,
491 +.os-my-wordpress__grid::-webkit-scrollbar-thumb {
492 + background: var( --os-ui-scrim, rgba( 0, 0, 0, 0.25 ) );
306 493 border-radius: 6px;
307 494 border: 3px solid transparent;
308 495 background-clip: padding-box;
309 496 }
310 497
311 -.desktop-mode-my-wordpress__list::-webkit-scrollbar-thumb:hover,
312 -.desktop-mode-my-wordpress__grid::-webkit-scrollbar-thumb:hover {
313 - background: rgba( 0, 0, 0, 0.4 );
498 +.os-my-wordpress__list::-webkit-scrollbar-thumb:hover,
499 +.os-my-wordpress__grid::-webkit-scrollbar-thumb:hover {
500 + background: var( --os-ui-scrim, rgba( 0, 0, 0, 0.4 ) );
314 501 background-clip: padding-box;
315 502 }
316 503
317 -.desktop-mode-my-wordpress__list::-webkit-scrollbar-track,
318 -.desktop-mode-my-wordpress__grid::-webkit-scrollbar-track {
504 +.os-my-wordpress__list::-webkit-scrollbar-track,
505 +.os-my-wordpress__grid::-webkit-scrollbar-track {
319 506 background: transparent;
320 507 }
321 508
322 -.desktop-mode-my-wordpress__sentinel {
509 +.os-my-wordpress__sentinel {
323 510 height: 1px;
324 511 }
325 512
326 513 /* Tile-grid loading skeleton — placeholder tiles that mimic the
@@ -337,50 +524,53 @@
337 524 * `src/my-wordpress/index.ts`. Per-tile shimmer delay and label
338 525 * width are inlined so a row of placeholders reads as a cascade,
339 526 * not a uniform pulse.
340 527 *
341 - * Tile dimensions mirror the real `.desktop-mode-file-tile` width
528 + * Tile dimensions mirror the real `.os-file-tile` width
342 529 * so a placeholder sits cleanly in the cell its successor will
343 530 * inherit.
344 531 */
345 -.desktop-mode-my-wordpress__skeleton-tile {
532 +.os-my-wordpress__skeleton-tile {
346 533 position: absolute;
347 534 display: flex;
348 535 flex-direction: column;
349 536 align-items: center;
350 537 gap: 6px;
351 - width: 88px;
538 + /* Same box as the real tile it stands in for — a skeleton that
539 + * doesn't match the grid makes the list jump when rows land. */
540 + width: var( --os-tile-w, 88px );
541 + height: var( --os-tile-h, 104px );
352 542 padding: 8px 4px;
353 543 box-sizing: border-box;
354 544 pointer-events: none;
355 545 }
356 546
357 -.desktop-mode-my-wordpress__skeleton-icon,
358 -.desktop-mode-my-wordpress__skeleton-label {
547 +.os-my-wordpress__skeleton-icon,
548 +.os-my-wordpress__skeleton-label {
359 549 background: linear-gradient(
360 550 90deg,
361 - var( --desktop-mode-skeleton-low, rgba( 0, 0, 0, 0.05 ) ) 0%,
362 - var( --desktop-mode-skeleton-high, rgba( 0, 0, 0, 0.13 ) ) 50%,
363 - var( --desktop-mode-skeleton-low, rgba( 0, 0, 0, 0.05 ) ) 100%
551 + var( --os-skeleton-low, var( --os-ui-hover, rgba( 0, 0, 0, 0.05 ) ) ) 0%,
552 + var( --os-skeleton-high, var( --os-ui-hover, rgba( 0, 0, 0, 0.13 ) ) ) 50%,
553 + var( --os-skeleton-low, var( --os-ui-hover, rgba( 0, 0, 0, 0.05 ) ) ) 100%
364 554 );
365 555 background-size: 200% 100%;
366 - animation: desktop-mode-my-wordpress-skeleton-shimmer 1.4s ease-in-out
367 - var( --desktop-mode-skeleton-delay, 0s ) infinite;
556 + animation: os-my-wordpress-skeleton-shimmer 1.4s ease-in-out
557 + var( --os-skeleton-delay, 0s ) infinite;
368 558 }
369 559
370 -.desktop-mode-my-wordpress__skeleton-icon {
560 +.os-my-wordpress__skeleton-icon {
371 561 width: 44px;
372 562 height: 44px;
373 563 border-radius: 10px;
374 564 }
375 565
376 -.desktop-mode-my-wordpress__skeleton-label {
566 +.os-my-wordpress__skeleton-label {
377 567 width: 72%;
378 568 height: 10px;
379 569 border-radius: 4px;
380 570 }
381 571
382 -@keyframes desktop-mode-my-wordpress-skeleton-shimmer {
572 +@keyframes os-my-wordpress-skeleton-shimmer {
383 573 from {
384 574 background-position: 200% 0;
385 575 }
386 576 to {
@@ -388,10 +578,10 @@
388 578 }
389 579 }
390 580
391 581 @media ( prefers-reduced-motion: reduce ) {
392 - .desktop-mode-my-wordpress__skeleton-icon,
393 - .desktop-mode-my-wordpress__skeleton-label {
582 + .os-my-wordpress__skeleton-icon,
583 + .os-my-wordpress__skeleton-label {
394 584 animation: none;
395 585 }
396 586 }
397 587
@@ -396,27 +586,52 @@
396 586 }
397 587
398 588 /* ----- Right pane: preview ----- */
399 589
400 -.desktop-mode-my-wordpress__preview {
590 +.os-my-wordpress__preview {
401 591 overflow: auto;
402 592 min-width: 0;
403 593 background: transparent;
404 594 }
405 595
406 -.desktop-mode-my-wordpress__preview-empty {
596 +.os-my-wordpress__preview-empty {
407 597 display: flex;
598 + flex-direction: column;
599 + gap: 6px;
408 600 align-items: center;
409 601 justify-content: center;
410 602 height: 100%;
411 - color: var( --desktop-mode-muted, #787c82 );
603 + color: var( --os-ui-fg-muted, #787c82 );
412 604 font-size: 13px;
413 605 padding: 24px;
414 606 text-align: center;
415 607 }
416 608
417 -.desktop-mode-my-wordpress__preview-loading {
609 +/* Type / status breakdown under a multi-selection's count. */
610 +.os-my-wordpress__preview-selection-breakdown {
611 + font-size: 12px;
612 + opacity: 0.75;
613 +}
614 +
615 +/* One labelled control in the bulk-edit modal. Label above field,
616 + * because the fields are wide (a category tree, a tag row) and a
617 + * two-column grid would put a one-word label beside a control four
618 + * times its height. */
619 +.os-my-wordpress__bulk-row {
418 620 display: flex;
621 + flex-direction: column;
622 + gap: 6px;
623 + margin-block-end: 16px;
624 +}
625 +
626 +.os-my-wordpress__bulk-label {
627 + font-size: 12px;
628 + font-weight: 600;
629 + color: var( --os-ui-fg-muted, #787c82 );
630 +}
631 +
632 +.os-my-wordpress__preview-loading {
633 + display: flex;
419 634 align-items: center;
420 635 justify-content: center;
421 636 height: 100%;
422 637 min-height: 320px;
@@ -425,37 +640,37 @@
425 640 }
426 641
427 642 /* Preview-pane loader — same scale curve as the tile-grid first
428 643 * spinner and the window-loading overlay. The JS used to hard-code
429 - * `size="128"`, which set an inline `--wpd-spinner-size` that
644 + * `size="128"`, which set an inline `--os-ui-spinner-size` that
430 645 * overrode any CSS knob; the size attribute is now omitted so this
431 646 * rule is the single source of truth for both the My WordPress
432 647 * preview and the wallpaper file-preview pane (which reuses this
433 648 * class deliberately).
434 649 */
435 -.desktop-mode-my-wordpress__preview-loading wpd-spinner {
436 - --wpd-spinner-size: clamp( 96px, 14vw, 192px );
650 +.os-my-wordpress__preview-loading os-spinner {
651 + --os-ui-spinner-size: clamp( 96px, 14vw, 192px );
437 652 }
438 653
439 -.desktop-mode-my-wordpress__article {
654 +.os-my-wordpress__article {
440 655 padding: 24px 32px;
441 656 max-width: 720px;
442 657 margin: 0 auto;
443 658 }
444 659
445 -.desktop-mode-my-wordpress__article-title {
660 +.os-my-wordpress__article-title {
446 661 font-size: 22px;
447 662 margin: 0 0 8px;
448 663 line-height: 1.3;
449 664 }
450 665
451 -.desktop-mode-my-wordpress__article-meta {
666 +.os-my-wordpress__article-meta {
452 667 margin: 0 0 16px;
453 - color: var( --desktop-mode-muted, #50575e );
668 + color: var( --os-ui-fg-muted, #50575e );
454 669 font-size: 12px;
455 670 }
456 671
457 -.desktop-mode-my-wordpress__article-hero {
672 +.os-my-wordpress__article-hero {
458 673 width: 100%;
459 674 height: auto;
460 675 border-radius: 6px;
461 676 margin-bottom: 16px;
@@ -461,22 +676,22 @@
461 676 margin-bottom: 16px;
462 677 display: block;
463 678 }
464 679
465 -.desktop-mode-my-wordpress__article-content {
680 +.os-my-wordpress__article-content {
466 681 font-size: 14px;
467 682 line-height: 1.6;
468 683 }
469 684
470 -.desktop-mode-my-wordpress__article-content img {
685 +.os-my-wordpress__article-content img {
471 686 max-width: 100%;
472 687 height: auto;
473 688 }
474 689
475 -.desktop-mode-my-wordpress__article-footer {
690 +.os-my-wordpress__article-footer {
476 691 margin-top: 24px;
477 692 padding-top: 16px;
478 - border-top: 1px solid var( --desktop-mode-border, #dcdcde );
693 + border-top: 1px solid var( --os-ui-border, #dcdcde );
479 694 display: flex;
480 695 justify-content: flex-end;
481 696 align-items: center;
482 697 gap: 8px;
@@ -484,59 +699,97 @@
484 699 }
485 700
486 701 /* ----- Empty / error states ----- */
487 702
488 -.desktop-mode-my-wordpress__empty,
489 -.desktop-mode-my-wordpress__error {
703 +.os-my-wordpress__empty,
704 +.os-my-wordpress__error {
490 705 padding: 32px 24px;
491 706 text-align: center;
492 - color: var( --desktop-mode-muted, #787c82 );
707 + color: var( --os-ui-fg-muted, #787c82 );
493 708 font-size: 13px;
494 709 }
495 710
496 -.desktop-mode-my-wordpress__error {
497 - color: var( --desktop-mode-danger, #b32d2e );
711 +.os-my-wordpress__error {
712 + color: var( --os-danger, var( --os-ui-danger, #b32d2e ) );
498 713 }
499 714
500 -/* ----- Hover tooltip (floats over body) ----- */
715 +/* ----- Hover card (floats over body) -----
716 + *
717 + * The card is summoned from a tile and belongs to the window that
718 + * tile is in, so it follows the active desktop theme rather than the
719 + * shell's tooltip chip. Every colour chains
720 + * `--os-my-wordpress-card-*` first — derived in `variables.css` from
721 + * the window family, so a theme that repaints the window repaints the
722 + * card with it — then the chip tokens, then the pre-brand literal.
723 + *
724 + * It is appended to `document.body`, not to the window, because it is
725 + * `position: fixed` and a window with `overflow: hidden` would clip
726 + * it. Theme tokens still reach it: a desktop theme declares on
727 + * `body.os-desktop-theme-<slug>`, an ancestor of both. What does NOT
728 + * reach it is anything scoped to `.desktop-mode-my-wordpress`, which
729 + * is why the card family is declared at palette level. */
501 730
502 -.desktop-mode-my-wordpress__tooltip {
731 +.os-my-wordpress__tooltip {
503 732 position: fixed;
504 733 z-index: 100000;
505 734 max-width: 320px;
506 - background: var( --desktop-mode-surface, #fff );
507 - color: var( --desktop-mode-fg, #1d2327 );
508 - border: 1px solid var( --desktop-mode-border, #dcdcde );
735 + background: var(
736 + --os-my-wordpress-card-bg,
737 + var(
738 + --os-tooltip-bg,
739 + var( --os-surface, var( --os-ui-surface, #fff ) )
740 + )
741 + );
742 + color: var(
743 + --os-my-wordpress-card-fg,
744 + var( --os-tooltip-fg, var( --os-fg, #1d2327 ) )
745 + );
746 + /* The card lands on the same colour as the window under it — the
747 + * border and the shadow are the only reason it reads as a separate
748 + * object, so neither is decoration. */
749 + border: 1px solid var( --os-my-wordpress-card-border, #dcdcde );
509 750 border-radius: 6px;
510 751 padding: 12px;
511 - box-shadow: 0 6px 24px rgba( 0, 0, 0, 0.18 );
752 + box-shadow: var(
753 + --os-my-wordpress-card-shadow,
754 + 0 6px 24px rgba( 0, 0, 0, 0.18 )
755 + );
512 756 font-size: 12px;
513 757 pointer-events: none;
514 758 }
515 759
516 -.desktop-mode-my-wordpress__tooltip-title {
760 +.os-my-wordpress__tooltip-title {
517 761 font-weight: 600;
518 762 margin-bottom: 6px;
519 763 font-size: 13px;
520 764 }
521 765
522 -.desktop-mode-my-wordpress__tooltip-thumb {
766 +/* Same neutral well the entry and media tiles give their thumbnails:
767 + * a transparent PNG or a still-loading image would otherwise show the
768 + * card straight through, and a photo whose edge matches the card
769 + * would have no boundary. */
770 +.os-my-wordpress__tooltip-thumb {
523 771 display: block;
524 772 max-width: 100%;
525 773 height: auto;
526 774 border-radius: 4px;
527 775 margin: 6px 0;
776 + background: var( --os-my-wordpress-card-thumb-bg, rgba( 0, 0, 0, 0.05 ) );
777 + box-shadow: inset 0 0 0 1px var(
778 + --os-my-wordpress-card-border,
779 + #dcdcde
780 + );
528 781 }
529 782
530 -.desktop-mode-my-wordpress__tooltip-excerpt {
783 +.os-my-wordpress__tooltip-excerpt {
531 784 margin: 0;
532 - color: var( --desktop-mode-muted, #50575e );
785 + color: var( --os-my-wordpress-card-fg-muted, #50575e );
533 786 line-height: 1.4;
534 787 }
535 788
536 789 /* ----- Context menu host ----- */
537 790
538 -.desktop-mode-my-wordpress__menu {
791 +.os-my-wordpress__menu {
539 792 position: fixed;
540 793 z-index: 100001;
541 794 }
542 795
@@ -548,13 +801,13 @@
548 801 * but to stretch nicely up to ~720px before the line-length stops
549 802 * helping readability.
550 803 * --------------------------------------------------------------- */
551 804
552 -.desktop-mode-my-wordpress__user {
805 +.os-my-wordpress__user {
553 806 max-width: 720px;
554 807 }
555 808
556 -.desktop-mode-my-wordpress__user-header {
809 +.os-my-wordpress__user-header {
557 810 display: flex;
558 811 gap: 16px;
559 812 align-items: center;
560 813 margin-bottom: 16px;
@@ -559,9 +812,9 @@
559 812 align-items: center;
560 813 margin-bottom: 16px;
561 814 }
562 815
563 -.desktop-mode-my-wordpress__user-avatar {
816 +.os-my-wordpress__user-avatar {
564 817 width: 96px;
565 818 height: 96px;
566 819 border-radius: 50%;
567 820 flex-shrink: 0;
@@ -567,19 +820,19 @@
567 820 flex-shrink: 0;
568 821 box-shadow: 0 2px 8px rgba( 0, 0, 0, 0.12 );
569 822 }
570 823
571 -.desktop-mode-my-wordpress__user-headline {
824 +.os-my-wordpress__user-headline {
572 825 flex: 1 1 auto;
573 826 min-width: 0;
574 827 }
575 828
576 -.desktop-mode-my-wordpress__user
577 - .desktop-mode-my-wordpress__article-title {
829 +.os-my-wordpress__user
830 + .os-my-wordpress__article-title {
578 831 margin: 0 0 4px;
579 832 }
580 833
581 -.desktop-mode-my-wordpress__user-roles {
834 +.os-my-wordpress__user-roles {
582 835 display: flex;
583 836 flex-wrap: wrap;
584 837 gap: 6px;
585 838 margin-bottom: 6px;
@@ -584,9 +837,9 @@
584 837 gap: 6px;
585 838 margin-bottom: 6px;
586 839 }
587 840
588 -.desktop-mode-my-wordpress__user-role {
841 +.os-my-wordpress__user-role {
589 842 display: inline-flex;
590 843 align-items: center;
591 844 padding: 2px 8px;
592 845 border-radius: 10px;
@@ -593,39 +846,39 @@
593 846 font-size: 11px;
594 847 font-weight: 600;
595 848 text-transform: uppercase;
596 849 letter-spacing: 0.04em;
597 - background: rgba( 34, 113, 177, 0.12 );
850 + background: color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 12%, transparent );
598 851 color: var( --wp-admin-theme-color, #2271b1 );
599 852 }
600 853
601 -.desktop-mode-my-wordpress__user-links {
854 +.os-my-wordpress__user-links {
602 855 display: flex;
603 856 gap: 12px;
604 857 font-size: 12px;
605 858 }
606 859
607 -.desktop-mode-my-wordpress__user-links a {
608 - color: var( --desktop-mode-link, #2271b1 );
860 +.os-my-wordpress__user-links a {
861 + color: var( --os-link, var( --os-ui-accent, #2271b1 ) );
609 862 text-decoration: none;
610 863 }
611 864
612 -.desktop-mode-my-wordpress__user-links a:hover {
865 +.os-my-wordpress__user-links a:hover {
613 866 text-decoration: underline;
614 867 }
615 868
616 -.desktop-mode-my-wordpress__user-bio {
869 +.os-my-wordpress__user-bio {
617 870 font-size: 14px;
618 871 line-height: 1.5;
619 - color: var( --desktop-mode-fg, #1d2327 );
872 + color: var( --os-my-wordpress-fg, var( --os-ui-fg, #1d2327 ) );
620 873 margin: 0 0 16px;
621 874 padding-left: 12px;
622 - border-left: 3px solid var( --desktop-mode-border, #dcdcde );
875 + border-left: 3px solid var( --os-ui-border, #dcdcde );
623 876 }
624 877
625 878 /* ----- Stat cards row ----- */
626 879
627 -.desktop-mode-my-wordpress__user-stats {
880 +.os-my-wordpress__user-stats {
628 881 display: grid;
629 882 grid-template-columns: repeat( auto-fit, minmax( 120px, 1fr ) );
630 883 gap: 8px;
631 884 margin-bottom: 20px;
@@ -630,19 +883,19 @@
630 883 gap: 8px;
631 884 margin-bottom: 20px;
632 885 }
633 886
634 -.desktop-mode-my-wordpress__user-stat {
887 +.os-my-wordpress__user-stat {
635 888 display: flex;
636 889 flex-direction: column;
637 890 gap: 2px;
638 891 padding: 12px 14px;
639 892 border-radius: 8px;
640 - background: var( --desktop-mode-hover, rgba( 0, 0, 0, 0.04 ) );
641 - border: 1px solid var( --desktop-mode-border, #dcdcde );
893 + background: var( --os-hover, var( --os-ui-hover, rgba( 0, 0, 0, 0.04 ) ) );
894 + border: 1px solid var( --os-ui-border, #dcdcde );
642 895 }
643 896
644 -.desktop-mode-my-wordpress__user-stat-value {
897 +.os-my-wordpress__user-stat-value {
645 898 font-size: 26px;
646 899 font-weight: 700;
647 900 line-height: 1.1;
648 901 color: var( --wp-admin-theme-color, #2271b1 );
@@ -648,36 +901,36 @@
648 901 color: var( --wp-admin-theme-color, #2271b1 );
649 902 font-variant-numeric: tabular-nums;
650 903 }
651 904
652 -.desktop-mode-my-wordpress__user-stat-label {
905 +.os-my-wordpress__user-stat-label {
653 906 font-size: 12px;
654 - color: var( --desktop-mode-muted, #50575e );
907 + color: var( --os-ui-fg-muted, #50575e );
655 908 text-transform: uppercase;
656 909 letter-spacing: 0.04em;
657 910 }
658 911
659 -.desktop-mode-my-wordpress__user-stat-caption {
912 +.os-my-wordpress__user-stat-caption {
660 913 font-size: 11px;
661 - color: var( --desktop-mode-muted, #787c82 );
914 + color: var( --os-ui-fg-muted, #787c82 );
662 915 }
663 916
664 917 /* ----- 12-month activity sparkline ----- */
665 918
666 -.desktop-mode-my-wordpress__user-section {
919 +.os-my-wordpress__user-section {
667 920 margin-bottom: 20px;
668 921 }
669 922
670 -.desktop-mode-my-wordpress__user-section h3 {
923 +.os-my-wordpress__user-section h3 {
671 924 font-size: 13px;
672 925 font-weight: 600;
673 - color: var( --desktop-mode-muted, #50575e );
926 + color: var( --os-ui-fg-muted, #50575e );
674 927 text-transform: uppercase;
675 928 letter-spacing: 0.04em;
676 929 margin: 0 0 8px;
677 930 }
678 931
679 -.desktop-mode-my-wordpress__user-spark-chart {
932 +.os-my-wordpress__user-spark-chart {
680 933 display: grid;
681 934 grid-template-columns: repeat( 12, 1fr );
682 935 gap: 4px;
683 936 height: 80px;
@@ -684,9 +937,9 @@
684 937 align-items: end;
685 938 padding: 6px 0;
686 939 }
687 940
688 -.desktop-mode-my-wordpress__user-spark-col {
941 +.os-my-wordpress__user-spark-col {
689 942 display: flex;
690 943 flex-direction: column;
691 944 align-items: stretch;
692 945 justify-content: flex-end;
@@ -694,13 +947,13 @@
694 947 height: 100%;
695 948 min-height: 0;
696 949 }
697 950
698 -.desktop-mode-my-wordpress__user-spark-bar {
951 +.os-my-wordpress__user-spark-bar {
699 952 background: linear-gradient(
700 953 180deg,
701 954 var( --wp-admin-theme-color, #2271b1 ) 0%,
702 - rgba( 34, 113, 177, 0.55 ) 100%
955 + color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 55%, transparent ) 100%
703 956 );
704 957 border-radius: 3px 3px 0 0;
705 958 min-height: 2px;
706 959 transition: height 0.3s ease;
@@ -705,23 +958,23 @@
705 958 min-height: 2px;
706 959 transition: height 0.3s ease;
707 960 }
708 961
709 -.desktop-mode-my-wordpress__user-spark-bar--empty {
710 - background: var( --desktop-mode-border, #dcdcde );
962 +.os-my-wordpress__user-spark-bar--empty {
963 + background: var( --os-ui-border, #dcdcde );
711 964 min-height: 2px;
712 965 height: 2px !important;
713 966 }
714 967
715 -.desktop-mode-my-wordpress__user-spark-label {
968 +.os-my-wordpress__user-spark-label {
716 969 font-size: 10px;
717 970 text-align: center;
718 - color: var( --desktop-mode-muted, #787c82 );
971 + color: var( --os-ui-fg-muted, #787c82 );
719 972 }
720 973
721 974 /* ----- Milestones ----- */
722 975
723 -.desktop-mode-my-wordpress__user-milestones {
976 +.os-my-wordpress__user-milestones {
724 977 display: grid;
725 978 grid-template-columns: repeat( auto-fit, minmax( 140px, 1fr ) );
726 979 gap: 12px;
727 980 margin: 0 0 20px;
@@ -726,17 +979,17 @@
726 979 gap: 12px;
727 980 margin: 0 0 20px;
728 981 }
729 982
730 -.desktop-mode-my-wordpress__user-milestones dt {
983 +.os-my-wordpress__user-milestones dt {
731 984 font-size: 11px;
732 - color: var( --desktop-mode-muted, #50575e );
985 + color: var( --os-ui-fg-muted, #50575e );
733 986 text-transform: uppercase;
734 987 letter-spacing: 0.04em;
735 988 margin-bottom: 2px;
736 989 }
737 990
738 -.desktop-mode-my-wordpress__user-milestones dd {
991 +.os-my-wordpress__user-milestones dd {
739 992 font-size: 14px;
740 993 font-weight: 600;
741 994 margin: 0;
742 995 }
@@ -742,9 +995,9 @@
742 995 }
743 996
744 997 /* ----- Recent posts list ----- */
745 998
746 -.desktop-mode-my-wordpress__user-recent {
999 +.os-my-wordpress__user-recent {
747 1000 list-style: none;
748 1001 margin: 0;
749 1002 padding: 0;
750 1003 display: flex;
@@ -751,41 +1004,41 @@
751 1004 flex-direction: column;
752 1005 gap: 6px;
753 1006 }
754 1007
755 -.desktop-mode-my-wordpress__user-recent li {
1008 +.os-my-wordpress__user-recent li {
756 1009 display: flex;
757 1010 flex-direction: column;
758 1011 gap: 2px;
759 1012 padding: 8px 10px;
760 1013 border-radius: 6px;
761 - background: rgba( 0, 0, 0, 0.02 );
1014 + background: var( --os-ui-hover, rgba( 0, 0, 0, 0.02 ) );
762 1015 }
763 1016
764 -.desktop-mode-my-wordpress__user-recent a {
1017 +.os-my-wordpress__user-recent a {
765 1018 font-weight: 600;
766 - color: var( --desktop-mode-link, #2271b1 );
1019 + color: var( --os-link, var( --os-ui-accent, #2271b1 ) );
767 1020 text-decoration: none;
768 1021 }
769 1022
770 -.desktop-mode-my-wordpress__user-recent a:hover {
1023 +.os-my-wordpress__user-recent a:hover {
771 1024 text-decoration: underline;
772 1025 }
773 1026
774 -.desktop-mode-my-wordpress__user-recent-meta {
1027 +.os-my-wordpress__user-recent-meta {
775 1028 font-size: 11px;
776 - color: var( --desktop-mode-muted, #787c82 );
1029 + color: var( --os-ui-fg-muted, #787c82 );
777 1030 }
778 1031
779 1032 /* ----- Top categories chips ----- */
780 1033
781 -.desktop-mode-my-wordpress__user-chips {
1034 +.os-my-wordpress__user-chips {
782 1035 display: flex;
783 1036 flex-wrap: wrap;
784 1037 gap: 6px;
785 1038 }
786 1039
787 -.desktop-mode-my-wordpress__user-chip {
1040 +.os-my-wordpress__user-chip {
788 1041 display: inline-flex;
789 1042 align-items: center;
790 1043 gap: 6px;
791 1044 padding: 4px 10px;
@@ -790,18 +1043,18 @@
790 1043 gap: 6px;
791 1044 padding: 4px 10px;
792 1045 border-radius: 999px;
793 1046 font-size: 12px;
794 - background: rgba( 0, 0, 0, 0.05 );
795 - border: 1px solid var( --desktop-mode-border, #dcdcde );
1047 + background: var( --os-ui-hover, rgba( 0, 0, 0, 0.05 ) );
1048 + border: 1px solid var( --os-ui-border, #dcdcde );
796 1049 }
797 1050
798 -.desktop-mode-my-wordpress__user-chip--tag {
1051 +.os-my-wordpress__user-chip--tag {
799 1052 background: rgba( 124, 58, 237, 0.08 );
800 1053 border-color: rgba( 124, 58, 237, 0.25 );
801 1054 }
802 1055
803 -.desktop-mode-my-wordpress__user-chip-count {
1056 +.os-my-wordpress__user-chip-count {
804 1057 font-weight: 700;
805 1058 color: var( --wp-admin-theme-color, #2271b1 );
806 1059 font-variant-numeric: tabular-nums;
807 1060 }
@@ -814,9 +1067,9 @@
814 1067 * "Top contributors" grid that pairs an author avatar with a
815 1068 * post count.
816 1069 * --------------------------------------------------------------- */
817 1070
818 -.desktop-mode-my-wordpress__term-header {
1071 +.os-my-wordpress__term-header {
819 1072 display: flex;
820 1073 align-items: center;
821 1074 gap: 16px;
822 1075 margin-bottom: 16px;
@@ -821,9 +1074,9 @@
821 1074 gap: 16px;
822 1075 margin-bottom: 16px;
823 1076 }
824 1077
825 -.desktop-mode-my-wordpress__term-icon {
1078 +.os-my-wordpress__term-icon {
826 1079 width: 64px;
827 1080 height: 64px;
828 1081 border-radius: 12px;
829 1082 display: inline-flex;
@@ -829,49 +1082,49 @@
829 1082 display: inline-flex;
830 1083 align-items: center;
831 1084 justify-content: center;
832 1085 flex-shrink: 0;
833 - color: #fff;
1086 + color: var( --os-ui-fg-on-accent, #fff );
834 1087 }
835 1088
836 -.desktop-mode-my-wordpress__term-icon--category {
837 - background: linear-gradient( 135deg, #2271b1 0%, #135e96 100% );
838 - box-shadow: 0 4px 12px rgba( 34, 113, 177, 0.32 );
1089 +.os-my-wordpress__term-icon--category {
1090 + background: linear-gradient( 135deg, var( --os-ui-accent, #2271b1 ) 0%, var( --os-ui-accent-strong, #135e96 ) 100% );
1091 + box-shadow: 0 4px 12px color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 32%, transparent );
839 1092 }
840 1093
841 -.desktop-mode-my-wordpress__term-icon--tag {
1094 +.os-my-wordpress__term-icon--tag {
842 1095 background: linear-gradient( 135deg, #7c3aed 0%, #5b21b6 100% );
843 1096 box-shadow: 0 4px 12px rgba( 124, 58, 237, 0.32 );
844 1097 }
845 1098
846 -.desktop-mode-my-wordpress__user-role--category {
847 - background: rgba( 34, 113, 177, 0.12 );
848 - color: #135e96;
1099 +.os-my-wordpress__user-role--category {
1100 + background: color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 12%, transparent );
1101 + color: var( --os-ui-accent-strong, #135e96 );
849 1102 }
850 1103
851 -.desktop-mode-my-wordpress__user-role--tag {
1104 +.os-my-wordpress__user-role--tag {
852 1105 background: rgba( 124, 58, 237, 0.12 );
853 1106 color: #6d28d9;
854 1107 }
855 1108
856 1109 /* Top contributors row — paired avatar + name + post count. */
857 -.desktop-mode-my-wordpress__term-authors {
1110 +.os-my-wordpress__term-authors {
858 1111 display: grid;
859 1112 grid-template-columns: repeat( auto-fit, minmax( 180px, 1fr ) );
860 1113 gap: 8px;
861 1114 }
862 1115
863 -.desktop-mode-my-wordpress__term-author {
1116 +.os-my-wordpress__term-author {
864 1117 display: flex;
865 1118 align-items: center;
866 1119 gap: 10px;
867 1120 padding: 8px 12px;
868 1121 border-radius: 8px;
869 - background: rgba( 0, 0, 0, 0.03 );
870 - border: 1px solid var( --desktop-mode-border, #dcdcde );
1122 + background: var( --os-ui-hover, rgba( 0, 0, 0, 0.03 ) );
1123 + border: 1px solid var( --os-ui-border, #dcdcde );
871 1124 }
872 1125
873 -.desktop-mode-my-wordpress__term-author-avatar {
1126 +.os-my-wordpress__term-author-avatar {
874 1127 width: 36px;
875 1128 height: 36px;
876 1129 border-radius: 50%;
877 1130 flex-shrink: 0;
@@ -876,9 +1129,9 @@
876 1129 border-radius: 50%;
877 1130 flex-shrink: 0;
878 1131 }
879 1132
880 -.desktop-mode-my-wordpress__term-author-text {
1133 +.os-my-wordpress__term-author-text {
881 1134 display: flex;
882 1135 flex-direction: column;
883 1136 gap: 2px;
884 1137 min-width: 0;
@@ -883,9 +1136,9 @@
883 1136 gap: 2px;
884 1137 min-width: 0;
885 1138 }
886 1139
887 -.desktop-mode-my-wordpress__term-author-name {
1140 +.os-my-wordpress__term-author-name {
888 1141 font-weight: 600;
889 1142 font-size: 13px;
890 1143 overflow: hidden;
891 1144 text-overflow: ellipsis;
@@ -891,11 +1144,11 @@
891 1144 text-overflow: ellipsis;
892 1145 white-space: nowrap;
893 1146 }
894 1147
895 -.desktop-mode-my-wordpress__term-author-count {
1148 +.os-my-wordpress__term-author-count {
896 1149 font-size: 11px;
897 - color: var( --desktop-mode-muted, #50575e );
1150 + color: var( --os-ui-fg-muted, #50575e );
898 1151 }
899 1152
900 1153 /* ---------------------------------------------------------------
901 1154 * Comment dossier — header (avatar + name + status / date / count
@@ -904,32 +1157,32 @@
904 1157 * direct-reply thread, and a moderation strip (IP + user agent)
905 1158 * for users with moderate_comments.
906 1159 * --------------------------------------------------------------- */
907 1160
908 -.desktop-mode-my-wordpress__comment-status--approved {
909 - background: rgba( 34, 113, 177, 0.12 );
910 - color: #135e96;
1161 +.os-my-wordpress__comment-status--approved {
1162 + background: color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 12%, transparent );
1163 + color: var( --os-ui-accent-strong, #135e96 );
911 1164 }
912 1165
913 -.desktop-mode-my-wordpress__comment-status--pending {
1166 +.os-my-wordpress__comment-status--pending {
914 1167 background: rgba( 217, 119, 6, 0.16 );
915 1168 color: #b45309;
916 1169 }
917 1170
918 -.desktop-mode-my-wordpress__comment-status--spam {
1171 +.os-my-wordpress__comment-status--spam {
919 1172 background: rgba( 179, 45, 46, 0.14 );
920 - color: #b32d2e;
1173 + color: var( --os-ui-danger-hover, #b32d2e );
921 1174 }
922 1175
923 -.desktop-mode-my-wordpress__comment-status--trash {
924 - background: rgba( 0, 0, 0, 0.08 );
925 - color: var( --desktop-mode-muted, #50575e );
1176 +.os-my-wordpress__comment-status--trash {
1177 + background: var( --os-ui-hover, rgba( 0, 0, 0, 0.08 ) );
1178 + color: var( --os-ui-fg-muted, #50575e );
926 1179 }
927 1180
928 -.desktop-mode-my-wordpress__comment-date-badge {
1181 +.os-my-wordpress__comment-date-badge {
929 1182 background: transparent;
930 - color: var( --desktop-mode-muted, #50575e );
931 - border: 1px solid var( --desktop-mode-border, #dcdcde );
1183 + color: var( --os-ui-fg-muted, #50575e );
1184 + border: 1px solid var( --os-ui-border, #dcdcde );
932 1185 text-transform: none;
933 1186 letter-spacing: normal;
934 1187 }
935 1188
@@ -934,68 +1187,68 @@
934 1187 }
935 1188
936 1189 /* "In reply to ..." quote shown above the comment body when this
937 1190 * is a thread reply. */
938 -.desktop-mode-my-wordpress__comment-quote {
1191 +.os-my-wordpress__comment-quote {
939 1192 margin: 0 0 16px;
940 1193 padding: 10px 14px;
941 1194 border-left: 3px solid var( --wp-admin-theme-color, #2271b1 );
942 - background: rgba( 34, 113, 177, 0.06 );
1195 + background: color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 6%, transparent );
943 1196 border-radius: 0 6px 6px 0;
944 1197 font-size: 13px;
945 1198 }
946 1199
947 -.desktop-mode-my-wordpress__comment-quote-lead {
1200 +.os-my-wordpress__comment-quote-lead {
948 1201 font-size: 11px;
949 1202 font-weight: 600;
950 - color: var( --desktop-mode-muted, #50575e );
1203 + color: var( --os-ui-fg-muted, #50575e );
951 1204 text-transform: uppercase;
952 1205 letter-spacing: 0.04em;
953 1206 margin-bottom: 4px;
954 1207 }
955 1208
956 -.desktop-mode-my-wordpress__comment-quote p {
1209 +.os-my-wordpress__comment-quote p {
957 1210 margin: 0;
958 - color: var( --desktop-mode-fg, #1d2327 );
1211 + color: var( --os-my-wordpress-fg, var( --os-ui-fg, #1d2327 ) );
959 1212 }
960 1213
961 1214 /* Comment body — same style as article-content but with a soft
962 1215 * card background so it reads as the focal element. */
963 -.desktop-mode-my-wordpress__comment-body {
1216 +.os-my-wordpress__comment-body {
964 1217 padding: 14px 16px;
965 - background: rgba( 0, 0, 0, 0.03 );
1218 + background: var( --os-ui-hover, rgba( 0, 0, 0, 0.03 ) );
966 1219 border-radius: 8px;
967 - border: 1px solid var( --desktop-mode-border, #dcdcde );
1220 + border: 1px solid var( --os-ui-border, #dcdcde );
968 1221 }
969 1222
970 1223 /* Parent-post card under the comment body. */
971 -.desktop-mode-my-wordpress__comment-post {
1224 +.os-my-wordpress__comment-post {
972 1225 display: flex;
973 1226 flex-direction: column;
974 1227 gap: 4px;
975 1228 padding: 10px 14px;
976 1229 border-radius: 8px;
977 - background: rgba( 0, 0, 0, 0.04 );
978 - border: 1px solid var( --desktop-mode-border, #dcdcde );
1230 + background: var( --os-ui-hover, rgba( 0, 0, 0, 0.04 ) );
1231 + border: 1px solid var( --os-ui-border, #dcdcde );
979 1232 }
980 1233
981 -.desktop-mode-my-wordpress__comment-post-title {
1234 +.os-my-wordpress__comment-post-title {
982 1235 font-weight: 600;
983 - color: var( --desktop-mode-link, #2271b1 );
1236 + color: var( --os-link, var( --os-ui-accent, #2271b1 ) );
984 1237 text-decoration: none;
985 1238 }
986 1239
987 -.desktop-mode-my-wordpress__comment-post-title:hover {
1240 +.os-my-wordpress__comment-post-title:hover {
988 1241 text-decoration: underline;
989 1242 }
990 1243
991 -.desktop-mode-my-wordpress__comment-post-meta {
1244 +.os-my-wordpress__comment-post-meta {
992 1245 font-size: 11px;
993 - color: var( --desktop-mode-muted, #787c82 );
1246 + color: var( --os-ui-fg-muted, #787c82 );
994 1247 }
995 1248
996 1249 /* Replies list. */
997 -.desktop-mode-my-wordpress__comment-replies {
1250 +.os-my-wordpress__comment-replies {
998 1251 list-style: none;
999 1252 margin: 0;
1000 1253 padding: 0;
1001 1254 display: flex;
@@ -1002,19 +1255,19 @@
1002 1255 flex-direction: column;
1003 1256 gap: 10px;
1004 1257 }
1005 1258
1006 -.desktop-mode-my-wordpress__comment-reply {
1259 +.os-my-wordpress__comment-reply {
1007 1260 display: flex;
1008 1261 gap: 10px;
1009 1262 align-items: flex-start;
1010 1263 padding: 10px 12px;
1011 1264 border-radius: 8px;
1012 - background: rgba( 0, 0, 0, 0.02 );
1013 - border: 1px solid var( --desktop-mode-border, #dcdcde );
1265 + background: var( --os-ui-hover, rgba( 0, 0, 0, 0.02 ) );
1266 + border: 1px solid var( --os-ui-border, #dcdcde );
1014 1267 }
1015 1268
1016 -.desktop-mode-my-wordpress__comment-reply-avatar {
1269 +.os-my-wordpress__comment-reply-avatar {
1017 1270 width: 32px;
1018 1271 height: 32px;
1019 1272 border-radius: 50%;
1020 1273 flex-shrink: 0;
@@ -1019,9 +1272,9 @@
1019 1272 border-radius: 50%;
1020 1273 flex-shrink: 0;
1021 1274 }
1022 1275
1023 -.desktop-mode-my-wordpress__comment-reply-text {
1276 +.os-my-wordpress__comment-reply-text {
1024 1277 display: flex;
1025 1278 flex-direction: column;
1026 1279 gap: 2px;
1027 1280 min-width: 0;
@@ -1026,9 +1279,9 @@
1026 1279 gap: 2px;
1027 1280 min-width: 0;
1028 1281 }
1029 1282
1030 -.desktop-mode-my-wordpress__comment-reply-head {
1283 +.os-my-wordpress__comment-reply-head {
1031 1284 display: flex;
1032 1285 align-items: baseline;
1033 1286 gap: 8px;
1034 1287 flex-wrap: wrap;
@@ -1033,22 +1286,22 @@
1033 1286 gap: 8px;
1034 1287 flex-wrap: wrap;
1035 1288 }
1036 1289
1037 -.desktop-mode-my-wordpress__comment-reply-name {
1290 +.os-my-wordpress__comment-reply-name {
1038 1291 font-weight: 600;
1039 1292 font-size: 13px;
1040 1293 }
1041 1294
1042 -.desktop-mode-my-wordpress__comment-reply-when {
1295 +.os-my-wordpress__comment-reply-when {
1043 1296 font-size: 11px;
1044 - color: var( --desktop-mode-muted, #787c82 );
1297 + color: var( --os-ui-fg-muted, #787c82 );
1045 1298 }
1046 1299
1047 -.desktop-mode-my-wordpress__comment-reply-excerpt {
1300 +.os-my-wordpress__comment-reply-excerpt {
1048 1301 margin: 0;
1049 1302 font-size: 13px;
1050 - color: var( --desktop-mode-fg, #1d2327 );
1303 + color: var( --os-my-wordpress-fg, var( --os-ui-fg, #1d2327 ) );
1051 1304 line-height: 1.45;
1052 1305 }
1053 1306
1054 1307 /* =================================================================== *
@@ -1063,9 +1316,9 @@
1063 1316 * Since 0.20.0.
1064 1317 * =================================================================== */
1065 1318
1066 1319 /* User tile — replaces the dashicon glyph with a real avatar */
1067 -.desktop-mode-my-wordpress__tile--user {
1320 +.os-my-wordpress__tile--user {
1068 1321 display: flex;
1069 1322 flex-direction: column;
1070 1323 align-items: center;
1071 1324 justify-content: flex-start;
@@ -1073,9 +1326,9 @@
1073 1326 padding: 8px 4px 6px;
1074 1327 box-sizing: border-box;
1075 1328 }
1076 1329
1077 -.desktop-mode-my-wordpress__user-tile-avatar {
1330 +.os-my-wordpress__user-tile-avatar {
1078 1331 display: inline-flex;
1079 1332 align-items: center;
1080 1333 justify-content: center;
1081 1334 width: 44px;
@@ -1083,10 +1336,10 @@
1083 1336 border-radius: 50%;
1084 1337 overflow: hidden;
1085 1338 background: linear-gradient(
1086 1339 135deg,
1087 - rgba( 34, 113, 177, 0.18 ),
1088 - rgba( 34, 113, 177, 0.04 )
1340 + color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 18%, transparent ),
1341 + color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 4%, transparent )
1089 1342 );
1090 1343 box-shadow:
1091 1344 inset 0 0 0 1px rgba( 0, 0, 0, 0.08 ),
1092 1345 0 2px 6px rgba( 0, 0, 0, 0.08 );
@@ -1092,9 +1345,9 @@
1092 1345 0 2px 6px rgba( 0, 0, 0, 0.08 );
1093 1346 flex: 0 0 auto;
1094 1347 }
1095 1348
1096 -.desktop-mode-my-wordpress__user-tile-avatar img {
1349 +.os-my-wordpress__user-tile-avatar img {
1097 1350 width: 100%;
1098 1351 height: 100%;
1099 1352 object-fit: cover;
1100 1353 display: block;
@@ -1099,9 +1352,9 @@
1099 1352 object-fit: cover;
1100 1353 display: block;
1101 1354 }
1102 1355
1103 -.desktop-mode-my-wordpress__user-tile-initials {
1356 +.os-my-wordpress__user-tile-initials {
1104 1357 font-weight: 600;
1105 1358 font-size: 14px;
1106 1359 letter-spacing: 0.02em;
1107 1360 color: var( --wp-admin-theme-color, #2271b1 );
@@ -1110,9 +1363,9 @@
1110 1363
1111 1364 /* Single-line label for user tiles — we already have a generic
1112 1365 * label clamp, but the user variant gets only ONE line so the
1113 1366 * sub-line ("Editor · 12 posts") can fit beneath it. */
1114 -.desktop-mode-my-wordpress__tile--user .desktop-mode-file-tile__label {
1367 +.os-my-wordpress__tile--user .os-file-tile__label {
1115 1368 font-size: 11px;
1116 1369 font-weight: 500;
1117 1370 line-height: 1.25;
1118 1371 max-height: 1.25em;
@@ -1123,12 +1376,12 @@
1123 1376 padding: 0 4px;
1124 1377 box-sizing: border-box;
1125 1378 }
1126 1379
1127 -.desktop-mode-my-wordpress__user-tile-sub {
1380 +.os-my-wordpress__user-tile-sub {
1128 1381 font-size: 10px;
1129 1382 line-height: 1.2;
1130 - color: var( --desktop-mode-tile-fg-muted, rgba( 0, 0, 0, 0.55 ) );
1383 + color: var( --os-tile-fg-muted, rgba( 0, 0, 0, 0.55 ) );
1131 1384 max-height: 1.2em;
1132 1385 white-space: nowrap;
1133 1386 overflow: hidden;
1134 1387 text-overflow: ellipsis;
@@ -1138,9 +1391,9 @@
1138 1391 box-sizing: border-box;
1139 1392 }
1140 1393
1141 1394 /* Selected/hover user tiles inherit the same chrome the post tiles
1142 - * use — see `.desktop-mode-my-wordpress__tile--selected` above. */
1395 + * use — see `.os-my-wordpress__tile--selected` above. */
1143 1396
1144 1397 /* ----- Activity footprint — full-width body surface -----
1145 1398 *
1146 1399 * Opens via the right-click context menu on a user tile (or the
@@ -1148,9 +1401,9 @@
1148 1401 * list/preview with a wide canvas so each section gets enough room
1149 1402 * to read.
1150 1403 */
1151 1404
1152 -.desktop-mode-my-wordpress__footprint {
1405 +.os-my-wordpress__footprint {
1153 1406 display: flex;
1154 1407 flex-direction: column;
1155 1408 gap: 20px;
1156 1409 padding: 24px 28px 32px;
@@ -1163,20 +1416,20 @@
1163 1416 * cap is applied to each immediate child instead (below). */
1164 1417 align-items: center;
1165 1418 }
1166 1419
1167 -.desktop-mode-my-wordpress__footprint > * {
1420 +.os-my-wordpress__footprint > * {
1168 1421 width: 100%;
1169 1422 max-width: 1080px;
1170 1423 }
1171 1424
1172 -.desktop-mode-my-wordpress__footprint-section {
1173 - border: 1px solid var( --desktop-mode-border, #dcdcde );
1425 +.os-my-wordpress__footprint-section {
1426 + border: 1px solid var( --os-ui-border, #dcdcde );
1174 1427 border-radius: 12px;
1175 1428 padding: 18px 20px;
1176 1429 background: var(
1177 - --desktop-mode-my-wordpress-surface,
1178 - var( --desktop-mode-surface, rgba( 255, 255, 255, 0.6 ) )
1430 + --os-my-wordpress-surface,
1431 + var( --os-surface, var( --os-ui-surface, rgba( 255, 255, 255, 0.6 ) ) )
1179 1432 );
1180 1433 box-shadow: 0 1px 2px rgba( 0, 0, 0, 0.04 );
1181 1434 /* The parent `.__footprint` is a flex column with `overflow-y:
1182 1435 * auto`. Flex items default to `flex-shrink: 1`, so each section
@@ -1188,20 +1441,20 @@
1188 1441 * overflow. */
1189 1442 flex: 0 0 auto;
1190 1443 }
1191 1444
1192 -.desktop-mode-my-wordpress__footprint-section h3 {
1445 +.os-my-wordpress__footprint-section h3 {
1193 1446 margin: 0 0 12px;
1194 1447 font-size: 13px;
1195 1448 font-weight: 600;
1196 1449 letter-spacing: 0.04em;
1197 1450 text-transform: uppercase;
1198 - color: var( --desktop-mode-muted, #50575e );
1451 + color: var( --os-ui-fg-muted, #50575e );
1199 1452 }
1200 1453
1201 1454 /* ----- Hero ----- */
1202 1455
1203 -.desktop-mode-my-wordpress__footprint-hero {
1456 +.os-my-wordpress__footprint-hero {
1204 1457 display: flex;
1205 1458 gap: 20px;
1206 1459 align-items: center;
1207 1460 padding: 24px;
@@ -1207,16 +1460,16 @@
1207 1460 padding: 24px;
1208 1461 border-radius: 16px;
1209 1462 background: linear-gradient(
1210 1463 135deg,
1211 - rgba( 34, 113, 177, 0.10 ) 0%,
1212 - rgba( 34, 113, 177, 0.02 ) 60%,
1464 + color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 10%, transparent ) 0%,
1465 + color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 2%, transparent ) 60%,
1213 1466 transparent 100%
1214 1467 );
1215 - border: 1px solid var( --desktop-mode-border, #dcdcde );
1468 + border: 1px solid var( --os-ui-border, #dcdcde );
1216 1469 }
1217 1470
1218 -.desktop-mode-my-wordpress__footprint-avatar {
1471 +.os-my-wordpress__footprint-avatar {
1219 1472 width: 112px;
1220 1473 height: 112px;
1221 1474 border-radius: 50%;
1222 1475 overflow: hidden;
@@ -1225,10 +1478,10 @@
1225 1478 inset 0 0 0 2px rgba( 255, 255, 255, 0.8 ),
1226 1479 0 6px 24px rgba( 0, 0, 0, 0.14 );
1227 1480 background: linear-gradient(
1228 1481 135deg,
1229 - rgba( 34, 113, 177, 0.18 ),
1230 - rgba( 34, 113, 177, 0.04 )
1482 + color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 18%, transparent ),
1483 + color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 4%, transparent )
1231 1484 );
1232 1485 display: inline-flex;
1233 1486 align-items: center;
1234 1487 justify-content: center;
@@ -1233,9 +1486,9 @@
1233 1486 align-items: center;
1234 1487 justify-content: center;
1235 1488 }
1236 1489
1237 -.desktop-mode-my-wordpress__footprint-avatar img {
1490 +.os-my-wordpress__footprint-avatar img {
1238 1491 width: 100%;
1239 1492 height: 100%;
1240 1493 object-fit: cover;
1241 1494 display: block;
@@ -1240,14 +1493,14 @@
1240 1493 object-fit: cover;
1241 1494 display: block;
1242 1495 }
1243 1496
1244 -.desktop-mode-my-wordpress__footprint-avatar
1245 - .desktop-mode-my-wordpress__user-tile-initials {
1497 +.os-my-wordpress__footprint-avatar
1498 + .os-my-wordpress__user-tile-initials {
1246 1499 font-size: 36px;
1247 1500 }
1248 1501
1249 -.desktop-mode-my-wordpress__footprint-headline {
1502 +.os-my-wordpress__footprint-headline {
1250 1503 min-width: 0;
1251 1504 flex: 1 1 auto;
1252 1505 display: flex;
1253 1506 flex-direction: column;
@@ -1253,17 +1506,20 @@
1253 1506 flex-direction: column;
1254 1507 gap: 8px;
1255 1508 }
1256 1509
1257 -.desktop-mode-my-wordpress__footprint-title {
1510 +/* Window text reads the app's own foreground, never `--os-fg`: that token
1511 + * is the shell's text ON THE DESK, so a light theme (Legacy) leaves it
1512 + * white and the name vanished into the white hero. */
1513 +.os-my-wordpress__footprint-title {
1258 1514 margin: 0;
1259 1515 font-size: 28px;
1260 1516 line-height: 1.15;
1261 1517 font-weight: 700;
1262 - color: var( --desktop-mode-fg, #1d2327 );
1518 + color: var( --os-my-wordpress-fg, var( --os-ui-fg, #1d2327 ) );
1263 1519 }
1264 1520
1265 -.desktop-mode-my-wordpress__footprint-meta {
1521 +.os-my-wordpress__footprint-meta {
1266 1522 display: flex;
1267 1523 flex-wrap: wrap;
1268 1524 gap: 6px;
1269 1525 align-items: center;
@@ -1268,16 +1524,16 @@
1268 1524 gap: 6px;
1269 1525 align-items: center;
1270 1526 }
1271 1527
1272 -.desktop-mode-my-wordpress__footprint-since {
1273 - background: rgba( 0, 0, 0, 0.06 );
1274 - color: var( --desktop-mode-muted, #50575e );
1528 +.os-my-wordpress__footprint-since {
1529 + background: var( --os-ui-hover, rgba( 0, 0, 0, 0.06 ) );
1530 + color: var( --os-ui-fg-muted, #50575e );
1275 1531 }
1276 1532
1277 1533 /* ----- Headline stats row (4 cards) ----- */
1278 1534
1279 -.desktop-mode-my-wordpress__footprint-stats-row {
1535 +.os-my-wordpress__footprint-stats-row {
1280 1536 display: grid;
1281 1537 grid-template-columns: repeat( auto-fit, minmax( 160px, 1fr ) );
1282 1538 gap: 12px;
1283 1539 padding: 16px 18px;
@@ -1282,21 +1538,21 @@
1282 1538 gap: 12px;
1283 1539 padding: 16px 18px;
1284 1540 }
1285 1541
1286 -.desktop-mode-my-wordpress__footprint-stats-row
1287 - .desktop-mode-my-wordpress__user-stat {
1288 - background: var( --desktop-mode-surface, rgba( 255, 255, 255, 0.9 ) );
1542 +.os-my-wordpress__footprint-stats-row
1543 + .os-my-wordpress__user-stat {
1544 + background: var( --os-surface, var( --os-ui-surface, rgba( 255, 255, 255, 0.9 ) ) );
1289 1545 box-shadow: 0 1px 4px rgba( 0, 0, 0, 0.04 );
1290 1546 }
1291 1547
1292 1548 /* ----- Calendar heatmap (GitHub-style) ----- */
1293 1549
1294 -.desktop-mode-my-wordpress__footprint-calendar-section {
1550 +.os-my-wordpress__footprint-calendar-section {
1295 1551 overflow-x: auto;
1296 1552 }
1297 1553
1298 -.desktop-mode-my-wordpress__footprint-calendar {
1554 +.os-my-wordpress__footprint-calendar {
1299 1555 display: flex;
1300 1556 flex-direction: column;
1301 1557 gap: 8px;
1302 1558 /* Size to the grid itself so the legend (justify-content: flex-end
@@ -1307,9 +1563,9 @@
1307 1563 max-width: 100%;
1308 1564 margin-inline: auto;
1309 1565 }
1310 1566
1311 -.desktop-mode-my-wordpress__footprint-grid {
1567 +.os-my-wordpress__footprint-grid {
1312 1568 display: grid;
1313 1569 /* Row 1 holds month labels (auto height); rows 2–8 are the 7
1314 1570 * weekdays at fixed 11px. Col 1 holds weekday labels (auto width);
1315 1571 * subsequent cols are 11px-wide week tracks, set per-cell via
@@ -1321,17 +1577,17 @@
1321 1577 row-gap: 3px;
1322 1578 width: max-content;
1323 1579 }
1324 1580
1325 -.desktop-mode-my-wordpress__footprint-month,
1326 -.desktop-mode-my-wordpress__footprint-weekday {
1581 +.os-my-wordpress__footprint-month,
1582 +.os-my-wordpress__footprint-weekday {
1327 1583 font-size: 10px;
1328 1584 line-height: 11px;
1329 - color: var( --desktop-mode-muted, #50575e );
1585 + color: var( --os-ui-fg-muted, #50575e );
1330 1586 white-space: nowrap;
1331 1587 }
1332 1588
1333 -.desktop-mode-my-wordpress__footprint-weekday {
1589 +.os-my-wordpress__footprint-weekday {
1334 1590 /* Sit flush to the right of the label gutter so each label reads
1335 1591 * adjacent to its row. The 6px breathing room is in addition to
1336 1592 * the grid's column-gap. */
1337 1593 padding-inline-end: 6px;
@@ -1338,68 +1594,68 @@
1338 1594 align-self: center;
1339 1595 justify-self: end;
1340 1596 }
1341 1597
1342 -.desktop-mode-my-wordpress__footprint-month {
1598 +.os-my-wordpress__footprint-month {
1343 1599 padding-bottom: 2px;
1344 1600 }
1345 1601
1346 -.desktop-mode-my-wordpress__footprint-cell {
1602 +.os-my-wordpress__footprint-cell {
1347 1603 width: 11px;
1348 1604 height: 11px;
1349 1605 border-radius: 2px;
1350 - background: var( --desktop-mode-border, #ebedf0 );
1606 + background: var( --os-ui-border, #ebedf0 );
1351 1607 display: inline-block;
1352 1608 transition: transform 0.12s ease;
1353 1609 }
1354 1610
1355 -.desktop-mode-my-wordpress__footprint-cell--pad {
1611 +.os-my-wordpress__footprint-cell--pad {
1356 1612 background: transparent;
1357 1613 }
1358 1614
1359 -.desktop-mode-my-wordpress__footprint-cell--l0 {
1360 - background: rgba( 0, 0, 0, 0.06 );
1615 +.os-my-wordpress__footprint-cell--l0 {
1616 + background: var( --os-ui-hover, rgba( 0, 0, 0, 0.06 ) );
1361 1617 }
1362 1618
1363 -.desktop-mode-my-wordpress__footprint-cell--l1 {
1364 - background: rgba( 34, 113, 177, 0.25 );
1619 +.os-my-wordpress__footprint-cell--l1 {
1620 + background: color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 25%, transparent );
1365 1621 }
1366 1622
1367 -.desktop-mode-my-wordpress__footprint-cell--l2 {
1368 - background: rgba( 34, 113, 177, 0.5 );
1623 +.os-my-wordpress__footprint-cell--l2 {
1624 + background: color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 50%, transparent );
1369 1625 }
1370 1626
1371 -.desktop-mode-my-wordpress__footprint-cell--l3 {
1372 - background: rgba( 34, 113, 177, 0.75 );
1627 +.os-my-wordpress__footprint-cell--l3 {
1628 + background: color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 75%, transparent );
1373 1629 }
1374 1630
1375 -.desktop-mode-my-wordpress__footprint-cell--l4 {
1631 +.os-my-wordpress__footprint-cell--l4 {
1376 1632 background: var( --wp-admin-theme-color, #2271b1 );
1377 1633 }
1378 1634
1379 -.desktop-mode-my-wordpress__footprint-cell:hover {
1635 +.os-my-wordpress__footprint-cell:hover {
1380 1636 transform: scale( 1.4 );
1381 1637 z-index: 1;
1382 1638 }
1383 1639
1384 -.desktop-mode-my-wordpress__footprint-legend {
1640 +.os-my-wordpress__footprint-legend {
1385 1641 display: flex;
1386 1642 gap: 4px;
1387 1643 align-items: center;
1388 1644 justify-content: flex-end;
1389 1645 font-size: 11px;
1390 - color: var( --desktop-mode-muted, #50575e );
1646 + color: var( --os-ui-fg-muted, #50575e );
1391 1647 }
1392 1648
1393 -.desktop-mode-my-wordpress__footprint-legend-label {
1649 +.os-my-wordpress__footprint-legend-label {
1394 1650 font-size: 11px;
1395 - color: var( --desktop-mode-muted, #50575e );
1651 + color: var( --os-ui-fg-muted, #50575e );
1396 1652 padding: 0 4px;
1397 1653 }
1398 1654
1399 1655 /* ----- Rhythm (weekday + hour bar charts) ----- */
1400 1656
1401 -.desktop-mode-my-wordpress__footprint-rhythm-grid {
1657 +.os-my-wordpress__footprint-rhythm-grid {
1402 1658 display: grid;
1403 1659 grid-template-columns: minmax( 0, 1fr ) minmax( 0, 1.7fr );
1404 1660 gap: 24px;
1405 1661 }
@@ -1404,20 +1660,20 @@
1404 1660 gap: 24px;
1405 1661 }
1406 1662
1407 1663 @container ( max-width: 720px ) {
1408 - .desktop-mode-my-wordpress__footprint-rhythm-grid {
1664 + .os-my-wordpress__footprint-rhythm-grid {
1409 1665 grid-template-columns: 1fr;
1410 1666 }
1411 1667 }
1412 1668
1413 -.desktop-mode-my-wordpress__footprint-chart-caption {
1669 +.os-my-wordpress__footprint-chart-caption {
1414 1670 font-size: 12px;
1415 - color: var( --desktop-mode-muted, #50575e );
1671 + color: var( --os-ui-fg-muted, #50575e );
1416 1672 margin-bottom: 6px;
1417 1673 }
1418 1674
1419 -.desktop-mode-my-wordpress__footprint-bars {
1675 +.os-my-wordpress__footprint-bars {
1420 1676 display: flex;
1421 1677 align-items: end;
1422 1678 gap: 4px;
1423 1679 height: 100px;
@@ -1424,9 +1680,9 @@
1424 1680 padding-bottom: 18px;
1425 1681 position: relative;
1426 1682 }
1427 1683
1428 -.desktop-mode-my-wordpress__footprint-bar-col {
1684 +.os-my-wordpress__footprint-bar-col {
1429 1685 flex: 1 1 0;
1430 1686 min-width: 0;
1431 1687 display: flex;
1432 1688 flex-direction: column;
@@ -1436,13 +1692,13 @@
1436 1692 height: 100%;
1437 1693 position: relative;
1438 1694 }
1439 1695
1440 -.desktop-mode-my-wordpress__footprint-bar {
1696 +.os-my-wordpress__footprint-bar {
1441 1697 background: linear-gradient(
1442 1698 180deg,
1443 1699 var( --wp-admin-theme-color, #2271b1 ) 0%,
1444 - rgba( 34, 113, 177, 0.55 ) 100%
1700 + color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 55%, transparent ) 100%
1445 1701 );
1446 1702 border-radius: 3px 3px 0 0;
1447 1703 min-height: 2px;
1448 1704 transition: opacity 0.2s ease;
@@ -1447,15 +1703,15 @@
1447 1703 min-height: 2px;
1448 1704 transition: opacity 0.2s ease;
1449 1705 }
1450 1706
1451 -.desktop-mode-my-wordpress__footprint-bar--empty {
1452 - background: var( --desktop-mode-border, #dcdcde );
1707 +.os-my-wordpress__footprint-bar--empty {
1708 + background: var( --os-ui-border, #dcdcde );
1453 1709 height: 2px !important;
1454 1710 min-height: 2px;
1455 1711 }
1456 1712
1457 -.desktop-mode-my-wordpress__footprint-bar-label {
1713 +.os-my-wordpress__footprint-bar-label {
1458 1714 position: absolute;
1459 1715 bottom: -16px;
1460 1716 left: 0;
1461 1717 right: 0;
@@ -1460,14 +1716,14 @@
1460 1716 left: 0;
1461 1717 right: 0;
1462 1718 text-align: center;
1463 1719 font-size: 10px;
1464 - color: var( --desktop-mode-muted, #787c82 );
1720 + color: var( --os-ui-fg-muted, #787c82 );
1465 1721 }
1466 1722
1467 1723 /* ----- Most-prolific-month callout ----- */
1468 1724
1469 -.desktop-mode-my-wordpress__footprint-callout {
1725 +.os-my-wordpress__footprint-callout {
1470 1726 display: flex;
1471 1727 flex-direction: column;
1472 1728 gap: 4px;
1473 1729 align-items: center;
@@ -1474,38 +1730,38 @@
1474 1730 text-align: center;
1475 1731 padding: 20px 24px;
1476 1732 background: linear-gradient(
1477 1733 135deg,
1478 - rgba( 34, 113, 177, 0.10 ),
1479 - rgba( 34, 113, 177, 0.02 )
1734 + color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 10%, transparent ),
1735 + color-mix( in srgb, var( --wp-admin-theme-color, #2271b1 ) 2%, transparent )
1480 1736 );
1481 1737 }
1482 1738
1483 -.desktop-mode-my-wordpress__footprint-callout-label {
1739 +.os-my-wordpress__footprint-callout-label {
1484 1740 font-size: 11px;
1485 1741 text-transform: uppercase;
1486 1742 letter-spacing: 0.08em;
1487 - color: var( --desktop-mode-muted, #50575e );
1743 + color: var( --os-ui-fg-muted, #50575e );
1488 1744 font-weight: 600;
1489 1745 }
1490 1746
1491 -.desktop-mode-my-wordpress__footprint-callout-value {
1747 +.os-my-wordpress__footprint-callout-value {
1492 1748 margin: 2px 0;
1493 1749 font-size: 24px;
1494 1750 font-weight: 700;
1495 - color: var( --desktop-mode-fg, #1d2327 );
1751 + color: var( --os-my-wordpress-fg, var( --os-ui-fg, #1d2327 ) );
1496 1752 }
1497 1753
1498 -.desktop-mode-my-wordpress__footprint-callout-detail {
1754 +.os-my-wordpress__footprint-callout-detail {
1499 1755 margin: 0;
1500 1756 font-size: 13px;
1501 - color: var( --desktop-mode-muted, #50575e );
1757 + color: var( --os-ui-fg-muted, #50575e );
1502 1758 max-width: 480px;
1503 1759 }
1504 1760
1505 1761 /* ----- Recent-activity timeline ----- */
1506 1762
1507 -.desktop-mode-my-wordpress__footprint-timeline {
1763 +.os-my-wordpress__footprint-timeline {
1508 1764 list-style: none;
1509 1765 margin: 0;
1510 1766 padding: 0;
1511 1767 position: relative;
@@ -1513,9 +1769,9 @@
1513 1769 flex-direction: column;
1514 1770 gap: 12px;
1515 1771 }
1516 1772
1517 -.desktop-mode-my-wordpress__footprint-timeline::before {
1773 +.os-my-wordpress__footprint-timeline::before {
1518 1774 content: '';
1519 1775 position: absolute;
1520 1776 inset-inline-start: 13px;
1521 1777 top: 4px;
@@ -1520,13 +1776,13 @@
1520 1776 inset-inline-start: 13px;
1521 1777 top: 4px;
1522 1778 bottom: 4px;
1523 1779 width: 2px;
1524 - background: var( --desktop-mode-border, #dcdcde );
1780 + background: var( --os-ui-border, #dcdcde );
1525 1781 border-radius: 1px;
1526 1782 }
1527 1783
1528 -.desktop-mode-my-wordpress__footprint-event {
1784 +.os-my-wordpress__footprint-event {
1529 1785 display: flex;
1530 1786 gap: 12px;
1531 1787 align-items: flex-start;
1532 1788 position: relative;
@@ -1533,9 +1789,9 @@
1533 1789 padding-inline-start: 36px;
1534 1790 min-height: 28px;
1535 1791 }
1536 1792
1537 -.desktop-mode-my-wordpress__footprint-dot {
1793 +.os-my-wordpress__footprint-dot {
1538 1794 position: absolute;
1539 1795 inset-inline-start: 0;
1540 1796 top: 0;
1541 1797 width: 28px;
@@ -1543,20 +1799,20 @@
1543 1799 border-radius: 50%;
1544 1800 display: inline-flex;
1545 1801 align-items: center;
1546 1802 justify-content: center;
1547 - background: var( --desktop-mode-surface, #fff );
1803 + background: var( --os-surface, var( --os-ui-surface, #fff ) );
1548 1804 border: 2px solid var( --wp-admin-theme-color, #2271b1 );
1549 1805 color: var( --wp-admin-theme-color, #2271b1 );
1550 1806 }
1551 1807
1552 -.desktop-mode-my-wordpress__footprint-event--comment
1553 - .desktop-mode-my-wordpress__footprint-dot {
1554 - border-color: var( --desktop-mode-muted, #787c82 );
1555 - color: var( --desktop-mode-muted, #787c82 );
1808 +.os-my-wordpress__footprint-event--comment
1809 + .os-my-wordpress__footprint-dot {
1810 + border-color: var( --os-ui-fg-muted, #787c82 );
1811 + color: var( --os-ui-fg-muted, #787c82 );
1556 1812 }
1557 1813
1558 -.desktop-mode-my-wordpress__footprint-dot .dashicons {
1814 +.os-my-wordpress__footprint-dot .dashicons {
1559 1815 font-size: 14px;
1560 1816 width: 14px;
1561 1817 height: 14px;
1562 1818 line-height: 1;
@@ -1561,9 +1817,9 @@
1561 1817 height: 14px;
1562 1818 line-height: 1;
1563 1819 }
1564 1820
1565 -.desktop-mode-my-wordpress__footprint-event-body {
1821 +.os-my-wordpress__footprint-event-body {
1566 1822 display: flex;
1567 1823 flex-direction: column;
1568 1824 gap: 2px;
1569 1825 min-width: 0;
@@ -1569,12 +1825,12 @@
1569 1825 min-width: 0;
1570 1826 flex: 1 1 auto;
1571 1827 }
1572 1828
1573 -.desktop-mode-my-wordpress__footprint-event-title {
1829 +.os-my-wordpress__footprint-event-title {
1574 1830 font-weight: 600;
1575 1831 font-size: 13px;
1576 - color: var( --desktop-mode-link, #2271b1 );
1832 + color: var( --os-link, var( --os-ui-accent, #2271b1 ) );
1577 1833 text-decoration: none;
1578 1834 overflow: hidden;
1579 1835 text-overflow: ellipsis;
1580 1836 white-space: nowrap;
@@ -1579,20 +1835,20 @@
1579 1835 text-overflow: ellipsis;
1580 1836 white-space: nowrap;
1581 1837 }
1582 1838
1583 -a.desktop-mode-my-wordpress__footprint-event-title:hover {
1839 +a.os-my-wordpress__footprint-event-title:hover {
1584 1840 text-decoration: underline;
1585 1841 }
1586 1842
1587 -.desktop-mode-my-wordpress__footprint-event-meta {
1843 +.os-my-wordpress__footprint-event-meta {
1588 1844 font-size: 11px;
1589 - color: var( --desktop-mode-muted, #787c82 );
1845 + color: var( --os-ui-fg-muted, #787c82 );
1590 1846 }
1591 1847
1592 1848 /* ----- Footer actions ----- */
1593 1849
1594 -.desktop-mode-my-wordpress__footprint-footer {
1850 +.os-my-wordpress__footprint-footer {
1595 1851 display: flex;
1596 1852 justify-content: flex-end;
1597 1853 align-items: center;
1598 1854 gap: 8px;
@@ -1620,9 +1876,9 @@
1620 1876 * banner across that corner. The strip extends past the
1621 1877 * tile edges; `overflow: hidden` on the parent crops it
1622 1878 * into a clean triangle.
1623 1879 *
1624 - * The status tiles need a positioning context. `.desktop-mode-
1880 + * The status tiles need a positioning context. `.os-
1625 1881 * file-tile` is `position: absolute` (canvas layout) on the
1626 1882 * Posts/Pages browse views — that satisfies the positioning-
1627 1883 * context requirement. For the Media drill-in usage tiles we
1628 1884 * swap from `static` to `relative` via the per-status rule
@@ -1629,9 +1885,9 @@
1629 1885 * below so the ribbon stays anchored to its own tile.
1630 1886 * ============================================================ */
1631 1887
1632 1888 /* Status ribbon — the diagonal corner banner — is now drawn by
1633 - * the `<wpd-ribbon>` web component slotted inside `<wpd-tile>`.
1889 + * the `<os-ribbon>` web component slotted inside `<os-tile>`.
1634 1890 * The component's own shadow-DOM styles own placement, rotation,
1635 1891 * background, lettering, and the WP admin-theme tint. The only
1636 1892 * surface-specific rule left here is dimming the icon on non-
1637 1893 * published tiles so the unpublished signal carries even when
@@ -1636,19 +1892,19 @@
1636 1892 * surface-specific rule left here is dimming the icon on non-
1637 1893 * published tiles so the unpublished signal carries even when
1638 1894 * the ribbon is hidden via the OS-settings toggle. */
1639 1895
1640 -.desktop-mode-my-wordpress__tile--draft,
1641 -.desktop-mode-my-wordpress__tile--pending,
1642 -.desktop-mode-my-wordpress__tile--private,
1643 -.desktop-mode-my-wordpress__tile--future {
1896 +.os-my-wordpress__tile--draft,
1897 +.os-my-wordpress__tile--pending,
1898 +.os-my-wordpress__tile--private,
1899 +.os-my-wordpress__tile--future {
1644 1900 overflow: hidden;
1645 1901 }
1646 1902
1647 -wpd-tile[ status='draft' ] .desktop-mode-file-tile__icon,
1648 -wpd-tile[ status='pending' ] .desktop-mode-file-tile__icon,
1649 -wpd-tile[ status='private' ] .desktop-mode-file-tile__icon,
1650 -wpd-tile[ status='future' ] .desktop-mode-file-tile__icon {
1903 +os-tile[ status='draft' ] .os-file-tile__icon,
1904 +os-tile[ status='pending' ] .os-file-tile__icon,
1905 +os-tile[ status='private' ] .os-file-tile__icon,
1906 +os-tile[ status='future' ] .os-file-tile__icon {
1651 1907 opacity: 0.7;
1652 1908 }
1653 1909
1654 1910 /* ============================================================ *
@@ -1654,19 +1910,23 @@
1654 1910 /* ============================================================ *
1655 1911 * Media section (since 0.21.0)
1656 1912 * ============================================================ */
1657 1913
1658 -.desktop-mode-my-wordpress__media-grid {
1914 +.os-my-wordpress__media-grid {
1659 1915 display: grid;
1660 1916 grid-template-columns: repeat( auto-fill, minmax( 120px, 1fr ) );
1661 - gap: 12px;
1662 - padding: 16px;
1917 + /* A flow grid rather than the absolute canvas, but the air
1918 + * between two icons should not depend on which window you are
1919 + * looking at — so the gaps and the gutter come from the same
1920 + * tokens the canvas pitch is built from. */
1921 + gap: var( --os-grid-gap-y, 16px ) var( --os-grid-gap-x, 20px );
1922 + padding: var( --os-grid-padding, 16px );
1663 1923 overflow-y: auto;
1664 1924 align-content: start;
1665 1925 }
1666 1926
1667 -.desktop-mode-my-wordpress__media-tile {
1668 - /* Override the base `.desktop-mode-file-tile` (position: absolute,
1927 +.os-my-wordpress__media-tile {
1928 + /* Override the base `.os-file-tile` (position: absolute,
1669 1929 * width: 88px) so media tiles flow inside the CSS Grid instead of
1670 1930 * stacking at (0,0) like the absolute-positioned post/user tiles.
1671 1931 *
1672 1932 * `relative` (not `static`) so the tile remains a containing
@@ -1671,14 +1931,18 @@
1671 1931 *
1672 1932 * `relative` (not `static`) so the tile remains a containing
1673 1933 * block for absolutely-positioned descendants — the `::after`
1674 1934 * shortcut-arrow badge on attachment tiles, and the
1675 - * `<wpd-ribbon>` post-status corner ribbon — both of which
1935 + * `<os-ribbon>` post-status corner ribbon — both of which
1676 1936 * would otherwise escape to the nearest positioned ancestor
1677 1937 * (the window, the desktop, the viewport) and render way off
1678 1938 * the tile. */
1679 1939 position: relative;
1680 1940 width: auto;
1941 + /* …and out of the fixed tile height for the same reason: a media
1942 + * tile is a square thumbnail plus a caption, sized by the grid
1943 + * column it lands in, not by the icon-canvas cell. */
1944 + height: auto;
1681 1945 display: flex;
1682 1946 flex-direction: column;
1683 1947 align-items: stretch;
1684 1948 gap: 6px;
@@ -1690,13 +1954,13 @@
1690 1954 text-align: center;
1691 1955 min-width: 0;
1692 1956 }
1693 1957
1694 -.desktop-mode-my-wordpress__media-tile:hover {
1695 - background: var( --desktop-mode-hover, rgba( 0, 0, 0, 0.04 ) );
1958 +.os-my-wordpress__media-tile:hover {
1959 + background: var( --os-hover, var( --os-ui-hover, rgba( 0, 0, 0, 0.04 ) ) );
1696 1960 }
1697 1961
1698 -/* Media tiles inherit the canonical `.desktop-mode-file-tile--selected`
1962 +/* Media tiles inherit the canonical `.os-file-tile--selected`
1699 1963 * rule from `desktop-files.css` — accent inset border + tinted
1700 1964 * background — same as every other tile in the shell. */
1701 1965
1702 1966 /* Override the canonical 48×48 visual/preview sizing — media tiles
@@ -1704,9 +1968,9 @@
1704 1968 * thumbnail (or icon-fallback square). Photos browser look, not
1705 1969 * folder-icon look. Applies to BOTH the `<img>` (real thumbnail)
1706 1970 * and the dashicon fallback (non-image MIME), so the two tile
1707 1971 * shapes are visually consistent in the grid. */
1708 -.desktop-mode-my-wordpress__media-tile .desktop-mode-file-tile__visual {
1972 +.os-my-wordpress__media-tile .os-file-tile__visual {
1709 1973 display: flex;
1710 1974 align-items: center;
1711 1975 justify-content: center;
1712 1976 width: 100%;
@@ -1714,9 +1978,9 @@
1714 1978 aspect-ratio: 1 / 1;
1715 1979 overflow: hidden;
1716 1980 border-radius: 6px;
1717 1981 background: var(
1718 - --desktop-mode-media-tile-bg,
1982 + --os-media-tile-bg,
1719 1983 rgba( 0, 0, 0, 0.05 )
1720 1984 );
1721 1985 /* Reset the base 32px font + 48px size since we're sizing the
1722 1986 * inner img/icon explicitly below. */
@@ -1723,9 +1987,9 @@
1723 1987 font-size: 0;
1724 1988 line-height: 1;
1725 1989 }
1726 1990
1727 -.desktop-mode-my-wordpress__media-tile .desktop-mode-file-tile__preview {
1991 +.os-my-wordpress__media-tile .os-file-tile__preview {
1728 1992 width: 100%;
1729 1993 height: 100%;
1730 1994 object-fit: cover;
1731 1995 border-radius: 0;
@@ -1730,18 +1994,18 @@
1730 1994 object-fit: cover;
1731 1995 border-radius: 0;
1732 1996 }
1733 1997
1734 -.desktop-mode-my-wordpress__media-tile .desktop-mode-file-tile__icon {
1998 +.os-my-wordpress__media-tile .os-file-tile__icon {
1735 1999 /* Centered dashicon fallback — proportional to the larger
1736 2000 * thumbnail well so it doesn't look like a postage stamp. */
1737 2001 width: auto;
1738 2002 height: auto;
1739 2003 font-size: 36px;
1740 - color: var( --desktop-mode-muted, #787c82 );
2004 + color: var( --os-ui-fg-muted, #787c82 );
1741 2005 }
1742 2006
1743 -.desktop-mode-my-wordpress__media-tile .desktop-mode-file-tile__label {
2007 +.os-my-wordpress__media-tile .os-file-tile__label {
1744 2008 font-size: 12px;
1745 2009 line-height: 1.3;
1746 2010 overflow: hidden;
1747 2011 text-overflow: ellipsis;
@@ -1751,9 +2015,9 @@
1751 2015 }
1752 2016
1753 2017 /* ----- Media preview pane ----- */
1754 2018
1755 -.desktop-mode-my-wordpress__media-pane {
2019 +.os-my-wordpress__media-pane {
1756 2020 display: flex;
1757 2021 flex-direction: column;
1758 2022 gap: 16px;
1759 2023 padding: 16px;
@@ -1758,19 +2022,19 @@
1758 2022 gap: 16px;
1759 2023 padding: 16px;
1760 2024 }
1761 2025
1762 -.desktop-mode-my-wordpress__media-title {
2026 +.os-my-wordpress__media-title {
1763 2027 font-size: 16px;
1764 2028 font-weight: 600;
1765 2029 margin: 0;
1766 2030 }
1767 2031
1768 -.desktop-mode-my-wordpress__media-visual {
2032 +.os-my-wordpress__media-visual {
1769 2033 display: flex;
1770 2034 align-items: center;
1771 2035 justify-content: center;
1772 - background: var( --desktop-mode-media-visual-bg, rgba( 0, 0, 0, 0.04 ) );
2036 + background: var( --os-media-visual-bg, var( --os-ui-hover, rgba( 0, 0, 0, 0.04 ) ) );
1773 2037 border-radius: 8px;
1774 2038 min-height: 200px;
1775 2039 max-height: 480px;
1776 2040 overflow: hidden;
@@ -1775,28 +2039,28 @@
1775 2039 max-height: 480px;
1776 2040 overflow: hidden;
1777 2041 }
1778 2042
1779 -.desktop-mode-my-wordpress__media-image,
1780 -.desktop-mode-my-wordpress__media-video {
2043 +.os-my-wordpress__media-image,
2044 +.os-my-wordpress__media-video {
1781 2045 max-width: 100%;
1782 2046 max-height: 480px;
1783 2047 object-fit: contain;
1784 2048 }
1785 2049
1786 -.desktop-mode-my-wordpress__media-fallback-icon {
2050 +.os-my-wordpress__media-fallback-icon {
1787 2051 font-size: 96px;
1788 2052 width: 96px;
1789 2053 height: 96px;
1790 - color: var( --desktop-mode-muted, #787c82 );
2054 + color: var( --os-ui-fg-muted, #787c82 );
1791 2055 }
1792 2056
1793 -.desktop-mode-my-wordpress__media-doc-link {
2057 +.os-my-wordpress__media-doc-link {
1794 2058 margin-inline-start: 16px;
1795 2059 align-self: center;
1796 2060 }
1797 2061
1798 -.desktop-mode-my-wordpress__media-audio-stack {
2062 +.os-my-wordpress__media-audio-stack {
1799 2063 display: flex;
1800 2064 flex-direction: column;
1801 2065 align-items: center;
1802 2066 gap: 12px;
@@ -1802,9 +2066,9 @@
1802 2066 gap: 12px;
1803 2067 padding: 24px;
1804 2068 }
1805 2069
1806 -.desktop-mode-my-wordpress__media-meta {
2070 +.os-my-wordpress__media-meta {
1807 2071 display: grid;
1808 2072 grid-template-columns: max-content 1fr;
1809 2073 gap: 4px 16px;
1810 2074 font-size: 13px;
@@ -1810,31 +2074,31 @@
1810 2074 font-size: 13px;
1811 2075 margin: 0;
1812 2076 }
1813 2077
1814 -.desktop-mode-my-wordpress__media-meta-term {
1815 - color: var( --desktop-mode-muted, #787c82 );
2078 +.os-my-wordpress__media-meta-term {
2079 + color: var( --os-ui-fg-muted, #787c82 );
1816 2080 margin: 0;
1817 2081 }
1818 2082
1819 -.desktop-mode-my-wordpress__media-meta-value {
1820 - color: var( --desktop-mode-text, #1d2327 );
2083 +.os-my-wordpress__media-meta-value {
2084 + color: var( --os-ui-fg, #1d2327 );
1821 2085 word-break: break-word;
1822 2086 margin: 0;
1823 2087 }
1824 2088
1825 -.desktop-mode-my-wordpress__media-actions {
2089 +.os-my-wordpress__media-actions {
1826 2090 display: flex;
1827 2091 flex-wrap: wrap;
1828 2092 gap: 8px;
1829 2093 padding-top: 8px;
1830 - border-top: 1px solid var( --desktop-mode-border, #dcdcde );
2094 + border-top: 1px solid var( --os-ui-border, #dcdcde );
1831 2095 }
1832 2096
1833 2097 /* ----- Media drill-in ----- */
1834 2098
1835 2099 /* Drill-in: referencing-posts list. Visually identical to the
1836 - * Posts / Pages tiles — same `desktop-mode-file-tile` chrome (48px
2100 + * Posts / Pages tiles — same `os-file-tile` chrome (48px
1837 2101 * dashicon + 88px-wide two-line label). We can't reuse the
1838 2102 * absolute-positioning canvas layout from `renderEntityList` here
1839 2103 * (those internals don't export), so this surface uses a flex-wrap
1840 2104 * of fixed-width tiles to reproduce the look.
@@ -1842,22 +2106,22 @@
1842 2106 * NOTE: this rule INTENTIONALLY overrides the `__media-grid`
1843 2107 * defaults (which target square thumbnails on 130px columns) so
1844 2108 * usage tiles match the canvas-flowed post tiles instead.
1845 2109 */
1846 -.desktop-mode-my-wordpress__usage-grid {
2110 +.os-my-wordpress__usage-grid {
1847 2111 display: flex;
1848 2112 flex-wrap: wrap;
1849 - gap: 12px 8px;
1850 - padding: 16px;
2113 + gap: var( --os-grid-gap-y, 16px ) var( --os-grid-gap-x, 20px );
2114 + padding: var( --os-grid-padding, 16px );
1851 2115 align-content: flex-start;
1852 2116 }
1853 2117
1854 2118 /* Reset the `__media-tile` overrides for usage tiles so they
1855 - * inherit the unmodified `.desktop-mode-file-tile` chrome the
2119 + * inherit the unmodified `.os-file-tile` chrome the
1856 2120 * canvas-positioned post tiles use — except for `position: static`
1857 2121 * so they participate in the flex layout. */
1858 -.desktop-mode-my-wordpress__tile--usage {
1859 - width: 88px;
2122 +.os-my-wordpress__tile--usage {
2123 + width: var( --os-tile-w, 88px );
1860 2124 align-items: center;
1861 2125 padding: 8px 4px;
1862 2126 gap: 6px;
1863 2127 }
@@ -1862,20 +2126,839 @@
1862 2126 gap: 6px;
1863 2127 }
1864 2128
1865 2129 /* Right-pane summary bar sits ABOVE the inline media preview. */
1866 -.desktop-mode-my-wordpress__media-detail-summary-bar {
2130 +.os-my-wordpress__media-detail-summary-bar {
1867 2131 padding: 12px 16px;
1868 - border-bottom: 1px solid var( --desktop-mode-border, #dcdcde );
2132 + border-bottom: 1px solid var( --os-ui-border, #dcdcde );
1869 2133 }
1870 2134
1871 -.desktop-mode-my-wordpress__media-detail-summary {
2135 +.os-my-wordpress__media-detail-summary {
1872 2136 margin: 0;
1873 - color: var( --desktop-mode-muted, #787c82 );
2137 + color: var( --os-ui-fg-muted, #787c82 );
1874 2138 font-size: 13px;
1875 2139 }
1876 2140
1877 -.desktop-mode-my-wordpress__media-detail-preview {
2141 +.os-my-wordpress__media-detail-preview {
1878 2142 /* Lets the embedded `__media-pane` keep its own padding without
1879 2143 * fighting the summary bar's spacing. */
1880 2144 display: block;
2145 +}
2146 +
2147 +/* ------------------------------------------------------------------ */
2148 +/* Agents section (`agent` entity kind — src/my-wordpress/agents-renderer.ts) */
2149 +/* ------------------------------------------------------------------ */
2150 +
2151 +.dm-agents {
2152 + display: flex;
2153 + flex-direction: column;
2154 + height: 100%;
2155 + min-height: 0;
2156 + padding: 12px;
2157 + gap: 10px;
2158 + overflow: hidden;
2159 + box-sizing: border-box;
2160 +}
2161 +
2162 +
2163 +/* Section-level loading — same scale curve as the My WordPress
2164 + preview loader and the window-loading overlay, instead of the bare
2165 + 48px component default. */
2166 +.dm-agents__loading {
2167 + display: flex;
2168 + align-items: center;
2169 + justify-content: center;
2170 + height: 100%;
2171 + min-height: 320px;
2172 +}
2173 +
2174 +.dm-agents__loading os-spinner {
2175 + --os-ui-spinner-size: clamp( 96px, 14vw, 192px );
2176 +}
2177 +
2178 +.dm-agents__detail {
2179 + flex: 1;
2180 + min-width: 0;
2181 + overflow-y: auto;
2182 + display: flex;
2183 + flex-direction: column;
2184 + gap: 10px;
2185 +}
2186 +
2187 +/* `<os-empty-state>` owns the icon + copy and centres them within
2188 + itself; the host is still a flex item that shrinks to its content,
2189 + so without this it sits at the top of a pane that is mostly empty
2190 + space. Auto margins on both axes absorb the slack — placement only,
2191 + same as the comments window. Covers the framework-off state and
2192 + "No agents yet" alike. */
2193 +.dm-agents__detail > os-empty-state {
2194 + margin: auto;
2195 +}
2196 +
2197 +.dm-agents__detail-head {
2198 + display: flex;
2199 + align-items: center;
2200 + gap: 10px;
2201 +}
2202 +
2203 +.dm-agents__detail-avatar {
2204 + width: 48px;
2205 + height: 48px;
2206 + border-radius: 50%;
2207 + /* Placeholder behind the avatar image while it loads — follows the
2208 + palette so it isn't a white disc on a dark station. */
2209 + background: var( --os-ui-surface-elevated, #fff );
2210 + flex: none;
2211 +}
2212 +
2213 +.dm-agents__detail-title {
2214 + flex: 1;
2215 + min-width: 0;
2216 +}
2217 +
2218 +.dm-agents__detail-title h3 {
2219 + margin: 0;
2220 + font-size: 16px;
2221 +}
2222 +
2223 +.dm-agents__detail-slug {
2224 + font-size: 12px;
2225 + opacity: 0.6;
2226 +}
2227 +
2228 +/* Verbs get their own row under the identity block: the set grows
2229 + (profile, contributions, desktop, chat, delete) and squeezing them
2230 + beside the name truncated it first. */
2231 +.dm-agents__detail-actions {
2232 + display: flex;
2233 + flex-wrap: wrap;
2234 + gap: 8px;
2235 +}
2236 +
2237 +.dm-agents__tabs {
2238 + display: flex;
2239 + gap: 4px;
2240 + border-bottom: 1px solid var( --os-border, rgba( 0, 0, 0, 0.08 ) );
2241 +}
2242 +
2243 +.dm-agents__tab {
2244 + appearance: none;
2245 + background: none;
2246 + border: none;
2247 + border-bottom: 2px solid transparent;
2248 + padding: 6px 10px;
2249 + font: inherit;
2250 + color: inherit;
2251 + cursor: pointer;
2252 + opacity: 0.7;
2253 +}
2254 +
2255 +.dm-agents__tab.is-active {
2256 + border-bottom-color: var( --os-accent, #2271b1 );
2257 + opacity: 1;
2258 + font-weight: 600;
2259 +}
2260 +
2261 +.dm-agents__pane {
2262 + display: flex;
2263 + flex-direction: column;
2264 + gap: 10px;
2265 + padding-bottom: 12px;
2266 +}
2267 +
2268 +/* Pane-level loading: same big, centered WordPress mark the section
2269 + loader uses, instead of a bare 48px spinner pinned to the top-left
2270 + of the pane. */
2271 +.dm-agents__pane--loading {
2272 + align-items: center;
2273 + justify-content: center;
2274 + flex: 1;
2275 + min-height: 260px;
2276 +}
2277 +
2278 +.dm-agents__pane--loading os-spinner {
2279 + --os-ui-spinner-size: clamp( 96px, 12vw, 160px );
2280 +}
2281 +
2282 +.dm-agents__hint {
2283 + margin: 0;
2284 + font-size: 12px;
2285 + opacity: 0.7;
2286 +}
2287 +
2288 +/* Role first: least privilege is the decision, so the control holds
2289 + the mockup's width instead of stretching into a landing strip. */
2290 +.dm-agents__role-select {
2291 + max-width: 280px;
2292 +}
2293 +
2294 +/* The ability filter. Sized like the role select rather than the
2295 + full pane: it sits above a list of rules, and a search box as wide
2296 + as the rules reads as another one of them. */
2297 +.dm-agents__ability-search {
2298 + display: block;
2299 + max-width: 320px;
2300 + margin: 12px 0 4px;
2301 +}
2302 +
2303 +/* Each category is a native disclosure. `<details>` because the
2304 + behaviour is exactly what it is for: keyboard, screen-reader
2305 + semantics and the open/closed state all arrive for free, and the
2306 + only thing left to write is the costume. */
2307 +.dm-agents__ability-group {
2308 + border-bottom: 1px solid var( --os-border, rgba( 0, 0, 0, 0.08 ) );
2309 +}
2310 +
2311 +.dm-agents__ability-group:last-of-type {
2312 + border-bottom: 0;
2313 +}
2314 +
2315 +.dm-agents__category {
2316 + margin: 18px 0 2px;
2317 + font-family: var( --os-ui-font-mono, ui-monospace, monospace );
2318 + font-size: 11px;
2319 + font-weight: 500;
2320 + text-transform: uppercase;
2321 + letter-spacing: 0.08em;
2322 + color: var( --os-ui-fg-muted, #646970 );
2323 +}
2324 +
2325 +/* A `<summary>` is a button, so it gets a button's affordances: a
2326 + pointer, a hover, and a focus ring that is visible on the dark
2327 + surface the section is drawn on. */
2328 +summary.dm-agents__category {
2329 + display: flex;
2330 + align-items: center;
2331 + gap: 8px;
2332 + margin: 0;
2333 + padding: 10px 0;
2334 + cursor: pointer;
2335 + list-style: none;
2336 + user-select: none;
2337 +}
2338 +
2339 +summary.dm-agents__category::-webkit-details-marker {
2340 + display: none;
2341 +}
2342 +
2343 +/* The marker is drawn here rather than left to the UA so it can be
2344 + the same triangle in every browser and turn with the disclosure.
2345 + Rotation only: a transform, so opening a group of forty rows
2346 + costs no layout. */
2347 +summary.dm-agents__category::before {
2348 + content: '';
2349 + flex: none;
2350 + width: 0;
2351 + height: 0;
2352 + border-inline-start: 5px solid currentcolor;
2353 + border-block: 4px solid transparent;
2354 + transition: transform 120ms ease;
2355 +}
2356 +
2357 +.dm-agents__ability-group[ open ] > summary.dm-agents__category::before {
2358 + transform: rotate( 90deg );
2359 +}
2360 +
2361 +@media ( prefers-reduced-motion: reduce ) {
2362 + summary.dm-agents__category::before {
2363 + transition: none;
2364 + }
2365 +}
2366 +
2367 +summary.dm-agents__category:hover {
2368 + color: var( --os-ui-fg, #1e1e1e );
2369 +}
2370 +
2371 +summary.dm-agents__category:focus-visible {
2372 + outline: 2px solid var( --os-ui-accent, #3858e9 );
2373 + outline-offset: 2px;
2374 + border-radius: 4px;
2375 +}
2376 +
2377 +.dm-agents__category-name {
2378 + flex: 1 1 auto;
2379 +}
2380 +
2381 +/* "3 of 12" when some are ticked, otherwise just the size of the
2382 + group. The count is why a closed group is still informative:
2383 + collapsing must not hide the fact that something in there is
2384 + switched on. */
2385 +.dm-agents__category-count {
2386 + flex: none;
2387 + font-variant-numeric: tabular-nums;
2388 + opacity: 0.75;
2389 +}
2390 +
2391 +/* One ability per row, ruled like the mockup: tick and name on the
2392 + left, badge on the right, the description indented under the name
2393 + (the checkbox column is the control's own 26px). */
2394 +.dm-agents__ability {
2395 + display: grid;
2396 + grid-template-columns: 1fr auto;
2397 + gap: 2px 10px;
2398 + align-items: start;
2399 + padding: 11px 0;
2400 + border-bottom: 1px solid var( --os-border, rgba( 0, 0, 0, 0.08 ) );
2401 +}
2402 +
2403 +.dm-agents__ability:last-of-type {
2404 + border-bottom: 0;
2405 +}
2406 +
2407 +.dm-agents__ability-desc {
2408 + grid-column: 1 / -1;
2409 + margin: 0;
2410 + padding-inline-start: 26px;
2411 + font-size: 12.5px;
2412 + color: var( --os-ui-fg-muted, #646970 );
2413 +}
2414 +
2415 +/* Access badges in the instrument voice. The palette's own warning
2416 + tokens carry the pale-yellow "can modify"; all this changes is the
2417 + costume: mono, uppercase, an outline instead of a wash. */
2418 +.dm-agents__ability os-badge {
2419 + --os-ui-badge-font: 500 10px/1.6 var( --os-ui-font-mono, ui-monospace, monospace );
2420 + --os-ui-badge-dot-size: 0;
2421 + --os-ui-badge-gap: 0;
2422 + --os-ui-badge-padding: 3px 8px;
2423 + --os-ui-badge-bg: transparent;
2424 + --os-ui-badge-border: 1px solid var( --os-border, rgba( 0, 0, 0, 0.12 ) );
2425 + text-transform: uppercase;
2426 + letter-spacing: 0.06em;
2427 + white-space: nowrap;
2428 + margin-top: 2px;
2429 +}
2430 +
2431 +.dm-agents__ability os-badge[ tone='warning' ] {
2432 + --os-ui-badge-border: 1px solid
2433 + var( --os-ui-warning-border, rgba( 154, 103, 0, 0.4 ) );
2434 +}
2435 +
2436 +.dm-agents__trigger {
2437 + border: 1px solid var( --os-border, rgba( 0, 0, 0, 0.08 ) );
2438 + border-radius: 8px;
2439 + padding: 8px 10px;
2440 + display: flex;
2441 + flex-direction: column;
2442 + gap: 6px;
2443 +}
2444 +
2445 +.dm-agents__trigger-head {
2446 + display: flex;
2447 + align-items: center;
2448 + gap: 8px;
2449 +}
2450 +
2451 +.dm-agents__trigger-desc {
2452 + margin: 0;
2453 + font-size: 12px;
2454 + opacity: 0.75;
2455 +}
2456 +
2457 +.dm-agents__trigger-config {
2458 + display: flex;
2459 + flex-wrap: wrap;
2460 + gap: 4px 14px;
2461 +}
2462 +
2463 +.dm-agents__actions {
2464 + display: flex;
2465 + gap: 8px;
2466 + align-items: center;
2467 + flex-wrap: wrap;
2468 + margin-block-start: 12px;
2469 +}
2470 +
2471 +/* ---------------------------------------------------------------------
2472 + The cast
2473 + ------------------------------------------------------------------ */
2474 +
2475 +/* One view at a time: the grid, an agent, or the wizard. A sidebar of
2476 + faces next to a detail form would leave neither enough room, and the
2477 + whole point of the grid is that the faces are big enough to tell
2478 + apart. */
2479 +/* The pane scrolls, and a scroll container clips ink overflow: a field
2480 + flush with its edge loses the focus halo the kit paints outside the
2481 + border (1px ring + 4px bloom), so the brief's ring read as a top and
2482 + bottom line with nothing at the sides. Trade 5px of the section's
2483 + 12px padding for a gutter inside the pane; the content does not move. */
2484 +.dm-agents__view {
2485 + display: flex;
2486 + flex-direction: column;
2487 + flex: 1;
2488 + min-height: 0;
2489 + overflow-y: auto;
2490 + gap: 12px;
2491 + margin-inline: -5px;
2492 + padding-inline: 5px;
2493 +}
2494 +
2495 +.dm-agents__cast-head {
2496 + display: flex;
2497 + align-items: baseline;
2498 + gap: 8px;
2499 +}
2500 +
2501 +.dm-agents__cast-head h3 {
2502 + margin: 0;
2503 +}
2504 +
2505 +.dm-agents__cast-count {
2506 + font-family: var( --os-ui-font-mono, ui-monospace, monospace );
2507 + font-size: 12px;
2508 + color: var( --os-ui-fg-muted, #646970 );
2509 +}
2510 +
2511 +.dm-agents__cast {
2512 + display: grid;
2513 + gap: 16px;
2514 + grid-template-columns: repeat( auto-fill, minmax( 288px, 1fr ) );
2515 + align-content: start;
2516 +}
2517 +
2518 +/* The card reacts like the mockup's: a lift and a brighter edge.
2519 + Transform and border-color only — both cheap, and the same pair the
2520 + mockup transitions. Document styles win over the component's own
2521 + :host rules, which is the sanctioned way to restyle a host. */
2522 +.dm-agents__cast-card,
2523 +.dm-agents__cast-new {
2524 + --os-ui-card-padding: 20px 18px 16px;
2525 + transition: border-color 0.18s ease, transform 0.18s ease;
2526 +}
2527 +
2528 +.dm-agents__cast-card:hover,
2529 +.dm-agents__cast-card:focus-within {
2530 + border-color: var( --os-ui-border-strong, #8c8f94 );
2531 + transform: translateY( -2px );
2532 +}
2533 +
2534 +/* The dashed door, same as the mockup's crew-new card. */
2535 +.dm-agents__cast-new {
2536 + border-style: dashed;
2537 + --os-ui-card-bg: var( --os-ui-surface-subtle, transparent );
2538 +}
2539 +
2540 +/* The crew breathes. Transform only, staggered so five faces do not
2541 + bob in lockstep, and gone entirely under reduced motion. */
2542 +@media ( prefers-reduced-motion: no-preference ) {
2543 + .dm-agents__cast-card .dm-agents__cast-face {
2544 + animation: dm-agents-bob 6s ease-in-out infinite;
2545 + }
2546 + .dm-agents__cast-card:nth-child( 2n ) .dm-agents__cast-face {
2547 + animation-duration: 7.2s;
2548 + animation-delay: -1.4s;
2549 + }
2550 + .dm-agents__cast-card:nth-child( 3n ) .dm-agents__cast-face {
2551 + animation-duration: 6.6s;
2552 + animation-delay: -2.8s;
2553 + }
2554 +}
2555 +
2556 +@keyframes dm-agents-bob {
2557 + 0%,
2558 + 100% {
2559 + transform: translateY( 0 );
2560 + }
2561 + 50% {
2562 + transform: translateY( -4px );
2563 + }
2564 +}
2565 +
2566 +/* The column lives on a wrapper we own, not on the host: the slotted
2567 + children sit inside the card's own container, so a flex rule on the
2568 + host never reaches them and the role badges land wherever the
2569 + description's line count leaves them. */
2570 +.dm-agents__cast-inner {
2571 + display: flex;
2572 + flex-direction: column;
2573 + align-items: center;
2574 + text-align: center;
2575 + gap: 2px;
2576 + height: 100%;
2577 +}
2578 +
2579 +/* The faces are the loud part of this surface, and deliberately so:
2580 + agent identity is the one place the station spends the mesh budget
2581 + on something other than a hero CTA. A cast has to be legible at a
2582 + glance, which is exactly what a flat accent cannot do. */
2583 +.dm-agents__cast-face {
2584 + width: 118px;
2585 + height: 118px;
2586 + margin: -10px 0 6px;
2587 + flex: none;
2588 +}
2589 +
2590 +.dm-agents__cast-name {
2591 + font-size: 17px;
2592 + font-weight: 600;
2593 + color: var( --os-ui-fg, #1d2327 );
2594 +}
2595 +
2596 +/* The voice line, in the instrument register: this is metadata about
2597 + the agent, not prose from it. */
2598 +.dm-agents__cast-vibes {
2599 + font-family: var( --os-ui-font-mono, ui-monospace, monospace );
2600 + font-size: 11.5px;
2601 + color: var( --os-ui-accent-strong, #2271b1 );
2602 +}
2603 +
2604 +.dm-agents__cast-good {
2605 + font-size: 13px;
2606 + color: var( --os-ui-fg-muted, #646970 );
2607 + margin-block: 4px 14px;
2608 + flex: 1;
2609 +}
2610 +
2611 +/* The role pill in the instrument voice: mono, uppercase, no status
2612 + dot — this is a fact about the agent, not a state to monitor. The
2613 + custom properties are the component's own theming hooks; the
2614 + inherited text properties flow into its shadow label. */
2615 +.dm-agents__cast-card os-badge {
2616 + --os-ui-badge-font: 500 11px/1.6 var( --os-ui-font-mono, ui-monospace, monospace );
2617 + --os-ui-badge-dot-size: 0;
2618 + --os-ui-badge-gap: 0;
2619 + --os-ui-badge-padding: 3px 10px;
2620 + text-transform: uppercase;
2621 + letter-spacing: 0.08em;
2622 +}
2623 +
2624 +/* The framework-off bar: the section's status and its one action, on
2625 + one line above the crew it would hire. It is deliberately not an
2626 + `os-empty-state` — that block is centred, icon-led and paragraph-
2627 + shaped, which is exactly the wall of text the cast replaced, and at
2628 + five cards tall it would push the button that undoes the situation
2629 + off the bottom of the window. `flex: none` because `.dm-agents__view`
2630 + is a scrolling flex column and the bar must not absorb the slack. */
2631 +.dm-agents__off-head {
2632 + display: flex;
2633 + align-items: center;
2634 + justify-content: space-between;
2635 + flex-wrap: wrap;
2636 + flex: none;
2637 + gap: 8px 16px;
2638 + padding: 12px 14px;
2639 + border-radius: 10px;
2640 + background: var( --os-ui-surface-elevated, #fff );
2641 + border: 1px solid var( --os-border, rgba( 0, 0, 0, 0.08 ) );
2642 +}
2643 +
2644 +.dm-agents__off-copy {
2645 + min-width: 0;
2646 +}
2647 +
2648 +.dm-agents__off-copy h3 {
2649 + margin: 0;
2650 +}
2651 +
2652 +.dm-agents__off-copy p {
2653 + margin: 2px 0 0;
2654 + font-size: 13px;
2655 + color: var( --os-ui-fg-muted, #646970 );
2656 +}
2657 +
2658 +/* The cast the site would get, drawn while the framework is off.
2659 + Dimmed as a whole rather than desaturated: the five hues ARE the
2660 + argument this state is making, and a greyscale filter would flatten
2661 + the crew into five identical blobs on the way to saying "not yet".
2662 + Opacity says inactive and leaves the faces telling each other apart.
2663 +
2664 + `pointer-events` is belt and braces — the cards are rendered without
2665 + `interactive` and without a click handler, so there is nothing to
2666 + press. It exists so a hover state cannot promise otherwise. */
2667 +.dm-agents__cast--preview {
2668 + opacity: 0.6;
2669 + pointer-events: none;
2670 +}
2671 +
2672 +.dm-agents__cast-new .dm-agents__cast-plus {
2673 + display: grid;
2674 + place-items: center;
2675 + width: 118px;
2676 + height: 118px;
2677 + margin: -10px 0 6px;
2678 + border-radius: 50%;
2679 + border: 1.5px dashed var( --os-ui-border-strong, #8c8f94 );
2680 + font-size: 30px;
2681 + font-weight: 300;
2682 + line-height: 1;
2683 + color: var( --os-ui-fg-muted, #646970 );
2684 +}
2685 +
2686 +/* ---------------------------------------------------------------------
2687 + The wizard
2688 + ------------------------------------------------------------------ */
2689 +
2690 +.dm-agents__wizard {
2691 + display: flex;
2692 + flex-direction: column;
2693 + gap: 10px;
2694 +}
2695 +
2696 +.dm-agents__wiz-head {
2697 + display: flex;
2698 + align-items: center;
2699 + justify-content: space-between;
2700 + gap: 8px 12px;
2701 + flex-wrap: wrap;
2702 +}
2703 +
2704 +.dm-agents__wiz-head h3 {
2705 + margin: 0;
2706 +}
2707 +
2708 +/* The trail wears the instrument voice: mono uppercase labels, 22px
2709 + dots, a thin rule between stations. All of it goes through the
2710 + component's own theming hooks; the host elements live in this light
2711 + DOM, so the per-state overrides below can select them directly. */
2712 +.dm-agents__trail {
2713 + margin-block: 6px 14px;
2714 + --os-ui-steps-gap: 10px;
2715 + --os-ui-step-gap: 7px;
2716 + --os-ui-step-chip-size: 22px;
2717 + --os-ui-step-chip-font-size: 11px;
2718 + --os-ui-step-chip-family: var( --os-ui-font-mono, ui-monospace, monospace );
2719 + --os-ui-step-title-size: 11px;
2720 + --os-ui-step-title-family: var( --os-ui-font-mono, ui-monospace, monospace );
2721 + --os-ui-step-title-transform: uppercase;
2722 + --os-ui-step-title-spacing: 0.08em;
2723 +}
2724 +
2725 +/* A station you have not reached is an outline, not a filled dot: the
2726 + mesh chip is where you ARE, and it only reads that way if it is the
2727 + only one lit. */
2728 +.dm-agents__trail os-step:not( [ done ] ):not( [ current ] ) {
2729 + --os-ui-step-chip-bg: transparent;
2730 + --os-ui-step-chip-border: 1px solid var( --os-ui-border-strong, #8c8f94 );
2731 + --os-ui-step-chip-fg: var( --os-ui-fg-muted, #646970 );
2732 +}
2733 +
2734 +/* Done is quiet: a filled tick on the elevated surface, muted like its
2735 + label. It reads as history, not as a second highlight. */
2736 +.dm-agents__trail os-step[ done ] {
2737 + --os-ui-step-chip-done-bg: var( --os-ui-surface-elevated, #f0f0f1 );
2738 + --os-ui-step-chip-fg: var( --os-ui-fg-muted, #646970 );
2739 +}
2740 +
2741 +.dm-agents__wiz-heading {
2742 + margin: 12px 0 2px;
2743 + font-size: 16px;
2744 + font-weight: 600;
2745 + color: var( --os-ui-fg, #1d2327 );
2746 +}
2747 +
2748 +/* The door. Five complete agents already ship with the plugin, and
2749 + until now the create flow showed them to nobody. */
2750 +.dm-agents__starters {
2751 + display: grid;
2752 + gap: 12px;
2753 + grid-template-columns: repeat( auto-fill, minmax( 148px, 1fr ) );
2754 + margin-block: 8px 16px;
2755 +}
2756 +
2757 +.dm-agents__starter {
2758 + display: flex;
2759 + flex-direction: column;
2760 + align-items: center;
2761 + text-align: center;
2762 + gap: 3px;
2763 + --os-ui-card-padding: 16px 14px;
2764 + --os-ui-card-radius: 10px;
2765 + --os-ui-card-bg: var( --os-ui-surface-subtle, transparent );
2766 + transition: border-color 0.18s ease;
2767 +}
2768 +
2769 +.dm-agents__starter:hover,
2770 +.dm-agents__starter:focus-within {
2771 + border-color: var( --os-ui-border-strong, #8c8f94 );
2772 +}
2773 +
2774 +.dm-agents__starter-face {
2775 + width: 76px;
2776 + height: 76px;
2777 + margin: -8px 0 4px;
2778 + flex: none;
2779 +}
2780 +
2781 +.dm-agents__starter-name {
2782 + font-size: 14px;
2783 + font-weight: 500;
2784 + color: var( --os-ui-fg, #1d2327 );
2785 +}
2786 +
2787 +.dm-agents__starter-vibes {
2788 + font-family: var( --os-ui-font-mono, ui-monospace, monospace );
2789 + font-size: 11.5px;
2790 + color: var( --os-ui-fg-muted, #646970 );
2791 +}
2792 +
2793 +/* Meet: the portrait beside the fields, so the thing being named is
2794 + visible while it is being named. */
2795 +.dm-agents__meet {
2796 + display: grid;
2797 + gap: 20px;
2798 + grid-template-columns: 220px 1fr;
2799 + align-items: start;
2800 +}
2801 +
2802 +/* The character card. Sunken rather than subtle: the portrait is the
2803 + hero of this step, and the mockup floats it on the darkest surface
2804 + so the face's own glow does the framing. */
2805 +.dm-agents__portrait {
2806 + display: flex;
2807 + flex-direction: column;
2808 + align-items: center;
2809 + gap: 10px;
2810 + padding: 20px 14px 14px;
2811 + border: 1px solid var( --os-border, rgba( 0, 0, 0, 0.08 ) );
2812 + border-radius: var( --os-ui-card-radius, 10px );
2813 + background: var( --os-ui-surface-sunken, #f6f7f7 );
2814 +}
2815 +
2816 +.dm-agents__portrait-face {
2817 + width: 176px;
2818 + height: 176px;
2819 + max-width: 100%;
2820 + margin-top: -12px;
2821 +}
2822 +
2823 +/* What this face is, in two words. */
2824 +.dm-agents__portrait-chips {
2825 + display: flex;
2826 + gap: 6px;
2827 + flex-wrap: wrap;
2828 + justify-content: center;
2829 +}
2830 +
2831 +.dm-agents__faces {
2832 + display: grid;
2833 + grid-template-columns: repeat( 6, 1fr );
2834 + gap: 2px;
2835 + width: 100%;
2836 +}
2837 +
2838 +.dm-agents__face-pick {
2839 + display: grid;
2840 + place-items: center;
2841 + padding: 2px;
2842 + border: 1px solid transparent;
2843 + border-radius: 8px;
2844 + background: none;
2845 + cursor: pointer;
2846 +}
2847 +
2848 +.dm-agents__face-pick img {
2849 + width: 100%;
2850 + height: auto;
2851 + display: block;
2852 +}
2853 +
2854 +.dm-agents__face-pick:hover {
2855 + border-color: var( --os-ui-border-strong, #8c8f94 );
2856 +}
2857 +
2858 +.dm-agents__face-pick.is-picked {
2859 + border-color: var( --os-ui-accent, #2271b1 );
2860 +}
2861 +
2862 +.dm-agents__face-pick:focus-visible {
2863 + outline: var( --os-ui-focus-ring, 2px solid #2271b1 );
2864 + outline-offset: 1px;
2865 +}
2866 +
2867 +.dm-agents__meet-fields {
2868 + display: flex;
2869 + flex-direction: column;
2870 + gap: 10px;
2871 + min-width: 0;
2872 +}
2873 +
2874 +/* Launch: one card, the brand's card radius, floating on the darkest
2875 + surface like the portrait it echoes. */
2876 +.dm-agents__summary {
2877 + display: grid;
2878 + grid-template-columns: 106px 1fr;
2879 + gap: 18px;
2880 + align-items: start;
2881 + --os-ui-card-padding: 18px;
2882 + --os-ui-card-radius: 10px;
2883 + --os-ui-card-bg: var( --os-ui-surface-sunken, #f6f7f7 );
2884 +}
2885 +
2886 +.dm-agents__summary-face {
2887 + width: 106px;
2888 + height: 106px;
2889 + flex: none;
2890 +}
2891 +
2892 +.dm-agents__summary-text h4 {
2893 + margin: 0 0 2px;
2894 + font-size: 17px;
2895 +}
2896 +
2897 +.dm-agents__summary-vibes {
2898 + font-family: var( --os-ui-font-mono, ui-monospace, monospace );
2899 + font-size: 11.5px;
2900 + color: var( --os-ui-accent-strong, #2271b1 );
2901 + margin: 0 0 6px;
2902 +}
2903 +
2904 +.dm-agents__summary-desc {
2905 + margin: 0;
2906 + font-size: 13px;
2907 + color: var( --os-ui-fg-muted, #646970 );
2908 +}
2909 +
2910 +.dm-agents__chips {
2911 + display: flex;
2912 + flex-wrap: wrap;
2913 + gap: 6px;
2914 + margin-block-start: 10px;
2915 +}
2916 +
2917 +/* What the agent will actually be told, under the chips. Clamped: a
2918 + summary card quotes the instructions, it does not host them. */
2919 +.dm-agents__summary-instr {
2920 + margin: 10px 0 0;
2921 + font-size: 13px;
2922 + color: var( --os-ui-fg-muted, #646970 );
2923 + display: -webkit-box;
2924 + -webkit-line-clamp: 3;
2925 + -webkit-box-orient: vertical;
2926 + overflow: hidden;
2927 +}
2928 +
2929 +/* Identity chips — role, abilities, silhouette, hue — all wear the
2930 + instrument voice: these are facts about the character, stamped
2931 + rather than said. */
2932 +.dm-agents__chips os-chip,
2933 +.dm-agents__portrait-chips os-chip {
2934 + --os-ui-chip-font-size: 10.5px;
2935 + --os-ui-chip-font-weight: 500;
2936 + --os-ui-chip-bg: transparent;
2937 + --os-ui-chip-fg: var( --os-ui-fg-muted, #646970 );
2938 + --os-ui-chip-border: 1px solid var( --os-border, rgba( 0, 0, 0, 0.12 ) );
2939 + font-family: var( --os-ui-font-mono, ui-monospace, monospace );
2940 + text-transform: uppercase;
2941 + letter-spacing: 0.06em;
2942 +}
2943 +
2944 +.dm-agents__spacer {
2945 + flex: 1;
2946 +}
2947 +
2948 +@media ( max-width: 640px ) {
2949 + .dm-agents__meet,
2950 + .dm-agents__summary {
2951 + grid-template-columns: 1fr;
2952 + }
2953 + .dm-agents__portrait-face {
2954 + width: 128px;
2955 + height: 128px;
2956 + }
2957 +}
2958 +
2959 +/* The way back to the grid. The window's own breadcrumb goes UP to the
2960 + folder, which is a different journey: this one returns to the cast. */
2961 +.dm-agents__back {
2962 + align-self: flex-start;
2963 + margin-block-end: 4px;
1881 2964 }