| 1 |
/** |
| 2 |
* Desktop Mode — Files-on-the-Desktop tile + layer styles. |
| 3 |
* |
| 4 |
* The layer is an absolutely-positioned container inside |
| 5 |
* `#desktop-mode-area`; tiles inside use absolute positioning |
| 6 |
* keyed off `(x, y)` coordinates persisted server-side. |
| 7 |
* |
| 8 |
* Tiles are intentionally close to the look of `desktop-mode-icon` |
| 9 |
* (the plugin-shortcut tiles) so the desktop reads as one |
| 10 |
* coherent surface — but they live in their own class namespace |
| 11 |
* (`desktop-mode-file-tile`) so plugins can theme each rail |
| 12 |
* independently. |
| 13 |
* |
| 14 |
* @since 0.9.0 |
| 15 |
*/ |
| 16 |
|
| 17 |
/* |
| 18 |
* Unified rail (since 0.9.0): plugin shortcuts now ride on the |
| 19 |
* same files layer as folders / posts / etc — they're a |
| 20 |
* `'shortcut'` file type. The legacy `.desktop-mode-icons` DIV |
| 21 |
* still renders for backwards compatibility (existing tests and |
| 22 |
* non-files-active code paths), but when a files layer is |
| 23 |
* mounted as a sibling we hide it so we don't end up with two |
| 24 |
* rails competing for the same wallpaper. |
| 25 |
*/ |
| 26 |
#desktop-mode-area:has( > .desktop-mode-files-layer ) > .desktop-mode-icons { |
| 27 |
display: none; |
| 28 |
} |
| 29 |
|
| 30 |
/* |
| 31 |
* Drop-target highlight — the `data-files-drop-active` attribute |
| 32 |
* is set on the FilesLayer host (desktop area or folder window |
| 33 |
* body) while a shortcut payload is being dragged over it. |
| 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. |
| 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 |
[ data-files-drop-active ] { |
| 49 |
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 |
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 |
transition: box-shadow 0.18s ease-out; |
| 79 |
} |
| 80 |
|
| 81 |
@media ( prefers-reduced-motion: reduce ) { |
| 82 |
[ data-files-drop-active ] { |
| 83 |
animation: none; |
| 84 |
} |
| 85 |
} |
| 86 |
|
| 87 |
.desktop-mode-files-layer { |
| 88 |
position: absolute; |
| 89 |
inset: 0; |
| 90 |
z-index: 0; |
| 91 |
/* |
| 92 |
* Layer doesn't intercept pointer events itself — tiles and |
| 93 |
* the wallpaper own that. Phase 4's wallpaper context menu |
| 94 |
* binds clicks on the parent `#desktop-mode-area`, which is |
| 95 |
* unblocked because of this rule. |
| 96 |
*/ |
| 97 |
pointer-events: none; |
| 98 |
} |
| 99 |
|
| 100 |
/* |
| 101 |
* Live drop-cell preview. A soft outline that hovers at the cell |
| 102 |
* the dropped tile will land in, so the user can predict where the |
| 103 |
* grid snap will place it before releasing. Positioned absolutely |
| 104 |
* inside the files layer; `translate3d` updated from JS on every |
| 105 |
* pointermove while a desktop-file drag hovers the canvas. |
| 106 |
* |
| 107 |
* The tile dimensions are baked into `grid.ts` (88 × 96 visual, |
| 108 |
* 96 × 110 cell pitch). The outline matches the cell pitch — slightly |
| 109 |
* larger than the tile — so the highlight reads as "this slot" rather |
| 110 |
* than "this tile." |
| 111 |
* |
| 112 |
* @since 0.20.0 |
| 113 |
*/ |
| 114 |
.desktop-mode-files-drop-preview { |
| 115 |
position: absolute; |
| 116 |
top: 0; |
| 117 |
left: 0; |
| 118 |
width: 88px; |
| 119 |
height: 96px; |
| 120 |
pointer-events: none; |
| 121 |
box-sizing: border-box; |
| 122 |
border-radius: 12px; |
| 123 |
background: var( |
| 124 |
--desktop-mode-drop-preview-bg, |
| 125 |
rgba( 34, 113, 177, 0.08 ) |
| 126 |
); |
| 127 |
border: 2px dashed |
| 128 |
var( |
| 129 |
--desktop-mode-drop-preview-border, |
| 130 |
rgba( 34, 113, 177, 0.55 ) |
| 131 |
); |
| 132 |
transition: transform 90ms ease-out; |
| 133 |
will-change: transform; |
| 134 |
/* Sit BELOW tiles so a tile being dragged over the cell isn't |
| 135 |
* visually clipped by the dashed outline; the outline still reads |
| 136 |
* because the tile is semi-transparent during drag (`--dragging` |
| 137 |
* sets `opacity: 0.4`). */ |
| 138 |
z-index: 0; |
| 139 |
} |
| 140 |
|
| 141 |
@media ( prefers-reduced-motion: reduce ) { |
| 142 |
.desktop-mode-files-drop-preview { |
| 143 |
transition: none; |
| 144 |
} |
| 145 |
} |
| 146 |
|
| 147 |
.desktop-mode-file-tile { |
| 148 |
pointer-events: auto; |
| 149 |
position: absolute; |
| 150 |
display: flex; |
| 151 |
flex-direction: column; |
| 152 |
align-items: center; |
| 153 |
justify-content: flex-start; |
| 154 |
gap: 6px; |
| 155 |
width: 88px; |
| 156 |
padding: 8px 4px; |
| 157 |
border: 0; |
| 158 |
background: transparent; |
| 159 |
/* Tile foreground driven by `--desktop-mode-tile-fg` so any |
| 160 |
* light-on-dark surface (folder window, My WordPress preview) |
| 161 |
* can retint tiles by overriding the variable in its scope — |
| 162 |
* no per-surface selectors needed here. */ |
| 163 |
color: var( --desktop-mode-tile-fg, var( --desktop-mode-fg, #fff ) ); |
| 164 |
cursor: pointer; |
| 165 |
border-radius: 8px; |
| 166 |
transition: background-color 0.15s ease, transform 0.05s linear; |
| 167 |
-webkit-user-select: none; |
| 168 |
user-select: none; |
| 169 |
touch-action: none; |
| 170 |
/* Soft fade-in on mount — each tile carries its own randomised |
| 171 |
* `--enter-delay` / `--enter-duration` (set inline by the |
| 172 |
* tile builder), so a freshly-painted grid reads as a cascade |
| 173 |
* rather than a synchronised pop-in. Both values land in the |
| 174 |
* decimal-of-a-second range — perceivable, never sluggish. |
| 175 |
* |
| 176 |
* `backwards` keeps the tile invisible during its delay so the |
| 177 |
* cascade is honest; the animation runs once, leaves the tile |
| 178 |
* at its static `opacity: 1`, and never re-fires from later |
| 179 |
* state changes (drag, hover, drop-target). |
| 180 |
*/ |
| 181 |
animation: desktop-mode-file-tile-enter |
| 182 |
var( --desktop-mode-file-tile-enter-duration, 0.4s ) |
| 183 |
ease-out |
| 184 |
var( --desktop-mode-file-tile-enter-delay, 0s ) |
| 185 |
backwards; |
| 186 |
} |
| 187 |
|
| 188 |
@keyframes desktop-mode-file-tile-enter { |
| 189 |
from { |
| 190 |
opacity: 0; |
| 191 |
} |
| 192 |
to { |
| 193 |
opacity: 1; |
| 194 |
} |
| 195 |
} |
| 196 |
|
| 197 |
@media ( prefers-reduced-motion: reduce ) { |
| 198 |
.desktop-mode-file-tile { |
| 199 |
animation: none; |
| 200 |
} |
| 201 |
} |
| 202 |
|
| 203 |
.desktop-mode-file-tile:hover, |
| 204 |
.desktop-mode-file-tile:focus-visible { |
| 205 |
background: var( |
| 206 |
--desktop-mode-tile-hover-bg, |
| 207 |
rgba( 255, 255, 255, 0.12 ) |
| 208 |
); |
| 209 |
outline: none; |
| 210 |
} |
| 211 |
|
| 212 |
.desktop-mode-file-tile:focus-visible { |
| 213 |
/* Inset focus ring — outset rings extended past the tile and |
| 214 |
* visually overlapped the colindant icon when the canvas cell |
| 215 |
* pitch is tight (96 px cell, 88 px tile → only 4 px clearance |
| 216 |
* per side). Inset keeps the ring fully inside the tile. */ |
| 217 |
box-shadow: inset 0 0 0 2px |
| 218 |
var( --desktop-mode-tile-focus-ring, var( --wp-admin-theme-color, #2271b1 ) ); |
| 219 |
} |
| 220 |
|
| 221 |
/* Status ribbon sizing inside tiles. The `<wpd-ribbon>` defaults |
| 222 |
* are tuned for cards (~90 px clipping window); 88 px-wide tiles |
| 223 |
* need a tighter footprint or the ribbon dominates the icon. We |
| 224 |
* override the component's CSS custom-property theming surface so |
| 225 |
* the ribbon stays a small accent in the corner. Authors who want |
| 226 |
* 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 ); |
| 236 |
} |
| 237 |
|
| 238 |
.desktop-mode-file-tile--dragging { |
| 239 |
/* The DragManager renders a separate ghost element that follows |
| 240 |
* the pointer; the SOURCE tile stays in place but is dimmed so |
| 241 |
* the user has a stable reference for "this is what I'm |
| 242 |
* dragging." |
| 243 |
* |
| 244 |
* @since 0.18.0 |
| 245 |
*/ |
| 246 |
opacity: 0.4; |
| 247 |
cursor: grabbing; |
| 248 |
} |
| 249 |
|
| 250 |
/* Pinned tiles ("My WordPress", Recycle Bin) anchor to a fixed slot |
| 251 |
* and DO NOT wire drag — but they look + behave identically to any |
| 252 |
* other tile until the user attempts a drag (which silently fails). |
| 253 |
* No upfront visual cue: feedback now happens at the moment of the |
| 254 |
* gesture, not before, per @since 0.9.0 design feedback. |
| 255 |
* |
| 256 |
* Default `cursor: pointer` from the base `.desktop-mode-file-tile` |
| 257 |
* rule covers click-to-open. Touch interactions stay as |
| 258 |
* `touch-action: auto` so the OS scroll gesture works on top of |
| 259 |
* the tile. |
| 260 |
*/ |
| 261 |
.desktop-mode-file-tile--pinned { |
| 262 |
touch-action: auto; |
| 263 |
} |
| 264 |
|
| 265 |
/* Folder tile is the drop target during a cross-window shortcut |
| 266 |
* drag — the user dragged a post / page / user tile out of My |
| 267 |
* WordPress and is hovering over a folder. Bright outline, soft |
| 268 |
* pulse, and a slight scale so the folder reads unmistakably as |
| 269 |
* "yes, drop here." @since 0.8.0; pulse added 0.20.0. */ |
| 270 |
@keyframes desktop-mode-drop-target-pulse { |
| 271 |
0% { |
| 272 |
box-shadow: |
| 273 |
0 0 0 0 rgba( 34, 113, 177, 0.5 ), |
| 274 |
inset 0 0 0 2px var( --wp-admin-theme-color, #2271b1 ); |
| 275 |
} |
| 276 |
100% { |
| 277 |
box-shadow: |
| 278 |
0 0 0 8px rgba( 34, 113, 177, 0 ), |
| 279 |
inset 0 0 0 2px var( --wp-admin-theme-color, #2271b1 ); |
| 280 |
} |
| 281 |
} |
| 282 |
|
| 283 |
.desktop-mode-file-tile--drop-target { |
| 284 |
outline: 2px solid var( --wp-admin-theme-color, #2271b1 ); |
| 285 |
outline-offset: -4px; |
| 286 |
background: rgba( 34, 113, 177, 0.2 ); |
| 287 |
transform: scale( 1.08 ); |
| 288 |
z-index: 5; |
| 289 |
animation: desktop-mode-drop-target-pulse 1s ease-out infinite; |
| 290 |
border-radius: 12px; |
| 291 |
} |
| 292 |
|
| 293 |
@media ( prefers-reduced-motion: reduce ) { |
| 294 |
.desktop-mode-file-tile--drop-target { |
| 295 |
animation: none; |
| 296 |
} |
| 297 |
} |
| 298 |
|
| 299 |
/* Drop-hint chip — floats next to the cursor during a drag and |
| 300 |
* shows context-aware text ("Drop here to create shortcut", |
| 301 |
* "Can't drop here", etc.). The chip text is owned by the |
| 302 |
* ghost module (`src/drag/ghost.ts`); these styles control the |
| 303 |
* appearance per accept/reject/neutral mode. |
| 304 |
* |
| 305 |
* @since 0.20.0 |
| 306 |
*/ |
| 307 |
.desktop-mode-drag-hint { |
| 308 |
position: fixed; |
| 309 |
top: 0; |
| 310 |
left: 0; |
| 311 |
padding: 6px 10px; |
| 312 |
border-radius: 999px; |
| 313 |
font-size: 12px; |
| 314 |
font-weight: 600; |
| 315 |
letter-spacing: 0.02em; |
| 316 |
white-space: nowrap; |
| 317 |
pointer-events: none; |
| 318 |
user-select: none; |
| 319 |
box-shadow: 0 4px 14px rgba( 0, 0, 0, 0.22 ); |
| 320 |
background: rgba( 30, 30, 30, 0.85 ); |
| 321 |
color: #fff; |
| 322 |
z-index: 2147483647; |
| 323 |
transition: |
| 324 |
background-color 0.12s ease, |
| 325 |
color 0.12s ease, |
| 326 |
transform 0.06s ease-out; |
| 327 |
} |
| 328 |
|
| 329 |
.desktop-mode-drag-hint--neutral { |
| 330 |
background: rgba( 30, 30, 30, 0.85 ); |
| 331 |
color: #fff; |
| 332 |
} |
| 333 |
|
| 334 |
.desktop-mode-drag-hint--accept { |
| 335 |
background: #1e8449; |
| 336 |
color: #fff; |
| 337 |
box-shadow: |
| 338 |
0 0 0 2px rgba( 30, 132, 73, 0.25 ), |
| 339 |
0 6px 18px rgba( 30, 132, 73, 0.3 ); |
| 340 |
} |
| 341 |
|
| 342 |
.desktop-mode-drag-hint--accept::before { |
| 343 |
/* Tiny checkmark chevron prefix so "Drop here" reads as an |
| 344 |
* actionable affirmation rather than a passive label. The |
| 345 |
* checkmark is a real character (U+2713) so screen readers |
| 346 |
* skip past it via the `aria-hidden` on the host chip. */ |
| 347 |
content: '✓ '; |
| 348 |
} |
| 349 |
|
| 350 |
.desktop-mode-drag-hint--reject { |
| 351 |
background: #b32d2e; |
| 352 |
color: #fff; |
| 353 |
box-shadow: |
| 354 |
0 0 0 2px rgba( 179, 45, 46, 0.25 ), |
| 355 |
0 6px 18px rgba( 179, 45, 46, 0.3 ); |
| 356 |
} |
| 357 |
|
| 358 |
.desktop-mode-drag-hint--reject::before { |
| 359 |
content: '⊘ '; |
| 360 |
} |
| 361 |
|
| 362 |
/* |
| 363 |
* No body-level cursor swap during drag — the user prefers the |
| 364 |
* default arrow cursor regardless of state, so the accept/reject |
| 365 |
* feedback lives entirely in the hint chip + outline animation. |
| 366 |
* Don't reintroduce a `cursor: grabbing/copy/no-drop` here. |
| 367 |
*/ |
| 368 |
|
| 369 |
/* Shortcut overlay — small arrow badge in the BOTTOM-RIGHT corner |
| 370 |
* of the icon visual on any tile that's a reference to an external |
| 371 |
* entity (post, attachment, comment, user, term — anything that |
| 372 |
* ISN'T a folder or a plugin shortcut). Mirrors the macOS / Windows |
| 373 |
* convention of an arrow decoration on alias/shortcut icons. |
| 374 |
* |
| 375 |
* The geometry: tile is 88px wide with `padding: 8px 4px`. The icon |
| 376 |
* visual is 48×48 centered horizontally, so the icon's bottom-right |
| 377 |
* corner lands at roughly (68, 56) from the tile's top-left. The |
| 378 |
* 18×18 arrow circle is anchored just inside that corner so it |
| 379 |
* reads as part of the icon, not floating off in space. |
| 380 |
* |
| 381 |
* @since 0.8.0 |
| 382 |
*/ |
| 383 |
/* Only real placements get the badge — i.e. tiles built by |
| 384 |
* `buildTile(placement)` on the desktop / folder windows, which |
| 385 |
* are the only surface where "this is a shortcut" actually means |
| 386 |
* something. Tiles in My WordPress grids (and any future content |
| 387 |
* surface) are the entity, not a shortcut to it, so the arrow |
| 388 |
* would just be noise. `[data-placement-id]` is the canonical |
| 389 |
* 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 { |
| 395 |
content: "↗"; |
| 396 |
position: absolute; |
| 397 |
right: 14px; |
| 398 |
top: 44px; |
| 399 |
width: 18px; |
| 400 |
height: 18px; |
| 401 |
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 ); |
| 404 |
font-size: 11px; |
| 405 |
line-height: 18px; |
| 406 |
text-align: center; |
| 407 |
box-shadow: var( |
| 408 |
--desktop-mode-tile-shortcut-shadow, |
| 409 |
0 1px 3px rgba( 0, 0, 0, 0.5 ) |
| 410 |
); |
| 411 |
pointer-events: none; |
| 412 |
} |
| 413 |
|
| 414 |
/* |
| 415 |
* Missing files (the underlying entity was deleted but the |
| 416 |
* placement still exists) render the tile dimmed so the user |
| 417 |
* can right-click → Remove without confusing it for an active |
| 418 |
* file. Phase 6's per-placement permission re-check uses the |
| 419 |
* same affordance for "you can't see this" placeholders. |
| 420 |
*/ |
| 421 |
.desktop-mode-file-tile--missing { |
| 422 |
opacity: 0.5; |
| 423 |
} |
| 424 |
|
| 425 |
/** |
| 426 |
* Access-gated tile — the recipient sees the icon (the owner |
| 427 |
* shared the folder containing it) but lacks `can_read` on the |
| 428 |
* underlying entity. Dim the tile, kill the pointer affordance, |
| 429 |
* and overlay a lock badge so the state reads at a glance. |
| 430 |
*/ |
| 431 |
.desktop-mode-file-tile--access-gated { |
| 432 |
opacity: 0.65; |
| 433 |
cursor: not-allowed; |
| 434 |
} |
| 435 |
.desktop-mode-file-tile--access-gated .desktop-mode-file-tile__visual, |
| 436 |
.desktop-mode-file-tile--access-gated .desktop-mode-file-tile__preview { |
| 437 |
filter: grayscale( 0.6 ); |
| 438 |
} |
| 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 ); |
| 442 |
} |
| 443 |
.desktop-mode-file-tile__lock { |
| 444 |
position: absolute; |
| 445 |
top: 4px; |
| 446 |
inset-inline-end: 4px; |
| 447 |
width: 20px; |
| 448 |
height: 20px; |
| 449 |
border-radius: 50%; |
| 450 |
background: rgba( 0, 0, 0, 0.7 ); |
| 451 |
color: #fff; |
| 452 |
font-size: 14px; |
| 453 |
line-height: 20px; |
| 454 |
text-align: center; |
| 455 |
pointer-events: none; |
| 456 |
box-shadow: 0 1px 3px rgba( 0, 0, 0, 0.5 ); |
| 457 |
} |
| 458 |
|
| 459 |
/** |
| 460 |
* Preview-pane empty state when a recipient selects a tile they |
| 461 |
* can't open. Big lock ring + clear copy + secondary hint. Designed |
| 462 |
* to read at a glance in the otherwise-busy preview column. |
| 463 |
*/ |
| 464 |
.desktop-mode-files__access-gated { |
| 465 |
display: flex; |
| 466 |
flex-direction: column; |
| 467 |
align-items: center; |
| 468 |
justify-content: center; |
| 469 |
gap: 16px; |
| 470 |
padding: 32px 24px; |
| 471 |
min-height: 240px; |
| 472 |
text-align: center; |
| 473 |
color: var( --desktop-mode-fg, inherit ); |
| 474 |
} |
| 475 |
.desktop-mode-files__access-gated-ring { |
| 476 |
display: flex; |
| 477 |
align-items: center; |
| 478 |
justify-content: center; |
| 479 |
width: 96px; |
| 480 |
height: 96px; |
| 481 |
border-radius: 50%; |
| 482 |
background: linear-gradient( |
| 483 |
145deg, |
| 484 |
rgba( 214, 54, 56, 0.22 ), |
| 485 |
rgba( 214, 54, 56, 0.08 ) |
| 486 |
); |
| 487 |
border: 2px solid rgba( 214, 54, 56, 0.45 ); |
| 488 |
box-shadow: |
| 489 |
inset 0 1px 0 rgba( 255, 255, 255, 0.08 ), |
| 490 |
0 8px 24px rgba( 214, 54, 56, 0.18 ); |
| 491 |
} |
| 492 |
.desktop-mode-files__access-gated-glyph { |
| 493 |
font-size: 44px; |
| 494 |
width: 44px; |
| 495 |
height: 44px; |
| 496 |
color: #ff8080; |
| 497 |
filter: drop-shadow( 0 1px 2px rgba( 0, 0, 0, 0.4 ) ); |
| 498 |
} |
| 499 |
.desktop-mode-files__access-gated-title { |
| 500 |
margin: 0; |
| 501 |
font-size: 17px; |
| 502 |
font-weight: 600; |
| 503 |
letter-spacing: 0.2px; |
| 504 |
} |
| 505 |
.desktop-mode-files__access-gated-sub { |
| 506 |
margin: 0; |
| 507 |
font-size: 13px; |
| 508 |
line-height: 1.5; |
| 509 |
max-width: 340px; |
| 510 |
opacity: 0.85; |
| 511 |
} |
| 512 |
.desktop-mode-files__access-gated-hint { |
| 513 |
margin: 0; |
| 514 |
font-size: 12px; |
| 515 |
line-height: 1.5; |
| 516 |
max-width: 340px; |
| 517 |
opacity: 0.6; |
| 518 |
} |
| 519 |
|
| 520 |
.desktop-mode-file-tile__visual { |
| 521 |
display: inline-flex; |
| 522 |
align-items: center; |
| 523 |
justify-content: center; |
| 524 |
width: 48px; |
| 525 |
height: 48px; |
| 526 |
font-size: 32px; |
| 527 |
line-height: 1; |
| 528 |
} |
| 529 |
|
| 530 |
.desktop-mode-file-tile__icon { |
| 531 |
display: inline-flex; |
| 532 |
align-items: center; |
| 533 |
justify-content: center; |
| 534 |
width: 48px; |
| 535 |
height: 48px; |
| 536 |
font-size: 32px; |
| 537 |
line-height: 1; |
| 538 |
} |
| 539 |
|
| 540 |
.desktop-mode-file-tile__preview { |
| 541 |
width: 48px; |
| 542 |
height: 48px; |
| 543 |
object-fit: cover; |
| 544 |
border-radius: 4px; |
| 545 |
} |
| 546 |
|
| 547 |
/* `<img>` defaults to `draggable=true`, which lets the browser |
| 548 |
* start a native HTML5 image-drag from a pointerdown — that |
| 549 |
* pre-empts the DragManager's pointer-event-driven tile rearrange |
| 550 |
* and the tile silently refuses to move. The renderer also sets |
| 551 |
* `draggable="false"` on every `<img>` it produces; this CSS rule |
| 552 |
* covers anything injected later (plugin filters, decorators) |
| 553 |
* without having to remember the attribute. */ |
| 554 |
.desktop-mode-file-tile img { |
| 555 |
-webkit-user-drag: none; |
| 556 |
user-select: none; |
| 557 |
} |
| 558 |
|
| 559 |
/* |
| 560 |
* Wallpaper + tile context menus use `<wpd-context-menu>` and |
| 561 |
* `<wpd-context-menu-option>` (Phase 4 / 0.9.0). Their host-level |
| 562 |
* 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- |
| 565 |
* wallpaper-menu*` rules were removed when the components landed. |
| 566 |
*/ |
| 567 |
|
| 568 |
/* |
| 569 |
* Folder native window — the body of `desktop-mode-folder-<id>` |
| 570 |
* contains a `FilesLayer` rendering that folder's contents. |
| 571 |
* We ensure the body has positioning context so absolutely- |
| 572 |
* positioned tiles inside the layer anchor correctly. |
| 573 |
*/ |
| 574 |
.desktop-mode-folder-window { |
| 575 |
position: relative; |
| 576 |
min-height: 200px; |
| 577 |
/* Same window background recipe as My WordPress — defaults to |
| 578 |
* the standard window bg (#fff) and themable per-window. */ |
| 579 |
background: var( |
| 580 |
--desktop-mode-folder-window-bg, |
| 581 |
var( --desktop-mode-window-bg, #fff ) |
| 582 |
); |
| 583 |
color: var( --desktop-mode-fg-on-light, #1d2327 ); |
| 584 |
display: flex; |
| 585 |
flex-direction: column; |
| 586 |
/* Light-on-dark context: the folder window opens inside a |
| 587 |
* standard window chrome whose body is white-ish. Retint the |
| 588 |
* tile color tokens here so dashicons + labels read against |
| 589 |
* a light background. Plugins / themes can override these |
| 590 |
* 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 ); |
| 594 |
/* Light-context label rendering — share the same recipe with |
| 595 |
* every other light-bg tile surface (My WordPress, future |
| 596 |
* 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 ); |
| 601 |
} |
| 602 |
|
| 603 |
/* Folder window's bottom status bar — paint with the same light- |
| 604 |
* context treatment My WordPress uses (transparent bg, soft border, |
| 605 |
* muted dark text). Without this, the wallpaper-targeted defaults |
| 606 |
* (`background: rgba(0,0,0,0.18); color: white`) would show as a |
| 607 |
* 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 ); |
| 610 |
background: transparent; |
| 611 |
color: var( --desktop-mode-muted, #50575e ); |
| 612 |
} |
| 613 |
|
| 614 |
.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 ) ); |
| 618 |
} |
| 619 |
|
| 620 |
/* Generic breadcrumb header — any surface that grows a navigation |
| 621 |
* stack (folder window, My WordPress folder, future drill-down |
| 622 |
* windows) renders one of these via `renderBreadcrumbs` from |
| 623 |
* `src/desktop-files/breadcrumbs.ts`. Visual vocabulary: small |
| 624 |
* icon-only Back button on the left, `›`-separated crumb buttons, |
| 625 |
* current segment is bold + non-interactive. |
| 626 |
* |
| 627 |
* @since 0.8.0 |
| 628 |
*/ |
| 629 |
.desktop-mode-breadcrumbs { |
| 630 |
display: flex; |
| 631 |
align-items: center; |
| 632 |
gap: 8px; |
| 633 |
padding: 6px 10px; |
| 634 |
border-bottom: 1px solid var( --desktop-mode-border, #dcdcde ); |
| 635 |
background: transparent; |
| 636 |
flex: 0 0 auto; |
| 637 |
} |
| 638 |
|
| 639 |
.desktop-mode-breadcrumbs__back { |
| 640 |
display: inline-flex; |
| 641 |
align-items: center; |
| 642 |
justify-content: center; |
| 643 |
width: 26px; |
| 644 |
height: 26px; |
| 645 |
padding: 0; |
| 646 |
border: 0; |
| 647 |
background: transparent; |
| 648 |
border-radius: 4px; |
| 649 |
cursor: pointer; |
| 650 |
color: inherit; |
| 651 |
flex: 0 0 auto; |
| 652 |
} |
| 653 |
|
| 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 ) ); |
| 657 |
outline: none; |
| 658 |
} |
| 659 |
|
| 660 |
.desktop-mode-breadcrumbs__back:disabled { |
| 661 |
opacity: 0.35; |
| 662 |
cursor: default; |
| 663 |
} |
| 664 |
|
| 665 |
.desktop-mode-breadcrumbs__back .dashicons { |
| 666 |
font-size: 18px; |
| 667 |
width: 18px; |
| 668 |
height: 18px; |
| 669 |
line-height: 1; |
| 670 |
} |
| 671 |
|
| 672 |
.desktop-mode-breadcrumbs__crumbs { |
| 673 |
display: flex; |
| 674 |
align-items: center; |
| 675 |
gap: 6px; |
| 676 |
font-size: 13px; |
| 677 |
min-width: 0; |
| 678 |
overflow: hidden; |
| 679 |
text-overflow: ellipsis; |
| 680 |
white-space: nowrap; |
| 681 |
} |
| 682 |
|
| 683 |
.desktop-mode-breadcrumbs__crumb { |
| 684 |
border: 0; |
| 685 |
background: transparent; |
| 686 |
color: var( --desktop-mode-link, #2271b1 ); |
| 687 |
cursor: pointer; |
| 688 |
padding: 2px 4px; |
| 689 |
border-radius: 4px; |
| 690 |
font: inherit; |
| 691 |
} |
| 692 |
|
| 693 |
.desktop-mode-breadcrumbs__crumb:hover { |
| 694 |
background: var( --desktop-mode-hover, rgba( 0, 0, 0, 0.06 ) ); |
| 695 |
} |
| 696 |
|
| 697 |
.desktop-mode-breadcrumbs__crumb--current { |
| 698 |
color: var( --desktop-mode-fg-on-light, #1d2327 ); |
| 699 |
cursor: default; |
| 700 |
font-weight: 600; |
| 701 |
} |
| 702 |
|
| 703 |
.desktop-mode-breadcrumbs__crumb--current:hover { |
| 704 |
background: transparent; |
| 705 |
} |
| 706 |
|
| 707 |
.desktop-mode-breadcrumbs__sep { |
| 708 |
color: var( --desktop-mode-muted, #787c82 ); |
| 709 |
} |
| 710 |
|
| 711 |
.desktop-mode-folder-window__layer { |
| 712 |
position: relative; |
| 713 |
flex: 1; |
| 714 |
min-height: 0; |
| 715 |
overflow: auto; |
| 716 |
} |
| 717 |
|
| 718 |
/* Two-pane shell — left: tile canvas, right: preview pane that |
| 719 |
* reflects the currently-selected tile. Same model as the My |
| 720 |
* WordPress two-pane view so the UX is unified. |
| 721 |
* |
| 722 |
* @since 0.8.0 */ |
| 723 |
.desktop-mode-folder-window__split { |
| 724 |
display: grid; |
| 725 |
grid-template-columns: minmax( 240px, 60% ) minmax( 0, 1fr ); |
| 726 |
flex: 1 1 auto; |
| 727 |
min-height: 0; |
| 728 |
} |
| 729 |
|
| 730 |
.desktop-mode-folder-window__preview { |
| 731 |
overflow-y: auto; |
| 732 |
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 ); |
| 736 |
} |
| 737 |
|
| 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 { |
| 743 |
background: var( |
| 744 |
--desktop-mode-tile-selected-bg, |
| 745 |
rgba( 34, 113, 177, 0.18 ) |
| 746 |
); |
| 747 |
box-shadow: inset 0 0 0 1px |
| 748 |
var( --desktop-mode-tile-focus-ring, var( --wp-admin-theme-color, #2271b1 ) ); |
| 749 |
} |
| 750 |
|
| 751 |
/* Inside a folder window the selected highlight should read on |
| 752 |
* white. */ |
| 753 |
.desktop-mode-folder-window { |
| 754 |
--desktop-mode-tile-selected-bg: rgba( 34, 113, 177, 0.12 ); |
| 755 |
} |
| 756 |
|
| 757 |
.desktop-mode-folder-status-bar { |
| 758 |
display: flex; |
| 759 |
justify-content: space-between; |
| 760 |
align-items: center; |
| 761 |
gap: 12px; |
| 762 |
padding: 6px 12px; |
| 763 |
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 ) ); |
| 766 |
font-size: 12px; |
| 767 |
flex-shrink: 0; |
| 768 |
} |
| 769 |
|
| 770 |
.desktop-mode-folder-status-bar__cluster { |
| 771 |
display: flex; |
| 772 |
align-items: center; |
| 773 |
gap: 12px; |
| 774 |
} |
| 775 |
|
| 776 |
.desktop-mode-folder-status-bar__segment { |
| 777 |
display: inline-flex; |
| 778 |
align-items: center; |
| 779 |
gap: 4px; |
| 780 |
padding: 0; |
| 781 |
border: 0; |
| 782 |
background: transparent; |
| 783 |
color: inherit; |
| 784 |
font: inherit; |
| 785 |
} |
| 786 |
|
| 787 |
button.desktop-mode-folder-status-bar__segment { |
| 788 |
cursor: pointer; |
| 789 |
border-radius: 4px; |
| 790 |
padding: 2px 6px; |
| 791 |
} |
| 792 |
|
| 793 |
button.desktop-mode-folder-status-bar__segment:hover { |
| 794 |
background: rgba( 255, 255, 255, 0.1 ); |
| 795 |
} |
| 796 |
|
| 797 |
.desktop-mode-folder-status-bar__icon { |
| 798 |
font-size: 14px; |
| 799 |
} |
| 800 |
|
| 801 |
/* |
| 802 |
* File Associations OS Settings tab (Phase 5). One row per file |
| 803 |
* type: label on the left, a `<wpd-select>` of compatible |
| 804 |
* openers on the right. Color tokens use the OS-Settings-canonical |
| 805 |
* `--wpd-text-muted` so the tab inherits theme colors instead of |
| 806 |
* falling back to white-on-light invisibility. |
| 807 |
*/ |
| 808 |
.desktop-mode-file-associations__intro { |
| 809 |
display: block; |
| 810 |
margin: 0 0 16px; |
| 811 |
color: var( --wpd-text-muted, #50575e ); |
| 812 |
font-size: 13px; |
| 813 |
line-height: 1.5; |
| 814 |
} |
| 815 |
|
| 816 |
.desktop-mode-file-associations__list { |
| 817 |
display: flex; |
| 818 |
flex-direction: column; |
| 819 |
gap: 8px; |
| 820 |
} |
| 821 |
|
| 822 |
.desktop-mode-file-associations__row { |
| 823 |
display: flex; |
| 824 |
align-items: center; |
| 825 |
justify-content: space-between; |
| 826 |
gap: 16px; |
| 827 |
padding: 8px 12px; |
| 828 |
background: rgba( 0, 0, 0, 0.04 ); |
| 829 |
border-radius: 6px; |
| 830 |
} |
| 831 |
|
| 832 |
.desktop-mode-file-associations__label { |
| 833 |
font-weight: 500; |
| 834 |
flex: 1; |
| 835 |
} |
| 836 |
|
| 837 |
.desktop-mode-file-associations__select { |
| 838 |
min-width: 220px; |
| 839 |
} |
| 840 |
|
| 841 |
.desktop-mode-file-associations__none, |
| 842 |
.desktop-mode-file-associations__empty { |
| 843 |
color: var( --wpd-text-muted, #50575e ); |
| 844 |
font-size: 12px; |
| 845 |
} |
| 846 |
|
| 847 |
/* |
| 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. |
| 852 |
*/ |
| 853 |
.desktop-mode-create-folder-dialog__overlay { |
| 854 |
position: fixed; |
| 855 |
inset: 0; |
| 856 |
background: rgba( 0, 0, 0, 0.45 ); |
| 857 |
backdrop-filter: blur( 2px ); |
| 858 |
display: flex; |
| 859 |
align-items: center; |
| 860 |
justify-content: center; |
| 861 |
z-index: 10000; |
| 862 |
} |
| 863 |
|
| 864 |
.desktop-mode-create-folder-dialog { |
| 865 |
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 ); |
| 869 |
border-radius: 10px; |
| 870 |
box-shadow: 0 20px 50px rgba( 0, 0, 0, 0.6 ); |
| 871 |
padding: 20px 22px 18px; |
| 872 |
display: flex; |
| 873 |
flex-direction: column; |
| 874 |
gap: 10px; |
| 875 |
} |
| 876 |
|
| 877 |
.desktop-mode-create-folder-dialog__title { |
| 878 |
margin: 0 0 4px; |
| 879 |
font-size: 16px; |
| 880 |
font-weight: 600; |
| 881 |
} |
| 882 |
|
| 883 |
.desktop-mode-create-folder-dialog__label { |
| 884 |
font-size: 12px; |
| 885 |
color: var( --desktop-mode-fg-muted, rgba( 255, 255, 255, 0.7 ) ); |
| 886 |
} |
| 887 |
|
| 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 { |
| 906 |
margin: 0; |
| 907 |
color: #ff8a8a; |
| 908 |
font-size: 12px; |
| 909 |
} |
| 910 |
|
| 911 |
.desktop-mode-create-folder-dialog__actions { |
| 912 |
display: flex; |
| 913 |
justify-content: flex-end; |
| 914 |
gap: 8px; |
| 915 |
margin-top: 6px; |
| 916 |
} |
| 917 |
|
| 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 { |
| 951 |
opacity: 0.7; |
| 952 |
} |
| 953 |
|
| 954 |
/* |
| 955 |
* Single label rule for every tile, regardless of host surface. |
| 956 |
* Visual properties read from `--desktop-mode-tile-label-*` |
| 957 |
* tokens — defined in `variables.css` for the dark wallpaper and |
| 958 |
* rebound by any light-context scope (folder window, My |
| 959 |
* WordPress, …) so all surfaces share one source of truth. |
| 960 |
*/ |
| 961 |
.desktop-mode-file-tile__label { |
| 962 |
font-size: 12px; |
| 963 |
line-height: 1.2; |
| 964 |
max-width: 84px; |
| 965 |
text-align: center; |
| 966 |
overflow: hidden; |
| 967 |
text-overflow: ellipsis; |
| 968 |
display: -webkit-box; |
| 969 |
-webkit-line-clamp: 2; |
| 970 |
-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 ); |
| 975 |
-moz-osx-font-smoothing: grayscale; |
| 976 |
} |
| 977 |
|
| 978 |
/* |
| 979 |
* DragManager ghost element (the visual that follows the cursor |
| 980 |
* during a drag). Cloned from the source by `mountGhost()` and |
| 981 |
* pinned to the body with `position: fixed` + transform-based |
| 982 |
* movement. `pointer-events: none` ensures the ghost itself |
| 983 |
* never obscures the drop targets underneath during hit-testing. |
| 984 |
* |
| 985 |
* The accept / reject classes are toggled on each hover transition |
| 986 |
* so the cursor matches the drop semantics: `copy` over an |
| 987 |
* accepting target, `no-drop` over rejecting (or no) target. |
| 988 |
* |
| 989 |
* @since 0.18.0 |
| 990 |
*/ |
| 991 |
.desktop-mode-drag-ghost { |
| 992 |
box-shadow: 0 6px 24px rgba( 0, 0, 0, 0.45 ); |
| 993 |
border-radius: 6px; |
| 994 |
opacity: 0.95; |
| 995 |
transition: none; |
| 996 |
} |
| 997 |
|
| 998 |
.desktop-mode-drag-ghost--accept { |
| 999 |
cursor: copy; |
| 1000 |
} |
| 1001 |
|
| 1002 |
.desktop-mode-drag-ghost--reject { |
| 1003 |
cursor: no-drop; |
| 1004 |
} |
| 1005 |
|
| 1006 |
/* ============================================================ * |
| 1007 |
* Upload progress HUD (since 0.31.0) |
| 1008 |
* |
| 1009 |
* Pinned floating panel that surfaces the OS-file-drop manager's |
| 1010 |
* in-flight uploads. One row per file with a `<wpd-progress-bar>`, |
| 1011 |
* a filename + status, and a Cancel/Dismiss action. The panel |
| 1012 |
* hides itself when there are no rows; it's purely reactive to |
| 1013 |
* the four upload-lifecycle hooks. |
| 1014 |
* ============================================================ */ |
| 1015 |
|
| 1016 |
.desktop-mode-upload-hud { |
| 1017 |
position: fixed; |
| 1018 |
inset-block-end: 16px; |
| 1019 |
inset-inline-end: 16px; |
| 1020 |
width: 320px; |
| 1021 |
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 ); |
| 1025 |
border-radius: 10px; |
| 1026 |
box-shadow: 0 8px 28px rgba( 0, 0, 0, 0.18 ); |
| 1027 |
z-index: 99998; |
| 1028 |
font: inherit; |
| 1029 |
pointer-events: auto; |
| 1030 |
overflow: hidden; |
| 1031 |
} |
| 1032 |
|
| 1033 |
.desktop-mode-upload-hud[ hidden ] { |
| 1034 |
display: none; |
| 1035 |
} |
| 1036 |
|
| 1037 |
.desktop-mode-upload-hud__header { |
| 1038 |
display: flex; |
| 1039 |
align-items: center; |
| 1040 |
justify-content: space-between; |
| 1041 |
gap: 8px; |
| 1042 |
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 ); |
| 1045 |
font-weight: 600; |
| 1046 |
font-size: 12px; |
| 1047 |
} |
| 1048 |
|
| 1049 |
.desktop-mode-upload-hud__title { |
| 1050 |
min-width: 0; |
| 1051 |
overflow: hidden; |
| 1052 |
text-overflow: ellipsis; |
| 1053 |
white-space: nowrap; |
| 1054 |
} |
| 1055 |
|
| 1056 |
.desktop-mode-upload-hud__close { |
| 1057 |
border: 0; |
| 1058 |
background: transparent; |
| 1059 |
color: inherit; |
| 1060 |
font-size: 16px; |
| 1061 |
line-height: 1; |
| 1062 |
width: 22px; |
| 1063 |
height: 22px; |
| 1064 |
border-radius: 4px; |
| 1065 |
cursor: pointer; |
| 1066 |
display: inline-flex; |
| 1067 |
align-items: center; |
| 1068 |
justify-content: center; |
| 1069 |
} |
| 1070 |
.desktop-mode-upload-hud__close:hover, |
| 1071 |
.desktop-mode-upload-hud__close:focus-visible { |
| 1072 |
background: rgba( 0, 0, 0, 0.08 ); |
| 1073 |
outline: none; |
| 1074 |
} |
| 1075 |
|
| 1076 |
.desktop-mode-upload-hud__list { |
| 1077 |
display: flex; |
| 1078 |
flex-direction: column; |
| 1079 |
gap: 10px; |
| 1080 |
padding: 10px 12px; |
| 1081 |
max-height: 50vh; |
| 1082 |
overflow-y: auto; |
| 1083 |
} |
| 1084 |
|
| 1085 |
.desktop-mode-upload-hud__row { |
| 1086 |
display: grid; |
| 1087 |
grid-template-columns: 1fr auto; |
| 1088 |
grid-template-areas: |
| 1089 |
'meta actions' |
| 1090 |
'bar bar'; |
| 1091 |
gap: 6px 8px; |
| 1092 |
align-items: center; |
| 1093 |
font-size: 12px; |
| 1094 |
} |
| 1095 |
|
| 1096 |
.desktop-mode-upload-hud__meta { |
| 1097 |
grid-area: meta; |
| 1098 |
min-width: 0; |
| 1099 |
display: flex; |
| 1100 |
flex-direction: column; |
| 1101 |
gap: 2px; |
| 1102 |
} |
| 1103 |
|
| 1104 |
.desktop-mode-upload-hud__name { |
| 1105 |
overflow: hidden; |
| 1106 |
text-overflow: ellipsis; |
| 1107 |
white-space: nowrap; |
| 1108 |
font-weight: 500; |
| 1109 |
} |
| 1110 |
|
| 1111 |
.desktop-mode-upload-hud__status { |
| 1112 |
font-size: 11px; |
| 1113 |
opacity: 0.75; |
| 1114 |
font-variant-numeric: tabular-nums; |
| 1115 |
} |
| 1116 |
|
| 1117 |
.desktop-mode-upload-hud__row wpd-progress-bar { |
| 1118 |
grid-area: bar; |
| 1119 |
} |
| 1120 |
|
| 1121 |
.desktop-mode-upload-hud__actions { |
| 1122 |
grid-area: actions; |
| 1123 |
display: inline-flex; |
| 1124 |
gap: 4px; |
| 1125 |
} |
| 1126 |
|