1/* plyr.fm design tokens */ 2:root { 3 --accent: #6a9fff; 4 --accent-hover: #8ab3ff; 5 --accent-muted: #4a7ddd; 6 7 --bg-primary: #0a0a0a; 8 --bg-secondary: #141414; 9 --bg-tertiary: #1a1a1a; 10 --bg-hover: #1f1f1f; 11 12 --border-subtle: #282828; 13 --border-default: #333333; 14 --border-emphasis: #444444; 15 16 --text-primary: #e8e8e8; 17 --text-secondary: #b0b0b0; 18 --text-tertiary: #808080; 19 --text-muted: #666666; 20 21 --success: #4ade80; 22 --warning: #fbbf24; 23 --error: #ef4444; 24} 25 26* { box-sizing: border-box; } 27 28body { 29 font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Code', 'Consolas', monospace; 30 background: var(--bg-primary); 31 color: var(--text-primary); 32 max-width: 900px; 33 margin: 0 auto; 34 padding: 24px; 35 line-height: 1.6; 36 -webkit-font-smoothing: antialiased; 37} 38 39h1 { 40 color: var(--text-primary); 41 font-size: 1.5rem; 42 font-weight: 600; 43 margin: 0 0 4px 0; 44} 45 46.subtitle { 47 color: var(--text-tertiary); 48 margin: 0 0 32px 0; 49 font-size: 0.9rem; 50} 51 52/* auth form */ 53.auth-section { 54 background: var(--bg-secondary); 55 border: 1px solid var(--border-subtle); 56 border-radius: 8px; 57 padding: 20px; 58 margin-bottom: 24px; 59} 60 61.auth-section input[type="password"] { 62 font-family: inherit; 63 background: var(--bg-tertiary); 64 border: 1px solid var(--border-default); 65 color: var(--text-primary); 66 padding: 10px 14px; 67 border-radius: 6px; 68 width: 280px; 69 font-size: 0.9rem; 70} 71 72.auth-section input:focus { 73 outline: none; 74 border-color: var(--accent); 75} 76 77/* buttons */ 78.btn { 79 font-family: inherit; 80 font-size: 0.85rem; 81 font-weight: 500; 82 padding: 10px 16px; 83 border-radius: 6px; 84 border: none; 85 cursor: pointer; 86 transition: all 0.15s ease; 87} 88 89.btn-primary { 90 background: var(--accent); 91 color: var(--bg-primary); 92} 93.btn-primary:hover { background: var(--accent-hover); } 94 95.btn-secondary { 96 background: var(--bg-tertiary); 97 color: var(--text-secondary); 98 border: 1px solid var(--border-default); 99} 100.btn-secondary:hover { 101 background: var(--bg-hover); 102 border-color: var(--border-emphasis); 103} 104 105.btn-warning { 106 background: var(--warning); 107 color: var(--bg-primary); 108} 109.btn-warning:hover { 110 background: #d97706; 111} 112 113.btn:disabled { 114 background: var(--bg-tertiary); 115 color: var(--text-muted); 116 cursor: not-allowed; 117 border: 1px solid var(--border-subtle); 118} 119 120/* header row */ 121.header-row { 122 display: flex; 123 align-items: center; 124 justify-content: space-between; 125 margin-bottom: 20px; 126} 127 128/* filter controls */ 129.filter-row { 130 display: flex; 131 align-items: center; 132 gap: 8px; 133 margin-bottom: 16px; 134 padding-bottom: 16px; 135 border-bottom: 1px solid var(--border-subtle); 136} 137 138.filter-label { 139 color: var(--text-tertiary); 140 font-size: 0.85rem; 141 margin-right: 4px; 142} 143 144.filter-btn { 145 font-family: inherit; 146 font-size: 0.8rem; 147 padding: 6px 12px; 148 border-radius: 4px; 149 border: 1px solid var(--border-default); 150 background: var(--bg-tertiary); 151 color: var(--text-secondary); 152 cursor: pointer; 153 transition: all 0.15s ease; 154} 155 156.filter-btn:hover { 157 background: var(--bg-hover); 158 border-color: var(--border-emphasis); 159 color: var(--text-primary); 160} 161 162.filter-btn.active { 163 background: var(--accent); 164 color: var(--bg-primary); 165 border-color: var(--accent); 166} 167 168.filter-count { 169 margin-left: auto; 170 color: var(--text-tertiary); 171 font-size: 0.85rem; 172} 173 174.header-row h2 { 175 margin: 0; 176 font-size: 1.1rem; 177 font-weight: 500; 178 color: var(--text-primary); 179} 180 181/* flags list */ 182.flags-list { 183 display: flex; 184 flex-direction: column; 185 gap: 16px; 186} 187 188.flag-card { 189 background: var(--bg-secondary); 190 border: 1px solid var(--border-subtle); 191 border-radius: 8px; 192 padding: 20px; 193} 194 195.flag-card.resolved { 196 opacity: 0.5; 197} 198 199.flag-header { 200 display: flex; 201 justify-content: space-between; 202 align-items: flex-start; 203 gap: 16px; 204} 205 206.track-info { 207 flex: 1; 208 min-width: 0; 209} 210 211.track-info h3 { 212 margin: 0 0 4px 0; 213 font-size: 1rem; 214 font-weight: 500; 215 color: var(--text-primary); 216} 217 218.track-info h3 a { 219 color: var(--text-primary); 220 text-decoration: none; 221} 222 223.track-info h3 a:hover { 224 color: var(--accent); 225 text-decoration: underline; 226} 227 228.track-info .artist { 229 color: var(--text-secondary); 230 font-size: 0.9rem; 231} 232 233.track-info .artist a { 234 color: var(--accent); 235 text-decoration: none; 236} 237 238.track-info .artist a:hover { 239 text-decoration: underline; 240} 241 242.track-info .uri { 243 font-size: 0.75rem; 244 color: var(--text-muted); 245 word-break: break-all; 246 margin-top: 8px; 247} 248 249.flag-badges { 250 display: flex; 251 flex-direction: column; 252 align-items: flex-end; 253 gap: 6px; 254 flex-shrink: 0; 255} 256 257.badge { 258 display: inline-block; 259 padding: 4px 10px; 260 border-radius: 4px; 261 font-size: 0.75rem; 262 font-weight: 500; 263} 264 265.badge.pending { 266 background: rgba(251, 191, 36, 0.15); 267 color: var(--warning); 268} 269 270.badge.resolved { 271 background: rgba(74, 222, 128, 0.15); 272 color: var(--success); 273} 274 275.badge.matches { 276 background: rgba(106, 159, 255, 0.15); 277 color: var(--accent); 278} 279 280.badge.env { 281 background: rgba(139, 92, 246, 0.15); 282 color: #a78bfa; 283 text-transform: uppercase; 284 letter-spacing: 0.5px; 285} 286 287/* matches section */ 288.matches { 289 background: var(--bg-primary); 290 border-radius: 6px; 291 padding: 14px; 292 margin-top: 16px; 293} 294 295.matches h4 { 296 margin: 0 0 10px 0; 297 color: var(--text-tertiary); 298 font-size: 0.8rem; 299 font-weight: 500; 300 text-transform: lowercase; 301} 302 303.match-item { 304 display: flex; 305 justify-content: space-between; 306 align-items: center; 307 padding: 8px 0; 308 border-bottom: 1px solid var(--border-subtle); 309 font-size: 0.85rem; 310} 311 312.match-item:last-child { border-bottom: none; } 313 314.match-item .title { 315 color: var(--text-primary); 316} 317 318.match-item .artist { 319 color: var(--text-tertiary); 320} 321 322/* actions */ 323.flag-actions { 324 display: flex; 325 justify-content: flex-end; 326 gap: 10px; 327 margin-top: 16px; 328 padding-top: 16px; 329 border-top: 1px solid var(--border-subtle); 330} 331 332/* resolution info display */ 333.resolution-info { 334 display: flex; 335 flex-direction: column; 336 gap: 8px; 337 width: 100%; 338} 339 340.resolution-reason { 341 color: var(--success); 342 font-size: 0.85rem; 343 font-weight: 500; 344 text-align: right; 345} 346 347.resolution-notes { 348 background: var(--bg-primary); 349 border: 1px solid var(--border-subtle); 350 border-radius: 6px; 351 padding: 12px 14px; 352 font-size: 0.8rem; 353 color: var(--text-secondary); 354 line-height: 1.5; 355 width: 100%; 356 text-align: left; 357} 358 359/* multi-step resolve flow */ 360.resolve-flow { 361 display: flex; 362 gap: 8px; 363 align-items: center; 364} 365 366/* reason selection (step 2) */ 367.reason-select { 368 display: flex; 369 gap: 6px; 370 flex-wrap: wrap; 371 align-items: center; 372} 373 374.reason-btn { 375 font-family: inherit; 376 font-size: 0.8rem; 377 padding: 6px 12px; 378 border-radius: 4px; 379 border: 1px solid var(--border-default); 380 background: var(--bg-tertiary); 381 color: var(--text-secondary); 382 cursor: pointer; 383 transition: all 0.15s ease; 384} 385 386.reason-btn:hover { 387 background: var(--bg-hover); 388 border-color: var(--border-emphasis); 389 color: var(--text-primary); 390} 391 392.reason-btn.selected { 393 background: var(--warning); 394 color: var(--bg-primary); 395 border-color: var(--warning); 396} 397 398.reason-btn.cancel { 399 background: transparent; 400 border-color: var(--border-subtle); 401 color: var(--text-muted); 402} 403 404.reason-btn.cancel:hover { 405 border-color: var(--error); 406 color: var(--error); 407} 408 409/* confirm step (step 3) */ 410.confirm-step { 411 display: flex; 412 gap: 8px; 413 align-items: center; 414} 415 416.confirm-text { 417 color: var(--text-secondary); 418 font-size: 0.85rem; 419} 420 421.confirm-text strong { 422 color: var(--warning); 423} 424 425.btn-confirm { 426 background: var(--error); 427 color: white; 428} 429 430.btn-confirm:hover { 431 background: #dc2626; 432} 433 434/* states */ 435.empty, .loading { 436 color: var(--text-muted); 437 text-align: center; 438 padding: 48px 24px; 439} 440 441.no-context { 442 color: var(--text-muted); 443 font-style: italic; 444} 445 446/* toast */ 447.toast { 448 position: fixed; 449 bottom: 24px; 450 left: 24px; 451 padding: 12px 20px; 452 border-radius: 6px; 453 font-size: 0.85rem; 454 animation: fadeInUp 0.2s ease, fadeOut 0.3s ease 2.7s forwards; 455} 456 457.toast.success { 458 background: rgba(74, 222, 128, 0.15); 459 color: var(--success); 460 border: 1px solid rgba(74, 222, 128, 0.3); 461} 462 463.toast.error { 464 background: rgba(239, 68, 68, 0.15); 465 color: var(--error); 466 border: 1px solid rgba(239, 68, 68, 0.3); 467} 468 469@keyframes fadeInUp { 470 from { opacity: 0; transform: translateY(10px); } 471 to { opacity: 1; transform: translateY(0); } 472} 473 474@keyframes fadeOut { 475 to { opacity: 0; } 476} 477 478/* htmx indicator */ 479.htmx-indicator { 480 opacity: 0; 481 transition: opacity 0.2s ease; 482} 483.htmx-request .htmx-indicator { 484 opacity: 1; 485} 486.htmx-request.htmx-indicator { 487 opacity: 1; 488} 489 490/* refresh button with inline indicator */ 491.btn-secondary .htmx-indicator { 492 display: none; 493 margin-right: 6px; 494} 495.btn-secondary.htmx-request .htmx-indicator { 496 display: inline; 497} 498 499/* mobile */ 500@media (max-width: 640px) { 501 body { padding: 16px; } 502 .auth-section input[type="password"] { width: 100%; margin-bottom: 12px; } 503 .flag-header { flex-direction: column; } 504 .flag-badges { margin-top: 12px; } 505}