Zero-copy FTP/HTTP Daemon compatible with all POSIX systems
| 1 | /* ══ BUTTONS ══════════════════════════════════════════════════════════════ */ |
| 2 | |
| 3 | .btn { |
| 4 | display: flex; |
| 5 | align-items: center; |
| 6 | gap: 5px; |
| 7 | border: 1px solid var(--bd2); |
| 8 | background: var(--sf2); |
| 9 | color: var(--tx2); |
| 10 | border-radius: 7px; |
| 11 | padding: 6px 11px; |
| 12 | font-size: 11px; |
| 13 | font-weight: 600; |
| 14 | cursor: pointer; |
| 15 | transition: border-color var(--transition-fast), background var(--transition-fast), color var(--transition-fast), transform .1s; |
| 16 | white-space: nowrap; |
| 17 | } |
| 18 | |
| 19 | .btn:hover { |
| 20 | border-color: var(--ac); |
| 21 | background: var(--sf3); |
| 22 | color: var(--tx); |
| 23 | } |
| 24 | |
| 25 | .btn:active { |
| 26 | transform: translateY(1px); |
| 27 | } |
| 28 | |
| 29 | .btn.primary { |
| 30 | background: var(--ac); |
| 31 | color: #fff; |
| 32 | border-color: var(--ac); |
| 33 | } |
| 34 | |
| 35 | .btn.primary:hover { |
| 36 | filter: brightness(1.15); |
| 37 | box-shadow: var(--glow-sm); |
| 38 | } |
| 39 | |
| 40 | .btn.danger { |
| 41 | color: var(--er); |
| 42 | border-color: rgba(255, 95, 87, .3); |
| 43 | } |
| 44 | |
| 45 | .btn.danger:hover { |
| 46 | background: rgba(255, 95, 87, .12); |
| 47 | border-color: var(--er); |
| 48 | } |
| 49 | |
| 50 | /* ══ VIEW TOGGLE GROUP ════════════════════════════════════════════════════ */ |
| 51 | |
| 52 | .vg { |
| 53 | display: flex; |
| 54 | align-items: center; |
| 55 | border: 1px solid var(--bd2); |
| 56 | border-radius: 7px; |
| 57 | overflow: hidden; |
| 58 | } |
| 59 | |
| 60 | .vg .vb { |
| 61 | background: var(--sf2); |
| 62 | color: var(--tx3); |
| 63 | border: none; |
| 64 | padding: 6px 10px; |
| 65 | cursor: pointer; |
| 66 | transition: background .1s, color .1s; |
| 67 | line-height: 1; |
| 68 | border-right: 1px solid var(--bd); |
| 69 | display: flex; |
| 70 | align-items: center; |
| 71 | justify-content: center; |
| 72 | } |
| 73 | |
| 74 | .vg .vb:last-child { border-right: none; } |
| 75 | .vg .vb:hover { background: var(--sf3); color: var(--tx); } |
| 76 | .vg .vb.active { background: var(--gw); color: var(--ac); } |
| 77 | |
| 78 | /* ══ STATUS PILL ══════════════════════════════════════════════════════════ */ |
| 79 | |
| 80 | .status-pill { |
| 81 | display: flex; |
| 82 | align-items: center; |
| 83 | gap: 6px; |
| 84 | font-size: 11px; |
| 85 | font-weight: 600; |
| 86 | padding: 5px 11px; |
| 87 | border-radius: var(--radius-pill); |
| 88 | border: 1px solid var(--bd2); |
| 89 | background: var(--sf2); |
| 90 | transition: color .2s; |
| 91 | white-space: nowrap; |
| 92 | } |
| 93 | |
| 94 | .sdot { |
| 95 | width: 6px; |
| 96 | height: 6px; |
| 97 | border-radius: 50%; |
| 98 | flex-shrink: 0; |
| 99 | background: var(--tx3); |
| 100 | transition: all .2s; |
| 101 | } |
| 102 | |
| 103 | .status-ok .sdot { background: var(--ok); box-shadow: 0 0 7px var(--ok); animation: statusPulse 2s infinite; } |
| 104 | .status-bad .sdot { background: var(--er); box-shadow: 0 0 7px var(--er); animation: statusPulse 2s infinite; } |
| 105 | .status-ok { color: var(--ok); } |
| 106 | .status-bad { color: var(--er); } |
| 107 | |
| 108 | @keyframes statusPulse { |
| 109 | 0%, 100% { box-shadow: 0 0 4px currentColor; } |
| 110 | 50% { box-shadow: 0 0 12px currentColor, 0 0 4px currentColor; } |
| 111 | } |
| 112 | |
| 113 | /* ══ SEARCH ═══════════════════════════════════════════════════════════════ */ |
| 114 | |
| 115 | .search-wrap { |
| 116 | position: relative; |
| 117 | display: flex; |
| 118 | align-items: center; |
| 119 | } |
| 120 | |
| 121 | .search-ico { |
| 122 | position: absolute; |
| 123 | left: 9px; |
| 124 | pointer-events: none; |
| 125 | color: var(--tx3); |
| 126 | } |
| 127 | |
| 128 | .search { |
| 129 | width: 260px; |
| 130 | max-width: 48vw; |
| 131 | border: 1px solid var(--bd2); |
| 132 | background: var(--bg); |
| 133 | color: var(--tx); |
| 134 | border-radius: 7px; |
| 135 | padding: 6px 10px 6px 30px; |
| 136 | font-size: 11px; |
| 137 | font-family: inherit; |
| 138 | outline: none; |
| 139 | transition: border-color var(--transition-fast); |
| 140 | } |
| 141 | |
| 142 | .search:focus { border-color: var(--ac); } |
| 143 | .search::placeholder { color: var(--tx3); } |
| 144 | |
| 145 | /* ══ BADGES ═══════════════════════════════════════════════════════════════ */ |
| 146 | |
| 147 | .xb { |
| 148 | display: inline-flex; |
| 149 | align-items: center; |
| 150 | padding: 1px 6px; |
| 151 | border-radius: 4px; |
| 152 | font-size: 9px; |
| 153 | font-weight: 700; |
| 154 | letter-spacing: .04em; |
| 155 | text-transform: uppercase; |
| 156 | border: 1px solid var(--tgb); |
| 157 | background: var(--tg); |
| 158 | color: var(--ac); |
| 159 | white-space: nowrap; |
| 160 | flex-shrink: 0; |
| 161 | line-height: 1.7; |
| 162 | } |
| 163 | |
| 164 | .sb { |
| 165 | font-size: 10px; |
| 166 | color: var(--tx2); |
| 167 | white-space: nowrap; |
| 168 | flex-shrink: 0; |
| 169 | font-weight: 500; |
| 170 | } |
| 171 | |
| 172 | .db { |
| 173 | font-size: 10px; |
| 174 | color: var(--tx3); |
| 175 | white-space: nowrap; |
| 176 | flex-shrink: 0; |
| 177 | } |
| 178 | |
| 179 | /* ══ TOAST ════════════════════════════════════════════════════════════════ */ |
| 180 | |
| 181 | .toast-wrap { |
| 182 | position: fixed; |
| 183 | bottom: 20px; |
| 184 | right: 20px; |
| 185 | z-index: 9000; |
| 186 | display: flex; |
| 187 | flex-direction: column; |
| 188 | gap: 8px; |
| 189 | pointer-events: none; |
| 190 | } |
| 191 | |
| 192 | .toast { |
| 193 | pointer-events: auto; |
| 194 | display: flex; |
| 195 | align-items: center; |
| 196 | gap: 8px; |
| 197 | padding: 9px 14px; |
| 198 | border-radius: 10px; |
| 199 | background: var(--glass); |
| 200 | backdrop-filter: blur(var(--glass-blur, 12px)); |
| 201 | -webkit-backdrop-filter: blur(var(--glass-blur, 12px)); |
| 202 | border: 1px solid var(--bd2); |
| 203 | font-size: 11px; |
| 204 | font-weight: 600; |
| 205 | box-shadow: 0 8px 32px var(--shadow); |
| 206 | animation: slideUp .2s ease; |
| 207 | max-width: 300px; |
| 208 | } |
| 209 | |
| 210 | .toast.ok { border-color: var(--ok); color: var(--ok); } |
| 211 | .toast.er { border-color: var(--er); color: var(--er); } |
| 212 | .toast.wn { border-color: var(--wn); color: var(--wn); } |
| 213 | |
| 214 | /* ══ GLASS CARD ═══════════════════════════════════════════════════════════ */ |
| 215 | |
| 216 | .glass-card { |
| 217 | background: var(--glass); |
| 218 | backdrop-filter: blur(var(--glass-blur, 12px)); |
| 219 | -webkit-backdrop-filter: blur(var(--glass-blur, 12px)); |
| 220 | border: 1px solid var(--glass-border); |
| 221 | border-radius: var(--radius-md); |
| 222 | padding: 16px; |
| 223 | box-shadow: var(--card-shadow); |
| 224 | } |
| 225 | |
| 226 | /* ══ MODAL OVERLAY ════════════════════════════════════════════════════════ */ |
| 227 | |
| 228 | .modal-overlay { |
| 229 | position: fixed; |
| 230 | inset: 0; |
| 231 | z-index: 5000; |
| 232 | background: rgba(0, 0, 0, .72); |
| 233 | backdrop-filter: blur(6px); |
| 234 | display: flex; |
| 235 | align-items: center; |
| 236 | justify-content: center; |
| 237 | opacity: 0; |
| 238 | pointer-events: none; |
| 239 | transition: opacity .28s ease; |
| 240 | } |
| 241 | |
| 242 | .modal-overlay.on { |
| 243 | opacity: 1; |
| 244 | pointer-events: auto; |
| 245 | } |
| 246 | |
| 247 | .modal-panel { |
| 248 | width: min(560px, 92vw); |
| 249 | max-height: 80vh; |
| 250 | display: flex; |
| 251 | flex-direction: column; |
| 252 | background: var(--sf); |
| 253 | border: 1px solid var(--bd2); |
| 254 | border-radius: var(--radius-lg); |
| 255 | box-shadow: 0 28px 80px var(--shadow); |
| 256 | overflow: hidden; |
| 257 | transform: translateY(20px); |
| 258 | opacity: 0; |
| 259 | transition: transform var(--transition-slow), opacity .28s ease; |
| 260 | } |
| 261 | |
| 262 | .modal-overlay.on .modal-panel { |
| 263 | transform: translateY(0); |
| 264 | opacity: 1; |
| 265 | } |
| 266 | |
| 267 | .modal-header { |
| 268 | display: flex; |
| 269 | align-items: center; |
| 270 | gap: 10px; |
| 271 | padding: 14px 18px; |
| 272 | border-bottom: 1px solid var(--bd); |
| 273 | font-size: 14px; |
| 274 | font-weight: 700; |
| 275 | color: var(--ac); |
| 276 | } |
| 277 | |
| 278 | .modal-close { |
| 279 | margin-left: auto; |
| 280 | background: none; |
| 281 | border: none; |
| 282 | color: var(--tx3); |
| 283 | cursor: pointer; |
| 284 | font-size: 18px; |
| 285 | line-height: 1; |
| 286 | padding: 4px; |
| 287 | } |
| 288 | |
| 289 | .modal-close:hover { color: var(--er); } |
| 290 | |
| 291 | .modal-body { |
| 292 | flex: 1; |
| 293 | overflow-y: auto; |
| 294 | padding: 16px 18px; |
| 295 | } |
| 296 | |
| 297 | .modal-footer { |
| 298 | display: flex; |
| 299 | align-items: center; |
| 300 | justify-content: flex-end; |
| 301 | gap: 8px; |
| 302 | padding: 12px 18px; |
| 303 | border-top: 1px solid var(--bd); |
| 304 | } |
| 305 | |
| 306 | /* ══ TOPBAR DOWNLOAD PILL ════════════════════════════════════════════════ */ |
| 307 | |
| 308 | .tb-dl-pill { |
| 309 | display: flex; |
| 310 | align-items: center; |
| 311 | gap: 6px; |
| 312 | font-size: 11px; |
| 313 | font-weight: 600; |
| 314 | padding: 5px 11px; |
| 315 | border-radius: var(--radius-pill); |
| 316 | border: 1px solid rgba(var(--acR), .35); |
| 317 | background: var(--tg); |
| 318 | color: var(--ac); |
| 319 | cursor: pointer; |
| 320 | transition: all .15s; |
| 321 | white-space: nowrap; |
| 322 | } |
| 323 | .tb-dl-pill:hover { border-color: var(--ac); background: rgba(var(--acR), .15); } |
| 324 | |
| 325 | .tb-dl-bar { |
| 326 | width: 40px; |
| 327 | height: 4px; |
| 328 | border-radius: 2px; |
| 329 | background: var(--bd); |
| 330 | overflow: hidden; |
| 331 | } |
| 332 | .tb-dl-bar-fill { |
| 333 | height: 100%; |
| 334 | width: 0%; |
| 335 | border-radius: 2px; |
| 336 | background: var(--ac); |
| 337 | transition: width .3s ease; |
| 338 | } |
| 339 | |
| 340 | /* ══ NOTIFICATION BELL ═══════════════════════════════════════════════════ */ |
| 341 | |
| 342 | .tb-notif-btn { |
| 343 | position: relative; |
| 344 | display: flex; |
| 345 | align-items: center; |
| 346 | justify-content: center; |
| 347 | width: 32px; |
| 348 | height: 32px; |
| 349 | border: 1px solid var(--bd2); |
| 350 | background: var(--sf2); |
| 351 | border-radius: 8px; |
| 352 | color: var(--tx2); |
| 353 | cursor: pointer; |
| 354 | transition: all .15s; |
| 355 | } |
| 356 | .tb-notif-btn:hover { border-color: var(--ac); color: var(--tx); } |
| 357 | |
| 358 | .tb-notif-badge { |
| 359 | position: absolute; |
| 360 | top: -4px; |
| 361 | right: -4px; |
| 362 | min-width: 16px; |
| 363 | height: 16px; |
| 364 | border-radius: 8px; |
| 365 | background: var(--er); |
| 366 | color: #fff; |
| 367 | font-size: 9px; |
| 368 | font-weight: 700; |
| 369 | display: flex; |
| 370 | align-items: center; |
| 371 | justify-content: center; |
| 372 | padding: 0 4px; |
| 373 | line-height: 1; |
| 374 | } |
| 375 | |
| 376 | .tb-notif-dd { |
| 377 | position: absolute; |
| 378 | top: calc(100% + 8px); |
| 379 | right: 0; |
| 380 | width: 320px; |
| 381 | max-height: 380px; |
| 382 | background: var(--sf); |
| 383 | border: 1px solid var(--bd2); |
| 384 | border-radius: 14px; |
| 385 | box-shadow: 0 24px 64px rgba(0,0,0,.6); |
| 386 | display: none; |
| 387 | z-index: 600; |
| 388 | animation: popIn .15s ease; |
| 389 | overflow: hidden; |
| 390 | } |
| 391 | .tb-notif-dd.show { display: block; } |
| 392 | |
| 393 | .tb-notif-list { |
| 394 | max-height: 340px; |
| 395 | overflow-y: auto; |
| 396 | padding: 4px 8px 8px; |
| 397 | } |
| 398 | |
| 399 | .tb-notif-empty { |
| 400 | text-align: center; |
| 401 | color: var(--tx3); |
| 402 | font-size: 11px; |
| 403 | padding: 24px 0; |
| 404 | } |
| 405 | |
| 406 | .tb-notif-item { |
| 407 | display: flex; |
| 408 | align-items: flex-start; |
| 409 | gap: 8px; |
| 410 | padding: 8px 10px; |
| 411 | border-radius: 8px; |
| 412 | cursor: default; |
| 413 | transition: background .1s; |
| 414 | } |
| 415 | .tb-notif-item:hover { background: var(--sf2); } |
| 416 | .tb-notif-item .ni-ico { flex-shrink: 0; color: var(--ac); margin-top: 2px; } |
| 417 | .tb-notif-item .ni-ico.ok { color: var(--ok); } |
| 418 | .tb-notif-item .ni-ico.er { color: var(--er); } |
| 419 | .tb-notif-item .ni-ico.wn { color: var(--wn); } |
| 420 | .tb-notif-item .ni-body { flex: 1; min-width: 0; } |
| 421 | .tb-notif-item .ni-title { font-size: 11px; font-weight: 600; color: var(--tx); } |
| 422 | .tb-notif-item .ni-desc { font-size: 10px; color: var(--tx3); margin-top: 1px; word-break: break-word; } |
| 423 | .tb-notif-item .ni-time { font-size: 9px; color: var(--tx3); flex-shrink: 0; margin-top: 2px; } |
| 424 | |
| 425 | /* ══ TRANSFER LOCK MODAL ═════════════════════════════════════════════════ |
| 426 | * ┌─────────────────────────────┐ |
| 427 | * │ ⬆ UPLOADING... 18 MB/s │ |
| 428 | * │ filename.pkg 44% │ |
| 429 | * │ → /data │ |
| 430 | * │ ████████░░░░░░░░░░░░ 17s │ |
| 431 | * │ [ Pause ] [ Cancel ] │ |
| 432 | * └─────────────────────────────┘ |
| 433 | * ════════════════════════════════════════════════════════════════════════ */ |
| 434 | |
| 435 | .xfer-lock-overlay { |
| 436 | position: fixed; |
| 437 | inset: 0; |
| 438 | z-index: 6000; |
| 439 | background: rgba(0, 0, 0, .5); |
| 440 | backdrop-filter: blur(4px); |
| 441 | display: flex; |
| 442 | align-items: flex-end; |
| 443 | justify-content: flex-end; |
| 444 | padding: 24px; |
| 445 | opacity: 0; |
| 446 | pointer-events: none; |
| 447 | transition: opacity .25s ease; |
| 448 | } |
| 449 | .xfer-lock-overlay.on { opacity: 1; pointer-events: auto; } |
| 450 | |
| 451 | .xfer-lock-card { |
| 452 | width: min(380px, 90vw); |
| 453 | background: var(--sf); |
| 454 | border: 1px solid var(--bd2); |
| 455 | border-radius: var(--radius-md); |
| 456 | box-shadow: 0 16px 48px rgba(0,0,0,.5); |
| 457 | overflow: hidden; |
| 458 | transform: translateY(20px); |
| 459 | opacity: 0; |
| 460 | transition: transform .3s cubic-bezier(.22,1,.36,1), opacity .25s ease; |
| 461 | } |
| 462 | .xfer-lock-overlay.on .xfer-lock-card { |
| 463 | transform: translateY(0); |
| 464 | opacity: 1; |
| 465 | } |
| 466 | |
| 467 | .xfer-lock-header { |
| 468 | display: flex; |
| 469 | align-items: center; |
| 470 | justify-content: space-between; |
| 471 | padding: 12px 16px; |
| 472 | font-size: 10px; |
| 473 | font-weight: 700; |
| 474 | text-transform: uppercase; |
| 475 | letter-spacing: .06em; |
| 476 | color: var(--ac); |
| 477 | } |
| 478 | .xfer-lock-speed { color: var(--tx2); font-weight: 600; } |
| 479 | .xfer-lock-time { color: var(--tx3); font-size: 10px; } |
| 480 | .xfer-lock-pct { color: var(--ok); font-weight: 700; font-size: 11px; } |
| 481 | |
| 482 | .xfer-lock-body { padding: 0 16px 10px; } |
| 483 | .xfer-lock-filename { |
| 484 | font-size: 12px; |
| 485 | font-weight: 600; |
| 486 | color: var(--tx); |
| 487 | white-space: nowrap; |
| 488 | overflow: hidden; |
| 489 | text-overflow: ellipsis; |
| 490 | } |
| 491 | .xfer-lock-dest { |
| 492 | font-size: 10px; |
| 493 | color: var(--tx3); |
| 494 | margin-top: 2px; |
| 495 | } |
| 496 | .xfer-lock-dest::before { content: "→ "; color: var(--ac); } |
| 497 | |
| 498 | .xfer-lock-bar { |
| 499 | width: 100%; |
| 500 | height: 4px; |
| 501 | border-radius: 2px; |
| 502 | background: var(--bd); |
| 503 | margin-top: 8px; |
| 504 | overflow: hidden; |
| 505 | } |
| 506 | .xfer-lock-bar-fill { |
| 507 | height: 100%; |
| 508 | width: 0%; |
| 509 | border-radius: 2px; |
| 510 | background: var(--ac); |
| 511 | transition: width .3s ease; |
| 512 | } |
| 513 | |
| 514 | .xfer-lock-footer { |
| 515 | display: flex; |
| 516 | align-items: center; |
| 517 | justify-content: center; |
| 518 | gap: 10px; |
| 519 | padding: 10px 16px 14px; |
| 520 | } |
| 521 | .xfer-lock-footer .btn { font-size: 11px; padding: 6px 16px; border-radius: 8px; } |
| 522 | |
| 523 | /* ══ LIGHT THEME REFINEMENTS ═════════════════════════════════════════════ */ |
| 524 | |
| 525 | [data-theme="cloud"] .topbar { box-shadow: 0 1px 3px rgba(0,0,0,.06); } |
| 526 | [data-theme="cloud"] .nav-tabs { box-shadow: 0 1px 2px rgba(0,0,0,.04); } |
| 527 | [data-theme="cloud"] .toast { box-shadow: 0 8px 24px rgba(0,0,0,.1); } |
| 528 | [data-theme="cloud"] .theme-dd { box-shadow: 0 16px 48px rgba(0,0,0,.12); } |
| 529 | [data-theme="cloud"] .tb-notif-dd { box-shadow: 0 16px 48px rgba(0,0,0,.12); } |
| 530 | [data-theme="cloud"] .modal-overlay { background: rgba(0,0,0,.35); } |
| 531 | [data-theme="cloud"] ::-webkit-scrollbar-track { background: var(--sf2); } |
| 532 | [data-theme="cloud"] ::-webkit-scrollbar-thumb { background: var(--bd2); } |
| 533 | [data-theme="cloud"] ::-webkit-scrollbar-thumb:hover { background: var(--ac); } |
| 534 | |
| 535 |