global.css (14504B)
1 /* ============================================================ 2 Loop Benchmarking - Ship the Loop Design System 3 Built on SMUI (SpaceMolt UI) -- terminal-aesthetic, Nord-inspired 4 Font: JetBrains Mono (monospace everywhere) 5 Modes: dark (default), light (Snow Storm) 6 ============================================================ */ 7 8 /* Self-hosted JetBrains Mono (variable weight, woff2) */ 9 /* latin-ext */ 10 @font-face { 11 font-family: 'JetBrains Mono'; 12 font-style: normal; 13 font-weight: 300 700; 14 font-display: swap; 15 src: url('/fonts/jetbrains-mono-latin-ext.woff2') format('woff2'); 16 unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; 17 } 18 /* latin */ 19 @font-face { 20 font-family: 'JetBrains Mono'; 21 font-style: normal; 22 font-weight: 300 700; 23 font-display: swap; 24 src: url('/fonts/jetbrains-mono-latin.woff2') format('woff2'); 25 unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 26 } 27 28 /* ============================================================ 29 Dark mode (default) 30 ============================================================ */ 31 32 :root { 33 /* shadcn/ui base variables (raw HSL triplets for alpha support) */ 34 --background: 213 16% 12%; 35 --foreground: 213 27% 88%; 36 --card: 217 16% 15.5%; 37 --card-foreground: 213 27% 88%; 38 --popover: 217 16% 15.5%; 39 --popover-foreground: 213 27% 88%; 40 --primary: 193 44% 67%; 41 --primary-foreground: 213 16% 12%; 42 --secondary: 216 15% 19%; 43 --secondary-foreground: 213 27% 88%; 44 --muted: 216 15% 19%; 45 --muted-foreground: 213 14% 65%; 46 --destructive: 355 52% 65%; 47 --destructive-foreground: 219 28% 94%; 48 --border: 217 17% 28%; 49 --input: 217 17% 28%; 50 --ring: 193 44% 67%; 51 --radius: 0rem; 52 53 /* Chart colors */ 54 --chart-1: 193 44% 67%; 55 --chart-2: 213 32% 52%; 56 --chart-3: 92 28% 65%; 57 --chart-4: 40 71% 73%; 58 --chart-5: 311 24% 63%; 59 60 /* Frost blues */ 61 --smui-frost-1: 176 25% 65%; 62 --smui-frost-2: 193 44% 67%; 63 --smui-frost-3: 210 34% 63%; 64 --smui-frost-4: 213 32% 52%; 65 66 /* Aurora status colors */ 67 --smui-green: 92 28% 65%; 68 --smui-yellow: 40 71% 73%; 69 --smui-orange: 14 51% 63%; 70 --smui-red: 355 52% 64%; 71 --smui-purple: 311 24% 63%; 72 73 /* Surface hierarchy (Polar Night) */ 74 --smui-surface-0: 213 16% 12%; 75 --smui-surface-1: 217 16% 15.5%; 76 --smui-surface-2: 216 15% 19%; 77 --smui-surface-3: 215 14% 22%; 78 79 /* Interactive */ 80 --smui-border-hover: 216 12% 37%; 81 82 /* Typography */ 83 --font-mono: "JetBrains Mono", monospace; 84 --text-label: 11px; 85 --text-ui: 13px; 86 --text-heading: 22px; 87 --text-stat: 26px; 88 --text-hero: 42px; 89 90 /* Legacy aliases so existing components keep working. 91 Components use var(--accent) to mean "frost blue text color", 92 but SMUI uses --accent for a different semantic role. 93 These resolved-color aliases bridge the gap. */ 94 --surface-0: hsl(var(--smui-surface-0)); 95 --surface-1: hsl(var(--smui-surface-1)); 96 --surface-2: hsl(var(--smui-surface-2)); 97 --surface-3: hsl(var(--smui-surface-3)); 98 --text: hsl(var(--foreground)); 99 --text-muted: hsl(var(--muted-foreground)); 100 --border-hover: hsl(var(--smui-border-hover)); 101 /* --accent in legacy components means the frost blue accent color */ 102 --accent: hsl(var(--primary)); 103 --accent-hover: hsl(var(--primary) / 0.8); 104 --green: hsl(var(--smui-green)); 105 --yellow: hsl(var(--smui-yellow)); 106 --orange: hsl(var(--smui-orange)); 107 --red: hsl(var(--smui-red)); 108 --purple: hsl(var(--smui-purple)); 109 --bg: var(--surface-0); 110 --bg-card: var(--surface-1); 111 --bg-hover: var(--surface-2); 112 } 113 114 /* ============================================================ 115 Light mode (Snow Storm) 116 ============================================================ */ 117 118 [data-theme="light"] { 119 --background: 218 27% 94%; 120 --foreground: 220 16% 22%; 121 --card: 218 27% 89%; 122 --card-foreground: 220 16% 22%; 123 --popover: 218 27% 89%; 124 --popover-foreground: 220 16% 22%; 125 --primary: 213 32% 40%; 126 --primary-foreground: 0 0% 100%; 127 --secondary: 219 28% 84%; 128 --secondary-foreground: 220 16% 22%; 129 --muted: 219 28% 84%; 130 --muted-foreground: 220 17% 28%; 131 --destructive: 355 60% 45%; 132 --destructive-foreground: 0 0% 100%; 133 --border: 219 18% 72%; 134 --input: 219 18% 72%; 135 --ring: 213 32% 40%; 136 137 /* Chart colors (darkened for light backgrounds) */ 138 --chart-1: 213 32% 44%; 139 --chart-2: 210 34% 42%; 140 --chart-3: 92 30% 36%; 141 --chart-4: 40 70% 35%; 142 --chart-5: 311 28% 42%; 143 144 /* Frost (darkened for light backgrounds) */ 145 --smui-frost-1: 176 30% 35%; 146 --smui-frost-2: 193 40% 38%; 147 --smui-frost-3: 210 34% 40%; 148 --smui-frost-4: 213 32% 36%; 149 150 /* Aurora (darkened for light backgrounds) */ 151 --smui-green: 92 35% 34%; 152 --smui-yellow: 40 70% 34%; 153 --smui-orange: 14 55% 44%; 154 --smui-red: 355 55% 44%; 155 --smui-purple: 311 28% 40%; 156 157 /* Surface hierarchy (Snow Storm) */ 158 --smui-surface-0: 218 27% 94%; 159 --smui-surface-1: 218 27% 89%; 160 --smui-surface-2: 219 28% 84%; 161 --smui-surface-3: 219 20% 76%; 162 163 /* Interactive */ 164 --smui-border-hover: 220 17% 50%; 165 } 166 167 /* Also support prefers-color-scheme for users without explicit toggle */ 168 @media (prefers-color-scheme: light) { 169 :root:not([data-theme="dark"]):not([data-theme="light"]) { 170 --background: 218 27% 94%; 171 --foreground: 220 16% 22%; 172 --card: 218 27% 89%; 173 --card-foreground: 220 16% 22%; 174 --popover: 218 27% 89%; 175 --popover-foreground: 220 16% 22%; 176 --primary: 213 32% 40%; 177 --primary-foreground: 0 0% 100%; 178 --secondary: 219 28% 84%; 179 --secondary-foreground: 220 16% 22%; 180 --muted: 219 28% 84%; 181 --muted-foreground: 220 17% 28%; 182 --destructive: 355 60% 45%; 183 --destructive-foreground: 0 0% 100%; 184 --border: 219 18% 72%; 185 --input: 219 18% 72%; 186 --ring: 213 32% 40%; 187 --chart-1: 213 32% 44%; 188 --chart-2: 210 34% 42%; 189 --chart-3: 92 30% 36%; 190 --chart-4: 40 70% 35%; 191 --chart-5: 311 28% 42%; 192 --smui-frost-1: 176 30% 35%; 193 --smui-frost-2: 193 40% 38%; 194 --smui-frost-3: 210 34% 40%; 195 --smui-frost-4: 213 32% 36%; 196 --smui-green: 92 35% 34%; 197 --smui-yellow: 40 70% 34%; 198 --smui-orange: 14 55% 44%; 199 --smui-red: 355 55% 44%; 200 --smui-purple: 311 28% 40%; 201 --smui-surface-0: 218 27% 94%; 202 --smui-surface-1: 218 27% 89%; 203 --smui-surface-2: 219 28% 84%; 204 --smui-surface-3: 219 20% 76%; 205 --smui-border-hover: 220 17% 50%; 206 } 207 } 208 209 /* ---- Reset ---- */ 210 211 * { 212 margin: 0; 213 padding: 0; 214 box-sizing: border-box; 215 } 216 217 /* ---- Selection ---- */ 218 219 ::selection { 220 background: hsl(var(--primary) / 0.2); 221 color: hsl(var(--primary)); 222 } 223 224 /* ---- Base ---- */ 225 226 body { 227 font-family: var(--font-mono); 228 background: hsl(var(--background)); 229 color: hsl(var(--foreground)); 230 font-size: var(--text-ui); 231 line-height: 1.5; 232 -webkit-font-smoothing: antialiased; 233 -moz-osx-font-smoothing: grayscale; 234 } 235 236 a { 237 color: hsl(var(--primary)); 238 text-decoration: none; 239 transition: color 0.15s; 240 } 241 242 a:hover { 243 color: hsl(var(--primary) / 0.8); 244 text-decoration: underline; 245 } 246 247 /* ---- Layout ---- */ 248 249 .container { 250 max-width: 1400px; 251 margin: 0 auto; 252 padding: 0 24px; 253 } 254 255 /* ---- Typography ---- */ 256 257 h1, h2, h3 { 258 font-family: var(--font-mono); 259 font-weight: 600; 260 line-height: 1.3; 261 text-transform: uppercase; 262 letter-spacing: 1px; 263 } 264 265 h1 { 266 font-size: var(--text-heading); 267 } 268 269 h2 { 270 font-size: 18px; 271 letter-spacing: 0.8px; 272 } 273 274 h3 { 275 font-size: 15px; 276 letter-spacing: 0.5px; 277 } 278 279 /* ---- Cards ---- */ 280 281 .card { 282 background: hsl(var(--card)); 283 border: 1px solid hsl(var(--border)); 284 border-radius: var(--radius); 285 padding: 20px; 286 transition: border-color 0.15s; 287 } 288 289 .card:hover { 290 border-color: hsl(var(--smui-border-hover)); 291 } 292 293 /* Card glow -- SMUI standard hover effect */ 294 .card-glow { 295 transition: border-color 0.15s; 296 } 297 298 .card-glow:hover { 299 border-color: hsl(var(--smui-border-hover)); 300 } 301 302 /* ---- Badges ---- */ 303 304 .badge { 305 display: inline-block; 306 padding: 1px 6px; 307 border: 1px solid transparent; 308 border-radius: var(--radius); 309 font-size: var(--text-label); 310 font-weight: 500; 311 font-family: var(--font-mono); 312 text-transform: uppercase; 313 letter-spacing: 0.5px; 314 } 315 316 .badge-pass { 317 color: hsl(var(--smui-green)); 318 border-color: hsl(var(--smui-green) / 0.3); 319 background: transparent; 320 } 321 322 .badge-fail { 323 color: hsl(var(--smui-red)); 324 border-color: hsl(var(--smui-red) / 0.3); 325 background: transparent; 326 } 327 328 .badge-neutral { 329 color: hsl(var(--primary)); 330 border-color: hsl(var(--primary) / 0.3); 331 background: transparent; 332 } 333 334 .badge-warn { 335 color: hsl(var(--smui-yellow)); 336 border-color: hsl(var(--smui-yellow) / 0.3); 337 background: transparent; 338 } 339 340 .badge-info { 341 color: hsl(var(--smui-purple)); 342 border-color: hsl(var(--smui-purple) / 0.3); 343 background: transparent; 344 } 345 346 /* ---- Tables ---- */ 347 348 table { 349 width: 100%; 350 border-collapse: collapse; 351 font-size: var(--text-ui); 352 } 353 354 th, td { 355 padding: 8px 12px; 356 text-align: left; 357 border-bottom: 1px solid hsl(var(--border)); 358 } 359 360 th { 361 background: hsl(var(--smui-surface-2)); 362 color: hsl(var(--muted-foreground)); 363 font-weight: 500; 364 font-size: var(--text-label); 365 text-transform: uppercase; 366 letter-spacing: 1px; 367 } 368 369 tr { 370 transition: background 0.15s; 371 } 372 373 tr:hover { 374 background: hsl(var(--smui-surface-2)); 375 } 376 377 /* ---- Score cells ---- */ 378 379 .score-cell { 380 font-family: var(--font-mono); 381 font-weight: 600; 382 } 383 384 .score-high { color: hsl(var(--smui-green)); } 385 .score-mid { color: hsl(var(--smui-yellow)); } 386 .score-low { color: hsl(var(--smui-red)); } 387 388 /* ---- Form controls ---- */ 389 390 select, input { 391 font-family: var(--font-mono); 392 background: hsl(var(--card)); 393 border: 1px solid hsl(var(--input)); 394 border-radius: var(--radius); 395 color: hsl(var(--foreground)); 396 padding: 6px 10px; 397 font-size: var(--text-ui); 398 transition: border-color 0.15s; 399 } 400 401 select:hover, input:hover { 402 border-color: hsl(var(--smui-border-hover)); 403 } 404 405 select:focus, input:focus { 406 outline: none; 407 border-color: hsl(var(--ring)); 408 box-shadow: 0 0 0 2px hsl(var(--ring) / 0.25); 409 } 410 411 /* ---- Buttons ---- */ 412 413 button { 414 font-family: var(--font-mono); 415 background: hsl(var(--smui-surface-2)); 416 border: 1px solid hsl(var(--border)); 417 border-radius: var(--radius); 418 color: hsl(var(--foreground)); 419 padding: 6px 14px; 420 font-size: var(--text-ui); 421 font-weight: 500; 422 text-transform: uppercase; 423 letter-spacing: 0.5px; 424 cursor: pointer; 425 transition: border-color 0.15s, background 0.15s; 426 } 427 428 button:hover { 429 border-color: hsl(var(--smui-border-hover)); 430 background: hsl(var(--smui-surface-3)); 431 } 432 433 button:focus { 434 outline: none; 435 box-shadow: 0 0 0 2px hsl(var(--ring) / 0.25); 436 } 437 438 /* ---- Filters ---- */ 439 440 .filters { 441 display: flex; 442 flex-wrap: wrap; 443 gap: 12px; 444 margin-bottom: 24px; 445 } 446 447 .filter-group { 448 display: flex; 449 flex-direction: column; 450 gap: 4px; 451 } 452 453 .filter-group label { 454 font-size: var(--text-label); 455 color: hsl(var(--muted-foreground)); 456 text-transform: uppercase; 457 letter-spacing: 1px; 458 font-weight: 500; 459 } 460 461 /* ---- Stats grid ---- */ 462 463 .stats-grid { 464 display: grid; 465 grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); 466 gap: 16px; 467 margin-bottom: 24px; 468 } 469 470 .stat-card { 471 background: hsl(var(--card)); 472 border: 1px solid hsl(var(--border)); 473 border-radius: var(--radius); 474 padding: 16px; 475 text-align: center; 476 transition: border-color 0.15s; 477 } 478 479 .stat-card:hover { 480 border-color: hsl(var(--smui-border-hover)); 481 } 482 483 .stat-value { 484 font-size: var(--text-stat); 485 font-weight: 700; 486 font-family: var(--font-mono); 487 color: hsl(var(--foreground)); 488 letter-spacing: -0.5px; 489 } 490 491 .stat-label { 492 font-size: var(--text-label); 493 color: hsl(var(--muted-foreground)); 494 text-transform: uppercase; 495 letter-spacing: 1.5px; 496 font-weight: 500; 497 margin-top: 4px; 498 } 499 500 /* ---- Status dots ---- */ 501 502 .status-dot { 503 display: inline-block; 504 width: 5px; 505 height: 5px; 506 border-radius: 9999px; 507 } 508 509 .status-dot-green { background: hsl(var(--smui-green)); } 510 .status-dot-yellow { background: hsl(var(--smui-yellow)); } 511 .status-dot-orange { background: hsl(var(--smui-orange)); } 512 .status-dot-red { background: hsl(var(--smui-red)); } 513 .status-dot-purple { background: hsl(var(--smui-purple)); } 514 515 /* ---- Keyboard shortcuts ---- */ 516 517 kbd { 518 font-family: var(--font-mono); 519 font-size: var(--text-label); 520 color: hsl(var(--muted-foreground)); 521 border: 1px solid hsl(var(--border)); 522 padding: 1px 4px; 523 background: hsl(var(--background)); 524 } 525 526 /* ---- Alerts ---- */ 527 528 .alert { 529 border: 1px solid hsl(var(--border)); 530 border-radius: var(--radius); 531 padding: 12px 16px; 532 font-size: var(--text-ui); 533 } 534 535 .alert-info { 536 border-color: hsl(var(--smui-frost-2) / 0.25); 537 background: hsl(var(--smui-frost-2) / 0.04); 538 color: hsl(var(--smui-frost-2)); 539 } 540 541 .alert-success { 542 border-color: hsl(var(--smui-green) / 0.25); 543 background: hsl(var(--smui-green) / 0.04); 544 color: hsl(var(--smui-green)); 545 } 546 547 .alert-warning { 548 border-color: hsl(var(--smui-yellow) / 0.25); 549 background: hsl(var(--smui-yellow) / 0.04); 550 color: hsl(var(--smui-yellow)); 551 } 552 553 .alert-error { 554 border-color: hsl(var(--smui-red) / 0.25); 555 background: hsl(var(--smui-red) / 0.04); 556 color: hsl(var(--smui-red)); 557 } 558 559 /* ---- Skeleton shimmer ---- */ 560 561 @keyframes shimmer { 562 0% { background-position: 200% 0; } 563 100% { background-position: -200% 0; } 564 } 565 566 .skeleton { 567 background: linear-gradient(90deg, 568 hsl(var(--smui-surface-2)) 25%, 569 hsl(var(--smui-surface-3)) 50%, 570 hsl(var(--smui-surface-2)) 75%); 571 background-size: 200% 100%; 572 animation: shimmer 1.5s infinite; 573 } 574 575 /* ---- Theme toggle button ---- */ 576 577 .theme-toggle { 578 display: inline-flex; 579 align-items: center; 580 justify-content: center; 581 width: 32px; 582 height: 32px; 583 padding: 0; 584 background: transparent; 585 border: 1px solid hsl(var(--border)); 586 border-radius: var(--radius); 587 color: hsl(var(--muted-foreground)); 588 cursor: pointer; 589 transition: border-color 0.15s, color 0.15s; 590 } 591 592 .theme-toggle:hover { 593 border-color: hsl(var(--smui-border-hover)); 594 color: hsl(var(--foreground)); 595 background: hsl(var(--smui-surface-2)); 596 } 597 598 .theme-toggle svg { 599 width: 14px; 600 height: 14px; 601 } 602 603 /* Hide the inactive icon */ 604 .theme-toggle .icon-sun { display: none; } 605 .theme-toggle .icon-moon { display: block; } 606 607 [data-theme="light"] .theme-toggle .icon-sun { display: block; } 608 [data-theme="light"] .theme-toggle .icon-moon { display: none; }