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