findbug 0.3.4 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/docs/index.html ADDED
@@ -0,0 +1,2288 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" class="dark">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>FindBug - Self-hosted Error Tracking for Rails</title>
7
+ <meta name="description" content="Self-hosted error tracking and performance monitoring for Rails applications. Sentry-like functionality with all data on your infrastructure.">
8
+ <meta name="keywords" content="error tracking, performance monitoring, rails, ruby, self-hosted, sentry alternative">
9
+ <link rel="canonical" href="https://findbug.dev">
10
+
11
+ <!-- Open Graph -->
12
+ <meta property="og:title" content="FindBug - Self-hosted Error Tracking for Rails">
13
+ <meta property="og:description" content="Self-hosted error tracking and performance monitoring for Rails applications. Full data ownership, zero monthly fees.">
14
+ <meta property="og:type" content="website">
15
+ <meta property="og:url" content="https://findbug.dev">
16
+
17
+ <!-- Twitter -->
18
+ <meta name="twitter:card" content="summary_large_image">
19
+ <meta name="twitter:title" content="FindBug - Self-hosted Error Tracking for Rails">
20
+ <meta name="twitter:description" content="Self-hosted error tracking and performance monitoring for Rails applications.">
21
+
22
+ <!-- Favicon -->
23
+ <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fafafa' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2l1.88 1.88'/%3E%3Cpath d='M14.12 3.88L16 2'/%3E%3Cpath d='M9 7.13v-1a3.003 3.003 0 1 1 6 0v1'/%3E%3Cpath d='M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6'/%3E%3Cpath d='M12 20v-9'/%3E%3Cpath d='M6.53 9C4.6 8.8 3 7.1 3 5'/%3E%3Cpath d='M6 13H2'/%3E%3Cpath d='M3 21c0-2.1 1.7-3.9 3.8-4'/%3E%3Cpath d='M20.97 5c0 2.1-1.6 3.8-3.5 4'/%3E%3Cpath d='M22 13h-4'/%3E%3Cpath d='M17.2 17c2.1.1 3.8 1.9 3.8 4'/%3E%3C/svg%3E">
24
+
25
+ <style>
26
+ /* ========================================
27
+ CSS Variables (shadcn neutral dark)
28
+ ======================================== */
29
+ :root {
30
+ --background: 0 0% 3.9%;
31
+ --foreground: 0 0% 98%;
32
+ --card: 0 0% 3.9%;
33
+ --card-foreground: 0 0% 98%;
34
+ --popover: 0 0% 3.9%;
35
+ --popover-foreground: 0 0% 98%;
36
+ --primary: 0 0% 98%;
37
+ --primary-foreground: 0 0% 9%;
38
+ --secondary: 0 0% 14.9%;
39
+ --secondary-foreground: 0 0% 98%;
40
+ --muted: 0 0% 14.9%;
41
+ --muted-foreground: 0 0% 63.9%;
42
+ --accent: 0 0% 14.9%;
43
+ --accent-foreground: 0 0% 98%;
44
+ --destructive: 0 62.8% 30.6%;
45
+ --destructive-foreground: 0 0% 98%;
46
+ --border: 0 0% 14.9%;
47
+ --input: 0 0% 14.9%;
48
+ --ring: 0 0% 83.1%;
49
+ --success: 142.1 76.2% 36.3%;
50
+ --warning: 38 92% 50%;
51
+ --error: 0 84.2% 60.2%;
52
+ --info: 217.2 91.2% 59.8%;
53
+ --radius: 0.5rem;
54
+ }
55
+
56
+ * { box-sizing: border-box; margin: 0; padding: 0; }
57
+
58
+ html { scroll-behavior: smooth; }
59
+
60
+ body {
61
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif;
62
+ background-color: hsl(var(--background));
63
+ color: hsl(var(--foreground));
64
+ line-height: 1.6;
65
+ min-height: 100vh;
66
+ -webkit-font-smoothing: antialiased;
67
+ -moz-osx-font-smoothing: grayscale;
68
+ }
69
+
70
+ a { color: inherit; text-decoration: none; transition: color 0.15s; }
71
+
72
+ .container { max-width: 1200px; margin: 0 auto; padding: 0 1.5rem; }
73
+
74
+ /* Main Site Navigation */
75
+ .site-nav {
76
+ position: fixed;
77
+ top: 0;
78
+ left: 0;
79
+ right: 0;
80
+ z-index: 50;
81
+ background-color: hsl(var(--background) / 0.95);
82
+ backdrop-filter: blur(10px);
83
+ }
84
+
85
+ .nav-container {
86
+ max-width: 1200px;
87
+ margin: 0 auto;
88
+ padding: 0 1.5rem;
89
+ display: flex;
90
+ align-items: center;
91
+ height: 3.5rem;
92
+ gap: 1.5rem;
93
+ }
94
+
95
+ .logo {
96
+ display: flex;
97
+ align-items: center;
98
+ gap: 0.5rem;
99
+ font-size: 0.875rem;
100
+ font-weight: 600;
101
+ color: hsl(var(--foreground));
102
+ }
103
+
104
+ .logo svg { width: 1.25rem; height: 1.25rem; }
105
+
106
+ .nav-links {
107
+ display: flex;
108
+ align-items: center;
109
+ gap: 0.125rem;
110
+ margin-left: 1rem;
111
+ }
112
+
113
+ .nav-links a {
114
+ padding: 0.375rem 0.75rem;
115
+ font-size: 0.875rem;
116
+ font-weight: 500;
117
+ color: hsl(var(--muted-foreground));
118
+ border-radius: var(--radius);
119
+ transition: all 0.15s;
120
+ }
121
+
122
+ .nav-links a:hover {
123
+ color: hsl(var(--foreground));
124
+ background-color: hsl(var(--accent));
125
+ }
126
+
127
+ .nav-right {
128
+ margin-left: auto;
129
+ display: flex;
130
+ align-items: center;
131
+ gap: 0.5rem;
132
+ }
133
+
134
+ /* Buttons */
135
+ .btn {
136
+ display: inline-flex;
137
+ align-items: center;
138
+ justify-content: center;
139
+ gap: 0.5rem;
140
+ padding: 0.5rem 1rem;
141
+ font-size: 0.875rem;
142
+ font-weight: 500;
143
+ border-radius: var(--radius);
144
+ cursor: pointer;
145
+ transition: all 0.15s;
146
+ border: none;
147
+ text-decoration: none;
148
+ }
149
+
150
+ .btn:hover { opacity: 0.9; }
151
+
152
+ .btn-primary {
153
+ background-color: hsl(var(--primary));
154
+ color: hsl(var(--primary-foreground));
155
+ }
156
+
157
+ .btn-secondary {
158
+ background-color: hsl(var(--secondary));
159
+ color: hsl(var(--secondary-foreground));
160
+ border: 1px solid hsl(var(--border));
161
+ }
162
+
163
+ .btn-outline {
164
+ background: transparent;
165
+ color: hsl(var(--foreground));
166
+ border: 1px solid hsl(var(--border));
167
+ }
168
+
169
+ .btn-outline:hover {
170
+ background-color: hsl(var(--accent));
171
+ }
172
+
173
+ .btn-sm {
174
+ padding: 0.375rem 0.75rem;
175
+ font-size: 0.8125rem;
176
+ }
177
+
178
+ /* Hero Section */
179
+ .hero {
180
+ padding: 8rem 0 5rem;
181
+ text-align: center;
182
+ }
183
+
184
+ .hero-badge {
185
+ display: inline-flex;
186
+ align-items: center;
187
+ gap: 0.5rem;
188
+ padding: 0.375rem 0.875rem;
189
+ background-color: hsl(var(--secondary));
190
+ border: 1px solid hsl(var(--border));
191
+ border-radius: 9999px;
192
+ font-size: 0.75rem;
193
+ color: hsl(var(--muted-foreground));
194
+ margin-bottom: 1.5rem;
195
+ }
196
+
197
+ .hero-badge span {
198
+ background-color: hsl(var(--success));
199
+ color: hsl(var(--primary-foreground));
200
+ padding: 0.125rem 0.5rem;
201
+ border-radius: 9999px;
202
+ font-size: 0.6875rem;
203
+ font-weight: 600;
204
+ }
205
+
206
+ h1 {
207
+ font-size: 3rem;
208
+ font-weight: 700;
209
+ letter-spacing: -0.025em;
210
+ line-height: 1.1;
211
+ margin-bottom: 1.25rem;
212
+ }
213
+
214
+ .hero p {
215
+ font-size: 1.125rem;
216
+ color: hsl(var(--muted-foreground));
217
+ margin-bottom: 2rem;
218
+ max-width: 600px;
219
+ margin-left: auto;
220
+ margin-right: auto;
221
+ }
222
+
223
+ .hero-buttons {
224
+ display: flex;
225
+ gap: 0.75rem;
226
+ justify-content: center;
227
+ flex-wrap: wrap;
228
+ margin-bottom: 3rem;
229
+ }
230
+
231
+ .hero-code {
232
+ background-color: hsl(0 0% 7%);
233
+ border: 1px solid hsl(var(--border));
234
+ border-radius: var(--radius);
235
+ padding: 1.25rem 1.5rem;
236
+ max-width: 480px;
237
+ margin: 0 auto;
238
+ text-align: left;
239
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
240
+ font-size: 0.8125rem;
241
+ line-height: 1.7;
242
+ }
243
+
244
+ .hero-code .comment { color: hsl(var(--muted-foreground)); }
245
+ .hero-code .keyword { color: hsl(var(--info)); }
246
+ .hero-code .string { color: hsl(var(--success)); }
247
+
248
+ /* Features Section */
249
+ .features {
250
+ padding: 5rem 0;
251
+ }
252
+
253
+ .section-header {
254
+ text-align: center;
255
+ margin-bottom: 3rem;
256
+ }
257
+
258
+ .section-header h2 {
259
+ font-size: 1.875rem;
260
+ font-weight: 700;
261
+ letter-spacing: -0.025em;
262
+ margin-bottom: 0.75rem;
263
+ }
264
+
265
+ .section-header p {
266
+ font-size: 1rem;
267
+ color: hsl(var(--muted-foreground));
268
+ max-width: 500px;
269
+ margin: 0 auto;
270
+ }
271
+
272
+ /* Bento Grid */
273
+ .bento-grid {
274
+ display: grid;
275
+ grid-template-columns: repeat(12, 1fr);
276
+ grid-template-rows: auto;
277
+ gap: 1rem;
278
+ }
279
+
280
+ .bento-card {
281
+ background-color: hsl(var(--card));
282
+ border: 1px solid hsl(var(--border));
283
+ border-radius: var(--radius);
284
+ padding: 1.5rem;
285
+ transition: all 0.2s ease;
286
+ overflow: hidden;
287
+ display: flex;
288
+ flex-direction: column;
289
+ }
290
+
291
+ .bento-card:hover {
292
+ border-color: hsl(var(--muted-foreground) / 0.4);
293
+ transform: translateY(-2px);
294
+ }
295
+
296
+ .bento-card h3 {
297
+ font-size: 1rem;
298
+ font-weight: 600;
299
+ margin-bottom: 0.5rem;
300
+ }
301
+
302
+ .bento-card p {
303
+ color: hsl(var(--muted-foreground));
304
+ font-size: 0.875rem;
305
+ line-height: 1.5;
306
+ }
307
+
308
+ .bento-card .visual {
309
+ margin-top: auto;
310
+ padding-top: 1.25rem;
311
+ }
312
+
313
+ /* Card Sizes */
314
+ .bento-wide { grid-column: span 8; }
315
+ .bento-narrow { grid-column: span 4; }
316
+ .bento-half { grid-column: span 6; }
317
+ .bento-third { grid-column: span 4; }
318
+
319
+ @media (max-width: 1024px) {
320
+ .bento-wide, .bento-narrow, .bento-half { grid-column: span 6; }
321
+ .bento-third { grid-column: span 6; }
322
+ }
323
+
324
+ @media (max-width: 640px) {
325
+ .bento-wide, .bento-narrow, .bento-half, .bento-third { grid-column: span 12; }
326
+ }
327
+
328
+ /* Bento Visual Elements */
329
+ .bento-code {
330
+ background-color: hsl(0 0% 6%);
331
+ border: 1px solid hsl(var(--border));
332
+ border-radius: calc(var(--radius) - 2px);
333
+ padding: 1rem;
334
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
335
+ font-size: 0.75rem;
336
+ line-height: 1.6;
337
+ overflow: hidden;
338
+ }
339
+
340
+ .bento-code .line {
341
+ display: block;
342
+ }
343
+
344
+ .bento-code .line-num {
345
+ color: hsl(var(--muted-foreground) / 0.4);
346
+ user-select: none;
347
+ display: inline-block;
348
+ min-width: 1rem;
349
+ text-align: right;
350
+ margin-right: 0.75rem;
351
+ }
352
+
353
+ .bento-code .keyword { color: hsl(280 80% 70%); }
354
+ .bento-code .class { color: hsl(35 90% 65%); }
355
+ .bento-code .method { color: hsl(200 90% 70%); }
356
+ .bento-code .string { color: hsl(var(--success)); }
357
+ .bento-code .comment { color: hsl(var(--muted-foreground)); }
358
+ .bento-code .symbol { color: hsl(0 70% 65%); }
359
+ .bento-code .number { color: hsl(30 90% 60%); }
360
+
361
+ /* Mock Dashboard Card */
362
+ .bento-dashboard {
363
+ background-color: hsl(0 0% 6%);
364
+ border: 1px solid hsl(var(--border));
365
+ border-radius: calc(var(--radius) - 2px);
366
+ overflow: hidden;
367
+ }
368
+
369
+ .bento-dashboard-header {
370
+ display: flex;
371
+ align-items: center;
372
+ gap: 0.5rem;
373
+ padding: 0.625rem 0.875rem;
374
+ border-bottom: 1px solid hsl(var(--border));
375
+ background-color: hsl(0 0% 8%);
376
+ }
377
+
378
+ .bento-dashboard-header .dot {
379
+ width: 8px;
380
+ height: 8px;
381
+ border-radius: 50%;
382
+ }
383
+
384
+ .bento-dashboard-header .dot.red { background: hsl(0 70% 50%); }
385
+ .bento-dashboard-header .dot.yellow { background: hsl(45 70% 50%); }
386
+ .bento-dashboard-header .dot.green { background: hsl(120 40% 45%); }
387
+
388
+ .bento-dashboard-content {
389
+ padding: 0.875rem;
390
+ }
391
+
392
+ /* Error List Mock */
393
+ .mock-error-list {
394
+ display: flex;
395
+ flex-direction: column;
396
+ gap: 0.5rem;
397
+ }
398
+
399
+ .mock-error-item {
400
+ display: flex;
401
+ align-items: center;
402
+ gap: 0.75rem;
403
+ padding: 0.625rem 0.75rem;
404
+ background-color: hsl(0 0% 9%);
405
+ border-radius: calc(var(--radius) - 4px);
406
+ font-size: 0.75rem;
407
+ }
408
+
409
+ .mock-error-item .severity {
410
+ width: 6px;
411
+ height: 6px;
412
+ border-radius: 50%;
413
+ flex-shrink: 0;
414
+ }
415
+
416
+ .mock-error-item .severity.error { background: hsl(var(--error)); }
417
+ .mock-error-item .severity.warning { background: hsl(var(--warning)); }
418
+ .mock-error-item .severity.info { background: hsl(var(--info)); }
419
+
420
+ .mock-error-item .error-name {
421
+ font-family: ui-monospace, SFMono-Regular, monospace;
422
+ color: hsl(var(--foreground));
423
+ flex: 1;
424
+ white-space: nowrap;
425
+ overflow: hidden;
426
+ text-overflow: ellipsis;
427
+ }
428
+
429
+ .mock-error-item .error-count {
430
+ color: hsl(var(--muted-foreground));
431
+ font-size: 0.6875rem;
432
+ padding: 0.125rem 0.5rem;
433
+ background: hsl(var(--secondary));
434
+ border-radius: 9999px;
435
+ }
436
+
437
+ /* Performance Bars */
438
+ .perf-bars {
439
+ display: flex;
440
+ flex-direction: column;
441
+ gap: 0.625rem;
442
+ }
443
+
444
+ .perf-bar-row {
445
+ display: flex;
446
+ align-items: center;
447
+ gap: 0.75rem;
448
+ font-size: 0.6875rem;
449
+ }
450
+
451
+ .perf-bar-label {
452
+ width: 5rem;
453
+ color: hsl(var(--muted-foreground));
454
+ text-align: right;
455
+ flex-shrink: 0;
456
+ }
457
+
458
+ .perf-bar-track {
459
+ flex: 1;
460
+ height: 6px;
461
+ background: hsl(var(--secondary));
462
+ border-radius: 3px;
463
+ overflow: hidden;
464
+ }
465
+
466
+ .perf-bar-fill {
467
+ height: 100%;
468
+ border-radius: 3px;
469
+ transition: width 0.3s ease;
470
+ }
471
+
472
+ .perf-bar-fill.db { background: hsl(var(--info)); width: 65%; }
473
+ .perf-bar-fill.view { background: hsl(var(--success)); width: 20%; }
474
+ .perf-bar-fill.ruby { background: hsl(280 70% 60%); width: 10%; }
475
+ .perf-bar-fill.other { background: hsl(var(--muted-foreground)); width: 5%; }
476
+
477
+ .perf-bar-time {
478
+ width: 3rem;
479
+ color: hsl(var(--foreground));
480
+ font-family: ui-monospace, SFMono-Regular, monospace;
481
+ }
482
+
483
+ /* Alert Icons Animation */
484
+ .alert-icons {
485
+ display: flex;
486
+ gap: 1rem;
487
+ justify-content: center;
488
+ padding: 1rem 0;
489
+ }
490
+
491
+ .alert-icon {
492
+ width: 3rem;
493
+ height: 3rem;
494
+ background: hsl(var(--secondary));
495
+ border: 1px solid hsl(var(--border));
496
+ border-radius: var(--radius);
497
+ display: flex;
498
+ align-items: center;
499
+ justify-content: center;
500
+ font-size: 1.25rem;
501
+ transition: all 0.2s ease;
502
+ }
503
+
504
+ .bento-card:hover .alert-icon {
505
+ transform: scale(1.1);
506
+ }
507
+
508
+ .alert-icon.slack { background: hsl(280 30% 20%); border-color: hsl(280 40% 35%); }
509
+ .alert-icon.discord { background: hsl(235 50% 25%); border-color: hsl(235 50% 40%); }
510
+ .alert-icon.email { background: hsl(200 40% 20%); border-color: hsl(200 40% 35%); }
511
+ .alert-icon.webhook { background: hsl(150 30% 20%); border-color: hsl(150 30% 35%); }
512
+
513
+ /* Terminal Mock */
514
+ .bento-terminal {
515
+ background: hsl(0 0% 6%);
516
+ border: 1px solid hsl(var(--border));
517
+ border-radius: calc(var(--radius) - 2px);
518
+ overflow: hidden;
519
+ }
520
+
521
+ .bento-terminal-header {
522
+ display: flex;
523
+ align-items: center;
524
+ gap: 0.375rem;
525
+ padding: 0.5rem 0.75rem;
526
+ background: hsl(0 0% 8%);
527
+ border-bottom: 1px solid hsl(var(--border));
528
+ }
529
+
530
+ .bento-terminal-header span {
531
+ width: 8px;
532
+ height: 8px;
533
+ border-radius: 50%;
534
+ background: hsl(var(--muted-foreground) / 0.3);
535
+ }
536
+
537
+ .bento-terminal-body {
538
+ padding: 0.875rem;
539
+ font-family: ui-monospace, SFMono-Regular, monospace;
540
+ font-size: 0.6875rem;
541
+ line-height: 1.7;
542
+ }
543
+
544
+ .bento-terminal-body .prompt { color: hsl(var(--success)); }
545
+ .bento-terminal-body .output { color: hsl(var(--muted-foreground)); }
546
+ .bento-terminal-body .success { color: hsl(var(--success)); }
547
+
548
+ /* Stats Grid */
549
+ .stats-mini {
550
+ display: grid;
551
+ grid-template-columns: repeat(2, 1fr);
552
+ gap: 0.75rem;
553
+ }
554
+
555
+ .stat-mini-item {
556
+ background: hsl(0 0% 8%);
557
+ border-radius: calc(var(--radius) - 2px);
558
+ padding: 0.875rem;
559
+ text-align: center;
560
+ }
561
+
562
+ .stat-mini-item .value {
563
+ font-size: 1.5rem;
564
+ font-weight: 700;
565
+ font-family: ui-monospace, SFMono-Regular, monospace;
566
+ color: hsl(var(--foreground));
567
+ }
568
+
569
+ .stat-mini-item .value.green { color: hsl(var(--success)); }
570
+ .stat-mini-item .value.blue { color: hsl(var(--info)); }
571
+
572
+ .stat-mini-item .label {
573
+ font-size: 0.6875rem;
574
+ color: hsl(var(--muted-foreground));
575
+ margin-top: 0.25rem;
576
+ }
577
+
578
+ /* Privacy Shield */
579
+ .privacy-visual {
580
+ display: flex;
581
+ align-items: center;
582
+ justify-content: center;
583
+ gap: 1rem;
584
+ padding: 1rem 0;
585
+ }
586
+
587
+ .server-icon {
588
+ display: flex;
589
+ flex-direction: column;
590
+ align-items: center;
591
+ gap: 0.375rem;
592
+ }
593
+
594
+ .server-icon .icon {
595
+ width: 3rem;
596
+ height: 3rem;
597
+ background: hsl(var(--secondary));
598
+ border: 1px solid hsl(var(--border));
599
+ border-radius: var(--radius);
600
+ display: flex;
601
+ align-items: center;
602
+ justify-content: center;
603
+ font-size: 1.25rem;
604
+ }
605
+
606
+ .server-icon .label {
607
+ font-size: 0.625rem;
608
+ color: hsl(var(--muted-foreground));
609
+ }
610
+
611
+ .data-flow {
612
+ display: flex;
613
+ align-items: center;
614
+ gap: 0.25rem;
615
+ color: hsl(var(--success));
616
+ font-size: 0.75rem;
617
+ }
618
+
619
+ .data-flow span {
620
+ animation: pulse 1.5s ease-in-out infinite;
621
+ }
622
+
623
+ .data-flow span:nth-child(2) { animation-delay: 0.2s; }
624
+ .data-flow span:nth-child(3) { animation-delay: 0.4s; }
625
+
626
+ @keyframes pulse {
627
+ 0%, 100% { opacity: 0.3; }
628
+ 50% { opacity: 1; }
629
+ }
630
+
631
+ /* Demo Section - Matching Real FindBug Dashboard 1:1 */
632
+ .demo {
633
+ padding: 5rem 0;
634
+ background: hsl(0 0% 2%);
635
+ }
636
+
637
+ .demo-container {
638
+ max-width: 1100px;
639
+ margin: 0 auto;
640
+ }
641
+
642
+ .demo-window {
643
+ background: hsl(var(--background));
644
+ border: 1px solid hsl(var(--border));
645
+ border-radius: var(--radius);
646
+ overflow: hidden;
647
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
648
+ }
649
+
650
+ .demo-titlebar {
651
+ display: flex;
652
+ align-items: center;
653
+ gap: 0.5rem;
654
+ padding: 0.75rem 1rem;
655
+ background: hsl(0 0% 8%);
656
+ border-bottom: 1px solid hsl(var(--border));
657
+ }
658
+
659
+ .demo-titlebar .dots {
660
+ display: flex;
661
+ gap: 0.375rem;
662
+ }
663
+
664
+ .demo-titlebar .dot {
665
+ width: 10px;
666
+ height: 10px;
667
+ border-radius: 50%;
668
+ }
669
+
670
+ .demo-titlebar .dot.red { background: #ff5f57; }
671
+ .demo-titlebar .dot.yellow { background: #febc2e; }
672
+ .demo-titlebar .dot.green { background: #28c840; }
673
+
674
+ .demo-titlebar .url {
675
+ flex: 1;
676
+ text-align: center;
677
+ font-size: 0.75rem;
678
+ color: hsl(var(--muted-foreground));
679
+ font-family: ui-monospace, monospace;
680
+ }
681
+
682
+ /* Dashboard Header - matches real Findbug header */
683
+ .demo-app-header {
684
+ display: flex;
685
+ align-items: center;
686
+ height: 3.5rem;
687
+ padding: 0 1.5rem;
688
+ gap: 1.5rem;
689
+ background: hsl(var(--background));
690
+ border-bottom: 1px solid hsl(var(--border));
691
+ }
692
+
693
+ .demo-app-logo {
694
+ display: flex;
695
+ align-items: center;
696
+ gap: 0.5rem;
697
+ font-size: 0.875rem;
698
+ font-weight: 600;
699
+ color: hsl(var(--foreground));
700
+ padding-right: 1rem;
701
+ border-right: 1px solid hsl(var(--border));
702
+ }
703
+
704
+ .demo-app-logo svg {
705
+ width: 1.25rem;
706
+ height: 1.25rem;
707
+ }
708
+
709
+ .demo-app-nav {
710
+ display: flex;
711
+ align-items: center;
712
+ gap: 0.125rem;
713
+ }
714
+
715
+ .demo-app-nav a {
716
+ padding: 0.375rem 0.75rem;
717
+ font-size: 0.875rem;
718
+ font-weight: 500;
719
+ color: hsl(var(--muted-foreground));
720
+ border-radius: var(--radius);
721
+ transition: all 0.15s;
722
+ cursor: pointer;
723
+ }
724
+
725
+ .demo-app-nav a:hover {
726
+ color: hsl(var(--foreground));
727
+ }
728
+
729
+ .demo-app-nav a.active {
730
+ color: hsl(var(--foreground));
731
+ background-color: hsl(var(--accent));
732
+ }
733
+
734
+ .demo-header-right {
735
+ margin-left: auto;
736
+ display: flex;
737
+ align-items: center;
738
+ gap: 0.5rem;
739
+ }
740
+
741
+ .demo-health-indicator {
742
+ display: flex;
743
+ align-items: center;
744
+ gap: 0.375rem;
745
+ font-size: 0.75rem;
746
+ color: hsl(var(--muted-foreground));
747
+ padding: 0.25rem 0.625rem;
748
+ background-color: hsl(var(--secondary));
749
+ border-radius: var(--radius);
750
+ }
751
+
752
+ .demo-health-dot {
753
+ width: 0.5rem;
754
+ height: 0.5rem;
755
+ border-radius: 50%;
756
+ background-color: hsl(var(--success));
757
+ }
758
+
759
+ /* Dashboard Main Content */
760
+ .demo-main {
761
+ padding: 2.5rem 1.5rem 3rem;
762
+ }
763
+
764
+ .demo-page-title {
765
+ font-size: 1.875rem;
766
+ font-weight: 700;
767
+ letter-spacing: -0.025em;
768
+ margin-bottom: 0.5rem;
769
+ }
770
+
771
+ .demo-page-description {
772
+ color: hsl(var(--muted-foreground));
773
+ font-size: 0.875rem;
774
+ margin-bottom: 1.5rem;
775
+ }
776
+
777
+ /* Stats Grid - matches real dashboard */
778
+ .demo-stats-grid {
779
+ display: grid;
780
+ grid-template-columns: repeat(4, 1fr);
781
+ gap: 1rem;
782
+ margin-bottom: 1.5rem;
783
+ }
784
+
785
+ .demo-stat-card {
786
+ background-color: hsl(var(--card));
787
+ border: 1px solid hsl(var(--border));
788
+ border-radius: var(--radius);
789
+ padding: 1.25rem;
790
+ }
791
+
792
+ .demo-stat-label {
793
+ font-size: 0.75rem;
794
+ font-weight: 500;
795
+ color: hsl(var(--muted-foreground));
796
+ }
797
+
798
+ .demo-stat-value {
799
+ font-size: 2rem;
800
+ font-weight: 700;
801
+ letter-spacing: -0.025em;
802
+ margin-top: 0.25rem;
803
+ line-height: 1;
804
+ }
805
+
806
+ .demo-stat-value.error { color: hsl(var(--error)); }
807
+ .demo-stat-value.warning { color: hsl(var(--warning)); }
808
+ .demo-stat-value.success { color: hsl(var(--success)); }
809
+
810
+ .demo-stat-value .unit {
811
+ font-size: 0.875rem;
812
+ color: hsl(var(--muted-foreground));
813
+ font-weight: 400;
814
+ }
815
+
816
+ .demo-stat-change {
817
+ font-size: 0.75rem;
818
+ margin-top: 0.5rem;
819
+ color: hsl(var(--muted-foreground));
820
+ }
821
+
822
+ /* Two Column Grid */
823
+ .demo-grid-2 {
824
+ display: grid;
825
+ grid-template-columns: repeat(2, 1fr);
826
+ gap: 1.5rem;
827
+ margin-bottom: 1.5rem;
828
+ }
829
+
830
+ /* Card Component - matches real dashboard */
831
+ .demo-card {
832
+ background-color: hsl(var(--card));
833
+ border: 1px solid hsl(var(--border));
834
+ border-radius: var(--radius);
835
+ }
836
+
837
+ .demo-card-header {
838
+ display: flex;
839
+ justify-content: space-between;
840
+ align-items: center;
841
+ padding: 1rem 1.25rem;
842
+ border-bottom: 1px solid hsl(var(--border));
843
+ }
844
+
845
+ .demo-card-title {
846
+ font-size: 0.875rem;
847
+ font-weight: 600;
848
+ }
849
+
850
+ .demo-card-description {
851
+ font-size: 0.75rem;
852
+ color: hsl(var(--muted-foreground));
853
+ margin-top: 0.125rem;
854
+ }
855
+
856
+ .demo-btn-outline {
857
+ display: inline-flex;
858
+ align-items: center;
859
+ justify-content: center;
860
+ padding: 0.25rem 0.625rem;
861
+ font-size: 0.75rem;
862
+ font-weight: 500;
863
+ height: 1.75rem;
864
+ background: transparent;
865
+ color: hsl(var(--foreground));
866
+ border: 1px solid hsl(var(--border));
867
+ border-radius: var(--radius);
868
+ cursor: pointer;
869
+ }
870
+
871
+ /* Table - matches real dashboard */
872
+ .demo-table {
873
+ width: 100%;
874
+ border-collapse: collapse;
875
+ font-size: 0.875rem;
876
+ }
877
+
878
+ .demo-table th {
879
+ padding: 0.75rem 1rem;
880
+ text-align: left;
881
+ font-weight: 500;
882
+ font-size: 0.75rem;
883
+ color: hsl(var(--muted-foreground));
884
+ border-bottom: 1px solid hsl(var(--border));
885
+ }
886
+
887
+ .demo-table td {
888
+ padding: 0.75rem 1rem;
889
+ border-bottom: 1px solid hsl(var(--border));
890
+ vertical-align: middle;
891
+ }
892
+
893
+ .demo-table tbody tr {
894
+ transition: background-color 0.15s;
895
+ }
896
+
897
+ .demo-table tbody tr:hover {
898
+ background-color: hsl(var(--muted) / 0.5);
899
+ }
900
+
901
+ .demo-table tbody tr:last-child td {
902
+ border-bottom: none;
903
+ }
904
+
905
+ .demo-table a {
906
+ color: hsl(var(--foreground));
907
+ }
908
+
909
+ .demo-table a:hover {
910
+ text-decoration: underline;
911
+ }
912
+
913
+ .demo-font-mono {
914
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
915
+ }
916
+
917
+ .demo-text-muted {
918
+ color: hsl(var(--muted-foreground));
919
+ }
920
+
921
+ .demo-text-sm {
922
+ font-size: 0.875rem;
923
+ }
924
+
925
+ .demo-text-xs {
926
+ font-size: 0.75rem;
927
+ }
928
+
929
+ /* Badges - matches real dashboard */
930
+ .demo-badge {
931
+ display: inline-flex;
932
+ align-items: center;
933
+ padding: 0.125rem 0.5rem;
934
+ font-size: 0.6875rem;
935
+ font-weight: 500;
936
+ border-radius: 9999px;
937
+ }
938
+
939
+ .demo-badge-error {
940
+ background-color: hsl(var(--error) / 0.15);
941
+ color: hsl(var(--error));
942
+ }
943
+
944
+ .demo-badge-warning {
945
+ background-color: hsl(var(--warning) / 0.15);
946
+ color: hsl(var(--warning));
947
+ }
948
+
949
+ .demo-badge-success {
950
+ background-color: hsl(var(--success) / 0.15);
951
+ color: hsl(var(--success));
952
+ }
953
+
954
+ .demo-badge-muted {
955
+ background-color: hsl(var(--muted));
956
+ color: hsl(var(--muted-foreground));
957
+ }
958
+
959
+ @media (max-width: 1024px) {
960
+ .demo-stats-grid { grid-template-columns: repeat(2, 1fr); }
961
+ .demo-grid-2 { grid-template-columns: 1fr; }
962
+ }
963
+
964
+ @media (max-width: 640px) {
965
+ .demo-stats-grid { grid-template-columns: 1fr; }
966
+ .demo-app-nav { display: none; }
967
+ }
968
+
969
+ /* Comparison Section - Modern Card Layout */
970
+ .comparison {
971
+ padding: 5rem 0;
972
+ }
973
+
974
+ .comparison-grid {
975
+ display: grid;
976
+ grid-template-columns: repeat(2, 1fr);
977
+ gap: 1.5rem;
978
+ max-width: 900px;
979
+ margin: 0 auto;
980
+ }
981
+
982
+ @media (max-width: 768px) {
983
+ .comparison-grid { grid-template-columns: 1fr; }
984
+ }
985
+
986
+ .comparison-card {
987
+ background-color: hsl(var(--card));
988
+ border: 1px solid hsl(var(--border));
989
+ border-radius: var(--radius);
990
+ padding: 1.5rem;
991
+ display: flex;
992
+ flex-direction: column;
993
+ gap: 1rem;
994
+ }
995
+
996
+ .comparison-card-header {
997
+ display: flex;
998
+ align-items: flex-start;
999
+ gap: 1rem;
1000
+ }
1001
+
1002
+ .comparison-icon {
1003
+ width: 2.5rem;
1004
+ height: 2.5rem;
1005
+ border-radius: var(--radius);
1006
+ display: flex;
1007
+ align-items: center;
1008
+ justify-content: center;
1009
+ flex-shrink: 0;
1010
+ }
1011
+
1012
+ .comparison-icon svg {
1013
+ width: 1.25rem;
1014
+ height: 1.25rem;
1015
+ }
1016
+
1017
+ .comparison-icon.green {
1018
+ background-color: hsl(var(--success) / 0.15);
1019
+ color: hsl(var(--success));
1020
+ }
1021
+
1022
+ .comparison-icon.blue {
1023
+ background-color: hsl(var(--info) / 0.15);
1024
+ color: hsl(var(--info));
1025
+ }
1026
+
1027
+ .comparison-icon.orange {
1028
+ background-color: hsl(var(--warning) / 0.15);
1029
+ color: hsl(var(--warning));
1030
+ }
1031
+
1032
+ .comparison-icon.purple {
1033
+ background-color: hsl(280 60% 50% / 0.15);
1034
+ color: hsl(280 60% 65%);
1035
+ }
1036
+
1037
+ .comparison-card-title {
1038
+ font-size: 1rem;
1039
+ font-weight: 600;
1040
+ margin-bottom: 0.25rem;
1041
+ }
1042
+
1043
+ .comparison-card-desc {
1044
+ font-size: 0.875rem;
1045
+ color: hsl(var(--muted-foreground));
1046
+ line-height: 1.5;
1047
+ }
1048
+
1049
+ .comparison-items {
1050
+ display: flex;
1051
+ flex-direction: column;
1052
+ gap: 0.75rem;
1053
+ padding-top: 0.5rem;
1054
+ border-top: 1px solid hsl(var(--border));
1055
+ }
1056
+
1057
+ .comparison-item {
1058
+ display: flex;
1059
+ align-items: center;
1060
+ justify-content: space-between;
1061
+ font-size: 0.8125rem;
1062
+ }
1063
+
1064
+ .comparison-item-label {
1065
+ color: hsl(var(--muted-foreground));
1066
+ }
1067
+
1068
+ .comparison-item-values {
1069
+ display: flex;
1070
+ align-items: center;
1071
+ gap: 1rem;
1072
+ }
1073
+
1074
+ .comparison-item-other {
1075
+ color: hsl(var(--muted-foreground));
1076
+ font-size: 0.75rem;
1077
+ text-decoration: line-through;
1078
+ opacity: 0.7;
1079
+ }
1080
+
1081
+ .comparison-item-findbug {
1082
+ color: hsl(var(--success));
1083
+ font-weight: 500;
1084
+ display: flex;
1085
+ align-items: center;
1086
+ gap: 0.375rem;
1087
+ }
1088
+
1089
+ .comparison-item-findbug svg {
1090
+ width: 0.875rem;
1091
+ height: 0.875rem;
1092
+ }
1093
+
1094
+ /* Full Width Comparison Card */
1095
+ .comparison-card.full-width {
1096
+ grid-column: span 2;
1097
+ }
1098
+
1099
+ @media (max-width: 768px) {
1100
+ .comparison-card.full-width { grid-column: span 1; }
1101
+ }
1102
+
1103
+ .comparison-highlight {
1104
+ display: flex;
1105
+ align-items: center;
1106
+ justify-content: center;
1107
+ gap: 3rem;
1108
+ padding: 1.5rem;
1109
+ background: linear-gradient(135deg, hsl(var(--success) / 0.08) 0%, hsl(var(--info) / 0.08) 100%);
1110
+ border-radius: calc(var(--radius) - 4px);
1111
+ flex-wrap: wrap;
1112
+ }
1113
+
1114
+ .comparison-highlight-item {
1115
+ text-align: center;
1116
+ }
1117
+
1118
+ .comparison-highlight-value {
1119
+ font-size: 2rem;
1120
+ font-weight: 700;
1121
+ letter-spacing: -0.025em;
1122
+ color: hsl(var(--foreground));
1123
+ }
1124
+
1125
+ .comparison-highlight-label {
1126
+ font-size: 0.75rem;
1127
+ color: hsl(var(--muted-foreground));
1128
+ margin-top: 0.25rem;
1129
+ }
1130
+
1131
+ /* Quick Start Section */
1132
+ .quickstart {
1133
+ padding: 5rem 0;
1134
+ background: hsl(0 0% 2%);
1135
+ }
1136
+
1137
+ .quickstart-container {
1138
+ max-width: 700px;
1139
+ margin: 0 auto;
1140
+ }
1141
+
1142
+ .quickstart-steps {
1143
+ display: flex;
1144
+ flex-direction: column;
1145
+ gap: 1.5rem;
1146
+ }
1147
+
1148
+ .quickstart-step {
1149
+ display: flex;
1150
+ gap: 1.25rem;
1151
+ align-items: flex-start;
1152
+ }
1153
+
1154
+ .step-number {
1155
+ width: 2rem;
1156
+ height: 2rem;
1157
+ background-color: hsl(var(--secondary));
1158
+ border: 1px solid hsl(var(--border));
1159
+ color: hsl(var(--foreground));
1160
+ border-radius: 50%;
1161
+ display: flex;
1162
+ align-items: center;
1163
+ justify-content: center;
1164
+ font-weight: 600;
1165
+ font-size: 0.8125rem;
1166
+ flex-shrink: 0;
1167
+ }
1168
+
1169
+ .step-content {
1170
+ flex: 1;
1171
+ }
1172
+
1173
+ .step-content h3 {
1174
+ font-size: 0.9375rem;
1175
+ font-weight: 600;
1176
+ margin-bottom: 0.625rem;
1177
+ }
1178
+
1179
+ .code-block {
1180
+ background-color: hsl(0 0% 7%);
1181
+ border: 1px solid hsl(var(--border));
1182
+ border-radius: var(--radius);
1183
+ padding: 1rem 1.25rem;
1184
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
1185
+ font-size: 0.8125rem;
1186
+ line-height: 1.6;
1187
+ overflow-x: auto;
1188
+ }
1189
+
1190
+ .code-block .prompt {
1191
+ color: hsl(var(--success));
1192
+ user-select: none;
1193
+ }
1194
+
1195
+ .code-block .comment {
1196
+ color: hsl(var(--muted-foreground));
1197
+ }
1198
+
1199
+ /* Architecture Section - Modern Flow Diagram */
1200
+ .architecture {
1201
+ padding: 5rem 0;
1202
+ }
1203
+
1204
+ .architecture-container {
1205
+ max-width: 1000px;
1206
+ margin: 0 auto;
1207
+ }
1208
+
1209
+ /* Flow Diagram */
1210
+ .flow-diagram {
1211
+ display: flex;
1212
+ flex-direction: column;
1213
+ gap: 2rem;
1214
+ padding: 2rem;
1215
+ background: linear-gradient(180deg, hsl(var(--card)) 0%, hsl(0 0% 5%) 100%);
1216
+ border: 1px solid hsl(var(--border));
1217
+ border-radius: var(--radius);
1218
+ position: relative;
1219
+ overflow: hidden;
1220
+ }
1221
+
1222
+
1223
+ /* Flow Row */
1224
+ .flow-row {
1225
+ display: flex;
1226
+ align-items: center;
1227
+ justify-content: center;
1228
+ gap: 1rem;
1229
+ position: relative;
1230
+ z-index: 1;
1231
+ }
1232
+
1233
+ .flow-row.split {
1234
+ display: grid;
1235
+ grid-template-columns: 1fr auto 1fr;
1236
+ gap: 1.5rem;
1237
+ }
1238
+
1239
+ /* Flow Nodes */
1240
+ .flow-node {
1241
+ background: hsl(var(--card));
1242
+ border: 1px solid hsl(var(--border));
1243
+ border-radius: var(--radius);
1244
+ padding: 1rem 1.25rem;
1245
+ text-align: center;
1246
+ min-width: 140px;
1247
+ transition: all 0.2s ease;
1248
+ }
1249
+
1250
+ .flow-node:hover {
1251
+ border-color: hsl(var(--muted-foreground) / 0.5);
1252
+ transform: translateY(-2px);
1253
+ }
1254
+
1255
+ .flow-node.primary {
1256
+ background: linear-gradient(135deg, hsl(var(--info) / 0.15) 0%, hsl(var(--info) / 0.05) 100%);
1257
+ border-color: hsl(var(--info) / 0.3);
1258
+ }
1259
+
1260
+ .flow-node.success {
1261
+ background: linear-gradient(135deg, hsl(var(--success) / 0.15) 0%, hsl(var(--success) / 0.05) 100%);
1262
+ border-color: hsl(var(--success) / 0.3);
1263
+ }
1264
+
1265
+ .flow-node.warning {
1266
+ background: linear-gradient(135deg, hsl(var(--warning) / 0.15) 0%, hsl(var(--warning) / 0.05) 100%);
1267
+ border-color: hsl(var(--warning) / 0.3);
1268
+ }
1269
+
1270
+ .flow-node.highlight {
1271
+ background: linear-gradient(135deg, hsl(280 60% 50% / 0.15) 0%, hsl(280 60% 50% / 0.05) 100%);
1272
+ border-color: hsl(280 60% 50% / 0.3);
1273
+ }
1274
+
1275
+ .flow-node-icon {
1276
+ width: 2.5rem;
1277
+ height: 2.5rem;
1278
+ margin: 0 auto 0.625rem;
1279
+ background: hsl(var(--secondary));
1280
+ border-radius: var(--radius);
1281
+ display: flex;
1282
+ align-items: center;
1283
+ justify-content: center;
1284
+ }
1285
+
1286
+ .flow-node-icon svg {
1287
+ width: 1.25rem;
1288
+ height: 1.25rem;
1289
+ color: hsl(var(--foreground));
1290
+ }
1291
+
1292
+ .flow-node-icon.blue { background: hsl(var(--info) / 0.2); }
1293
+ .flow-node-icon.blue svg { color: hsl(var(--info)); }
1294
+ .flow-node-icon.green { background: hsl(var(--success) / 0.2); }
1295
+ .flow-node-icon.green svg { color: hsl(var(--success)); }
1296
+ .flow-node-icon.orange { background: hsl(var(--warning) / 0.2); }
1297
+ .flow-node-icon.orange svg { color: hsl(var(--warning)); }
1298
+ .flow-node-icon.purple { background: hsl(280 60% 50% / 0.2); }
1299
+ .flow-node-icon.purple svg { color: hsl(280 60% 65%); }
1300
+
1301
+ .flow-node-title {
1302
+ font-size: 0.8125rem;
1303
+ font-weight: 600;
1304
+ margin-bottom: 0.25rem;
1305
+ }
1306
+
1307
+ .flow-node-desc {
1308
+ font-size: 0.6875rem;
1309
+ color: hsl(var(--muted-foreground));
1310
+ }
1311
+
1312
+ .flow-node-badge {
1313
+ display: inline-flex;
1314
+ padding: 0.125rem 0.5rem;
1315
+ font-size: 0.625rem;
1316
+ font-weight: 500;
1317
+ border-radius: 9999px;
1318
+ margin-top: 0.5rem;
1319
+ background: hsl(var(--success) / 0.15);
1320
+ color: hsl(var(--success));
1321
+ }
1322
+
1323
+ /* Flow Arrows */
1324
+ .flow-arrow {
1325
+ display: flex;
1326
+ align-items: center;
1327
+ justify-content: center;
1328
+ color: hsl(var(--muted-foreground));
1329
+ }
1330
+
1331
+ .flow-arrow svg {
1332
+ width: 1.5rem;
1333
+ height: 1.5rem;
1334
+ }
1335
+
1336
+ .flow-arrow.vertical {
1337
+ padding: 0.5rem 0;
1338
+ }
1339
+
1340
+ .flow-arrow.vertical svg {
1341
+ transform: rotate(90deg);
1342
+ animation: arrowPulseDown 2s ease-in-out infinite;
1343
+ }
1344
+
1345
+ @keyframes arrowPulseDown {
1346
+ 0%, 100% {
1347
+ opacity: 0.4;
1348
+ transform: rotate(90deg) translateX(0);
1349
+ }
1350
+ 50% {
1351
+ opacity: 1;
1352
+ transform: rotate(90deg) translateX(4px);
1353
+ }
1354
+ }
1355
+
1356
+ /* Flow Center Column */
1357
+ .flow-center {
1358
+ display: flex;
1359
+ flex-direction: column;
1360
+ align-items: center;
1361
+ gap: 0.5rem;
1362
+ }
1363
+
1364
+ /* Flow Side Nodes */
1365
+ .flow-side {
1366
+ display: flex;
1367
+ flex-direction: column;
1368
+ gap: 0.75rem;
1369
+ }
1370
+
1371
+ .flow-side.left {
1372
+ align-items: flex-end;
1373
+ }
1374
+
1375
+ .flow-side.right {
1376
+ align-items: flex-start;
1377
+ }
1378
+
1379
+ .flow-mini-node {
1380
+ display: flex;
1381
+ align-items: center;
1382
+ gap: 0.5rem;
1383
+ padding: 0.5rem 0.75rem;
1384
+ background: hsl(var(--secondary));
1385
+ border: 1px solid hsl(var(--border));
1386
+ border-radius: var(--radius);
1387
+ font-size: 0.75rem;
1388
+ }
1389
+
1390
+ .flow-mini-node svg {
1391
+ width: 0.875rem;
1392
+ height: 0.875rem;
1393
+ color: hsl(var(--muted-foreground));
1394
+ }
1395
+
1396
+ /* Architecture Stats */
1397
+ .architecture-stats {
1398
+ display: grid;
1399
+ grid-template-columns: repeat(4, 1fr);
1400
+ gap: 1rem;
1401
+ margin-top: 2rem;
1402
+ }
1403
+
1404
+ .arch-stat {
1405
+ background: hsl(var(--card));
1406
+ border: 1px solid hsl(var(--border));
1407
+ border-radius: var(--radius);
1408
+ padding: 1rem;
1409
+ text-align: center;
1410
+ transition: all 0.2s ease;
1411
+ }
1412
+
1413
+ .arch-stat:hover {
1414
+ border-color: hsl(var(--success) / 0.5);
1415
+ }
1416
+
1417
+ .arch-stat-icon {
1418
+ width: 2rem;
1419
+ height: 2rem;
1420
+ margin: 0 auto 0.5rem;
1421
+ background: hsl(var(--success) / 0.15);
1422
+ border-radius: 50%;
1423
+ display: flex;
1424
+ align-items: center;
1425
+ justify-content: center;
1426
+ }
1427
+
1428
+ .arch-stat-icon svg {
1429
+ width: 1rem;
1430
+ height: 1rem;
1431
+ color: hsl(var(--success));
1432
+ }
1433
+
1434
+ .arch-stat-value {
1435
+ font-size: 1.125rem;
1436
+ font-weight: 700;
1437
+ margin-bottom: 0.125rem;
1438
+ }
1439
+
1440
+ .arch-stat-label {
1441
+ font-size: 0.6875rem;
1442
+ color: hsl(var(--muted-foreground));
1443
+ }
1444
+
1445
+ @media (max-width: 768px) {
1446
+ .architecture-stats { grid-template-columns: repeat(2, 1fr); }
1447
+ .flow-row.split { grid-template-columns: 1fr; gap: 1rem; }
1448
+ .flow-side { flex-direction: row; flex-wrap: wrap; justify-content: center; }
1449
+ .flow-side.left, .flow-side.right { align-items: center; }
1450
+ .flow-diagram::before { display: none; }
1451
+ }
1452
+
1453
+ /* CTA Section */
1454
+ .cta {
1455
+ padding: 5rem 0;
1456
+ text-align: center;
1457
+ }
1458
+
1459
+ .cta h2 {
1460
+ font-size: 1.875rem;
1461
+ font-weight: 700;
1462
+ letter-spacing: -0.025em;
1463
+ margin-bottom: 0.75rem;
1464
+ }
1465
+
1466
+ .cta p {
1467
+ font-size: 1rem;
1468
+ color: hsl(var(--muted-foreground));
1469
+ margin-bottom: 1.5rem;
1470
+ max-width: 400px;
1471
+ margin-left: auto;
1472
+ margin-right: auto;
1473
+ }
1474
+
1475
+ /* Footer */
1476
+ footer {
1477
+ padding: 2rem 0;
1478
+ text-align: center;
1479
+ }
1480
+
1481
+ .footer-links {
1482
+ display: flex;
1483
+ justify-content: center;
1484
+ gap: 1.5rem;
1485
+ margin-bottom: 1rem;
1486
+ flex-wrap: wrap;
1487
+ }
1488
+
1489
+ .footer-links a {
1490
+ color: hsl(var(--muted-foreground));
1491
+ font-size: 0.875rem;
1492
+ transition: color 0.15s;
1493
+ }
1494
+
1495
+ .footer-links a:hover {
1496
+ color: hsl(var(--foreground));
1497
+ }
1498
+
1499
+ .footer-copyright {
1500
+ font-size: 0.8125rem;
1501
+ color: hsl(var(--muted-foreground));
1502
+ }
1503
+
1504
+ .footer-copyright a {
1505
+ color: hsl(var(--foreground));
1506
+ }
1507
+
1508
+ /* Responsive */
1509
+ @media (max-width: 768px) {
1510
+ h1 { font-size: 2.25rem; }
1511
+ .hero { padding: 6rem 0 4rem; }
1512
+ .nav-links { display: none; }
1513
+ .quickstart-step { flex-direction: column; gap: 0.75rem; }
1514
+ }
1515
+ </style>
1516
+ </head>
1517
+ <body>
1518
+ <!-- Navigation -->
1519
+ <nav class="site-nav">
1520
+ <div class="nav-container">
1521
+ <a href="#" class="logo">
1522
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1523
+ <path d="M8 2l1.88 1.88"/>
1524
+ <path d="M14.12 3.88L16 2"/>
1525
+ <path d="M9 7.13v-1a3.003 3.003 0 1 1 6 0v1"/>
1526
+ <path d="M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6"/>
1527
+ <path d="M12 20v-9"/>
1528
+ <path d="M6.53 9C4.6 8.8 3 7.1 3 5"/>
1529
+ <path d="M6 13H2"/>
1530
+ <path d="M3 21c0-2.1 1.7-3.9 3.8-4"/>
1531
+ <path d="M20.97 5c0 2.1-1.6 3.8-3.5 4"/>
1532
+ <path d="M22 13h-4"/>
1533
+ <path d="M17.2 17c2.1.1 3.8 1.9 3.8 4"/>
1534
+ </svg>
1535
+ <span>FindBug</span>
1536
+ </a>
1537
+ <div class="nav-links">
1538
+ <a href="#features">Features</a>
1539
+ <a href="#comparison">Compare</a>
1540
+ <a href="#architecture">Architecture</a>
1541
+ <a href="#demo">Demo</a>
1542
+ </div>
1543
+ <div class="nav-right">
1544
+ <a href="#demo" class="btn btn-primary btn-sm">
1545
+ Dashboard Demo
1546
+ </a>
1547
+ <a href="https://github.com/ITSSOUMIT/findbug" target="_blank" class="btn btn-outline btn-sm">
1548
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
1549
+ GitHub
1550
+ </a>
1551
+ </div>
1552
+ </div>
1553
+ </nav>
1554
+
1555
+ <!-- Hero Section -->
1556
+ <section class="hero">
1557
+ <div class="container">
1558
+ <div class="hero-badge">
1559
+ <span>NEW</span>
1560
+ v0.3.5 released with multi-tenant support
1561
+ </div>
1562
+ <h1>Catch bugs<br>before your users do</h1>
1563
+ <p>
1564
+ Self-hosted error tracking for Rails.<br>One gem. Zero SaaS. Full control.
1565
+ </p>
1566
+ <div class="hero-buttons">
1567
+ <!-- <a href="#quickstart" class="btn btn-primary">
1568
+ Get Started
1569
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
1570
+ </a> -->
1571
+ <a href="https://github.com/ITSSOUMIT/findbug" target="_blank" class="btn btn-secondary">
1572
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
1573
+ View on GitHub
1574
+ </a>
1575
+ </div>
1576
+ <div class="hero-code">
1577
+ <span class="comment"># Add to your Gemfile:</span><br>
1578
+ <span class="keyword">gem</span> <span class="string">"findbug", "~> 0.3.5"</span><br><br>
1579
+ <span class="comment"># Install and you're done!</span><br>
1580
+ $ rails generate findbug:install<br>
1581
+ $ rails db:migrate<br><br>
1582
+ <span class="comment"># Access the dashboard</span><br>
1583
+ http://localhost:3010/findbug<br><br>
1584
+ <span class="comment"># Default credentials:</span><br>
1585
+ <span class="comment"># Username: admin</span><br>
1586
+ <span class="comment"># Password: findbug</span><br>
1587
+ </div>
1588
+ </div>
1589
+ </section>
1590
+
1591
+ <!-- Features Section -->
1592
+ <section class="features" id="features">
1593
+ <div class="container">
1594
+ <div class="section-header">
1595
+ <h2>Everything you need to track errors</h2>
1596
+ <p>Production-ready error tracking and performance monitoring without the complexity or cost.</p>
1597
+ </div>
1598
+ <div class="bento-grid">
1599
+ <!-- Error Tracking - Wide Card with Code Snippet -->
1600
+ <div class="bento-card bento-wide">
1601
+ <h3>Error Tracking</h3>
1602
+ <p>Capture exceptions with full stack traces, request data, and custom context. Automatic grouping of similar errors.</p>
1603
+ <div class="visual">
1604
+ <div class="bento-code">
1605
+ <div class="line"><span class="line-num">1</span><span class="keyword">class</span> <span class="class">OrdersController</span> &lt; <span class="class">ApplicationController</span></div>
1606
+ <div class="line"><span class="line-num">2</span>&nbsp;&nbsp;<span class="keyword">def</span> <span class="method">create</span></div>
1607
+ <div class="line"><span class="line-num">3</span>&nbsp;&nbsp;&nbsp;&nbsp;@order = <span class="class">Order</span>.<span class="method">new</span>(order_params)</div>
1608
+ <div class="line" style="background: hsl(0 50% 15% / 0.5); margin: 0 -1rem; padding: 0 1rem;"><span class="line-num">4</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">raise</span> <span class="class">PaymentError</span>, <span class="string">"Card declined"</span> <span class="comment"># FindBug captures this</span></div>
1609
+ <div class="line"><span class="line-num">5</span>&nbsp;&nbsp;<span class="keyword">end</span></div>
1610
+ <div class="line"><span class="line-num">6</span><span class="keyword">end</span></div>
1611
+ </div>
1612
+ </div>
1613
+ </div>
1614
+
1615
+ <!-- Performance Stats - Narrow Card -->
1616
+ <div class="bento-card bento-narrow">
1617
+ <h3>Zero Impact</h3>
1618
+ <p>Async writes via Redis buffer. Never blocks your requests.</p>
1619
+ <div class="visual">
1620
+ <div class="stats-mini">
1621
+ <div class="stat-mini-item">
1622
+ <div class="value green">~1ms</div>
1623
+ <div class="label">Capture time</div>
1624
+ </div>
1625
+ <div class="stat-mini-item">
1626
+ <div class="value blue">0%</div>
1627
+ <div class="label">Request blocking</div>
1628
+ </div>
1629
+ </div>
1630
+ </div>
1631
+ </div>
1632
+
1633
+ <!-- Self-Hosted - Narrow Card with Privacy Visual -->
1634
+ <div class="bento-card bento-narrow">
1635
+ <h3>Self-Hosted</h3>
1636
+ <p>Your data stays on your infrastructure. Full privacy.</p>
1637
+ <div class="visual">
1638
+ <div class="privacy-visual">
1639
+ <div class="server-icon">
1640
+ <div class="icon">🌐</div>
1641
+ <span class="label">Your App</span>
1642
+ </div>
1643
+ <div class="data-flow">
1644
+ <span>→</span>
1645
+ <span>→</span>
1646
+ <span>→</span>
1647
+ </div>
1648
+ <div class="server-icon">
1649
+ <div class="icon">🗄️</div>
1650
+ <span class="label">Your DB</span>
1651
+ </div>
1652
+ </div>
1653
+ </div>
1654
+ </div>
1655
+
1656
+ <!-- Performance Monitoring - Wide Card with Bars -->
1657
+ <div class="bento-card bento-wide">
1658
+ <h3>Performance Monitoring</h3>
1659
+ <p>Track request timing, SQL queries, and automatic N+1 detection. Know exactly what's slowing your app down.</p>
1660
+ <div class="visual">
1661
+ <div class="perf-bars">
1662
+ <div class="perf-bar-row">
1663
+ <span class="perf-bar-label">Database</span>
1664
+ <div class="perf-bar-track"><div class="perf-bar-fill db"></div></div>
1665
+ <span class="perf-bar-time">156ms</span>
1666
+ </div>
1667
+ <div class="perf-bar-row">
1668
+ <span class="perf-bar-label">View</span>
1669
+ <div class="perf-bar-track"><div class="perf-bar-fill view"></div></div>
1670
+ <span class="perf-bar-time">48ms</span>
1671
+ </div>
1672
+ <div class="perf-bar-row">
1673
+ <span class="perf-bar-label">Ruby</span>
1674
+ <div class="perf-bar-track"><div class="perf-bar-fill ruby"></div></div>
1675
+ <span class="perf-bar-time">24ms</span>
1676
+ </div>
1677
+ <div class="perf-bar-row">
1678
+ <span class="perf-bar-label">Other</span>
1679
+ <div class="perf-bar-track"><div class="perf-bar-fill other"></div></div>
1680
+ <span class="perf-bar-time">12ms</span>
1681
+ </div>
1682
+ </div>
1683
+ </div>
1684
+ </div>
1685
+
1686
+ <!-- Dashboard - Half Card with Mock UI -->
1687
+ <div class="bento-card bento-half">
1688
+ <h3>Built-in Dashboard</h3>
1689
+ <p>Beautiful web UI for viewing errors and performance metrics.</p>
1690
+ <div class="visual">
1691
+ <div class="bento-dashboard">
1692
+ <div class="bento-dashboard-header">
1693
+ <span class="dot red"></span>
1694
+ <span class="dot yellow"></span>
1695
+ <span class="dot green"></span>
1696
+ </div>
1697
+ <div class="bento-dashboard-content">
1698
+ <div class="mock-error-list">
1699
+ <div class="mock-error-item">
1700
+ <span class="severity error"></span>
1701
+ <span class="error-name">PaymentError: Card declined</span>
1702
+ <span class="error-count">142</span>
1703
+ </div>
1704
+ <div class="mock-error-item">
1705
+ <span class="severity warning"></span>
1706
+ <span class="error-name">TimeoutError: Request timed out</span>
1707
+ <span class="error-count">38</span>
1708
+ </div>
1709
+ <div class="mock-error-item">
1710
+ <span class="severity info"></span>
1711
+ <span class="error-name">ValidationError: Email invalid</span>
1712
+ <span class="error-count">12</span>
1713
+ </div>
1714
+ </div>
1715
+ </div>
1716
+ </div>
1717
+ </div>
1718
+ </div>
1719
+
1720
+ <!-- Alerts - Half Card with Icons -->
1721
+ <div class="bento-card bento-half">
1722
+ <h3>Multi-channel Alerts</h3>
1723
+ <p>Get notified via Email, Slack, Discord, or custom webhooks.</p>
1724
+ <div class="visual">
1725
+ <div class="alert-icons">
1726
+ <div class="alert-icon slack">
1727
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zM6.313 15.165a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zM8.834 6.313a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zM18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zM17.688 8.834a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zM15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zM15.165 17.688a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z"/></svg>
1728
+ </div>
1729
+ <div class="alert-icon discord">
1730
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor"><path d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z"/></svg>
1731
+ </div>
1732
+ <div class="alert-icon email">
1733
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>
1734
+ </div>
1735
+ <div class="alert-icon webhook">
1736
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 16.98h-5.99c-1.1 0-1.95.94-2.48 1.9A4 4 0 0 1 2 17c.01-.7.2-1.4.57-2"/><path d="m6 17 3.13-5.78c.53-.97.1-2.18-.5-3.1a4 4 0 1 1 6.89-4.06"/><path d="m12 6 3.13 5.73C15.66 12.7 16.9 13 18 13a4 4 0 0 1 0 8H12"/></svg>
1737
+ </div>
1738
+ </div>
1739
+ </div>
1740
+ </div>
1741
+ </div>
1742
+ </div>
1743
+ </section>
1744
+
1745
+ <!-- Comparison Section - Problem Statement (Why existing solutions are painful) -->
1746
+ <section class="comparison" id="comparison">
1747
+ <div class="container">
1748
+ <div class="section-header">
1749
+ <h2>Why choose FindBug?</h2>
1750
+ <p>Self-hosted means you own everything. Here's what that unlocks.</p>
1751
+ </div>
1752
+ <div class="comparison-grid">
1753
+ <!-- Cost Card -->
1754
+ <div class="comparison-card">
1755
+ <div class="comparison-card-header">
1756
+ <div class="comparison-icon green">
1757
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/></svg>
1758
+ </div>
1759
+ <div>
1760
+ <h3 class="comparison-card-title">Zero Cost</h3>
1761
+ <p class="comparison-card-desc">No per-seat pricing, no usage limits, no surprise bills.</p>
1762
+ </div>
1763
+ </div>
1764
+ <div class="comparison-items">
1765
+ <div class="comparison-item">
1766
+ <span class="comparison-item-label">Monthly cost</span>
1767
+ <div class="comparison-item-values">
1768
+ <span class="comparison-item-other">$26+/seat</span>
1769
+ <span class="comparison-item-findbug">
1770
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>
1771
+ Free forever
1772
+ </span>
1773
+ </div>
1774
+ </div>
1775
+ <div class="comparison-item">
1776
+ <span class="comparison-item-label">Team size limits</span>
1777
+ <div class="comparison-item-values">
1778
+ <span class="comparison-item-other">Pay per user</span>
1779
+ <span class="comparison-item-findbug">
1780
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>
1781
+ Unlimited
1782
+ </span>
1783
+ </div>
1784
+ </div>
1785
+ <div class="comparison-item">
1786
+ <span class="comparison-item-label">Event quotas</span>
1787
+ <div class="comparison-item-values">
1788
+ <span class="comparison-item-other">Tier limits</span>
1789
+ <span class="comparison-item-findbug">
1790
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>
1791
+ No limits
1792
+ </span>
1793
+ </div>
1794
+ </div>
1795
+ </div>
1796
+ </div>
1797
+
1798
+ <!-- Privacy Card -->
1799
+ <div class="comparison-card">
1800
+ <div class="comparison-card-header">
1801
+ <div class="comparison-icon blue">
1802
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
1803
+ </div>
1804
+ <div>
1805
+ <h3 class="comparison-card-title">Full Data Ownership</h3>
1806
+ <p class="comparison-card-desc">Your error data never leaves your infrastructure.</p>
1807
+ </div>
1808
+ </div>
1809
+ <div class="comparison-items">
1810
+ <div class="comparison-item">
1811
+ <span class="comparison-item-label">Data location</span>
1812
+ <div class="comparison-item-values">
1813
+ <span class="comparison-item-other">Third-party</span>
1814
+ <span class="comparison-item-findbug">
1815
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>
1816
+ Your servers
1817
+ </span>
1818
+ </div>
1819
+ </div>
1820
+ <div class="comparison-item">
1821
+ <span class="comparison-item-label">GDPR/HIPAA</span>
1822
+ <div class="comparison-item-values">
1823
+ <span class="comparison-item-other">Requires DPA</span>
1824
+ <span class="comparison-item-findbug">
1825
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>
1826
+ Built-in
1827
+ </span>
1828
+ </div>
1829
+ </div>
1830
+ <div class="comparison-item">
1831
+ <span class="comparison-item-label">Data retention</span>
1832
+ <div class="comparison-item-values">
1833
+ <span class="comparison-item-other">Plan limits</span>
1834
+ <span class="comparison-item-findbug">
1835
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>
1836
+ You decide
1837
+ </span>
1838
+ </div>
1839
+ </div>
1840
+ </div>
1841
+ </div>
1842
+
1843
+ <!-- Simplicity Card -->
1844
+ <div class="comparison-card">
1845
+ <div class="comparison-card-header">
1846
+ <div class="comparison-icon orange">
1847
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
1848
+ </div>
1849
+ <div>
1850
+ <h3 class="comparison-card-title">Dead Simple Setup</h3>
1851
+ <p class="comparison-card-desc">One gem, one command. No SDK configuration hell.</p>
1852
+ </div>
1853
+ </div>
1854
+ <div class="comparison-items">
1855
+ <div class="comparison-item">
1856
+ <span class="comparison-item-label">Installation</span>
1857
+ <div class="comparison-item-values">
1858
+ <span class="comparison-item-other">SDK + API keys</span>
1859
+ <span class="comparison-item-findbug">
1860
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>
1861
+ One gem
1862
+ </span>
1863
+ </div>
1864
+ </div>
1865
+ <div class="comparison-item">
1866
+ <span class="comparison-item-label">Configuration</span>
1867
+ <div class="comparison-item-values">
1868
+ <span class="comparison-item-other">DSN, tokens</span>
1869
+ <span class="comparison-item-findbug">
1870
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>
1871
+ Zero config
1872
+ </span>
1873
+ </div>
1874
+ </div>
1875
+ <div class="comparison-item">
1876
+ <span class="comparison-item-label">Background jobs</span>
1877
+ <div class="comparison-item-values">
1878
+ <span class="comparison-item-other">Sidekiq required</span>
1879
+ <span class="comparison-item-findbug">
1880
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>
1881
+ Built-in
1882
+ </span>
1883
+ </div>
1884
+ </div>
1885
+ </div>
1886
+ </div>
1887
+
1888
+ <!-- Reliability Card -->
1889
+ <div class="comparison-card">
1890
+ <div class="comparison-card-header">
1891
+ <div class="comparison-icon purple">
1892
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
1893
+ </div>
1894
+ <div>
1895
+ <h3 class="comparison-card-title">Always Available</h3>
1896
+ <p class="comparison-card-desc">No external dependencies. Works even when the internet doesn't.</p>
1897
+ </div>
1898
+ </div>
1899
+ <div class="comparison-items">
1900
+ <div class="comparison-item">
1901
+ <span class="comparison-item-label">Network dependency</span>
1902
+ <div class="comparison-item-values">
1903
+ <span class="comparison-item-other">Required</span>
1904
+ <span class="comparison-item-findbug">
1905
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>
1906
+ None
1907
+ </span>
1908
+ </div>
1909
+ </div>
1910
+ <div class="comparison-item">
1911
+ <span class="comparison-item-label">Service outages</span>
1912
+ <div class="comparison-item-values">
1913
+ <span class="comparison-item-other">Data loss risk</span>
1914
+ <span class="comparison-item-findbug">
1915
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>
1916
+ Impossible
1917
+ </span>
1918
+ </div>
1919
+ </div>
1920
+ <div class="comparison-item">
1921
+ <span class="comparison-item-label">Capture latency</span>
1922
+ <div class="comparison-item-values">
1923
+ <span class="comparison-item-other">Network RTT</span>
1924
+ <span class="comparison-item-findbug">
1925
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>
1926
+ ~1ms local
1927
+ </span>
1928
+ </div>
1929
+ </div>
1930
+ </div>
1931
+ </div>
1932
+
1933
+ <!-- Bottom Highlight -->
1934
+ <div class="comparison-card full-width">
1935
+ <div class="comparison-highlight">
1936
+ <div class="comparison-highlight-item">
1937
+ <div class="comparison-highlight-value">$0</div>
1938
+ <div class="comparison-highlight-label">Monthly cost</div>
1939
+ </div>
1940
+ <div class="comparison-highlight-item">
1941
+ <div class="comparison-highlight-value">~1ms</div>
1942
+ <div class="comparison-highlight-label">Capture time</div>
1943
+ </div>
1944
+ <div class="comparison-highlight-item">
1945
+ <div class="comparison-highlight-value">100%</div>
1946
+ <div class="comparison-highlight-label">Data ownership</div>
1947
+ </div>
1948
+ <div class="comparison-highlight-item">
1949
+ <div class="comparison-highlight-value">2 min</div>
1950
+ <div class="comparison-highlight-label">Setup time</div>
1951
+ </div>
1952
+ </div>
1953
+ </div>
1954
+ </div>
1955
+ </div>
1956
+ </section>
1957
+
1958
+ <!-- Architecture Section -->
1959
+ <section class="architecture" id="architecture">
1960
+ <div class="container">
1961
+ <div class="architecture-container">
1962
+ <div class="section-header">
1963
+ <h2>Built for performance</h2>
1964
+ <p>FindBug is designed to never slow down your application.</p>
1965
+ </div>
1966
+
1967
+ <div class="flow-diagram">
1968
+ <!-- Row 1: Rails App -->
1969
+ <div class="flow-row">
1970
+ <div class="flow-node primary" style="min-width: 200px;">
1971
+ <div class="flow-node-icon blue">
1972
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
1973
+ </div>
1974
+ <div class="flow-node-title">Your Rails App</div>
1975
+ <div class="flow-node-desc">Requests flow through normally</div>
1976
+ </div>
1977
+ </div>
1978
+
1979
+ <!-- Arrow Down -->
1980
+ <div class="flow-arrow vertical">
1981
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
1982
+ </div>
1983
+
1984
+ <!-- Row 2: Split - Error & Performance Capture -->
1985
+ <div class="flow-row split">
1986
+ <div class="flow-side left">
1987
+ <div class="flow-mini-node">
1988
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
1989
+ Exception Middleware
1990
+ </div>
1991
+ <div class="flow-mini-node">
1992
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg>
1993
+ Performance Instrumentation
1994
+ </div>
1995
+ </div>
1996
+
1997
+ <div class="flow-center">
1998
+ <div class="flow-node warning">
1999
+ <div class="flow-node-icon orange">
2000
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/></svg>
2001
+ </div>
2002
+ <div class="flow-node-title">Redis Buffer</div>
2003
+ <div class="flow-node-desc">Async queue for events</div>
2004
+ <div class="flow-node-badge">~1ms write</div>
2005
+ </div>
2006
+ </div>
2007
+
2008
+ <div class="flow-side right">
2009
+ <div class="flow-mini-node">
2010
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
2011
+ Non-blocking
2012
+ </div>
2013
+ <div class="flow-mini-node">
2014
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
2015
+ Circuit breaker
2016
+ </div>
2017
+ </div>
2018
+ </div>
2019
+
2020
+ <!-- Arrow Down -->
2021
+ <div class="flow-arrow vertical">
2022
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
2023
+ </div>
2024
+
2025
+ <!-- Row 3: Background Thread -->
2026
+ <div class="flow-row">
2027
+ <div class="flow-node highlight">
2028
+ <div class="flow-node-icon purple">
2029
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
2030
+ </div>
2031
+ <div class="flow-node-title">Background Thread</div>
2032
+ <div class="flow-node-desc">Flushes every 30 seconds</div>
2033
+ <div class="flow-node-badge">No Sidekiq needed</div>
2034
+ </div>
2035
+ </div>
2036
+
2037
+ <!-- Arrow Down -->
2038
+ <div class="flow-arrow vertical">
2039
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
2040
+ </div>
2041
+
2042
+ <!-- Row 4: Database & Dashboard -->
2043
+ <div class="flow-row" style="gap: 2rem;">
2044
+ <div class="flow-node success">
2045
+ <div class="flow-node-icon green">
2046
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/></svg>
2047
+ </div>
2048
+ <div class="flow-node-title">Your Database</div>
2049
+ <div class="flow-node-desc">PostgreSQL / MySQL</div>
2050
+ </div>
2051
+
2052
+ <div class="flow-arrow">
2053
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>
2054
+ </div>
2055
+
2056
+ <div class="flow-node success">
2057
+ <div class="flow-node-icon green">
2058
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="9" y1="21" x2="9" y2="9"/></svg>
2059
+ </div>
2060
+ <div class="flow-node-title">Dashboard</div>
2061
+ <div class="flow-node-desc">/findbug</div>
2062
+ </div>
2063
+ </div>
2064
+ </div>
2065
+
2066
+ <!-- Stats Grid -->
2067
+ <div class="architecture-stats">
2068
+ <div class="arch-stat">
2069
+ <div class="arch-stat-icon">
2070
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
2071
+ </div>
2072
+ <div class="arch-stat-value">~1ms</div>
2073
+ <div class="arch-stat-label">Capture time</div>
2074
+ </div>
2075
+ <div class="arch-stat">
2076
+ <div class="arch-stat-icon">
2077
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
2078
+ </div>
2079
+ <div class="arch-stat-value">Zero</div>
2080
+ <div class="arch-stat-label">Request blocking</div>
2081
+ </div>
2082
+ <div class="arch-stat">
2083
+ <div class="arch-stat-icon">
2084
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
2085
+ </div>
2086
+ <div class="arch-stat-value">30s</div>
2087
+ <div class="arch-stat-label">Flush interval</div>
2088
+ </div>
2089
+ <div class="arch-stat">
2090
+ <div class="arch-stat-icon">
2091
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>
2092
+ </div>
2093
+ <div class="arch-stat-value">Built-in</div>
2094
+ <div class="arch-stat-label">Circuit breaker</div>
2095
+ </div>
2096
+ </div>
2097
+ </div>
2098
+ </div>
2099
+ </section>
2100
+
2101
+ <!-- Demo Section -->
2102
+ <section class="demo" id="demo">
2103
+ <div class="container">
2104
+ <div class="section-header">
2105
+ <h2>See it in action</h2>
2106
+ <p>A preview of what your FindBug dashboard looks like with real error data.</p>
2107
+ </div>
2108
+ <div class="demo-container">
2109
+ <div class="demo-window">
2110
+ <!-- Browser Title Bar -->
2111
+ <div class="demo-titlebar">
2112
+ <div class="dots">
2113
+ <span class="dot red"></span>
2114
+ <span class="dot yellow"></span>
2115
+ <span class="dot green"></span>
2116
+ </div>
2117
+ <div class="url">localhost:3010/findbug</div>
2118
+ </div>
2119
+
2120
+ <!-- App Header - Matches real Findbug layout -->
2121
+ <div class="demo-app-header">
2122
+ <div class="demo-app-logo">
2123
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2124
+ <path d="M8 2l1.88 1.88"/><path d="M14.12 3.88L16 2"/><path d="M9 7.13v-1a3.003 3.003 0 1 1 6 0v1"/><path d="M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6"/><path d="M12 20v-9"/><path d="M6.53 9C4.6 8.8 3 7.1 3 5"/><path d="M6 13H2"/><path d="M3 21c0-2.1 1.7-3.9 3.8-4"/><path d="M20.97 5c0 2.1-1.6 3.8-3.5 4"/><path d="M22 13h-4"/><path d="M17.2 17c2.1.1 3.8 1.9 3.8 4"/>
2125
+ </svg>
2126
+ <span>FindBug</span>
2127
+ </div>
2128
+ <nav class="demo-app-nav">
2129
+ <a class="active">Dashboard</a>
2130
+ <a>Errors</a>
2131
+ <a>Performance</a>
2132
+ </nav>
2133
+ <div class="demo-header-right">
2134
+ <div class="demo-health-indicator">
2135
+ <span class="demo-health-dot"></span>
2136
+ <span>Healthy</span>
2137
+ </div>
2138
+ </div>
2139
+ </div>
2140
+
2141
+ <!-- Main Content - Dashboard View -->
2142
+ <div class="demo-main">
2143
+ <h1 class="demo-page-title">Dashboard</h1>
2144
+ <p class="demo-page-description">Monitor errors and performance across your application.</p>
2145
+
2146
+ <!-- Stats Grid - Matches real dashboard exactly -->
2147
+ <div class="demo-stats-grid">
2148
+ <div class="demo-stat-card">
2149
+ <div class="demo-stat-label">Unresolved Errors</div>
2150
+ <div class="demo-stat-value error">12</div>
2151
+ <div class="demo-stat-change">Total: 247</div>
2152
+ </div>
2153
+ <div class="demo-stat-card">
2154
+ <div class="demo-stat-label">Errors (24h)</div>
2155
+ <div class="demo-stat-value">38</div>
2156
+ <div class="demo-stat-change">Last 7d: 156</div>
2157
+ </div>
2158
+ <div class="demo-stat-card">
2159
+ <div class="demo-stat-label">Avg Response Time</div>
2160
+ <div class="demo-stat-value">142<span class="unit">ms</span></div>
2161
+ <div class="demo-stat-change">1,847 requests (24h)</div>
2162
+ </div>
2163
+ <div class="demo-stat-card">
2164
+ <div class="demo-stat-label">N+1 Issues (24h)</div>
2165
+ <div class="demo-stat-value warning">3</div>
2166
+ <div class="demo-stat-change">Performance issues detected</div>
2167
+ </div>
2168
+ </div>
2169
+
2170
+ <!-- Two Column Grid -->
2171
+ <div class="demo-grid-2">
2172
+ <!-- Recent Errors Card -->
2173
+ <div class="demo-card">
2174
+ <div class="demo-card-header">
2175
+ <div>
2176
+ <h2 class="demo-card-title">Recent Errors</h2>
2177
+ <p class="demo-card-description">Unresolved errors from your application</p>
2178
+ </div>
2179
+ <button class="demo-btn-outline">View All</button>
2180
+ </div>
2181
+ <table class="demo-table">
2182
+ <thead>
2183
+ <tr>
2184
+ <th>Error</th>
2185
+ <th>Count</th>
2186
+ <th>Last Seen</th>
2187
+ </tr>
2188
+ </thead>
2189
+ <tbody>
2190
+ <tr>
2191
+ <td>
2192
+ <a href="#" class="demo-font-mono" style="font-weight: 600;">Stripe::CardError</a><br>
2193
+ <span class="demo-text-muted demo-text-sm">Your card was declined</span>
2194
+ </td>
2195
+ <td><span class="demo-badge demo-badge-error">142</span></td>
2196
+ <td class="demo-text-muted demo-text-sm">2 minutes ago</td>
2197
+ </tr>
2198
+ <tr>
2199
+ <td>
2200
+ <a href="#" class="demo-font-mono" style="font-weight: 600;">ActiveRecord::RecordInvalid</a><br>
2201
+ <span class="demo-text-muted demo-text-sm">Validation failed: Email taken</span>
2202
+ </td>
2203
+ <td><span class="demo-badge demo-badge-error">89</span></td>
2204
+ <td class="demo-text-muted demo-text-sm">5 minutes ago</td>
2205
+ </tr>
2206
+ <tr>
2207
+ <td>
2208
+ <a href="#" class="demo-font-mono" style="font-weight: 600;">Net::ReadTimeout</a><br>
2209
+ <span class="demo-text-muted demo-text-sm">Request to api.example.com...</span>
2210
+ </td>
2211
+ <td><span class="demo-badge demo-badge-muted">8</span></td>
2212
+ <td class="demo-text-muted demo-text-sm">12 minutes ago</td>
2213
+ </tr>
2214
+ </tbody>
2215
+ </table>
2216
+ </div>
2217
+
2218
+ <!-- Slowest Endpoints Card -->
2219
+ <div class="demo-card">
2220
+ <div class="demo-card-header">
2221
+ <div>
2222
+ <h2 class="demo-card-title">Slowest Endpoints</h2>
2223
+ <p class="demo-card-description">Performance data from the last 24 hours</p>
2224
+ </div>
2225
+ <button class="demo-btn-outline">View All</button>
2226
+ </div>
2227
+ <table class="demo-table">
2228
+ <thead>
2229
+ <tr>
2230
+ <th>Endpoint</th>
2231
+ <th>Avg</th>
2232
+ <th>Max</th>
2233
+ </tr>
2234
+ </thead>
2235
+ <tbody>
2236
+ <tr>
2237
+ <td><a href="#" class="demo-font-mono demo-text-sm">OrdersController#create</a></td>
2238
+ <td><span class="demo-badge demo-badge-warning">847ms</span></td>
2239
+ <td class="demo-text-muted demo-text-sm">1,245ms</td>
2240
+ </tr>
2241
+ <tr>
2242
+ <td><a href="#" class="demo-font-mono demo-text-sm">ReportsController#index</a></td>
2243
+ <td><span class="demo-badge demo-badge-warning">623ms</span></td>
2244
+ <td class="demo-text-muted demo-text-sm">982ms</td>
2245
+ </tr>
2246
+ <tr>
2247
+ <td><a href="#" class="demo-font-mono demo-text-sm">UsersController#show</a></td>
2248
+ <td><span class="demo-badge demo-badge-muted">156ms</span></td>
2249
+ <td class="demo-text-muted demo-text-sm">298ms</td>
2250
+ </tr>
2251
+ </tbody>
2252
+ </table>
2253
+ </div>
2254
+ </div>
2255
+ </div>
2256
+ </div>
2257
+ </div>
2258
+ </div>
2259
+ </section>
2260
+
2261
+ <!-- CTA Section -->
2262
+ <section class="cta">
2263
+ <div class="container">
2264
+ <h2>Ready to own your error data?</h2>
2265
+ <p>Start tracking errors in your Rails application today. No credit card, no sign-up required.</p>
2266
+ <a href="https://github.com/ITSSOUMIT/findbug" target="_blank" class="btn btn-primary">
2267
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
2268
+ Get Started on GitHub
2269
+ </a>
2270
+ </div>
2271
+ </section>
2272
+
2273
+ <!-- Footer -->
2274
+ <footer>
2275
+ <div class="container">
2276
+ <div class="footer-links">
2277
+ <a href="https://github.com/ITSSOUMIT/findbug" target="_blank">GitHub</a>
2278
+ <a href="https://rubygems.org/gems/findbug" target="_blank">RubyGems</a>
2279
+ <a href="https://github.com/ITSSOUMIT/findbug/issues" target="_blank">Report Issue</a>
2280
+ <a href="mailto:hey@soumit.in">Contact</a>
2281
+ </div>
2282
+ <p class="footer-copyright">
2283
+ Built by <a href="https://www.linkedin.com/in/itssoumit" target="_blank">Soumit Das</a> · MIT License
2284
+ </p>
2285
+ </div>
2286
+ </footer>
2287
+ </body>
2288
+ </html>