globals.css
1 @import 'tailwindcss'; 2 @import 'tw-animate-css'; 3 4 /* Tell Tailwind to scan components and lib at the project root */ 5 @source "../components"; 6 @source "../lib"; 7 8 @custom-variant dark (&:is(.dark *)); 9 10 @theme inline { 11 --color-background: var(--background); 12 --color-foreground: var(--foreground); 13 --font-sans: var(--font-sans); 14 --font-mono: var(--font-mono); 15 --font-display: var(--font-display); 16 --color-sidebar-ring: var(--sidebar-ring); 17 --color-sidebar-border: var(--sidebar-border); 18 --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); 19 --color-sidebar-accent: var(--sidebar-accent); 20 --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); 21 --color-sidebar-primary: var(--sidebar-primary); 22 --color-sidebar-foreground: var(--sidebar-foreground); 23 --color-sidebar: var(--sidebar); 24 --color-chart-5: var(--chart-5); 25 --color-chart-4: var(--chart-4); 26 --color-chart-3: var(--chart-3); 27 --color-chart-2: var(--chart-2); 28 --color-chart-1: var(--chart-1); 29 --color-ring: var(--ring); 30 --color-input: var(--input); 31 --color-border: var(--border); 32 --color-destructive: var(--destructive); 33 --color-accent-foreground: var(--accent-foreground); 34 --color-accent: var(--accent); 35 --color-muted-foreground: var(--muted-foreground); 36 --color-muted: var(--muted); 37 --color-secondary-foreground: var(--secondary-foreground); 38 --color-secondary: var(--secondary); 39 --color-primary-foreground: var(--primary-foreground); 40 --color-primary: var(--primary); 41 --color-popover-foreground: var(--popover-foreground); 42 --color-popover: var(--popover); 43 --color-card-foreground: var(--card-foreground); 44 --color-card: var(--card); 45 --radius-sm: calc(var(--radius) - 4px); 46 --radius-md: calc(var(--radius) - 2px); 47 --radius-lg: var(--radius); 48 --radius-xl: calc(var(--radius) + 4px); 49 --radius-2xl: calc(var(--radius) + 8px); 50 --radius-3xl: calc(var(--radius) + 12px); 51 --radius-4xl: calc(var(--radius) + 16px); 52 } 53 54 :root { 55 --font-sans: 'Inter', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; 56 --font-display: 'Sora', ui-sans-serif, system-ui, sans-serif; 57 --font-mono: 'JetBrains Mono', ui-monospace, 'Cascadia Code', 'Fira Code', monospace; 58 59 --radius: 0.625rem; 60 --background: oklch(1 0 0); 61 --foreground: oklch(0.145 0 0); 62 --card: oklch(1 0 0); 63 --card-foreground: oklch(0.145 0 0); 64 --popover: oklch(1 0 0); 65 --popover-foreground: oklch(0.145 0 0); 66 --primary: oklch(0.205 0 0); 67 --primary-foreground: oklch(0.985 0 0); 68 --secondary: oklch(0.97 0 0); 69 --secondary-foreground: oklch(0.205 0 0); 70 --muted: oklch(0.97 0 0); 71 --muted-foreground: oklch(0.556 0 0); 72 --accent: oklch(0.97 0 0); 73 --accent-foreground: oklch(0.205 0 0); 74 --destructive: oklch(0.577 0.245 27.325); 75 --border: oklch(0.922 0 0); 76 --input: oklch(0.922 0 0); 77 --ring: oklch(0.708 0 0); 78 --chart-1: oklch(0.646 0.222 41.116); 79 --chart-2: oklch(0.6 0.118 184.704); 80 --chart-3: oklch(0.398 0.07 227.392); 81 --chart-4: oklch(0.828 0.189 84.429); 82 --chart-5: oklch(0.769 0.188 70.08); 83 --sidebar: oklch(0.985 0 0); 84 --sidebar-foreground: oklch(0.145 0 0); 85 --sidebar-primary: oklch(0.205 0 0); 86 --sidebar-primary-foreground: oklch(0.985 0 0); 87 --sidebar-accent: oklch(0.97 0 0); 88 --sidebar-accent-foreground: oklch(0.205 0 0); 89 --sidebar-border: oklch(0.922 0 0); 90 --sidebar-ring: oklch(0.708 0 0); 91 } 92 93 .dark { 94 --background: oklch(0.145 0 0); 95 --foreground: oklch(0.985 0 0); 96 --card: oklch(0.205 0 0); 97 --card-foreground: oklch(0.985 0 0); 98 --popover: oklch(0.205 0 0); 99 --popover-foreground: oklch(0.985 0 0); 100 --primary: oklch(0.65 0.15 195); 101 --primary-foreground: oklch(0.13 0.02 195); 102 --secondary: oklch(0.269 0 0); 103 --secondary-foreground: oklch(0.985 0 0); 104 --muted: oklch(0.269 0 0); 105 --muted-foreground: oklch(0.708 0 0); 106 --accent: oklch(0.269 0 0); 107 --accent-foreground: oklch(0.985 0 0); 108 --destructive: oklch(0.704 0.191 22.216); 109 --border: oklch(1 0 0 / 10%); 110 --input: oklch(1 0 0 / 15%); 111 --ring: oklch(0.55 0.12 195); 112 --chart-1: oklch(0.488 0.243 264.376); 113 --chart-2: oklch(0.696 0.17 162.48); 114 --chart-3: oklch(0.769 0.188 70.08); 115 --chart-4: oklch(0.627 0.265 303.9); 116 --chart-5: oklch(0.645 0.246 16.439); 117 --sidebar: oklch(0.205 0 0); 118 --sidebar-foreground: oklch(0.985 0 0); 119 --sidebar-primary: oklch(0.65 0.15 195); 120 --sidebar-primary-foreground: oklch(0.985 0 0); 121 --sidebar-accent: oklch(0.269 0 0); 122 --sidebar-accent-foreground: oklch(0.985 0 0); 123 --sidebar-border: oklch(1 0 0 / 10%); 124 --sidebar-ring: oklch(0.556 0 0); 125 --accent-glow: oklch(0.65 0.15 195 / 30%); 126 } 127 128 @layer base { 129 * { 130 @apply border-border outline-ring/50; 131 scrollbar-color: oklch(0.35 0 0) transparent; 132 -webkit-tap-highlight-color: transparent; 133 -webkit-touch-callout: none; 134 } 135 136 html, 137 body { 138 overscroll-behavior: none; 139 overflow: hidden; 140 } 141 142 body { 143 @apply bg-background text-foreground; 144 font-family: var(--font-sans); 145 -webkit-user-select: none; 146 user-select: none; 147 -webkit-font-smoothing: antialiased; 148 -moz-osx-font-smoothing: grayscale; 149 text-rendering: optimizeLegibility; 150 -webkit-text-size-adjust: 100%; 151 } 152 153 input, 154 textarea, 155 [contenteditable], 156 .selectable { 157 -webkit-user-select: text; 158 user-select: text; 159 } 160 161 label, 162 button, 163 [role='button'], 164 span, 165 p, 166 h1, 167 h2, 168 h3, 169 h4, 170 h5, 171 h6, 172 .ui-label { 173 cursor: default; 174 } 175 176 input, 177 textarea, 178 [contenteditable] { 179 cursor: text; 180 } 181 182 a, 183 button, 184 summary, 185 [role='button'], 186 .clickable { 187 cursor: pointer; 188 } 189 190 img, 191 a, 192 svg { 193 -webkit-user-drag: none; 194 } 195 196 button:focus:not(:focus-visible), 197 [role='button']:focus:not(:focus-visible) { 198 outline: none; 199 } 200 201 button:focus-visible, 202 [role='button']:focus-visible { 203 outline: 2px solid var(--ring); 204 outline-offset: 2px; 205 } 206 } 207 208 /* ─── Dark scrollbars (WebKit) ───────────────────────────────── */ 209 ::-webkit-scrollbar { 210 width: 8px; 211 height: 8px; 212 } 213 214 ::-webkit-scrollbar-track { 215 background: transparent; 216 } 217 218 ::-webkit-scrollbar-thumb { 219 background: oklch(0.35 0 0); 220 border-radius: 4px; 221 } 222 223 ::-webkit-scrollbar-thumb:hover { 224 background: oklch(0.45 0 0); 225 } 226 227 ::-webkit-scrollbar-corner { 228 background: transparent; 229 } 230 231 /* ─── Shiki base ─────────────────────────────────────────────── */ 232 .shiki { 233 font-family: var(--font-mono) !important; 234 overflow-x: auto; 235 padding: 0.5rem 0 !important; 236 } 237 238 /* Shiki renders \n text nodes between <span class="line"> elements. 239 Setting font-size:0 here collapses those text nodes to zero height 240 so they don't create extra blank lines between code lines. 241 font-size is restored on .line. */ 242 .shiki code { 243 display: block; 244 font-size: 0; 245 /* wide enough that backgrounds fill the full scrollable area */ 246 min-width: 100%; 247 width: max-content; 248 } 249 250 .shiki .line { 251 display: block; 252 font-size: 0.8125rem; 253 line-height: 1.5; 254 padding: 0 1.25rem; 255 } 256 257 /* ─── Diff gutter (only inside has-diff blocks) ──────────────── */ 258 259 /* All lines in a diff block get a fixed-width gutter column so 260 indentation stays perfectly aligned between +, - and context. */ 261 .has-diff .line { 262 padding-left: 0; 263 } 264 265 .has-diff .line::before { 266 /* 1ch = one character width in the current monospace font */ 267 display: inline-block; 268 width: 1ch; 269 margin-right: 1ch; /* one char gap between gutter and code */ 270 padding-left: 0.75rem; 271 content: ' '; 272 user-select: none; 273 pointer-events: none; 274 } 275 276 /* Added lines */ 277 .has-diff .line.diff.add { 278 background-color: rgba(46, 160, 67, 0.15); 279 } 280 281 .has-diff .line.diff.add::before { 282 content: '+'; 283 color: #3fb950; 284 } 285 286 /* Removed lines */ 287 .has-diff .line.diff.remove { 288 background-color: rgba(248, 81, 73, 0.15); 289 } 290 291 .has-diff .line.diff.remove::before { 292 content: '-'; 293 color: #f85149; 294 } 295 296 /* ─── Interactive diff lines ─────────────────────────────────── */ 297 298 /* Override the default gutter for interactive lines since we render our own */ 299 .has-diff .line.interactive-line::before { 300 display: none; 301 } 302 303 .line.interactive-line:hover .add-comment-icon { 304 opacity: 1 !important; 305 } 306 307 .line.interactive-line:hover .line-number-gutter { 308 color: rgba(255, 255, 255, 0.7) !important; 309 } 310 311 .line.interactive-line { 312 padding-left: 0 !important; 313 } 314 315 /* ─── Split diff view ─────────────────────────────────────────── */ 316 317 .split-diff-cell-add { 318 background-color: rgba(46, 160, 67, 0.15); 319 } 320 321 .split-diff-cell-remove { 322 background-color: rgba(248, 81, 73, 0.15); 323 } 324 325 .split-diff-cell-empty { 326 background: oklch(0.2 0 0 / 30%); 327 } 328 329 .split-diff-separator { 330 background-color: rgba(255, 255, 255, 0.06); 331 } 332 333 .split-diff-grid > span.split-diff-line-num:hover { 334 color: rgba(255, 255, 255, 0.7) !important; 335 } 336 337 .split-diff-grid > span.split-diff-comment-icon:hover .split-icon-hover { 338 opacity: 1 !important; 339 } 340 341 /* ─── Check suggestion jump highlight ────────────────────────── */ 342 343 .check-highlight { 344 position: relative; 345 } 346 .check-highlight::after { 347 content: ''; 348 position: absolute; 349 inset: 0; 350 pointer-events: none; 351 background-color: oklch(0.65 0.15 195 / 30%); 352 animation: check-highlight-fade 1.5s ease-out forwards; 353 } 354 @keyframes check-highlight-fade { 355 from { 356 opacity: 1; 357 } 358 to { 359 opacity: 0; 360 } 361 } 362 363 /* ─── Freshness banner ────────────────────────────────────────── */ 364 365 .staleBanner-current { 366 border: 1px solid oklch(0.55 0.12 155 / 30%); 367 background: oklch(0.25 0.04 155 / 40%); 368 color: oklch(0.78 0.1 155); 369 } 370 371 .staleBanner-unknown { 372 border: 1px solid oklch(0.45 0 0 / 40%); 373 background: oklch(0.22 0 0 / 50%); 374 color: oklch(0.65 0 0); 375 } 376 377 .staleBanner-warn { 378 border: 1px solid oklch(0.55 0.12 75 / 40%); 379 background: oklch(0.25 0.05 75 / 40%); 380 color: oklch(0.82 0.1 80); 381 } 382 383 .staleBanner-warn-toggle:hover { 384 color: oklch(0.9 0.1 80); 385 } 386 387 .staleBanner-warn-btn { 388 border: 1px solid oklch(0.5 0.1 75 / 40%); 389 background: oklch(0.3 0.06 75 / 50%); 390 color: oklch(0.82 0.1 80); 391 } 392 393 .staleBanner-warn-btn:hover { 394 background: oklch(0.35 0.08 75 / 55%); 395 } 396 397 .staleBanner-warn-list { 398 border-top: 1px solid oklch(0.5 0.1 75 / 20%); 399 } 400 401 .staleBanner-warn-sha { 402 color: oklch(0.72 0.08 80 / 70%); 403 } 404 405 .staleBanner-warn-meta { 406 color: oklch(0.72 0.08 80 / 50%); 407 } 408 409 /* ─── Update banner ──────────────────────────────────────────── */ 410 411 .updateBanner { 412 border-bottom: 1px solid oklch(0.55 0.12 230 / 30%); 413 background: oklch(0.25 0.04 230 / 40%); 414 color: oklch(0.78 0.1 230); 415 } 416 417 .updateBanner-btn { 418 border: 1px solid oklch(0.5 0.1 230 / 40%); 419 background: oklch(0.3 0.06 230 / 50%); 420 color: oklch(0.85 0.08 230); 421 } 422 423 .updateBanner-btn:hover { 424 background: oklch(0.35 0.08 230 / 55%); 425 } 426 427 /* ─── PR status pills ─────────────────────────────────────────── */ 428 429 .statusPill-green, 430 .statusPill-red, 431 .statusPill-amber, 432 .statusPill-neutral, 433 .statusPill-label { 434 display: inline-flex; 435 align-items: center; 436 gap: 0.375rem; 437 padding: 0.25rem 0.625rem; 438 border-radius: 9999px; 439 font-size: 0.75rem; 440 font-weight: 500; 441 line-height: 1; 442 white-space: nowrap; 443 } 444 445 .statusPill-green { 446 border: 1px solid oklch(0.55 0.12 155 / 40%); 447 background: oklch(0.25 0.04 155 / 40%); 448 color: oklch(0.78 0.1 155); 449 } 450 451 .statusPill-red { 452 border: 1px solid oklch(0.55 0.15 25 / 40%); 453 background: oklch(0.25 0.05 25 / 40%); 454 color: oklch(0.78 0.12 25); 455 } 456 457 .statusPill-amber { 458 border: 1px solid oklch(0.55 0.12 75 / 40%); 459 background: oklch(0.25 0.05 75 / 40%); 460 color: oklch(0.82 0.1 80); 461 } 462 463 .statusPill-neutral { 464 border: 1px solid oklch(0.45 0 0 / 30%); 465 background: oklch(0.22 0 0 / 40%); 466 color: oklch(0.65 0 0); 467 } 468 469 .statusPill-label { 470 border: 1px solid oklch(0.5 0.08 260 / 35%); 471 background: oklch(0.25 0.03 260 / 40%); 472 color: oklch(0.75 0.06 260); 473 } 474 475 .statusPill-skeleton { 476 border: 1px solid oklch(0.35 0 0 / 20%); 477 background: oklch(0.22 0 0 / 50%); 478 } 479 480 /* ─── Review focus callout ────────────────────────────────────── */ 481 482 .review-focus-content ul, 483 ul.review-focus-content { 484 list-style: none; 485 padding-left: 0; 486 } 487 488 .review-focus-content ul > li, 489 ul.review-focus-content > li { 490 position: relative; 491 padding-left: 1.5rem; 492 } 493 494 .review-focus-content ul > li::before, 495 ul.review-focus-content > li::before { 496 content: '▸'; 497 position: absolute; 498 left: 0; 499 color: var(--primary); 500 opacity: 0.7; 501 font-size: 0.875rem; 502 line-height: inherit; 503 } 504 505 /* ─── Mermaid fullscreen dialog ───────────────────────────────── */ 506 507 .mermaid-fullscreen svg { 508 width: auto !important; 509 max-width: 100% !important; 510 height: auto !important; 511 max-height: calc(90vh - 6rem); 512 } 513 514 /* ─── Slide transitions (Priority 3) ─────────────────────────── */ 515 516 @keyframes slide-enter { 517 from { 518 opacity: 0; 519 transform: translateY(6px); 520 } 521 to { 522 opacity: 1; 523 transform: translateY(0); 524 } 525 } 526 527 .slide-enter { 528 animation: slide-enter 0.25s ease-out; 529 } 530 531 /* ─── Entrance animations (Priority 5) ────────────────────────── */ 532 533 @keyframes fade-in-up { 534 from { 535 opacity: 0; 536 transform: translateY(8px); 537 } 538 to { 539 opacity: 1; 540 transform: translateY(0); 541 } 542 } 543 544 .animate-fade-in-up { 545 animation: fade-in-up 0.35s ease-out both; 546 } 547 548 /* ─── Hero glow (Priority 7) ──────────────────────────────────── */ 549 550 .hero-glow { 551 position: relative; 552 } 553 554 .hero-glow::before { 555 content: ''; 556 position: absolute; 557 top: -200px; 558 left: 50%; 559 transform: translateX(-50%); 560 width: 800px; 561 height: 600px; 562 background: radial-gradient(ellipse, oklch(0.65 0.15 195 / 15%) 0%, transparent 70%); 563 pointer-events: none; 564 z-index: 0; 565 } 566 567 /* ─── Loading screen rings (Priority 4) ──────────────────────── */ 568 569 @keyframes pulse-ring { 570 0% { 571 opacity: 0.4; 572 transform: scale(1); 573 } 574 100% { 575 opacity: 0; 576 transform: scale(1.6); 577 } 578 } 579 580 .loading-ring { 581 animation: pulse-ring 2s ease-out infinite; 582 } 583 584 .loading-ring-delayed { 585 animation: pulse-ring 2s ease-out 0.5s infinite; 586 } 587 588 .loading-ring-delayed-2 { 589 animation: pulse-ring 2s ease-out 1s infinite; 590 }