| @@ -1,15 +1,15 @@ | ||
| 1 | 1 | /** |
| 2 | - * Desktop Mode — Files-on-the-Desktop tile + layer styles. | |
| 2 | + * OpenStation — Files-on-the-Desktop tile + layer styles. | |
| 3 | 3 | * |
| 4 | 4 | * The layer is an absolutely-positioned container inside |
| 5 | - * `#desktop-mode-area`; tiles inside use absolute positioning | |
| 5 | + * `#os-area`; tiles inside use absolute positioning | |
| 6 | 6 | * keyed off `(x, y)` coordinates persisted server-side. |
| 7 | 7 | * |
| 8 | - * Tiles are intentionally close to the look of `desktop-mode-icon` | |
| 8 | + * Tiles are intentionally close to the look of `os-icon` | |
| 9 | 9 | * (the plugin-shortcut tiles) so the desktop reads as one |
| 10 | 10 | * coherent surface — but they live in their own class namespace |
| 11 | - * (`desktop-mode-file-tile`) so plugins can theme each rail | |
| 11 | + * (`os-file-tile`) so plugins can theme each rail | |
| 12 | 12 | * independently. |
| 13 | 13 | * |
| 14 | 14 | * @since 0.9.0 |
| 15 | 15 | */ |
| @@ -16,15 +16,15 @@ | ||
| 16 | 16 | |
| 17 | 17 | /* |
| 18 | 18 | * Unified rail (since 0.9.0): plugin shortcuts now ride on the |
| 19 | 19 | * same files layer as folders / posts / etc — they're a |
| 20 | - * `'shortcut'` file type. The legacy `.desktop-mode-icons` DIV | |
| 20 | + * `'shortcut'` file type. The legacy `.os-icons` DIV | |
| 21 | 21 | * still renders for backwards compatibility (existing tests and |
| 22 | 22 | * non-files-active code paths), but when a files layer is |
| 23 | 23 | * mounted as a sibling we hide it so we don't end up with two |
| 24 | 24 | * rails competing for the same wallpaper. |
| 25 | 25 | */ |
| 26 | -#desktop-mode-area:has( > .desktop-mode-files-layer ) > .desktop-mode-icons { | |
| 26 | +#os-area:has( > .os-files-layer ) > .os-icons { | |
| 27 | 27 | display: none; |
| 28 | 28 | } |
| 29 | 29 | |
| 30 | 30 | /* |
| @@ -31,61 +31,22 @@ | ||
| 31 | 31 | * Drop-target highlight — the `data-files-drop-active` attribute |
| 32 | 32 | * is set on the FilesLayer host (desktop area or folder window |
| 33 | 33 | * body) while a shortcut payload is being dragged over it. |
| 34 | 34 | * |
| 35 | - * Marching-ants animation makes the affordance unmissable even | |
| 36 | - * against the busiest wallpaper, and the soft inner glow draws | |
| 37 | - * the eye when the user is "shopping" for a drop target. Both | |
| 38 | - * effects respect prefers-reduced-motion below. | |
| 39 | - * | |
| 40 | - * @since 0.18.0; visuals strengthened in 0.20.0. | |
| 35 | + * A quiet inner glow only. This used to be a dashed, animated | |
| 36 | + * marching-ants frame around the whole wallpaper, and on a full | |
| 37 | + * desktop that read as a large moving grid behind the tile in hand | |
| 38 | + * — loud, and design asked for it to go. The ghost's accept / | |
| 39 | + * reject chip and the per-cell drop preview already say where the | |
| 40 | + * tile will land; the glow just confirms the surface is listening. | |
| 41 | 41 | */ |
| 42 | -@keyframes desktop-mode-drop-marching-ants { | |
| 43 | - to { | |
| 44 | - background-position: 24px 0, -24px 0, 0 24px, 0 -24px; | |
| 45 | - } | |
| 46 | -} | |
| 47 | - | |
| 48 | 42 | [ data-files-drop-active ] { |
| 49 | 43 | position: relative; |
| 50 | - outline: 3px dashed var( --wp-admin-theme-color, #2271b1 ); | |
| 51 | - outline-offset: -8px; | |
| 52 | - background-image: | |
| 53 | - linear-gradient( | |
| 54 | - 90deg, | |
| 55 | - rgba( 34, 113, 177, 0.45 ) 50%, | |
| 56 | - transparent 0 | |
| 57 | - ), | |
| 58 | - linear-gradient( | |
| 59 | - 90deg, | |
| 60 | - rgba( 34, 113, 177, 0.45 ) 50%, | |
| 61 | - transparent 0 | |
| 62 | - ), | |
| 63 | - linear-gradient( | |
| 64 | - 0deg, | |
| 65 | - rgba( 34, 113, 177, 0.45 ) 50%, | |
| 66 | - transparent 0 | |
| 67 | - ), | |
| 68 | - linear-gradient( | |
| 69 | - 0deg, | |
| 70 | - rgba( 34, 113, 177, 0.45 ) 50%, | |
| 71 | - transparent 0 | |
| 72 | - ); | |
| 73 | - background-repeat: repeat-x, repeat-x, repeat-y, repeat-y; | |
| 74 | - background-size: 12px 3px, 12px 3px, 3px 12px, 3px 12px; | |
| 75 | - background-position: 0 6px, 0 calc( 100% - 6px ), 6px 0, calc( 100% - 6px ) 0; | |
| 76 | 44 | box-shadow: inset 0 0 32px 4px rgba( 34, 113, 177, 0.12 ); |
| 77 | - animation: desktop-mode-drop-marching-ants 0.6s linear infinite; | |
| 78 | 45 | transition: box-shadow 0.18s ease-out; |
| 79 | 46 | } |
| 80 | 47 | |
| 81 | -@media ( prefers-reduced-motion: reduce ) { | |
| 82 | - [ data-files-drop-active ] { | |
| 83 | - animation: none; | |
| 84 | - } | |
| 85 | -} | |
| 86 | - | |
| 87 | -.desktop-mode-files-layer { | |
| 48 | +.os-files-layer { | |
| 88 | 49 | position: absolute; |
| 89 | 50 | inset: 0; |
| 90 | 51 | z-index: 0; |
| 91 | 52 | /* |
| @@ -90,9 +51,9 @@ | ||
| 90 | 51 | z-index: 0; |
| 91 | 52 | /* |
| 92 | 53 | * Layer doesn't intercept pointer events itself — tiles and |
| 93 | 54 | * the wallpaper own that. Phase 4's wallpaper context menu |
| 94 | - * binds clicks on the parent `#desktop-mode-area`, which is | |
| 55 | + * binds clicks on the parent `#os-area`, which is | |
| 95 | 56 | * unblocked because of this rule. |
| 96 | 57 | */ |
| 97 | 58 | pointer-events: none; |
| 98 | 59 | } |
| @@ -110,9 +71,9 @@ | ||
| 110 | 71 | * than "this tile." |
| 111 | 72 | * |
| 112 | 73 | * @since 0.20.0 |
| 113 | 74 | */ |
| 114 | -.desktop-mode-files-drop-preview { | |
| 75 | +.os-files-drop-preview { | |
| 115 | 76 | position: absolute; |
| 116 | 77 | top: 0; |
| 117 | 78 | left: 0; |
| 118 | 79 | width: 88px; |
| @@ -120,14 +81,14 @@ | ||
| 120 | 81 | pointer-events: none; |
| 121 | 82 | box-sizing: border-box; |
| 122 | 83 | border-radius: 12px; |
| 123 | 84 | background: var( |
| 124 | - --desktop-mode-drop-preview-bg, | |
| 85 | + --os-drop-preview-bg, | |
| 125 | 86 | rgba( 34, 113, 177, 0.08 ) |
| 126 | 87 | ); |
| 127 | 88 | border: 2px dashed |
| 128 | 89 | var( |
| 129 | - --desktop-mode-drop-preview-border, | |
| 90 | + --os-drop-preview-border, | |
| 130 | 91 | rgba( 34, 113, 177, 0.55 ) |
| 131 | 92 | ); |
| 132 | 93 | transition: transform 90ms ease-out; |
| 133 | 94 | will-change: transform; |
| @@ -138,14 +99,14 @@ | ||
| 138 | 99 | z-index: 0; |
| 139 | 100 | } |
| 140 | 101 | |
| 141 | 102 | @media ( prefers-reduced-motion: reduce ) { |
| 142 | - .desktop-mode-files-drop-preview { | |
| 103 | + .os-files-drop-preview { | |
| 143 | 104 | transition: none; |
| 144 | 105 | } |
| 145 | 106 | } |
| 146 | 107 | |
| 147 | -.desktop-mode-file-tile { | |
| 108 | +.os-file-tile { | |
| 148 | 109 | pointer-events: auto; |
| 149 | 110 | position: absolute; |
| 150 | 111 | display: flex; |
| 151 | 112 | flex-direction: column; |
| @@ -151,17 +112,35 @@ | ||
| 151 | 112 | flex-direction: column; |
| 152 | 113 | align-items: center; |
| 153 | 114 | justify-content: flex-start; |
| 154 | 115 | gap: 6px; |
| 155 | - width: 88px; | |
| 116 | + /* | |
| 117 | + * `box-sizing` is load-bearing, not housekeeping. Without it the | |
| 118 | + * horizontal padding is ADDED to the declared width, so an 88px | |
| 119 | + * tile occupies 96px — which was exactly the desktop's old cell | |
| 120 | + * pitch, and why icons sat edge to edge with no gap at all while | |
| 121 | + * the maths insisted there were 8px between them. | |
| 122 | + * | |
| 123 | + * The tile is the size the grid says it is. Padding lives inside. | |
| 124 | + */ | |
| 125 | + box-sizing: border-box; | |
| 126 | + width: var( --os-tile-w, 88px ); | |
| 127 | + /* | |
| 128 | + * Fixed, not minimum. The tile box IS the selection ring, and a | |
| 129 | + * box that grows with its label gives a row of selected icons a | |
| 130 | + * ragged top edge — one height per label that happened to wrap | |
| 131 | + * to two lines. Every tile occupies its cell; short labels leave | |
| 132 | + * the slack inside the ring, where it reads as padding. | |
| 133 | + */ | |
| 134 | + height: var( --os-tile-h, 104px ); | |
| 156 | 135 | padding: 8px 4px; |
| 157 | 136 | border: 0; |
| 158 | 137 | background: transparent; |
| 159 | - /* Tile foreground driven by `--desktop-mode-tile-fg` so any | |
| 138 | + /* Tile foreground driven by `--os-tile-fg` so any | |
| 160 | 139 | * light-on-dark surface (folder window, My WordPress preview) |
| 161 | 140 | * can retint tiles by overriding the variable in its scope — |
| 162 | 141 | * no per-surface selectors needed here. */ |
| 163 | - color: var( --desktop-mode-tile-fg, var( --desktop-mode-fg, #fff ) ); | |
| 142 | + color: var( --os-tile-fg, var( --os-fg, #fff ) ); | |
| 164 | 143 | cursor: pointer; |
| 165 | 144 | border-radius: 8px; |
| 166 | 145 | transition: background-color 0.15s ease, transform 0.05s linear; |
| 167 | 146 | -webkit-user-select: none; |
| @@ -177,16 +156,16 @@ | ||
| 177 | 156 | * cascade is honest; the animation runs once, leaves the tile |
| 178 | 157 | * at its static `opacity: 1`, and never re-fires from later |
| 179 | 158 | * state changes (drag, hover, drop-target). |
| 180 | 159 | */ |
| 181 | - animation: desktop-mode-file-tile-enter | |
| 182 | - var( --desktop-mode-file-tile-enter-duration, 0.4s ) | |
| 160 | + animation: os-file-tile-enter | |
| 161 | + var( --os-file-tile-enter-duration, 0.4s ) | |
| 183 | 162 | ease-out |
| 184 | - var( --desktop-mode-file-tile-enter-delay, 0s ) | |
| 163 | + var( --os-file-tile-enter-delay, 0s ) | |
| 185 | 164 | backwards; |
| 186 | 165 | } |
| 187 | 166 | |
| 188 | -@keyframes desktop-mode-file-tile-enter { | |
| 167 | +@keyframes os-file-tile-enter { | |
| 189 | 168 | from { |
| 190 | 169 | opacity: 0; |
| 191 | 170 | } |
| 192 | 171 | to { |
| @@ -194,49 +173,49 @@ | ||
| 194 | 173 | } |
| 195 | 174 | } |
| 196 | 175 | |
| 197 | 176 | @media ( prefers-reduced-motion: reduce ) { |
| 198 | - .desktop-mode-file-tile { | |
| 177 | + .os-file-tile { | |
| 199 | 178 | animation: none; |
| 200 | 179 | } |
| 201 | 180 | } |
| 202 | 181 | |
| 203 | -.desktop-mode-file-tile:hover, | |
| 204 | -.desktop-mode-file-tile:focus-visible { | |
| 182 | +.os-file-tile:hover, | |
| 183 | +.os-file-tile:focus-visible { | |
| 205 | 184 | background: var( |
| 206 | - --desktop-mode-tile-hover-bg, | |
| 185 | + --os-tile-hover-bg, | |
| 207 | 186 | rgba( 255, 255, 255, 0.12 ) |
| 208 | 187 | ); |
| 209 | 188 | outline: none; |
| 210 | 189 | } |
| 211 | 190 | |
| 212 | -.desktop-mode-file-tile:focus-visible { | |
| 191 | +.os-file-tile:focus-visible { | |
| 213 | 192 | /* Inset focus ring — outset rings extended past the tile and |
| 214 | 193 | * visually overlapped the colindant icon when the canvas cell |
| 215 | 194 | * pitch is tight (96 px cell, 88 px tile → only 4 px clearance |
| 216 | 195 | * per side). Inset keeps the ring fully inside the tile. */ |
| 217 | 196 | box-shadow: inset 0 0 0 2px |
| 218 | - var( --desktop-mode-tile-focus-ring, var( --wp-admin-theme-color, #2271b1 ) ); | |
| 197 | + var( --os-tile-focus-ring, var( --wp-admin-theme-color, #2271b1 ) ); | |
| 219 | 198 | } |
| 220 | 199 | |
| 221 | -/* Status ribbon sizing inside tiles. The `<wpd-ribbon>` defaults | |
| 200 | +/* Status ribbon sizing inside tiles. The `<os-ribbon>` defaults | |
| 222 | 201 | * are tuned for cards (~90 px clipping window); 88 px-wide tiles |
| 223 | 202 | * need a tighter footprint or the ribbon dominates the icon. We |
| 224 | 203 | * override the component's CSS custom-property theming surface so |
| 225 | 204 | * the ribbon stays a small accent in the corner. Authors who want |
| 226 | 205 | * different sizing can override per-tile or per-section. */ |
| 227 | -.desktop-mode-file-tile > wpd-ribbon { | |
| 228 | - --wpd-ribbon-size: 48px; | |
| 229 | - --wpd-ribbon-banner-width: 72px; | |
| 230 | - --wpd-ribbon-banner-offset: 12px; | |
| 231 | - --wpd-ribbon-banner-pull: -18px; | |
| 232 | - --wpd-ribbon-padding: 1px 0; | |
| 233 | - --wpd-ribbon-font: 700 7px/1.4 var( --desktop-mode-font, system-ui ); | |
| 234 | - --wpd-ribbon-tracking: 0.05em; | |
| 235 | - --wpd-ribbon-shadow: 0 1px 2px rgba( 0, 0, 0, 0.2 ); | |
| 206 | +.os-file-tile > os-ribbon { | |
| 207 | + --os-ui-ribbon-size: 48px; | |
| 208 | + --os-ui-ribbon-banner-width: 72px; | |
| 209 | + --os-ui-ribbon-banner-offset: 12px; | |
| 210 | + --os-ui-ribbon-banner-pull: -18px; | |
| 211 | + --os-ui-ribbon-padding: 1px 0; | |
| 212 | + --os-ui-ribbon-font: 700 7px/1.4 var( --os-font, system-ui ); | |
| 213 | + --os-ui-ribbon-tracking: 0.05em; | |
| 214 | + --os-ui-ribbon-shadow: 0 1px 2px rgba( 0, 0, 0, 0.2 ); | |
| 236 | 215 | } |
| 237 | 216 | |
| 238 | -.desktop-mode-file-tile--dragging { | |
| 217 | +.os-file-tile--dragging { | |
| 239 | 218 | /* The DragManager renders a separate ghost element that follows |
| 240 | 219 | * the pointer; the SOURCE tile stays in place but is dimmed so |
| 241 | 220 | * the user has a stable reference for "this is what I'm |
| 242 | 221 | * dragging." |
| @@ -252,14 +231,14 @@ | ||
| 252 | 231 | * other tile until the user attempts a drag (which silently fails). |
| 253 | 232 | * No upfront visual cue: feedback now happens at the moment of the |
| 254 | 233 | * gesture, not before, per @since 0.9.0 design feedback. |
| 255 | 234 | * |
| 256 | - * Default `cursor: pointer` from the base `.desktop-mode-file-tile` | |
| 235 | + * Default `cursor: pointer` from the base `.os-file-tile` | |
| 257 | 236 | * rule covers click-to-open. Touch interactions stay as |
| 258 | 237 | * `touch-action: auto` so the OS scroll gesture works on top of |
| 259 | 238 | * the tile. |
| 260 | 239 | */ |
| 261 | -.desktop-mode-file-tile--pinned { | |
| 240 | +.os-file-tile--pinned { | |
| 262 | 241 | touch-action: auto; |
| 263 | 242 | } |
| 264 | 243 | |
| 265 | 244 | /* Folder tile is the drop target during a cross-window shortcut |
| @@ -266,9 +245,9 @@ | ||
| 266 | 245 | * drag — the user dragged a post / page / user tile out of My |
| 267 | 246 | * WordPress and is hovering over a folder. Bright outline, soft |
| 268 | 247 | * pulse, and a slight scale so the folder reads unmistakably as |
| 269 | 248 | * "yes, drop here." @since 0.8.0; pulse added 0.20.0. */ |
| 270 | -@keyframes desktop-mode-drop-target-pulse { | |
| 249 | +@keyframes os-drop-target-pulse { | |
| 271 | 250 | 0% { |
| 272 | 251 | box-shadow: |
| 273 | 252 | 0 0 0 0 rgba( 34, 113, 177, 0.5 ), |
| 274 | 253 | inset 0 0 0 2px var( --wp-admin-theme-color, #2271b1 ); |
| @@ -279,20 +258,20 @@ | ||
| 279 | 258 | inset 0 0 0 2px var( --wp-admin-theme-color, #2271b1 ); |
| 280 | 259 | } |
| 281 | 260 | } |
| 282 | 261 | |
| 283 | -.desktop-mode-file-tile--drop-target { | |
| 262 | +.os-file-tile--drop-target { | |
| 284 | 263 | outline: 2px solid var( --wp-admin-theme-color, #2271b1 ); |
| 285 | 264 | outline-offset: -4px; |
| 286 | 265 | background: rgba( 34, 113, 177, 0.2 ); |
| 287 | 266 | transform: scale( 1.08 ); |
| 288 | 267 | z-index: 5; |
| 289 | - animation: desktop-mode-drop-target-pulse 1s ease-out infinite; | |
| 268 | + animation: os-drop-target-pulse 1s ease-out infinite; | |
| 290 | 269 | border-radius: 12px; |
| 291 | 270 | } |
| 292 | 271 | |
| 293 | 272 | @media ( prefers-reduced-motion: reduce ) { |
| 294 | - .desktop-mode-file-tile--drop-target { | |
| 273 | + .os-file-tile--drop-target { | |
| 295 | 274 | animation: none; |
| 296 | 275 | } |
| 297 | 276 | } |
| 298 | 277 | |
| @@ -303,9 +282,9 @@ | ||
| 303 | 282 | * appearance per accept/reject/neutral mode. |
| 304 | 283 | * |
| 305 | 284 | * @since 0.20.0 |
| 306 | 285 | */ |
| 307 | -.desktop-mode-drag-hint { | |
| 286 | +.os-drag-hint { | |
| 308 | 287 | position: fixed; |
| 309 | 288 | top: 0; |
| 310 | 289 | left: 0; |
| 311 | 290 | padding: 6px 10px; |
| @@ -317,9 +296,9 @@ | ||
| 317 | 296 | pointer-events: none; |
| 318 | 297 | user-select: none; |
| 319 | 298 | box-shadow: 0 4px 14px rgba( 0, 0, 0, 0.22 ); |
| 320 | 299 | background: rgba( 30, 30, 30, 0.85 ); |
| 321 | - color: #fff; | |
| 300 | + color: var( --os-ui-fg-on-accent, #fff ); | |
| 322 | 301 | z-index: 2147483647; |
| 323 | 302 | transition: |
| 324 | 303 | background-color 0.12s ease, |
| 325 | 304 | color 0.12s ease, |
| @@ -325,22 +304,22 @@ | ||
| 325 | 304 | color 0.12s ease, |
| 326 | 305 | transform 0.06s ease-out; |
| 327 | 306 | } |
| 328 | 307 | |
| 329 | -.desktop-mode-drag-hint--neutral { | |
| 308 | +.os-drag-hint--neutral { | |
| 330 | 309 | background: rgba( 30, 30, 30, 0.85 ); |
| 331 | - color: #fff; | |
| 310 | + color: var( --os-ui-fg-on-accent, #fff ); | |
| 332 | 311 | } |
| 333 | 312 | |
| 334 | -.desktop-mode-drag-hint--accept { | |
| 313 | +.os-drag-hint--accept { | |
| 335 | 314 | background: #1e8449; |
| 336 | - color: #fff; | |
| 315 | + color: var( --os-ui-fg-on-accent, #fff ); | |
| 337 | 316 | box-shadow: |
| 338 | 317 | 0 0 0 2px rgba( 30, 132, 73, 0.25 ), |
| 339 | 318 | 0 6px 18px rgba( 30, 132, 73, 0.3 ); |
| 340 | 319 | } |
| 341 | 320 | |
| 342 | -.desktop-mode-drag-hint--accept::before { | |
| 321 | +.os-drag-hint--accept::before { | |
| 343 | 322 | /* Tiny checkmark chevron prefix so "Drop here" reads as an |
| 344 | 323 | * actionable affirmation rather than a passive label. The |
| 345 | 324 | * checkmark is a real character (U+2713) so screen readers |
| 346 | 325 | * skip past it via the `aria-hidden` on the host chip. */ |
| @@ -346,17 +325,17 @@ | ||
| 346 | 325 | * skip past it via the `aria-hidden` on the host chip. */ |
| 347 | 326 | content: '✓ '; |
| 348 | 327 | } |
| 349 | 328 | |
| 350 | -.desktop-mode-drag-hint--reject { | |
| 351 | - background: #b32d2e; | |
| 352 | - color: #fff; | |
| 329 | +.os-drag-hint--reject { | |
| 330 | + background: var( --os-ui-danger-hover, #b32d2e ); | |
| 331 | + color: var( --os-ui-fg-on-accent, #fff ); | |
| 353 | 332 | box-shadow: |
| 354 | 333 | 0 0 0 2px rgba( 179, 45, 46, 0.25 ), |
| 355 | 334 | 0 6px 18px rgba( 179, 45, 46, 0.3 ); |
| 356 | 335 | } |
| 357 | 336 | |
| 358 | -.desktop-mode-drag-hint--reject::before { | |
| 337 | +.os-drag-hint--reject::before { | |
| 359 | 338 | content: '⊘ '; |
| 360 | 339 | } |
| 361 | 340 | |
| 362 | 341 | /* |
| @@ -386,13 +365,13 @@ | ||
| 386 | 365 | * something. Tiles in My WordPress grids (and any future content |
| 387 | 366 | * surface) are the entity, not a shortcut to it, so the arrow |
| 388 | 367 | * would just be noise. `[data-placement-id]` is the canonical |
| 389 | 368 | * placement marker. */ |
| 390 | -.desktop-mode-file-tile[ data-placement-id ][ data-file-type="post" ]::after, | |
| 391 | -.desktop-mode-file-tile[ data-placement-id ][ data-file-type="attachment" ]::after, | |
| 392 | -.desktop-mode-file-tile[ data-placement-id ][ data-file-type="comment" ]::after, | |
| 393 | -.desktop-mode-file-tile[ data-placement-id ][ data-file-type="user" ]::after, | |
| 394 | -.desktop-mode-file-tile[ data-placement-id ][ data-file-type="term" ]::after { | |
| 369 | +.os-file-tile[ data-placement-id ][ data-file-type="post" ]::after, | |
| 370 | +.os-file-tile[ data-placement-id ][ data-file-type="attachment" ]::after, | |
| 371 | +.os-file-tile[ data-placement-id ][ data-file-type="comment" ]::after, | |
| 372 | +.os-file-tile[ data-placement-id ][ data-file-type="user" ]::after, | |
| 373 | +.os-file-tile[ data-placement-id ][ data-file-type="term" ]::after { | |
| 395 | 374 | content: "↗"; |
| 396 | 375 | position: absolute; |
| 397 | 376 | right: 14px; |
| 398 | 377 | top: 44px; |
| @@ -398,15 +377,15 @@ | ||
| 398 | 377 | top: 44px; |
| 399 | 378 | width: 18px; |
| 400 | 379 | height: 18px; |
| 401 | 380 | border-radius: 50%; |
| 402 | - background: var( --desktop-mode-tile-shortcut-bg, rgba( 0, 0, 0, 0.65 ) ); | |
| 403 | - color: var( --desktop-mode-tile-shortcut-fg, #fff ); | |
| 381 | + background: var( --os-tile-shortcut-bg, rgba( 0, 0, 0, 0.65 ) ); | |
| 382 | + color: var( --os-tile-shortcut-fg, #fff ); | |
| 404 | 383 | font-size: 11px; |
| 405 | 384 | line-height: 18px; |
| 406 | 385 | text-align: center; |
| 407 | 386 | box-shadow: var( |
| 408 | - --desktop-mode-tile-shortcut-shadow, | |
| 387 | + --os-tile-shortcut-shadow, | |
| 409 | 388 | 0 1px 3px rgba( 0, 0, 0, 0.5 ) |
| 410 | 389 | ); |
| 411 | 390 | pointer-events: none; |
| 412 | 391 | } |
| @@ -417,9 +396,9 @@ | ||
| 417 | 396 | * can right-click → Remove without confusing it for an active |
| 418 | 397 | * file. Phase 6's per-placement permission re-check uses the |
| 419 | 398 | * same affordance for "you can't see this" placeholders. |
| 420 | 399 | */ |
| 421 | -.desktop-mode-file-tile--missing { | |
| 400 | +.os-file-tile--missing { | |
| 422 | 401 | opacity: 0.5; |
| 423 | 402 | } |
| 424 | 403 | |
| 425 | 404 | /** |
| @@ -427,21 +406,21 @@ | ||
| 427 | 406 | * shared the folder containing it) but lacks `can_read` on the |
| 428 | 407 | * underlying entity. Dim the tile, kill the pointer affordance, |
| 429 | 408 | * and overlay a lock badge so the state reads at a glance. |
| 430 | 409 | */ |
| 431 | -.desktop-mode-file-tile--access-gated { | |
| 410 | +.os-file-tile--access-gated { | |
| 432 | 411 | opacity: 0.65; |
| 433 | 412 | cursor: not-allowed; |
| 434 | 413 | } |
| 435 | -.desktop-mode-file-tile--access-gated .desktop-mode-file-tile__visual, | |
| 436 | -.desktop-mode-file-tile--access-gated .desktop-mode-file-tile__preview { | |
| 414 | +.os-file-tile--access-gated .os-file-tile__visual, | |
| 415 | +.os-file-tile--access-gated .os-file-tile__preview { | |
| 437 | 416 | filter: grayscale( 0.6 ); |
| 438 | 417 | } |
| 439 | -.desktop-mode-file-tile--access-gated:hover, | |
| 440 | -.desktop-mode-file-tile--access-gated:focus-visible { | |
| 441 | - background: rgba( 0, 0, 0, 0.06 ); | |
| 418 | +.os-file-tile--access-gated:hover, | |
| 419 | +.os-file-tile--access-gated:focus-visible { | |
| 420 | + background: var( --os-ui-hover, rgba( 0, 0, 0, 0.06 ) ); | |
| 442 | 421 | } |
| 443 | -.desktop-mode-file-tile__lock { | |
| 422 | +.os-file-tile__lock { | |
| 444 | 423 | position: absolute; |
| 445 | 424 | top: 4px; |
| 446 | 425 | inset-inline-end: 4px; |
| 447 | 426 | width: 20px; |
| @@ -446,10 +425,10 @@ | ||
| 446 | 425 | inset-inline-end: 4px; |
| 447 | 426 | width: 20px; |
| 448 | 427 | height: 20px; |
| 449 | 428 | border-radius: 50%; |
| 450 | - background: rgba( 0, 0, 0, 0.7 ); | |
| 451 | - color: #fff; | |
| 429 | + background: var( --os-ui-scrim, rgba( 0, 0, 0, 0.7 ) ); | |
| 430 | + color: var( --os-ui-fg-on-accent, #fff ); | |
| 452 | 431 | font-size: 14px; |
| 453 | 432 | line-height: 20px; |
| 454 | 433 | text-align: center; |
| 455 | 434 | pointer-events: none; |
| @@ -460,9 +439,9 @@ | ||
| 460 | 439 | * Preview-pane empty state when a recipient selects a tile they |
| 461 | 440 | * can't open. Big lock ring + clear copy + secondary hint. Designed |
| 462 | 441 | * to read at a glance in the otherwise-busy preview column. |
| 463 | 442 | */ |
| 464 | -.desktop-mode-files__access-gated { | |
| 443 | +.os-files__access-gated { | |
| 465 | 444 | display: flex; |
| 466 | 445 | flex-direction: column; |
| 467 | 446 | align-items: center; |
| 468 | 447 | justify-content: center; |
| @@ -469,11 +448,11 @@ | ||
| 469 | 448 | gap: 16px; |
| 470 | 449 | padding: 32px 24px; |
| 471 | 450 | min-height: 240px; |
| 472 | 451 | text-align: center; |
| 473 | - color: var( --desktop-mode-fg, inherit ); | |
| 452 | + color: var( --os-fg, inherit ); | |
| 474 | 453 | } |
| 475 | -.desktop-mode-files__access-gated-ring { | |
| 454 | +.os-files__access-gated-ring { | |
| 476 | 455 | display: flex; |
| 477 | 456 | align-items: center; |
| 478 | 457 | justify-content: center; |
| 479 | 458 | width: 96px; |
| @@ -488,9 +467,9 @@ | ||
| 488 | 467 | box-shadow: |
| 489 | 468 | inset 0 1px 0 rgba( 255, 255, 255, 0.08 ), |
| 490 | 469 | 0 8px 24px rgba( 214, 54, 56, 0.18 ); |
| 491 | 470 | } |
| 492 | -.desktop-mode-files__access-gated-glyph { | |
| 471 | +.os-files__access-gated-glyph { | |
| 493 | 472 | font-size: 44px; |
| 494 | 473 | width: 44px; |
| 495 | 474 | height: 44px; |
| 496 | 475 | color: #ff8080; |
| @@ -495,15 +474,15 @@ | ||
| 495 | 474 | height: 44px; |
| 496 | 475 | color: #ff8080; |
| 497 | 476 | filter: drop-shadow( 0 1px 2px rgba( 0, 0, 0, 0.4 ) ); |
| 498 | 477 | } |
| 499 | -.desktop-mode-files__access-gated-title { | |
| 478 | +.os-files__access-gated-title { | |
| 500 | 479 | margin: 0; |
| 501 | 480 | font-size: 17px; |
| 502 | 481 | font-weight: 600; |
| 503 | 482 | letter-spacing: 0.2px; |
| 504 | 483 | } |
| 505 | -.desktop-mode-files__access-gated-sub { | |
| 484 | +.os-files__access-gated-sub { | |
| 506 | 485 | margin: 0; |
| 507 | 486 | font-size: 13px; |
| 508 | 487 | line-height: 1.5; |
| 509 | 488 | max-width: 340px; |
| @@ -508,9 +487,9 @@ | ||
| 508 | 487 | line-height: 1.5; |
| 509 | 488 | max-width: 340px; |
| 510 | 489 | opacity: 0.85; |
| 511 | 490 | } |
| 512 | -.desktop-mode-files__access-gated-hint { | |
| 491 | +.os-files__access-gated-hint { | |
| 513 | 492 | margin: 0; |
| 514 | 493 | font-size: 12px; |
| 515 | 494 | line-height: 1.5; |
| 516 | 495 | max-width: 340px; |
| @@ -516,9 +495,9 @@ | ||
| 516 | 495 | max-width: 340px; |
| 517 | 496 | opacity: 0.6; |
| 518 | 497 | } |
| 519 | 498 | |
| 520 | -.desktop-mode-file-tile__visual { | |
| 499 | +.os-file-tile__visual { | |
| 521 | 500 | display: inline-flex; |
| 522 | 501 | align-items: center; |
| 523 | 502 | justify-content: center; |
| 524 | 503 | width: 48px; |
| @@ -526,9 +505,9 @@ | ||
| 526 | 505 | font-size: 32px; |
| 527 | 506 | line-height: 1; |
| 528 | 507 | } |
| 529 | 508 | |
| 530 | -.desktop-mode-file-tile__icon { | |
| 509 | +.os-file-tile__icon { | |
| 531 | 510 | display: inline-flex; |
| 532 | 511 | align-items: center; |
| 533 | 512 | justify-content: center; |
| 534 | 513 | width: 48px; |
| @@ -536,9 +515,9 @@ | ||
| 536 | 515 | font-size: 32px; |
| 537 | 516 | line-height: 1; |
| 538 | 517 | } |
| 539 | 518 | |
| 540 | -.desktop-mode-file-tile__preview { | |
| 519 | +.os-file-tile__preview { | |
| 541 | 520 | width: 48px; |
| 542 | 521 | height: 48px; |
| 543 | 522 | object-fit: cover; |
| 544 | 523 | border-radius: 4px; |
| @@ -550,24 +529,24 @@ | ||
| 550 | 529 | * and the tile silently refuses to move. The renderer also sets |
| 551 | 530 | * `draggable="false"` on every `<img>` it produces; this CSS rule |
| 552 | 531 | * covers anything injected later (plugin filters, decorators) |
| 553 | 532 | * without having to remember the attribute. */ |
| 554 | -.desktop-mode-file-tile img { | |
| 533 | +.os-file-tile img { | |
| 555 | 534 | -webkit-user-drag: none; |
| 556 | 535 | user-select: none; |
| 557 | 536 | } |
| 558 | 537 | |
| 559 | 538 | /* |
| 560 | - * Wallpaper + tile context menus use `<wpd-context-menu>` and | |
| 561 | - * `<wpd-context-menu-option>` (Phase 4 / 0.9.0). Their host-level | |
| 539 | + * Wallpaper + tile context menus use `<os-context-menu>` and | |
| 540 | + * `<os-context-menu-option>` (Phase 4 / 0.9.0). Their host-level | |
| 562 | 541 | * styles live inside the component shadow DOM — see |
| 563 | - * `src/ui/components/wpd-context-menu/wpd-context-menu.styles.ts`. | |
| 564 | - * No project CSS rules needed here; the legacy `.desktop-mode- | |
| 542 | + * `src/ui/components/os-context-menu/os-context-menu.styles.ts`. | |
| 543 | + * No project CSS rules needed here; the legacy `.os- | |
| 565 | 544 | * wallpaper-menu*` rules were removed when the components landed. |
| 566 | 545 | */ |
| 567 | 546 | |
| 568 | 547 | /* |
| 569 | - * Folder native window — the body of `desktop-mode-folder-<id>` | |
| 548 | + * Folder native window — the body of `os-folder-<id>` | |
| 570 | 549 | * contains a `FilesLayer` rendering that folder's contents. |
| 571 | 550 | * We ensure the body has positioning context so absolutely- |
| 572 | 551 | * positioned tiles inside the layer anchor correctly. |
| 573 | 552 | */ |
| @@ -576,12 +555,12 @@ | ||
| 576 | 555 | min-height: 200px; |
| 577 | 556 | /* Same window background recipe as My WordPress — defaults to |
| 578 | 557 | * the standard window bg (#fff) and themable per-window. */ |
| 579 | 558 | background: var( |
| 580 | - --desktop-mode-folder-window-bg, | |
| 581 | - var( --desktop-mode-window-bg, #fff ) | |
| 559 | + --os-folder-window-bg, | |
| 560 | + var( --os-window-bg, #fff ) | |
| 582 | 561 | ); |
| 583 | - color: var( --desktop-mode-fg-on-light, #1d2327 ); | |
| 562 | + color: var( --os-fg-on-light, var( --os-ui-fg, #1d2327 ) ); | |
| 584 | 563 | display: flex; |
| 585 | 564 | flex-direction: column; |
| 586 | 565 | /* Light-on-dark context: the folder window opens inside a |
| 587 | 566 | * standard window chrome whose body is white-ish. Retint the |
| @@ -587,18 +566,26 @@ | ||
| 587 | 566 | * standard window chrome whose body is white-ish. Retint the |
| 588 | 567 | * tile color tokens here so dashicons + labels read against |
| 589 | 568 | * a light background. Plugins / themes can override these |
| 590 | 569 | * same variables at any scope to retint further. */ |
| 591 | - --desktop-mode-tile-fg: var( --desktop-mode-fg-on-light, #1d2327 ); | |
| 592 | - --desktop-mode-tile-fg-muted: rgba( 0, 0, 0, 0.55 ); | |
| 593 | - --desktop-mode-tile-hover-bg: rgba( 0, 0, 0, 0.06 ); | |
| 570 | + --os-tile-fg: var( --os-fg-on-light, var( --os-ui-fg, #1d2327 ) ); | |
| 571 | + /* Chains through the palette for the same reason as | |
| 572 | + * `--os-tile-fg` beside it: a bare literal here outranks the | |
| 573 | + * palette's own value and pins every tile's secondary line to | |
| 574 | + * near-black, which disappears the moment the surface is dark. | |
| 575 | + * The literal stays as the pre-brand floor. */ | |
| 576 | + --os-tile-fg-muted: var( | |
| 577 | + --os-folder-window-fg-muted, | |
| 578 | + var( --os-ui-fg-muted, rgba( 0, 0, 0, 0.55 ) ) | |
| 579 | + ); | |
| 580 | + --os-tile-hover-bg: rgba( 0, 0, 0, 0.06 ); | |
| 594 | 581 | /* Light-context label rendering — share the same recipe with |
| 595 | 582 | * every other light-bg tile surface (My WordPress, future |
| 596 | 583 | * windows). One set of tokens, no per-surface duplication. */ |
| 597 | - --desktop-mode-tile-label-shadow: none; | |
| 598 | - --desktop-mode-tile-label-weight: 500; | |
| 599 | - --desktop-mode-tile-label-smoothing: antialiased; | |
| 600 | - --desktop-mode-tile-label-color: var( --desktop-mode-fg-on-light, #1d2327 ); | |
| 584 | + --os-tile-label-shadow: none; | |
| 585 | + --os-tile-label-weight: 500; | |
| 586 | + --os-tile-label-smoothing: antialiased; | |
| 587 | + --os-tile-label-color: var( --os-fg-on-light, var( --os-ui-fg, #1d2327 ) ); | |
| 601 | 588 | } |
| 602 | 589 | |
| 603 | 590 | /* Folder window's bottom status bar — paint with the same light- |
| 604 | 591 | * context treatment My WordPress uses (transparent bg, soft border, |
| @@ -604,18 +591,18 @@ | ||
| 604 | 591 | * context treatment My WordPress uses (transparent bg, soft border, |
| 605 | 592 | * muted dark text). Without this, the wallpaper-targeted defaults |
| 606 | 593 | * (`background: rgba(0,0,0,0.18); color: white`) would show as a |
| 607 | 594 | * dark band against the white window bg. */ |
| 608 | -.desktop-mode-folder-window .desktop-mode-folder-status-bar { | |
| 609 | - border-top: 1px solid var( --desktop-mode-border, #dcdcde ); | |
| 595 | +.desktop-mode-folder-window .os-folder-status-bar { | |
| 596 | + border-top: 1px solid var( --os-ui-border, #dcdcde ); | |
| 610 | 597 | background: transparent; |
| 611 | - color: var( --desktop-mode-muted, #50575e ); | |
| 598 | + color: var( --os-ui-fg-muted, #50575e ); | |
| 612 | 599 | } |
| 613 | 600 | |
| 614 | 601 | .desktop-mode-folder-window |
| 615 | - .desktop-mode-folder-status-bar | |
| 616 | - button.desktop-mode-folder-status-bar__segment:hover { | |
| 617 | - background: var( --desktop-mode-hover, rgba( 0, 0, 0, 0.06 ) ); | |
| 602 | + .os-folder-status-bar | |
| 603 | + button.os-folder-status-bar__segment:hover { | |
| 604 | + background: var( --os-hover, var( --os-ui-hover, rgba( 0, 0, 0, 0.06 ) ) ); | |
| 618 | 605 | } |
| 619 | 606 | |
| 620 | 607 | /* Generic breadcrumb header — any surface that grows a navigation |
| 621 | 608 | * stack (folder window, My WordPress folder, future drill-down |
| @@ -625,19 +612,19 @@ | ||
| 625 | 612 | * current segment is bold + non-interactive. |
| 626 | 613 | * |
| 627 | 614 | * @since 0.8.0 |
| 628 | 615 | */ |
| 629 | -.desktop-mode-breadcrumbs { | |
| 616 | +.os-breadcrumbs { | |
| 630 | 617 | display: flex; |
| 631 | 618 | align-items: center; |
| 632 | 619 | gap: 8px; |
| 633 | 620 | padding: 6px 10px; |
| 634 | - border-bottom: 1px solid var( --desktop-mode-border, #dcdcde ); | |
| 621 | + border-bottom: 1px solid var( --os-ui-border, #dcdcde ); | |
| 635 | 622 | background: transparent; |
| 636 | 623 | flex: 0 0 auto; |
| 637 | 624 | } |
| 638 | 625 | |
| 639 | -.desktop-mode-breadcrumbs__back { | |
| 626 | +.os-breadcrumbs__back { | |
| 640 | 627 | display: inline-flex; |
| 641 | 628 | align-items: center; |
| 642 | 629 | justify-content: center; |
| 643 | 630 | width: 26px; |
| @@ -650,20 +637,20 @@ | ||
| 650 | 637 | color: inherit; |
| 651 | 638 | flex: 0 0 auto; |
| 652 | 639 | } |
| 653 | 640 | |
| 654 | -.desktop-mode-breadcrumbs__back:hover:not(:disabled), | |
| 655 | -.desktop-mode-breadcrumbs__back:focus-visible:not(:disabled) { | |
| 656 | - background: var( --desktop-mode-hover, rgba( 0, 0, 0, 0.06 ) ); | |
| 641 | +.os-breadcrumbs__back:hover:not(:disabled), | |
| 642 | +.os-breadcrumbs__back:focus-visible:not(:disabled) { | |
| 643 | + background: var( --os-hover, var( --os-ui-hover, rgba( 0, 0, 0, 0.06 ) ) ); | |
| 657 | 644 | outline: none; |
| 658 | 645 | } |
| 659 | 646 | |
| 660 | -.desktop-mode-breadcrumbs__back:disabled { | |
| 647 | +.os-breadcrumbs__back:disabled { | |
| 661 | 648 | opacity: 0.35; |
| 662 | 649 | cursor: default; |
| 663 | 650 | } |
| 664 | 651 | |
| 665 | -.desktop-mode-breadcrumbs__back .dashicons { | |
| 652 | +.os-breadcrumbs__back .dashicons { | |
| 666 | 653 | font-size: 18px; |
| 667 | 654 | width: 18px; |
| 668 | 655 | height: 18px; |
| 669 | 656 | line-height: 1; |
| @@ -668,9 +655,9 @@ | ||
| 668 | 655 | height: 18px; |
| 669 | 656 | line-height: 1; |
| 670 | 657 | } |
| 671 | 658 | |
| 672 | -.desktop-mode-breadcrumbs__crumbs { | |
| 659 | +.os-breadcrumbs__crumbs { | |
| 673 | 660 | display: flex; |
| 674 | 661 | align-items: center; |
| 675 | 662 | gap: 6px; |
| 676 | 663 | font-size: 13px; |
| @@ -679,12 +666,12 @@ | ||
| 679 | 666 | text-overflow: ellipsis; |
| 680 | 667 | white-space: nowrap; |
| 681 | 668 | } |
| 682 | 669 | |
| 683 | -.desktop-mode-breadcrumbs__crumb { | |
| 670 | +.os-breadcrumbs__crumb { | |
| 684 | 671 | border: 0; |
| 685 | 672 | background: transparent; |
| 686 | - color: var( --desktop-mode-link, #2271b1 ); | |
| 673 | + color: var( --os-link, var( --os-ui-accent, #2271b1 ) ); | |
| 687 | 674 | cursor: pointer; |
| 688 | 675 | padding: 2px 4px; |
| 689 | 676 | border-radius: 4px; |
| 690 | 677 | font: inherit; |
| @@ -689,27 +676,27 @@ | ||
| 689 | 676 | border-radius: 4px; |
| 690 | 677 | font: inherit; |
| 691 | 678 | } |
| 692 | 679 | |
| 693 | -.desktop-mode-breadcrumbs__crumb:hover { | |
| 694 | - background: var( --desktop-mode-hover, rgba( 0, 0, 0, 0.06 ) ); | |
| 680 | +.os-breadcrumbs__crumb:hover { | |
| 681 | + background: var( --os-hover, var( --os-ui-hover, rgba( 0, 0, 0, 0.06 ) ) ); | |
| 695 | 682 | } |
| 696 | 683 | |
| 697 | -.desktop-mode-breadcrumbs__crumb--current { | |
| 698 | - color: var( --desktop-mode-fg-on-light, #1d2327 ); | |
| 684 | +.os-breadcrumbs__crumb--current { | |
| 685 | + color: var( --os-fg-on-light, var( --os-ui-fg, #1d2327 ) ); | |
| 699 | 686 | cursor: default; |
| 700 | 687 | font-weight: 600; |
| 701 | 688 | } |
| 702 | 689 | |
| 703 | -.desktop-mode-breadcrumbs__crumb--current:hover { | |
| 690 | +.os-breadcrumbs__crumb--current:hover { | |
| 704 | 691 | background: transparent; |
| 705 | 692 | } |
| 706 | 693 | |
| 707 | -.desktop-mode-breadcrumbs__sep { | |
| 708 | - color: var( --desktop-mode-muted, #787c82 ); | |
| 694 | +.os-breadcrumbs__sep { | |
| 695 | + color: var( --os-ui-fg-muted, #787c82 ); | |
| 709 | 696 | } |
| 710 | 697 | |
| 711 | -.desktop-mode-folder-window__layer { | |
| 698 | +.os-folder-window__layer { | |
| 712 | 699 | position: relative; |
| 713 | 700 | flex: 1; |
| 714 | 701 | min-height: 0; |
| 715 | 702 | overflow: auto; |
| @@ -719,9 +706,9 @@ | ||
| 719 | 706 | * reflects the currently-selected tile. Same model as the My |
| 720 | 707 | * WordPress two-pane view so the UX is unified. |
| 721 | 708 | * |
| 722 | 709 | * @since 0.8.0 */ |
| 723 | -.desktop-mode-folder-window__split { | |
| 710 | +.os-folder-window__split { | |
| 724 | 711 | display: grid; |
| 725 | 712 | grid-template-columns: minmax( 240px, 60% ) minmax( 0, 1fr ); |
| 726 | 713 | flex: 1 1 auto; |
| 727 | 714 | min-height: 0; |
| @@ -726,36 +713,89 @@ | ||
| 726 | 713 | flex: 1 1 auto; |
| 727 | 714 | min-height: 0; |
| 728 | 715 | } |
| 729 | 716 | |
| 730 | -.desktop-mode-folder-window__preview { | |
| 717 | +.os-folder-window__preview { | |
| 731 | 718 | overflow-y: auto; |
| 732 | 719 | min-width: 0; |
| 733 | - background: var( --desktop-mode-window-bg, #fff ); | |
| 734 | - border-inline-start: 1px solid var( --desktop-mode-border, #dcdcde ); | |
| 735 | - color: var( --desktop-mode-fg-on-light, #1d2327 ); | |
| 720 | + background: var( --os-window-bg, #fff ); | |
| 721 | + border-inline-start: 1px solid var( --os-ui-border, #dcdcde ); | |
| 722 | + color: var( --os-fg-on-light, var( --os-ui-fg, #1d2327 ) ); | |
| 736 | 723 | } |
| 737 | 724 | |
| 738 | -/* Selected file tile — light-blue accent on the wallpaper, soft | |
| 739 | - * accent inside light-context windows. Variable-driven so plugins | |
| 740 | - * can retune. */ | |
| 741 | -.desktop-mode-file-tile--selected, | |
| 742 | -.desktop-mode-file-tile--selected:hover { | |
| 725 | +/* Selected file tile — a fill, and an inset accent ring whose width | |
| 726 | + * the palette decides (0 on OpenStation's, which lifts the tile with | |
| 727 | + * the fill alone; 1px on Legacy). Variable-driven so plugins can | |
| 728 | + * retune. */ | |
| 729 | +.os-file-tile--selected, | |
| 730 | +.os-file-tile--selected:hover { | |
| 743 | 731 | background: var( |
| 744 | - --desktop-mode-tile-selected-bg, | |
| 732 | + --os-tile-selected-bg, | |
| 745 | 733 | rgba( 34, 113, 177, 0.18 ) |
| 746 | 734 | ); |
| 747 | - box-shadow: inset 0 0 0 1px | |
| 748 | - var( --desktop-mode-tile-focus-ring, var( --wp-admin-theme-color, #2271b1 ) ); | |
| 735 | + box-shadow: inset 0 0 0 var( --os-tile-selected-ring-width, 1px ) | |
| 736 | + var( --os-tile-focus-ring, var( --wp-admin-theme-color, #2271b1 ) ); | |
| 749 | 737 | } |
| 750 | 738 | |
| 751 | 739 | /* Inside a folder window the selected highlight should read on |
| 752 | 740 | * white. */ |
| 753 | 741 | .desktop-mode-folder-window { |
| 754 | - --desktop-mode-tile-selected-bg: rgba( 34, 113, 177, 0.12 ); | |
| 742 | + --os-tile-selected-bg: rgba( 34, 113, 177, 0.12 ); | |
| 755 | 743 | } |
| 756 | 744 | |
| 757 | -.desktop-mode-folder-status-bar { | |
| 745 | +/* Type breakdown under a multi-selection's count in a folder | |
| 746 | + * window's preview pane. The count is the headline; this is the | |
| 747 | + * detail that tells you which actions the menu will offer. */ | |
| 748 | +.os-files-preview__selection-breakdown { | |
| 749 | + font-size: 12px; | |
| 750 | + opacity: 0.75; | |
| 751 | +} | |
| 752 | + | |
| 753 | +/* While a rubber band is live, nothing in the shell is selectable. | |
| 754 | + * | |
| 755 | + * The band starts on bare canvas, which — unlike a tile — IS | |
| 756 | + * selectable, so the browser begins its own text selection on the | |
| 757 | + * same press and keeps extending it as the pointer travels. Inside | |
| 758 | + * the canvas that stays invisible; drag out over another window and | |
| 759 | + * it starts highlighting that window's text in blue, mid-gesture. | |
| 760 | + * | |
| 761 | + * The controller also refuses `selectstart` outright while the band | |
| 762 | + * is up. This rule is the second half: it covers anything already | |
| 763 | + * selectable that the event route misses. */ | |
| 764 | +body[ data-os-marquee ] { | |
| 765 | + -webkit-user-select: none; | |
| 766 | + user-select: none; | |
| 767 | +} | |
| 768 | + | |
| 769 | +/* Marquee (rubber-band) selection box. Painted by the shared | |
| 770 | + * selection controller on any canvas that opts into it — the | |
| 771 | + * wallpaper, folder windows, every My WordPress list — so this one | |
| 772 | + * declaration dresses all of them. | |
| 773 | + * | |
| 774 | + * `pointer-events: none` is load-bearing: the box tracks under the | |
| 775 | + * cursor for the whole gesture, and without it every hit-test | |
| 776 | + * (drop targets, the controller's own tile lookup) would land on | |
| 777 | + * the box instead of what's beneath it. */ | |
| 778 | +.os-selection-marquee { | |
| 779 | + position: absolute; | |
| 780 | + z-index: 5; | |
| 781 | + pointer-events: none; | |
| 782 | + border: 1px solid | |
| 783 | + var( --os-tile-focus-ring, var( --wp-admin-theme-color, #2271b1 ) ); | |
| 784 | + border-radius: 2px; | |
| 785 | + /* A WASH, not a fill — the whole point of a rubber band is that | |
| 786 | + * you can see what it is about to catch. `--os-ui-accent-dim` is a | |
| 787 | + * solid hex (Pulse, one step back), so reaching for it directly | |
| 788 | + * paints an opaque rectangle over the icons; `--os-ui-accent-soft` | |
| 789 | + * is that same colour already taken down to a 14% wash, which is | |
| 790 | + * what every other ambient accent surface in the shell uses. */ | |
| 791 | + background: var( | |
| 792 | + --os-selection-marquee-bg, | |
| 793 | + var( --os-ui-accent-soft, rgba( 34, 113, 177, 0.14 ) ) | |
| 794 | + ); | |
| 795 | +} | |
| 796 | + | |
| 797 | +.os-folder-status-bar { | |
| 758 | 798 | display: flex; |
| 759 | 799 | justify-content: space-between; |
| 760 | 800 | align-items: center; |
| 761 | 801 | gap: 12px; |
| @@ -760,21 +800,21 @@ | ||
| 760 | 800 | align-items: center; |
| 761 | 801 | gap: 12px; |
| 762 | 802 | padding: 6px 12px; |
| 763 | 803 | border-top: 1px solid rgba( 255, 255, 255, 0.08 ); |
| 764 | - background: rgba( 0, 0, 0, 0.18 ); | |
| 765 | - color: var( --desktop-mode-fg-muted, rgba( 255, 255, 255, 0.7 ) ); | |
| 804 | + background: var( --os-ui-scrim, rgba( 0, 0, 0, 0.18 ) ); | |
| 805 | + color: var( --os-fg-muted, rgba( 255, 255, 255, 0.7 ) ); | |
| 766 | 806 | font-size: 12px; |
| 767 | 807 | flex-shrink: 0; |
| 768 | 808 | } |
| 769 | 809 | |
| 770 | -.desktop-mode-folder-status-bar__cluster { | |
| 810 | +.os-folder-status-bar__cluster { | |
| 771 | 811 | display: flex; |
| 772 | 812 | align-items: center; |
| 773 | 813 | gap: 12px; |
| 774 | 814 | } |
| 775 | 815 | |
| 776 | -.desktop-mode-folder-status-bar__segment { | |
| 816 | +.os-folder-status-bar__segment { | |
| 777 | 817 | display: inline-flex; |
| 778 | 818 | align-items: center; |
| 779 | 819 | gap: 4px; |
| 780 | 820 | padding: 0; |
| @@ -783,78 +823,100 @@ | ||
| 783 | 823 | color: inherit; |
| 784 | 824 | font: inherit; |
| 785 | 825 | } |
| 786 | 826 | |
| 787 | -button.desktop-mode-folder-status-bar__segment { | |
| 827 | +button.os-folder-status-bar__segment { | |
| 788 | 828 | cursor: pointer; |
| 789 | 829 | border-radius: 4px; |
| 790 | 830 | padding: 2px 6px; |
| 791 | 831 | } |
| 792 | 832 | |
| 793 | -button.desktop-mode-folder-status-bar__segment:hover { | |
| 833 | +button.os-folder-status-bar__segment:hover { | |
| 794 | 834 | background: rgba( 255, 255, 255, 0.1 ); |
| 795 | 835 | } |
| 796 | 836 | |
| 797 | -.desktop-mode-folder-status-bar__icon { | |
| 837 | +.os-folder-status-bar__icon { | |
| 798 | 838 | font-size: 14px; |
| 799 | 839 | } |
| 800 | 840 | |
| 801 | 841 | /* |
| 802 | 842 | * File Associations OS Settings tab (Phase 5). One row per file |
| 803 | - * type: label on the left, a `<wpd-select>` of compatible | |
| 843 | + * type: label on the left, a `<os-select>` of compatible | |
| 804 | 844 | * openers on the right. Color tokens use the OS-Settings-canonical |
| 805 | - * `--wpd-text-muted` so the tab inherits theme colors instead of | |
| 845 | + * `--os-ui-fg-muted` so the tab inherits theme colors instead of | |
| 806 | 846 | * falling back to white-on-light invisibility. |
| 807 | 847 | */ |
| 808 | -.desktop-mode-file-associations__intro { | |
| 848 | +.os-file-associations__intro { | |
| 809 | 849 | display: block; |
| 810 | 850 | margin: 0 0 16px; |
| 811 | - color: var( --wpd-text-muted, #50575e ); | |
| 851 | + color: var( --os-ui-fg-muted, #50575e ); | |
| 812 | 852 | font-size: 13px; |
| 813 | 853 | line-height: 1.5; |
| 814 | 854 | } |
| 815 | 855 | |
| 816 | -.desktop-mode-file-associations__list { | |
| 856 | +.os-file-associations__list { | |
| 817 | 857 | display: flex; |
| 818 | 858 | flex-direction: column; |
| 819 | 859 | gap: 8px; |
| 820 | 860 | } |
| 821 | 861 | |
| 822 | -.desktop-mode-file-associations__row { | |
| 862 | +.os-file-associations__row { | |
| 823 | 863 | display: flex; |
| 824 | 864 | align-items: center; |
| 825 | 865 | justify-content: space-between; |
| 826 | 866 | gap: 16px; |
| 827 | 867 | padding: 8px 12px; |
| 828 | - background: rgba( 0, 0, 0, 0.04 ); | |
| 868 | + background: var( --os-ui-hover, rgba( 0, 0, 0, 0.04 ) ); | |
| 829 | 869 | border-radius: 6px; |
| 830 | 870 | } |
| 831 | 871 | |
| 832 | -.desktop-mode-file-associations__label { | |
| 872 | +.os-file-associations__label { | |
| 833 | 873 | font-weight: 500; |
| 834 | 874 | flex: 1; |
| 835 | 875 | } |
| 836 | 876 | |
| 837 | -.desktop-mode-file-associations__select { | |
| 877 | +.os-file-associations__select { | |
| 838 | 878 | min-width: 220px; |
| 839 | 879 | } |
| 840 | 880 | |
| 841 | -.desktop-mode-file-associations__none, | |
| 842 | -.desktop-mode-file-associations__empty { | |
| 843 | - color: var( --wpd-text-muted, #50575e ); | |
| 881 | +.os-file-associations__none, | |
| 882 | +.os-file-associations__empty { | |
| 883 | + color: var( --os-ui-fg-muted, #50575e ); | |
| 844 | 884 | font-size: 12px; |
| 845 | 885 | } |
| 846 | 886 | |
| 847 | 887 | /* |
| 848 | - * "New folder" inline dialog. Centered modal with a focused | |
| 849 | - * input — replaces the placeholder window.prompt. Plain HTML | |
| 850 | - * controls so it works as a building block before richer | |
| 851 | - * dialog primitives land. | |
| 888 | + * The shell's two built-in modals — "New folder" / "Rename", and the | |
| 889 | + * web-link dialog, which reuses this class set for its surface. Both | |
| 890 | + * are light-DOM overlays that slot `<os-text-field>` + | |
| 891 | + * `<os-button>` for their controls. | |
| 892 | + * | |
| 893 | + * The surface reads the same `--os-ui-modal-*` family that | |
| 894 | + * `<os-modal>` and `<os-confirm-dialog>` do, so the three look like | |
| 895 | + * one dialog system and answer to a desktop theme together. Two | |
| 896 | + * things it must NOT do, both of which it used to: | |
| 897 | + * | |
| 898 | + * - Paint from `--os-bg`. That is the WALLPAPER token: the desk | |
| 899 | + * default is a gradient and the wallpaper layer overwrites it | |
| 900 | + * with whatever artwork is active. A dialog is a surface, not a | |
| 901 | + * desk. Same note as `os-modal.styles.ts`. | |
| 902 | + * - Style raw form controls. Core's `forms.css` reaches every | |
| 903 | + * `<input>` in the parent shell through `input[type="text"]` — | |
| 904 | + * (0,1,1), which outranks a single class of ours — so a plain | |
| 905 | + * input rendered as a white core-chrome box on this dark | |
| 906 | + * surface no matter what we declared. The controls live in | |
| 907 | + * shadow DOM now, where that sheet cannot follow. | |
| 852 | 908 | */ |
| 853 | -.desktop-mode-create-folder-dialog__overlay { | |
| 909 | +.os-create-folder-dialog__overlay { | |
| 854 | 910 | position: fixed; |
| 855 | 911 | inset: 0; |
| 856 | - background: rgba( 0, 0, 0, 0.45 ); | |
| 912 | + background: var( --os-ui-scrim, rgba( 0, 0, 0, 0.45 ) ); | |
| 913 | + /* Desktop-theme texture slot: unset resolves to none. Mirrors | |
| 914 | + the scrim treatment in os-modal. */ | |
| 915 | + background-image: var( --os-ui-scrim-image, none ); | |
| 916 | + background-repeat: var( --os-ui-scrim-image-repeat, repeat ); | |
| 917 | + background-size: var( --os-ui-scrim-image-size, auto ); | |
| 918 | + background-position: var( --os-ui-scrim-image-position, center ); | |
| 857 | 919 | backdrop-filter: blur( 2px ); |
| 858 | 920 | display: flex; |
| 859 | 921 | align-items: center; |
| 860 | 922 | justify-content: center; |
| @@ -860,13 +922,42 @@ | ||
| 860 | 922 | justify-content: center; |
| 861 | 923 | z-index: 10000; |
| 862 | 924 | } |
| 863 | 925 | |
| 864 | -.desktop-mode-create-folder-dialog { | |
| 926 | +.os-create-folder-dialog { | |
| 927 | + /* | |
| 928 | + * Re-point the shared control tokens for a dark dialog surface, | |
| 929 | + * exactly as `<os-modal>` does on its host. The slotted | |
| 930 | + * `<os-text-field>` / `<os-button>` inherit these across the | |
| 931 | + * shadow boundary, so the field resolves a dark input with light | |
| 932 | + * ink instead of the light-admin defaults (`--os-window-bg` is | |
| 933 | + * `#fff` in an unthemed shell, which under a light `--os-ui-fg` | |
| 934 | + * is the invisible-value trap the modal styles call out). | |
| 935 | + * | |
| 936 | + * Each reads a palette-owned `--os-ui-modal-*` name first, so a | |
| 937 | + * desktop theme can still reach every one of them; the literals | |
| 938 | + * are only the floor for a shell whose stylesheet never loaded. | |
| 939 | + */ | |
| 940 | + --os-ui-fg: var( --os-ui-modal-text, #f0f0f1 ); | |
| 941 | + --os-ui-fg-muted: var( --os-ui-modal-text-muted, #a7aaad ); | |
| 942 | + --os-ui-border: var( --os-ui-modal-border, rgba( 255, 255, 255, 0.25 ) ); | |
| 943 | + --os-window-bg: var( --os-ui-modal-field-bg, #2c3338 ); | |
| 944 | + --os-ui-button-bg-hover: var( | |
| 945 | + --os-ui-modal-button-bg-hover, | |
| 946 | + rgba( 255, 255, 255, 0.08 ) | |
| 947 | + ); | |
| 948 | + | |
| 865 | 949 | width: min( 420px, 92vw ); |
| 866 | - background: var( --desktop-mode-bg, #1d2327 ); | |
| 867 | - color: var( --desktop-mode-fg, #fff ); | |
| 868 | - border: 1px solid rgba( 255, 255, 255, 0.08 ); | |
| 950 | + /* Longhand, and a literal fallback: the shorthand would reset the | |
| 951 | + texture slot below, and a gradient is invalid as a | |
| 952 | + background-color — it would leave the dialog transparent. */ | |
| 953 | + background-color: var( --os-ui-modal-bg, #1d2327 ); | |
| 954 | + background-image: var( --os-ui-dialog-bg-image, none ); | |
| 955 | + background-repeat: var( --os-ui-dialog-bg-image-repeat, repeat ); | |
| 956 | + background-size: var( --os-ui-dialog-bg-image-size, auto ); | |
| 957 | + background-position: var( --os-ui-dialog-bg-image-position, center ); | |
| 958 | + color: var( --os-ui-modal-fg, var( --os-fg, #fff ) ); | |
| 959 | + border: 1px solid var( --os-ui-border, rgba( 255, 255, 255, 0.08 ) ); | |
| 869 | 960 | border-radius: 10px; |
| 870 | 961 | box-shadow: 0 20px 50px rgba( 0, 0, 0, 0.6 ); |
| 871 | 962 | padding: 20px 22px 18px; |
| 872 | 963 | display: flex; |
| @@ -873,43 +964,29 @@ | ||
| 873 | 964 | flex-direction: column; |
| 874 | 965 | gap: 10px; |
| 875 | 966 | } |
| 876 | 967 | |
| 877 | -.desktop-mode-create-folder-dialog__title { | |
| 968 | +.os-create-folder-dialog__title { | |
| 878 | 969 | margin: 0 0 4px; |
| 879 | 970 | font-size: 16px; |
| 880 | 971 | font-weight: 600; |
| 972 | + color: var( --os-ui-fg, #f0f0f1 ); | |
| 881 | 973 | } |
| 882 | 974 | |
| 883 | -.desktop-mode-create-folder-dialog__label { | |
| 975 | +.os-url-dialog__description { | |
| 976 | + margin: 0 0 4px; | |
| 884 | 977 | font-size: 12px; |
| 885 | - color: var( --desktop-mode-fg-muted, rgba( 255, 255, 255, 0.7 ) ); | |
| 978 | + line-height: 1.5; | |
| 979 | + color: var( --os-ui-fg-muted, #a7aaad ); | |
| 886 | 980 | } |
| 887 | 981 | |
| 888 | -.desktop-mode-create-folder-dialog__input { | |
| 889 | - width: 100%; | |
| 890 | - padding: 8px 10px; | |
| 891 | - background: rgba( 255, 255, 255, 0.06 ); | |
| 892 | - color: inherit; | |
| 893 | - border: 1px solid rgba( 255, 255, 255, 0.16 ); | |
| 894 | - border-radius: 6px; | |
| 895 | - font-size: 14px; | |
| 896 | - outline: none; | |
| 897 | - box-sizing: border-box; | |
| 898 | -} | |
| 899 | - | |
| 900 | -.desktop-mode-create-folder-dialog__input:focus { | |
| 901 | - border-color: var( --wp-admin-theme-color, #2271b1 ); | |
| 902 | - box-shadow: 0 0 0 2px rgba( 34, 113, 177, 0.4 ); | |
| 903 | -} | |
| 904 | - | |
| 905 | -.desktop-mode-create-folder-dialog__error { | |
| 982 | +.os-create-folder-dialog__error { | |
| 906 | 983 | margin: 0; |
| 907 | - color: #ff8a8a; | |
| 984 | + color: var( --os-ui-danger-hover, #ff8a8a ); | |
| 908 | 985 | font-size: 12px; |
| 909 | 986 | } |
| 910 | 987 | |
| 911 | -.desktop-mode-create-folder-dialog__actions { | |
| 988 | +.os-create-folder-dialog__actions { | |
| 912 | 989 | display: flex; |
| 913 | 990 | justify-content: flex-end; |
| 914 | 991 | gap: 8px; |
| 915 | 992 | margin-top: 6px; |
| @@ -914,55 +991,29 @@ | ||
| 914 | 991 | gap: 8px; |
| 915 | 992 | margin-top: 6px; |
| 916 | 993 | } |
| 917 | 994 | |
| 918 | -.desktop-mode-create-folder-dialog__btn { | |
| 919 | - border: 0; | |
| 920 | - border-radius: 6px; | |
| 921 | - padding: 8px 14px; | |
| 922 | - font-size: 13px; | |
| 923 | - cursor: pointer; | |
| 924 | - font-weight: 500; | |
| 925 | -} | |
| 926 | - | |
| 927 | -.desktop-mode-create-folder-dialog__btn--secondary { | |
| 928 | - background: rgba( 255, 255, 255, 0.08 ); | |
| 929 | - color: inherit; | |
| 930 | -} | |
| 931 | - | |
| 932 | -.desktop-mode-create-folder-dialog__btn--secondary:hover { | |
| 933 | - background: rgba( 255, 255, 255, 0.14 ); | |
| 934 | -} | |
| 935 | - | |
| 936 | -.desktop-mode-create-folder-dialog__btn--primary { | |
| 937 | - background: var( --wp-admin-theme-color, #2271b1 ); | |
| 938 | - color: #fff; | |
| 939 | -} | |
| 940 | - | |
| 941 | -.desktop-mode-create-folder-dialog__btn--primary:hover { | |
| 942 | - filter: brightness( 1.08 ); | |
| 943 | -} | |
| 944 | - | |
| 945 | -.desktop-mode-create-folder-dialog__btn:disabled { | |
| 946 | - opacity: 0.55; | |
| 947 | - cursor: not-allowed; | |
| 948 | -} | |
| 949 | - | |
| 950 | -.desktop-mode-create-folder-dialog--busy .desktop-mode-create-folder-dialog__input { | |
| 995 | +/* The busy state dims the whole form area rather than the input | |
| 996 | + alone — the buttons carry their own disabled treatment from | |
| 997 | + os-button, and dimming one control of three read as a glitch. */ | |
| 998 | +.os-create-folder-dialog--busy .os-create-folder-dialog__field { | |
| 951 | 999 | opacity: 0.7; |
| 952 | 1000 | } |
| 953 | 1001 | |
| 954 | 1002 | /* |
| 955 | 1003 | * Single label rule for every tile, regardless of host surface. |
| 956 | - * Visual properties read from `--desktop-mode-tile-label-*` | |
| 1004 | + * Visual properties read from `--os-tile-label-*` | |
| 957 | 1005 | * tokens — defined in `variables.css` for the dark wallpaper and |
| 958 | 1006 | * rebound by any light-context scope (folder window, My |
| 959 | 1007 | * WordPress, …) so all surfaces share one source of truth. |
| 960 | 1008 | */ |
| 961 | -.desktop-mode-file-tile__label { | |
| 1009 | +.os-file-tile__label { | |
| 962 | 1010 | font-size: 12px; |
| 963 | 1011 | line-height: 1.2; |
| 964 | - max-width: 84px; | |
| 1012 | + /* Follows the tile rather than restating its width, so a section | |
| 1013 | + * that re-points `--os-tile-w` (image-led sections do) gets a | |
| 1014 | + * label that grows with the tile instead of staying narrow. */ | |
| 1015 | + max-width: calc( var( --os-tile-w, 88px ) - 4px ); | |
| 965 | 1016 | text-align: center; |
| 966 | 1017 | overflow: hidden; |
| 967 | 1018 | text-overflow: ellipsis; |
| 968 | 1019 | display: -webkit-box; |
| @@ -967,12 +1018,12 @@ | ||
| 967 | 1018 | text-overflow: ellipsis; |
| 968 | 1019 | display: -webkit-box; |
| 969 | 1020 | -webkit-line-clamp: 2; |
| 970 | 1021 | -webkit-box-orient: vertical; |
| 971 | - color: var( --desktop-mode-tile-label-color, var( --desktop-mode-tile-fg, #fff ) ); | |
| 972 | - font-weight: var( --desktop-mode-tile-label-weight, 400 ); | |
| 973 | - text-shadow: var( --desktop-mode-tile-label-shadow, 0 1px 2px rgba( 0, 0, 0, 0.5 ) ); | |
| 974 | - -webkit-font-smoothing: var( --desktop-mode-tile-label-smoothing, auto ); | |
| 1022 | + color: var( --os-tile-label-color, var( --os-tile-fg, #fff ) ); | |
| 1023 | + font-weight: var( --os-tile-label-weight, 400 ); | |
| 1024 | + text-shadow: var( --os-tile-label-shadow, 0 1px 2px rgba( 0, 0, 0, 0.5 ) ); | |
| 1025 | + -webkit-font-smoothing: var( --os-tile-label-smoothing, auto ); | |
| 975 | 1026 | -moz-osx-font-smoothing: grayscale; |
| 976 | 1027 | } |
| 977 | 1028 | |
| 978 | 1029 | /* |
| @@ -987,9 +1038,9 @@ | ||
| 987 | 1038 | * accepting target, `no-drop` over rejecting (or no) target. |
| 988 | 1039 | * |
| 989 | 1040 | * @since 0.18.0 |
| 990 | 1041 | */ |
| 991 | -.desktop-mode-drag-ghost { | |
| 1042 | +.os-drag-ghost { | |
| 992 | 1043 | box-shadow: 0 6px 24px rgba( 0, 0, 0, 0.45 ); |
| 993 | 1044 | border-radius: 6px; |
| 994 | 1045 | opacity: 0.95; |
| 995 | 1046 | transition: none; |
| @@ -994,35 +1045,94 @@ | ||
| 994 | 1045 | opacity: 0.95; |
| 995 | 1046 | transition: none; |
| 996 | 1047 | } |
| 997 | 1048 | |
| 998 | -.desktop-mode-drag-ghost--accept { | |
| 1049 | +.os-drag-ghost--accept { | |
| 999 | 1050 | cursor: copy; |
| 1000 | 1051 | } |
| 1001 | 1052 | |
| 1002 | -.desktop-mode-drag-ghost--reject { | |
| 1053 | +.os-drag-ghost--reject { | |
| 1003 | 1054 | cursor: no-drop; |
| 1004 | 1055 | } |
| 1005 | 1056 | |
| 1057 | +/* Multi-item drag ghost: the grabbed tile, with the rest of the set | |
| 1058 | + * implied by two offset cards behind it and stated by a count badge. | |
| 1059 | + * The stack is drawn with pseudo-elements rather than real clones — | |
| 1060 | + * three cloned tiles cost three subtree copies per lift, and only | |
| 1061 | + * the top one is ever legible. */ | |
| 1062 | +.os-drag-stack { | |
| 1063 | + /* The drag manager overwrites this with `position: fixed` when it | |
| 1064 | + * mounts the ghost. It stays declared so the stack still composes | |
| 1065 | + * correctly if the helper is used outside a live drag — both | |
| 1066 | + * values establish the containing block the cards and the badge | |
| 1067 | + * are placed against. */ | |
| 1068 | + position: relative; | |
| 1069 | +} | |
| 1070 | + | |
| 1071 | +.os-drag-stack::before, | |
| 1072 | +.os-drag-stack::after { | |
| 1073 | + content: ''; | |
| 1074 | + position: absolute; | |
| 1075 | + inset: 0; | |
| 1076 | + z-index: -1; | |
| 1077 | + border-radius: 6px; | |
| 1078 | + background: var( --os-ui-surface, rgba( 30, 30, 40, 0.9 ) ); | |
| 1079 | + box-shadow: 0 4px 14px rgba( 0, 0, 0, 0.35 ); | |
| 1080 | +} | |
| 1081 | + | |
| 1082 | +.os-drag-stack::before { | |
| 1083 | + transform: translate( 6px, 6px ); | |
| 1084 | + opacity: 0.7; | |
| 1085 | +} | |
| 1086 | + | |
| 1087 | +.os-drag-stack::after { | |
| 1088 | + transform: translate( 12px, 12px ); | |
| 1089 | + opacity: 0.45; | |
| 1090 | +} | |
| 1091 | + | |
| 1092 | +.os-drag-stack__count { | |
| 1093 | + position: absolute; | |
| 1094 | + inset-block-start: -8px; | |
| 1095 | + inset-inline-end: -8px; | |
| 1096 | + z-index: 1; | |
| 1097 | + min-width: 20px; | |
| 1098 | + height: 20px; | |
| 1099 | + padding: 0 6px; | |
| 1100 | + box-sizing: border-box; | |
| 1101 | + display: flex; | |
| 1102 | + align-items: center; | |
| 1103 | + justify-content: center; | |
| 1104 | + border-radius: 10px; | |
| 1105 | + background: var( | |
| 1106 | + --os-ui-accent, | |
| 1107 | + var( --wp-admin-theme-color, #2271b1 ) | |
| 1108 | + ); | |
| 1109 | + color: #fff; | |
| 1110 | + font-size: 11px; | |
| 1111 | + font-weight: 600; | |
| 1112 | + line-height: 1; | |
| 1113 | + box-shadow: 0 2px 8px rgba( 0, 0, 0, 0.4 ); | |
| 1114 | +} | |
| 1115 | + | |
| 1006 | 1116 | /* ============================================================ * |
| 1007 | 1117 | * Upload progress HUD (since 0.31.0) |
| 1008 | 1118 | * |
| 1009 | 1119 | * Pinned floating panel that surfaces the OS-file-drop manager's |
| 1010 | - * in-flight uploads. One row per file with a `<wpd-progress-bar>`, | |
| 1120 | + * in-flight uploads. One row per file with a `<os-progress-bar>`, | |
| 1011 | 1121 | * a filename + status, and a Cancel/Dismiss action. The panel |
| 1012 | 1122 | * hides itself when there are no rows; it's purely reactive to |
| 1013 | 1123 | * the four upload-lifecycle hooks. |
| 1014 | 1124 | * ============================================================ */ |
| 1015 | 1125 | |
| 1016 | -.desktop-mode-upload-hud { | |
| 1126 | +.os-upload-hud { | |
| 1017 | 1127 | position: fixed; |
| 1018 | 1128 | inset-block-end: 16px; |
| 1019 | 1129 | inset-inline-end: 16px; |
| 1020 | 1130 | width: 320px; |
| 1021 | 1131 | max-width: calc( 100vw - 32px ); |
| 1022 | - background: var( --desktop-mode-panel-bg, #fff ); | |
| 1023 | - color: var( --desktop-mode-fg-on-light, #1d2327 ); | |
| 1024 | - border: 1px solid var( --desktop-mode-border, #dcdcde ); | |
| 1132 | + background: var( --os-panel-bg, var( --os-ui-surface, #fff ) ); | |
| 1133 | + color: var( --os-fg-on-light, var( --os-ui-fg, #1d2327 ) ); | |
| 1134 | + border: 1px solid var( --os-ui-border, #dcdcde ); | |
| 1025 | 1135 | border-radius: 10px; |
| 1026 | 1136 | box-shadow: 0 8px 28px rgba( 0, 0, 0, 0.18 ); |
| 1027 | 1137 | z-index: 99998; |
| 1028 | 1138 | font: inherit; |
| @@ -1029,25 +1139,25 @@ | ||
| 1029 | 1139 | pointer-events: auto; |
| 1030 | 1140 | overflow: hidden; |
| 1031 | 1141 | } |
| 1032 | 1142 | |
| 1033 | -.desktop-mode-upload-hud[ hidden ] { | |
| 1143 | +.os-upload-hud[ hidden ] { | |
| 1034 | 1144 | display: none; |
| 1035 | 1145 | } |
| 1036 | 1146 | |
| 1037 | -.desktop-mode-upload-hud__header { | |
| 1147 | +.os-upload-hud__header { | |
| 1038 | 1148 | display: flex; |
| 1039 | 1149 | align-items: center; |
| 1040 | 1150 | justify-content: space-between; |
| 1041 | 1151 | gap: 8px; |
| 1042 | 1152 | padding: 8px 12px; |
| 1043 | - background: var( --desktop-mode-panel-header-bg, rgba( 0, 0, 0, 0.04 ) ); | |
| 1044 | - border-block-end: 1px solid var( --desktop-mode-border, #dcdcde ); | |
| 1153 | + background: var( --os-panel-header-bg, var( --os-ui-hover, rgba( 0, 0, 0, 0.04 ) ) ); | |
| 1154 | + border-block-end: 1px solid var( --os-ui-border, #dcdcde ); | |
| 1045 | 1155 | font-weight: 600; |
| 1046 | 1156 | font-size: 12px; |
| 1047 | 1157 | } |
| 1048 | 1158 | |
| 1049 | -.desktop-mode-upload-hud__title { | |
| 1159 | +.os-upload-hud__title { | |
| 1050 | 1160 | min-width: 0; |
| 1051 | 1161 | overflow: hidden; |
| 1052 | 1162 | text-overflow: ellipsis; |
| 1053 | 1163 | white-space: nowrap; |
| @@ -1052,9 +1162,9 @@ | ||
| 1052 | 1162 | text-overflow: ellipsis; |
| 1053 | 1163 | white-space: nowrap; |
| 1054 | 1164 | } |
| 1055 | 1165 | |
| 1056 | -.desktop-mode-upload-hud__close { | |
| 1166 | +.os-upload-hud__close { | |
| 1057 | 1167 | border: 0; |
| 1058 | 1168 | background: transparent; |
| 1059 | 1169 | color: inherit; |
| 1060 | 1170 | font-size: 16px; |
| @@ -1066,15 +1176,15 @@ | ||
| 1066 | 1176 | display: inline-flex; |
| 1067 | 1177 | align-items: center; |
| 1068 | 1178 | justify-content: center; |
| 1069 | 1179 | } |
| 1070 | -.desktop-mode-upload-hud__close:hover, | |
| 1071 | -.desktop-mode-upload-hud__close:focus-visible { | |
| 1072 | - background: rgba( 0, 0, 0, 0.08 ); | |
| 1180 | +.os-upload-hud__close:hover, | |
| 1181 | +.os-upload-hud__close:focus-visible { | |
| 1182 | + background: var( --os-ui-hover, rgba( 0, 0, 0, 0.08 ) ); | |
| 1073 | 1183 | outline: none; |
| 1074 | 1184 | } |
| 1075 | 1185 | |
| 1076 | -.desktop-mode-upload-hud__list { | |
| 1186 | +.os-upload-hud__list { | |
| 1077 | 1187 | display: flex; |
| 1078 | 1188 | flex-direction: column; |
| 1079 | 1189 | gap: 10px; |
| 1080 | 1190 | padding: 10px 12px; |
| @@ -1081,9 +1191,9 @@ | ||
| 1081 | 1191 | max-height: 50vh; |
| 1082 | 1192 | overflow-y: auto; |
| 1083 | 1193 | } |
| 1084 | 1194 | |
| 1085 | -.desktop-mode-upload-hud__row { | |
| 1195 | +.os-upload-hud__row { | |
| 1086 | 1196 | display: grid; |
| 1087 | 1197 | grid-template-columns: 1fr auto; |
| 1088 | 1198 | grid-template-areas: |
| 1089 | 1199 | 'meta actions' |
| @@ -1092,9 +1202,9 @@ | ||
| 1092 | 1202 | align-items: center; |
| 1093 | 1203 | font-size: 12px; |
| 1094 | 1204 | } |
| 1095 | 1205 | |
| 1096 | -.desktop-mode-upload-hud__meta { | |
| 1206 | +.os-upload-hud__meta { | |
| 1097 | 1207 | grid-area: meta; |
| 1098 | 1208 | min-width: 0; |
| 1099 | 1209 | display: flex; |
| 1100 | 1210 | flex-direction: column; |
| @@ -1100,9 +1210,9 @@ | ||
| 1100 | 1210 | flex-direction: column; |
| 1101 | 1211 | gap: 2px; |
| 1102 | 1212 | } |
| 1103 | 1213 | |
| 1104 | -.desktop-mode-upload-hud__name { | |
| 1214 | +.os-upload-hud__name { | |
| 1105 | 1215 | overflow: hidden; |
| 1106 | 1216 | text-overflow: ellipsis; |
| 1107 | 1217 | white-space: nowrap; |
| 1108 | 1218 | font-weight: 500; |
| @@ -1107,19 +1217,19 @@ | ||
| 1107 | 1217 | white-space: nowrap; |
| 1108 | 1218 | font-weight: 500; |
| 1109 | 1219 | } |
| 1110 | 1220 | |
| 1111 | -.desktop-mode-upload-hud__status { | |
| 1221 | +.os-upload-hud__status { | |
| 1112 | 1222 | font-size: 11px; |
| 1113 | 1223 | opacity: 0.75; |
| 1114 | 1224 | font-variant-numeric: tabular-nums; |
| 1115 | 1225 | } |
| 1116 | 1226 | |
| 1117 | -.desktop-mode-upload-hud__row wpd-progress-bar { | |
| 1227 | +.os-upload-hud__row os-progress-bar { | |
| 1118 | 1228 | grid-area: bar; |
| 1119 | 1229 | } |
| 1120 | 1230 | |
| 1121 | -.desktop-mode-upload-hud__actions { | |
| 1231 | +.os-upload-hud__actions { | |
| 1122 | 1232 | grid-area: actions; |
| 1123 | 1233 | display: inline-flex; |
| 1124 | 1234 | gap: 4px; |
| 1125 | 1235 | } |