solidstats 1.1.0 → 2.0.0

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.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +68 -0
  3. data/README.md +33 -0
  4. data/app/assets/javascripts/solidstats/application.js +257 -0
  5. data/app/assets/javascripts/solidstats/dashboard.js +225 -0
  6. data/app/assets/javascripts/solidstats/gem_metadata.js +554 -0
  7. data/app/assets/stylesheets/solidstats/application.css +6 -1
  8. data/app/assets/stylesheets/solidstats/components/action_button.css +99 -0
  9. data/app/assets/stylesheets/solidstats/components/dashboard.css +151 -0
  10. data/app/assets/stylesheets/solidstats/components/dashboard_header.css +93 -0
  11. data/app/assets/stylesheets/solidstats/components/dashboard_layout.css +97 -0
  12. data/app/assets/stylesheets/solidstats/components/gem_metadata.css +1403 -0
  13. data/app/assets/stylesheets/solidstats/components/navigation.css +80 -0
  14. data/app/assets/stylesheets/solidstats/components/quick_navigation.css +54 -0
  15. data/app/assets/stylesheets/solidstats/components/security.css +332 -0
  16. data/app/assets/stylesheets/solidstats/components/status_badge.css +58 -0
  17. data/app/assets/stylesheets/solidstats/components/summary_card.css +66 -0
  18. data/app/assets/stylesheets/solidstats/components/tab_navigation.css +95 -0
  19. data/app/components/solidstats/base_component.rb +88 -0
  20. data/app/components/solidstats/code_quality/code_quality_section_component.html.erb +0 -0
  21. data/app/components/solidstats/code_quality/code_quality_section_component.rb +0 -0
  22. data/app/components/solidstats/code_quality/section_component.html.erb +45 -0
  23. data/app/components/solidstats/code_quality/section_component.rb +34 -0
  24. data/app/components/solidstats/dashboard_header_component.html.erb +39 -0
  25. data/app/components/solidstats/dashboard_header_component.rb +33 -0
  26. data/app/components/solidstats/previews/action_button_component_preview/button_vs_link.html.erb +6 -0
  27. data/app/components/solidstats/previews/action_button_component_preview/sizes.html.erb +6 -0
  28. data/app/components/solidstats/previews/action_button_component_preview/variants.html.erb +6 -0
  29. data/app/components/solidstats/previews/action_button_component_preview/with_icons.html.erb +6 -0
  30. data/app/components/solidstats/previews/action_button_component_preview.rb +64 -0
  31. data/app/components/solidstats/previews/navigation_component_preview.rb +74 -0
  32. data/app/components/solidstats/previews/stats_overview_component_preview.rb +100 -0
  33. data/app/components/solidstats/previews/status_badge_component_preview/sizes.html.erb +6 -0
  34. data/app/components/solidstats/previews/status_badge_component_preview/statuses.html.erb +6 -0
  35. data/app/components/solidstats/previews/status_badge_component_preview/with_icons.html.erb +6 -0
  36. data/app/components/solidstats/previews/status_badge_component_preview.rb +49 -0
  37. data/app/components/solidstats/previews/summary_card_component_preview/clickable.html.erb +9 -0
  38. data/app/components/solidstats/previews/summary_card_component_preview/dashboard_layout.html.erb +9 -0
  39. data/app/components/solidstats/previews/summary_card_component_preview/statuses.html.erb +6 -0
  40. data/app/components/solidstats/previews/summary_card_component_preview/value_formats.html.erb +6 -0
  41. data/app/components/solidstats/previews/summary_card_component_preview.rb +67 -0
  42. data/app/components/solidstats/quick_navigation_component.html.erb +8 -0
  43. data/app/components/solidstats/quick_navigation_component.rb +21 -0
  44. data/app/components/solidstats/security/gem_impact_analysis_component.html.erb +44 -0
  45. data/app/components/solidstats/security/gem_impact_analysis_component.rb +45 -0
  46. data/app/components/solidstats/security/overview_component.html.erb +21 -0
  47. data/app/components/solidstats/security/overview_component.rb +104 -0
  48. data/app/components/solidstats/security/section_component.html.erb +26 -0
  49. data/app/components/solidstats/security/section_component.rb +52 -0
  50. data/app/components/solidstats/security/timeline_component.html.erb +39 -0
  51. data/app/components/solidstats/security/timeline_component.rb +43 -0
  52. data/app/components/solidstats/tasks_section_component.html.erb +17 -0
  53. data/app/components/solidstats/tasks_section_component.rb +22 -0
  54. data/app/components/solidstats/ui/action_button_component.html.erb +6 -0
  55. data/app/components/solidstats/ui/action_button_component.rb +71 -0
  56. data/app/components/solidstats/ui/dashboard_layout_component.html.erb +19 -0
  57. data/app/components/solidstats/ui/dashboard_layout_component.rb +85 -0
  58. data/app/components/solidstats/ui/navigation_component.html.erb +34 -0
  59. data/app/components/solidstats/ui/navigation_component.rb +72 -0
  60. data/app/components/solidstats/ui/stats_overview_component.html.erb +14 -0
  61. data/app/components/solidstats/ui/stats_overview_component.rb +78 -0
  62. data/app/components/solidstats/ui/status_badge_component.html.erb +6 -0
  63. data/app/components/solidstats/ui/status_badge_component.rb +42 -0
  64. data/app/components/solidstats/ui/summary_card_component.html.erb +12 -0
  65. data/app/components/solidstats/ui/summary_card_component.rb +63 -0
  66. data/app/components/solidstats/ui/tab_navigation_component.html.erb +22 -0
  67. data/app/components/solidstats/ui/tab_navigation_component.rb +79 -0
  68. data/app/controllers/solidstats/dashboard_controller.rb +8 -5
  69. data/app/controllers/solidstats/gem_metadata_controller.rb +12 -0
  70. data/app/helpers/solidstats/application_helper.rb +42 -0
  71. data/app/services/solidstats/gem_metadata/fetcher_service.rb +136 -0
  72. data/app/services/solidstats/log_size_monitor_service.rb +10 -10
  73. data/app/views/layouts/solidstats/application.html.erb +2 -1
  74. data/app/views/solidstats/dashboard/index.html.erb +67 -1337
  75. data/app/views/solidstats/gem_metadata/_panel.html.erb +419 -0
  76. data/config/routes.rb +5 -2
  77. data/lib/generators/solidstats/feature/feature_generator.rb +170 -0
  78. data/lib/generators/solidstats/feature/templates/component.html.erb +84 -0
  79. data/lib/generators/solidstats/feature/templates/component.rb.erb +103 -0
  80. data/lib/generators/solidstats/feature/templates/component.scss +243 -0
  81. data/lib/generators/solidstats/feature/templates/component_test.rb.erb +183 -0
  82. data/lib/generators/solidstats/feature/templates/controller.rb.erb +44 -0
  83. data/lib/generators/solidstats/feature/templates/controller_test.rb.erb +111 -0
  84. data/lib/generators/solidstats/feature/templates/detail_view.html.erb +755 -0
  85. data/lib/generators/solidstats/feature/templates/preview.rb.erb +107 -0
  86. data/lib/generators/solidstats/feature/templates/service.rb.erb +132 -0
  87. data/lib/generators/solidstats/feature/templates/service_test.rb.erb +109 -0
  88. data/lib/generators/solidstats/install_generator.rb +109 -0
  89. data/lib/generators/solidstats/templates/initializer.rb +112 -0
  90. data/lib/solidstats/asset_compatibility.rb +238 -0
  91. data/lib/solidstats/asset_manifest.rb +205 -0
  92. data/lib/solidstats/engine.rb +114 -9
  93. data/lib/solidstats/version.rb +1 -1
  94. data/lib/solidstats.rb +299 -2
  95. data/lib/tasks/solidstats_install.rake +122 -2
  96. metadata +97 -2
@@ -0,0 +1,1403 @@
1
+
2
+ /* ========================================
3
+ SECURITY.CSS CONFLICT OVERRIDE
4
+ Override any conflicting styles from security.css
5
+ ======================================== */
6
+
7
+ /* Ensure the gem metadata page grid is not affected by security.css .gems-container */
8
+ .gem-metadata-index .gems-container {
9
+ /* Reset any inherited grid properties from security.css */
10
+ display: block;
11
+ grid-template-columns: unset;
12
+ gap: unset;
13
+ margin-top: unset;
14
+ }
15
+
16
+ /* Modern Gem Metadata Index Styles */
17
+ .gem-metadata-index {
18
+ min-height: 100vh;
19
+ background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
20
+ padding: 2rem;
21
+ width: 100%;
22
+ max-width: 100%;
23
+ box-sizing: border-box;
24
+ }
25
+
26
+ /* Page Header */
27
+ .page-header {
28
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
29
+ border-radius: 16px;
30
+ padding: 2rem;
31
+ margin-bottom: 2rem;
32
+ color: white;
33
+ box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
34
+ }
35
+
36
+ .header-content {
37
+ display: flex;
38
+ justify-content: space-between;
39
+ align-items: center;
40
+ }
41
+
42
+ .header-title-section {
43
+ flex: 1;
44
+ }
45
+
46
+ .page-title {
47
+ font-size: 2rem;
48
+ font-weight: 700;
49
+ margin: 0 0 0.5rem 0;
50
+ display: flex;
51
+ align-items: center;
52
+ gap: 0.75rem;
53
+ }
54
+
55
+ .page-icon {
56
+ font-size: 2.25rem;
57
+ }
58
+
59
+ .page-subtitle {
60
+ font-size: 1rem;
61
+ opacity: 0.9;
62
+ font-weight: 400;
63
+ }
64
+
65
+ .header-actions {
66
+ display: flex;
67
+ gap: 1rem;
68
+ }
69
+
70
+ .action-btn {
71
+ display: flex;
72
+ align-items: center;
73
+ gap: 0.5rem;
74
+ padding: 0.75rem 1.5rem;
75
+ border-radius: 8px;
76
+ text-decoration: none;
77
+ font-weight: 600;
78
+ font-size: 0.875rem;
79
+ transition: all 0.2s ease;
80
+ border: 1px solid transparent;
81
+ }
82
+
83
+ .refresh-btn {
84
+ background: rgba(255, 255, 255, 0.2);
85
+ color: white;
86
+ backdrop-filter: blur(10px);
87
+ }
88
+
89
+ .refresh-btn:hover {
90
+ background: rgba(255, 255, 255, 0.3);
91
+ color: white;
92
+ transform: translateY(-1px);
93
+ }
94
+
95
+ .refresh-btn.primary {
96
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
97
+ color: white;
98
+ }
99
+
100
+ /* Stats Overview */
101
+ .stats-overview {
102
+ display: grid;
103
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
104
+ gap: 1.5rem;
105
+ margin-bottom: 2rem;
106
+ }
107
+
108
+ .stat-card {
109
+ background: white;
110
+ border-radius: 12px;
111
+ padding: 1.5rem;
112
+ display: flex;
113
+ align-items: center;
114
+ gap: 1rem;
115
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
116
+ border: 1px solid rgba(0, 0, 0, 0.05);
117
+ transition: transform 0.2s ease;
118
+ }
119
+
120
+ .stat-card:hover {
121
+ transform: translateY(-2px);
122
+ }
123
+
124
+ .stat-icon {
125
+ font-size: 2rem;
126
+ width: 60px;
127
+ height: 60px;
128
+ display: flex;
129
+ align-items: center;
130
+ justify-content: center;
131
+ border-radius: 12px;
132
+ background: #f8fafc;
133
+ }
134
+
135
+ .stat-card.total .stat-icon {
136
+ background: linear-gradient(135deg, #e0f2fe 0%, #b3e5fc 100%);
137
+ }
138
+
139
+ .stat-card.outdated .stat-icon {
140
+ background: linear-gradient(135deg, #fff3e0 0%, #ffcc02 50%);
141
+ }
142
+
143
+ .stat-card.up-to-date .stat-icon {
144
+ background: linear-gradient(135deg, #e8f5e8 0%, #c8e6c9 100%);
145
+ }
146
+
147
+ .stat-card.unavailable .stat-icon {
148
+ background: linear-gradient(135deg, #fafafa 0%, #eeeeee 100%);
149
+ }
150
+
151
+ .stat-content {
152
+ flex: 1;
153
+ }
154
+
155
+ .stat-number {
156
+ font-size: 2rem;
157
+ font-weight: 700;
158
+ color: #1f2937;
159
+ margin-bottom: 0.25rem;
160
+ }
161
+
162
+ .stat-label {
163
+ font-size: 0.875rem;
164
+ color: #6b7280;
165
+ font-weight: 500;
166
+ }
167
+
168
+ /* Search and Filters */
169
+ .search-filters {
170
+ background: white;
171
+ border-radius: 12px;
172
+ padding: 1.5rem;
173
+ margin-bottom: 2rem;
174
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
175
+ border: 1px solid rgba(0, 0, 0, 0.05);
176
+ }
177
+
178
+ .search-section {
179
+ margin-bottom: 1.5rem;
180
+ }
181
+
182
+ .search-input-wrapper {
183
+ position: relative;
184
+ max-width: 400px;
185
+ }
186
+
187
+ .search-icon {
188
+ position: absolute;
189
+ left: 1rem;
190
+ top: 50%;
191
+ transform: translateY(-50%);
192
+ color: #9ca3af;
193
+ font-size: 0.875rem;
194
+ }
195
+
196
+ .search-input {
197
+ width: 100%;
198
+ padding: 0.75rem 1rem 0.75rem 2.5rem;
199
+ border: 2px solid #e5e7eb;
200
+ border-radius: 8px;
201
+ font-size: 0.875rem;
202
+ transition: all 0.2s ease;
203
+ background: #f9fafb;
204
+ }
205
+
206
+ .search-input:focus {
207
+ outline: none;
208
+ border-color: #667eea;
209
+ background: white;
210
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
211
+ }
212
+
213
+ .clear-search {
214
+ position: absolute;
215
+ right: 0.75rem;
216
+ top: 50%;
217
+ transform: translateY(-50%);
218
+ background: none;
219
+ border: none;
220
+ color: #9ca3af;
221
+ cursor: pointer;
222
+ padding: 0.25rem;
223
+ border-radius: 4px;
224
+ transition: color 0.2s ease;
225
+ }
226
+
227
+ .clear-search:hover {
228
+ color: #6b7280;
229
+ }
230
+
231
+ .filters-section {
232
+ display: flex;
233
+ flex-wrap: wrap;
234
+ gap: 1rem;
235
+ align-items: center;
236
+ }
237
+
238
+ .filter-group {
239
+ display: flex;
240
+ align-items: center;
241
+ gap: 0.5rem;
242
+ }
243
+
244
+ .filter-label {
245
+ font-size: 0.875rem;
246
+ font-weight: 600;
247
+ color: #374151;
248
+ margin: 0;
249
+ }
250
+
251
+ .filter-select {
252
+ padding: 0.5rem 0.75rem;
253
+ border: 1px solid #d1d5db;
254
+ border-radius: 6px;
255
+ font-size: 0.875rem;
256
+ background: white;
257
+ color: #374151;
258
+ cursor: pointer;
259
+ transition: border-color 0.2s ease;
260
+ }
261
+
262
+ .filter-select:focus {
263
+ outline: none;
264
+ border-color: #667eea;
265
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
266
+ }
267
+
268
+ .reset-filters {
269
+ padding: 0.5rem 1rem;
270
+ background: #f3f4f6;
271
+ border: 1px solid #d1d5db;
272
+ border-radius: 6px;
273
+ font-size: 0.875rem;
274
+ color: #374151;
275
+ cursor: pointer;
276
+ display: flex;
277
+ align-items: center;
278
+ gap: 0.5rem;
279
+ transition: all 0.2s ease;
280
+ }
281
+
282
+ .reset-filters:hover {
283
+ background: #e5e7eb;
284
+ }
285
+
286
+ /* View Toggle */
287
+ .view-toggle-group {
288
+ display: flex;
289
+ align-items: center;
290
+ gap: 0.75rem;
291
+ }
292
+
293
+ .view-toggle {
294
+ display: flex;
295
+ background: #f3f4f6;
296
+ border-radius: 8px;
297
+ padding: 0.25rem;
298
+ border: 1px solid #d1d5db;
299
+ }
300
+
301
+ .view-toggle-btn {
302
+ padding: 0.5rem 0.75rem;
303
+ background: transparent;
304
+ border: none;
305
+ border-radius: 6px;
306
+ font-size: 0.875rem;
307
+ color: #6b7280;
308
+ cursor: pointer;
309
+ transition: all 0.2s ease;
310
+ display: flex;
311
+ align-items: center;
312
+ justify-content: center;
313
+ min-width: 2.5rem;
314
+ }
315
+
316
+ .view-toggle-btn:hover {
317
+ color: #374151;
318
+ background: rgba(255, 255, 255, 0.5);
319
+ }
320
+
321
+ .view-toggle-btn.active {
322
+ background: #667eea;
323
+ color: white;
324
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
325
+ }
326
+
327
+ .view-toggle-btn i {
328
+ font-size: 0.875rem;
329
+ }
330
+
331
+ /* Export Button */
332
+ .export-group {
333
+ display: flex;
334
+ align-items: center;
335
+ gap: 0.5rem;
336
+ }
337
+
338
+ .export-btn {
339
+ padding: 0.5rem 1rem;
340
+ background: linear-gradient(135deg, #10b981 0%, #059669 100%);
341
+ color: white;
342
+ border: none;
343
+ border-radius: 6px;
344
+ font-size: 0.875rem;
345
+ font-weight: 500;
346
+ cursor: pointer;
347
+ display: flex;
348
+ align-items: center;
349
+ gap: 0.5rem;
350
+ transition: all 0.2s ease;
351
+ }
352
+
353
+ .export-btn:hover {
354
+ background: linear-gradient(135deg, #059669 0%, #047857 100%);
355
+ transform: translateY(-1px);
356
+ box-shadow: 0 4px 8px -2px rgba(16, 185, 129, 0.3);
357
+ }
358
+
359
+ /* ========================================
360
+ GEMS DISPLAY LAYOUT - GRID AND TABLE VIEWS
361
+ ======================================== */
362
+
363
+ /* Main Container for both views */
364
+ .gem-metadata-index .gems-container {
365
+ width: 100%;
366
+ max-width: none;
367
+ margin: 0;
368
+ padding: 0;
369
+ }
370
+
371
+ /* ========================================
372
+ GRID VIEW - CLEAN REWRITE
373
+ Highly specific selectors to avoid conflicts with security.css
374
+ ======================================== */
375
+
376
+ /* Main grid container for gem metadata */
377
+ .gem-metadata-index .gems-container .gems-grid {
378
+ display: grid;
379
+ grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
380
+ gap: 2rem;
381
+ width: 100%;
382
+ max-width: 100%;
383
+ margin: 0;
384
+ padding: 0;
385
+ box-sizing: border-box;
386
+ grid-auto-rows: auto;
387
+
388
+ /* Ensure proper grid flow */
389
+ grid-auto-flow: row;
390
+ align-items: start;
391
+ }
392
+
393
+ /* Fallback for when gems-container class is not present */
394
+ .gem-metadata-index .gems-grid {
395
+ display: grid;
396
+ grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
397
+ gap: 2rem;
398
+ width: 100%;
399
+ max-width: 100%;
400
+ margin: 0;
401
+ padding: 0;
402
+ box-sizing: border-box;
403
+ }
404
+
405
+ /* Ensure grid is visible when active */
406
+ .gem-metadata-index .gems-container .gems-grid:not([style*="display: none"]),
407
+ .gem-metadata-index .gems-grid:not([style*="display: none"]) {
408
+ display: grid;
409
+ }
410
+
411
+ /* Gem Card Hover and State Effects */
412
+ .gem-card-full:hover {
413
+ transform: translateY(-4px);
414
+ box-shadow: 0 12px 30px -5px rgba(0, 0, 0, 0.15);
415
+ border-color: #d1d5db;
416
+ background: white;
417
+ }
418
+
419
+ .gem-card-full.unavailable {
420
+ opacity: 0.7;
421
+ background: #f9fafb;
422
+ border-color: #e5e7eb;
423
+ }
424
+
425
+ .gem-card-header {
426
+ margin-bottom: 1.25rem;
427
+ }
428
+
429
+ .gem-title-section {
430
+ display: flex;
431
+ justify-content: space-between;
432
+ align-items: flex-start;
433
+ gap: 1rem;
434
+ }
435
+
436
+ .gem-name {
437
+ font-size: 1.25rem;
438
+ font-weight: 700;
439
+ color: #1f2937;
440
+ margin: 0;
441
+ flex: 1;
442
+ }
443
+
444
+ .gem-status-badges {
445
+ display: flex;
446
+ gap: 0.5rem;
447
+ }
448
+
449
+ .status-badge {
450
+ font-size: 0.75rem;
451
+ padding: 0.375rem 0.75rem;
452
+ border-radius: 8px;
453
+ font-weight: 600;
454
+ display: flex;
455
+ align-items: center;
456
+ gap: 0.375rem;
457
+ text-transform: uppercase;
458
+ letter-spacing: 0.025em;
459
+ }
460
+
461
+ .status-badge.upgrade-available {
462
+ background: linear-gradient(135deg, #fef3c7 0%, #fcd34d 100%);
463
+ color: #d97706;
464
+ border: 1px solid #f59e0b;
465
+ }
466
+
467
+ .status-badge.up-to-date {
468
+ background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);
469
+ color: #059669;
470
+ border: 1px solid #10b981;
471
+ }
472
+
473
+ .status-badge.unavailable {
474
+ background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%);
475
+ color: #6b7280;
476
+ border: 1px solid #d1d5db;
477
+ }
478
+
479
+ .gem-card-body {
480
+ display: flex;
481
+ flex-direction: column;
482
+ gap: 1.25rem;
483
+ }
484
+
485
+ .versions-section {
486
+ background: white;
487
+ border-radius: 8px;
488
+ padding: 1rem;
489
+ border: 1px solid #f3f4f6;
490
+ }
491
+
492
+ .version-group {
493
+ display: grid;
494
+ grid-template-columns: 1fr 1fr;
495
+ gap: 1rem;
496
+ }
497
+
498
+ .version-item {
499
+ display: flex;
500
+ flex-direction: column;
501
+ gap: 0.375rem;
502
+ }
503
+
504
+ .version-label {
505
+ font-size: 0.75rem;
506
+ color: #6b7280;
507
+ font-weight: 600;
508
+ text-transform: uppercase;
509
+ letter-spacing: 0.05em;
510
+ }
511
+
512
+ .version-badge {
513
+ font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
514
+ font-size: 0.875rem;
515
+ padding: 0.5rem 0.75rem;
516
+ border-radius: 6px;
517
+ font-weight: 600;
518
+ text-align: center;
519
+ border: 1px solid transparent;
520
+ }
521
+
522
+ .version-badge.current {
523
+ background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%);
524
+ color: #1d4ed8;
525
+ border-color: #3b82f6;
526
+ }
527
+
528
+ .version-badge.latest {
529
+ background: linear-gradient(135deg, #dcfce7 0%, #bbf7d0 100%);
530
+ color: #166534;
531
+ border-color: #22c55e;
532
+ }
533
+
534
+ .version-badge.unknown {
535
+ background: #f9fafb;
536
+ color: #6b7280;
537
+ border-color: #e5e7eb;
538
+ }
539
+
540
+ .gem-info-section {
541
+ display: flex;
542
+ flex-direction: column;
543
+ gap: 0.75rem;
544
+ }
545
+
546
+ .release-info, .gem-description {
547
+ display: flex;
548
+ align-items: flex-start;
549
+ gap: 0.5rem;
550
+ font-size: 0.875rem;
551
+ color: #6b7280;
552
+ }
553
+
554
+ .gem-description {
555
+ line-height: 1.5;
556
+ }
557
+
558
+ .dependencies-section {
559
+ border-top: 1px solid #f3f4f6;
560
+ padding-top: 1rem;
561
+ }
562
+
563
+ .deps-header {
564
+ display: flex;
565
+ align-items: center;
566
+ gap: 0.5rem;
567
+ font-size: 0.875rem;
568
+ color: #6b7280;
569
+ font-weight: 600;
570
+ margin-bottom: 0.75rem;
571
+ }
572
+
573
+ .deps-grid {
574
+ display: flex;
575
+ flex-wrap: wrap;
576
+ gap: 0.5rem;
577
+ }
578
+
579
+ .dep-badge {
580
+ font-size: 0.75rem;
581
+ padding: 0.375rem 0.75rem;
582
+ border-radius: 8px;
583
+ background: #f8fafc;
584
+ color: #374151;
585
+ font-weight: 500;
586
+ border: 1px solid #e5e7eb;
587
+ display: flex;
588
+ flex-direction: column;
589
+ align-items: center;
590
+ gap: 0.125rem;
591
+ min-width: 60px;
592
+ }
593
+
594
+ .dep-badge.rails-dep {
595
+ background: linear-gradient(135deg, #fef3c7 0%, #fcd34d 100%);
596
+ color: #d97706;
597
+ border-color: #f59e0b;
598
+ font-weight: 700;
599
+ }
600
+
601
+ .dep-version {
602
+ font-size: 0.625rem;
603
+ opacity: 0.8;
604
+ font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
605
+ }
606
+
607
+ .dep-more {
608
+ font-size: 0.75rem;
609
+ color: #6b7280;
610
+ font-weight: 600;
611
+ cursor: help;
612
+ padding: 0.375rem 0.75rem;
613
+ border-radius: 8px;
614
+ background: #f3f4f6;
615
+ border: 1px solid #d1d5db;
616
+ }
617
+
618
+ .results-info {
619
+ text-align: center;
620
+ padding: 1rem;
621
+ font-size: 0.875rem;
622
+ color: #6b7280;
623
+ font-weight: 500;
624
+ }
625
+
626
+ /* Table View */
627
+ .table-wrapper {
628
+ width: 100%;
629
+ }
630
+
631
+ .gems-table {
632
+ width: 100%;
633
+ border-collapse: collapse;
634
+ font-size: 0.875rem;
635
+ min-width: 100%;
636
+ table-layout: auto;
637
+ }
638
+
639
+ .gems-table thead {
640
+ background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
641
+ }
642
+
643
+ .gems-table th {
644
+ padding: 1rem 0.75rem;
645
+ text-align: left;
646
+ font-weight: 600;
647
+ color: #374151;
648
+ border-bottom: 2px solid #e5e7eb;
649
+ position: relative;
650
+ }
651
+
652
+ .gems-table th.sortable {
653
+ cursor: pointer;
654
+ user-select: none;
655
+ transition: background-color 0.2s ease;
656
+ }
657
+
658
+ .gems-table th.sortable:hover {
659
+ background: rgba(102, 126, 234, 0.1);
660
+ }
661
+
662
+ .gems-table th.sortable .sort-icon {
663
+ margin-left: 0.5rem;
664
+ opacity: 0.3;
665
+ transition: opacity 0.2s ease;
666
+ }
667
+
668
+ .gems-table th.sortable:hover .sort-icon {
669
+ opacity: 0.7;
670
+ }
671
+
672
+ .gems-table th.sorted .sort-icon {
673
+ opacity: 1;
674
+ color: #667eea;
675
+ }
676
+
677
+ /* Flexible column widths */
678
+ .gems-table th:first-child,
679
+ .gems-table td:first-child {
680
+ width: 20%; /* Gem name */
681
+ }
682
+
683
+ .gems-table th:nth-child(2),
684
+ .gems-table td:nth-child(2) {
685
+ width: 15%; /* Status */
686
+ }
687
+
688
+ .gems-table th:nth-child(3),
689
+ .gems-table td:nth-child(3) {
690
+ width: 15%; /* Current version */
691
+ }
692
+
693
+ .gems-table th:nth-child(4),
694
+ .gems-table td:nth-child(4) {
695
+ width: 15%; /* Latest version */
696
+ }
697
+
698
+ .gems-table tbody tr {
699
+ transition: background-color 0.2s ease;
700
+ }
701
+
702
+ .gems-table tbody tr:hover {
703
+ background: #f8fafc;
704
+ }
705
+
706
+ .gems-table tbody tr.unavailable {
707
+ opacity: 0.6;
708
+ background: #f9fafb;
709
+ }
710
+
711
+ .gems-table td {
712
+ padding: 1rem 0.75rem;
713
+ border-bottom: 1px solid #f3f4f6;
714
+ vertical-align: top;
715
+ }
716
+
717
+ .gem-name-table {
718
+ color: #1f2937;
719
+ font-weight: 600;
720
+ }
721
+
722
+ .status-badge-table {
723
+ font-size: 0.75rem;
724
+ padding: 0.25rem 0.5rem;
725
+ border-radius: 6px;
726
+ font-weight: 500;
727
+ display: inline-flex;
728
+ align-items: center;
729
+ gap: 0.25rem;
730
+ white-space: nowrap;
731
+ }
732
+
733
+ .status-badge-table.upgrade-available {
734
+ background: #fef3c7;
735
+ color: #d97706;
736
+ }
737
+
738
+ .status-badge-table.up-to-date {
739
+ background: #d1fae5;
740
+ color: #059669;
741
+ }
742
+
743
+ .status-badge-table.unavailable {
744
+ background: #f3f4f6;
745
+ color: #6b7280;
746
+ }
747
+
748
+ .status-badge-table.unknown {
749
+ background: #f3f4f6;
750
+ color: #9ca3af;
751
+ }
752
+
753
+ .version-badge-table {
754
+ font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
755
+ font-size: 0.8rem;
756
+ padding: 0.25rem 0.5rem;
757
+ border-radius: 6px;
758
+ font-weight: 500;
759
+ white-space: nowrap;
760
+ }
761
+
762
+ .version-badge-table.current {
763
+ background: #dbeafe;
764
+ color: #1d4ed8;
765
+ }
766
+
767
+ .version-badge-table.latest {
768
+ background: #dcfce7;
769
+ color: #166534;
770
+ }
771
+
772
+ .version-badge-table.unknown {
773
+ background: #f3f4f6;
774
+ color: #6b7280;
775
+ }
776
+
777
+ .description-cell {
778
+ width: 30%;
779
+ word-wrap: break-word;
780
+ }
781
+
782
+ .dependencies-cell {
783
+ width: 25%;
784
+ word-wrap: break-word;
785
+ }
786
+
787
+ .table-deps {
788
+ display: flex;
789
+ flex-wrap: wrap;
790
+ gap: 0.25rem;
791
+ }
792
+
793
+ .dep-badge-table {
794
+ font-size: 0.7rem;
795
+ padding: 0.125rem 0.375rem;
796
+ border-radius: 4px;
797
+ background: #f3f4f6;
798
+ color: #374151;
799
+ font-weight: 500;
800
+ white-space: nowrap;
801
+ }
802
+
803
+ .dep-badge-table.rails-dep {
804
+ background: #fef3c7;
805
+ color: #d97706;
806
+ font-weight: 600;
807
+ }
808
+
809
+ .dep-more-table {
810
+ font-size: 0.7rem;
811
+ color: #6b7280;
812
+ font-weight: 500;
813
+ cursor: help;
814
+ }
815
+
816
+ .text-muted {
817
+ color: #9ca3af;
818
+ }
819
+
820
+ /* Empty State */
821
+ .empty-state {
822
+ text-align: center;
823
+ padding: 4rem 2rem;
824
+ color: #6b7280;
825
+ }
826
+
827
+ .empty-icon {
828
+ font-size: 4rem;
829
+ margin-bottom: 1.5rem;
830
+ opacity: 0.5;
831
+ }
832
+
833
+ .empty-title {
834
+ font-size: 1.5rem;
835
+ font-weight: 700;
836
+ color: #374151;
837
+ margin-bottom: 0.75rem;
838
+ }
839
+
840
+ .empty-description {
841
+ margin-bottom: 2rem;
842
+ max-width: 500px;
843
+ margin-left: auto;
844
+ margin-right: auto;
845
+ line-height: 1.6;
846
+ }
847
+
848
+ .empty-actions {
849
+ display: flex;
850
+ justify-content: center;
851
+ gap: 1rem;
852
+ }
853
+
854
+ /* Filter Empty State - Enhanced centering for table view */
855
+ .filter-empty-state {
856
+ text-align: center;
857
+ padding: 2rem;
858
+ color: #6b7280;
859
+ display: flex;
860
+ flex-direction: column;
861
+ justify-content: center;
862
+ align-items: center;
863
+ width: 100%;
864
+ max-width: 500px;
865
+ margin: 0 auto;
866
+ }
867
+
868
+ .filter-empty-state .empty-icon {
869
+ font-size: 3rem;
870
+ margin-bottom: 1.5rem;
871
+ opacity: 0.5;
872
+ }
873
+
874
+ .filter-empty-state .empty-title {
875
+ font-size: 1.25rem;
876
+ font-weight: 700;
877
+ color: #374151;
878
+ margin-bottom: 0.75rem;
879
+ }
880
+
881
+ .filter-empty-state .empty-description {
882
+ margin-bottom: 2rem;
883
+ max-width: 400px;
884
+ line-height: 1.5;
885
+ font-size: 0.9rem;
886
+ }
887
+
888
+ .filter-empty-state .action-btn {
889
+ margin: 0 auto;
890
+ }
891
+
892
+ /* Empty state responsive adjustments */
893
+ @media (max-width: 768px) {
894
+ .filter-empty-state {
895
+ padding: 1.5rem;
896
+ max-width: 90%;
897
+ }
898
+
899
+ .filter-empty-state .empty-icon {
900
+ font-size: 2.5rem;
901
+ margin-bottom: 1rem;
902
+ }
903
+
904
+ .filter-empty-state .empty-title {
905
+ font-size: 1.1rem;
906
+ }
907
+
908
+ .filter-empty-state .empty-description {
909
+ font-size: 0.85rem;
910
+ max-width: 300px;
911
+ }
912
+
913
+ .filter-empty-state-row td {
914
+ height: 300px;
915
+ }
916
+
917
+ .empty-state-cell {
918
+ height: 300px;
919
+ }
920
+
921
+ .gems-table-container.has-empty-state {
922
+ min-height: 300px;
923
+ }
924
+ }
925
+
926
+ /* Table empty state row */
927
+ .filter-empty-state-row {
928
+ background: transparent !important;
929
+ height: 400px;
930
+ }
931
+
932
+ .filter-empty-state-row:hover {
933
+ background: transparent !important;
934
+ }
935
+
936
+ .filter-empty-state-row td {
937
+ padding: 0 !important;
938
+ border: none !important;
939
+ text-align: center;
940
+ height: 400px;
941
+ }
942
+
943
+ /* Empty state cell styling */
944
+ .empty-state-cell {
945
+ position: relative;
946
+ height: 400px;
947
+ vertical-align: middle;
948
+ text-align: center;
949
+ }
950
+
951
+ /* Additional centering improvements for empty state */
952
+ .filter-empty-state-row td.empty-state-cell {
953
+ position: relative;
954
+ display: table-cell;
955
+ vertical-align: middle;
956
+ text-align: center;
957
+ }
958
+
959
+ .empty-state-cell .filter-empty-state {
960
+ position: static;
961
+ margin: 0 auto;
962
+ }
963
+
964
+ /* Table container styling with empty state */
965
+ .gems-table-container.has-empty-state {
966
+ min-height: 400px;
967
+ }
968
+
969
+ /* Table body styling */
970
+ .gems-table {
971
+ width: 100%;
972
+ border-collapse: collapse;
973
+ font-size: 0.875rem;
974
+ min-width: 100%;
975
+ table-layout: auto;
976
+ }
977
+
978
+ /* Table container with empty state */
979
+ .gems-table-container.has-empty-state {
980
+ min-height: 400px;
981
+ }
982
+
983
+ .gems-table-container.has-empty-state .table-wrapper {
984
+ width: 100%;
985
+ }
986
+
987
+ .gems-table-container.has-empty-state .gems-table {
988
+ height: 100%;
989
+ width: 100%;
990
+ }
991
+
992
+ /* Fallback for browsers without :has() support */
993
+ .gems-table-container.has-empty-state {
994
+ min-height: 400px;
995
+ display: flex;
996
+ flex-direction: column;
997
+ }
998
+
999
+ .gems-table-container.has-empty-state .table-wrapper {
1000
+ flex: 1;
1001
+ display: flex;
1002
+ flex-direction: column;
1003
+ }
1004
+
1005
+ .gems-table-container.has-empty-state .gems-table {
1006
+ height: 100%;
1007
+ }
1008
+
1009
+ /* Page Footer */
1010
+ .page-footer {
1011
+ background: white;
1012
+ border-radius: 12px;
1013
+ padding: 1.5rem;
1014
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
1015
+ border: 1px solid rgba(0, 0, 0, 0.05);
1016
+ }
1017
+
1018
+ .footer-content {
1019
+ display: flex;
1020
+ justify-content: space-between;
1021
+ align-items: center;
1022
+ }
1023
+
1024
+ .footer-link {
1025
+ font-size: 0.875rem;
1026
+ color: #6366f1;
1027
+ text-decoration: none;
1028
+ font-weight: 500;
1029
+ display: flex;
1030
+ align-items: center;
1031
+ gap: 0.5rem;
1032
+ transition: color 0.2s ease;
1033
+ }
1034
+
1035
+ .footer-link:hover {
1036
+ color: #4f46e5;
1037
+ text-decoration: underline;
1038
+ }
1039
+
1040
+ .footer-link.external {
1041
+ color: #059669;
1042
+ }
1043
+
1044
+ .footer-link.external:hover {
1045
+ color: #047857;
1046
+ }
1047
+
1048
+ .footer-stats {
1049
+ font-size: 0.875rem;
1050
+ color: #6b7280;
1051
+ }
1052
+
1053
+ /* Loading States */
1054
+ .refresh-btn.loading {
1055
+ opacity: 0.6;
1056
+ pointer-events: none;
1057
+ }
1058
+
1059
+ .refresh-btn.loading i {
1060
+ animation: spin 1s linear infinite;
1061
+ }
1062
+
1063
+ .loading-overlay {
1064
+ position: fixed;
1065
+ top: 0;
1066
+ left: 0;
1067
+ right: 0;
1068
+ bottom: 0;
1069
+ background: rgba(255, 255, 255, 0.9);
1070
+ backdrop-filter: blur(4px);
1071
+ display: flex;
1072
+ align-items: center;
1073
+ justify-content: center;
1074
+ z-index: 1000;
1075
+ }
1076
+
1077
+ .loading-content {
1078
+ text-align: center;
1079
+ padding: 2rem;
1080
+ background: white;
1081
+ border-radius: 12px;
1082
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
1083
+ border: 1px solid rgba(0, 0, 0, 0.05);
1084
+ }
1085
+
1086
+ .loading-spinner {
1087
+ width: 40px;
1088
+ height: 40px;
1089
+ border: 3px solid #f3f4f6;
1090
+ border-top: 3px solid #667eea;
1091
+ border-radius: 50%;
1092
+ animation: spin 1s linear infinite;
1093
+ margin: 0 auto 1rem auto;
1094
+ }
1095
+
1096
+ @keyframes spin {
1097
+ 0% { transform: rotate(0deg); }
1098
+ 100% { transform: rotate(360deg); }
1099
+ }
1100
+
1101
+ .loading-text {
1102
+ color: #6b7280;
1103
+ font-weight: 500;
1104
+ }
1105
+
1106
+ /* Toast Notifications */
1107
+ .toast-notification {
1108
+ position: fixed;
1109
+ top: 20px;
1110
+ right: 20px;
1111
+ padding: 1rem 1.5rem;
1112
+ border-radius: 8px;
1113
+ font-weight: 500;
1114
+ font-size: 0.875rem;
1115
+ box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
1116
+ transform: translateX(100%);
1117
+ transition: transform 0.3s ease;
1118
+ z-index: 1001;
1119
+ }
1120
+
1121
+ .toast-notification.visible {
1122
+ transform: translateX(0);
1123
+ }
1124
+
1125
+ .toast-notification.success {
1126
+ background: #10b981;
1127
+ color: white;
1128
+ }
1129
+
1130
+ .toast-notification.error {
1131
+ background: #ef4444;
1132
+ color: white;
1133
+ }
1134
+
1135
+ .toast-notification.info {
1136
+ background: #3b82f6;
1137
+ color: white;
1138
+ }
1139
+
1140
+ /* ========================================
1141
+ RESPONSIVE GRID BREAKPOINTS - CLEAN REWRITE
1142
+ ======================================== */
1143
+
1144
+ /* Extra large screens: 3+ cards per row (1400px+) */
1145
+ @media (min-width: 1400px) {
1146
+ .gem-metadata-index .gems-container .gems-grid,
1147
+ .gem-metadata-index .gems-grid {
1148
+ grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
1149
+ gap: 2.5rem;
1150
+ }
1151
+ }
1152
+
1153
+ /* Large screens: 3 cards per row (1200px - 1399px) */
1154
+ @media (min-width: 1200px) and (max-width: 1399px) {
1155
+ .gem-metadata-index .gems-container .gems-grid,
1156
+ .gem-metadata-index .gems-grid {
1157
+ grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
1158
+ gap: 2rem;
1159
+ }
1160
+ }
1161
+
1162
+ /* Medium-large screens: 2-3 cards per row (900px - 1199px) */
1163
+ @media (min-width: 900px) and (max-width: 1199px) {
1164
+ .gem-metadata-index .gems-container .gems-grid,
1165
+ .gem-metadata-index .gems-grid {
1166
+ grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
1167
+ gap: 1.5rem;
1168
+ }
1169
+ }
1170
+
1171
+ /* Medium screens: 2 cards per row (600px - 899px) */
1172
+ @media (min-width: 600px) and (max-width: 899px) {
1173
+ .gem-metadata-index .gems-container .gems-grid,
1174
+ .gem-metadata-index .gems-grid {
1175
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
1176
+ gap: 1.5rem;
1177
+ }
1178
+ }
1179
+
1180
+ /* Small screens: 1 card per row (under 600px) */
1181
+ @media (max-width: 599px) {
1182
+ .gem-metadata-index .gems-container .gems-grid,
1183
+ .gem-metadata-index .gems-grid {
1184
+ grid-template-columns: 1fr;
1185
+ gap: 1rem;
1186
+ }
1187
+ }
1188
+
1189
+ /* Responsive Design */
1190
+ @media (max-width: 1024px) {
1191
+ .gem-metadata-index {
1192
+ padding: 1rem;
1193
+ }
1194
+ }
1195
+
1196
+ @media (max-width: 768px) {
1197
+ .header-content {
1198
+ flex-direction: column;
1199
+ gap: 1.5rem;
1200
+ text-align: center;
1201
+ }
1202
+
1203
+ .page-title {
1204
+ font-size: 1.75rem;
1205
+ }
1206
+
1207
+ .stats-overview {
1208
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
1209
+ gap: 1rem;
1210
+ }
1211
+
1212
+ .filters-section {
1213
+ flex-direction: column;
1214
+ align-items: stretch;
1215
+ gap: 1rem;
1216
+ }
1217
+
1218
+ .filter-group {
1219
+ justify-content: space-between;
1220
+ }
1221
+
1222
+ .gem-title-section {
1223
+ flex-direction: column;
1224
+ align-items: flex-start;
1225
+ gap: 0.75rem;
1226
+ }
1227
+
1228
+ .version-group {
1229
+ grid-template-columns: 1fr;
1230
+ }
1231
+
1232
+ .footer-content {
1233
+ flex-direction: column;
1234
+ gap: 1rem;
1235
+ text-align: center;
1236
+ }
1237
+
1238
+ /* Table responsive adjustments */
1239
+ .gems-table th,
1240
+ .gems-table td {
1241
+ padding: 0.75rem 0.5rem;
1242
+ font-size: 0.8rem;
1243
+ }
1244
+
1245
+ .gems-table .description-cell {
1246
+ max-width: 150px;
1247
+ font-size: 0.75rem;
1248
+ }
1249
+
1250
+ .gems-table .dependencies-cell {
1251
+ max-width: 120px;
1252
+ font-size: 0.75rem;
1253
+ }
1254
+
1255
+ .view-toggle-group {
1256
+ flex-direction: column;
1257
+ align-items: flex-start;
1258
+ gap: 0.5rem;
1259
+ }
1260
+ }
1261
+
1262
+ @media (max-width: 480px) {
1263
+ .gem-metadata-index {
1264
+ padding: 0.5rem;
1265
+ }
1266
+
1267
+ .page-header {
1268
+ padding: 1.5rem;
1269
+ }
1270
+
1271
+ .stats-overview {
1272
+ grid-template-columns: repeat(2, 1fr);
1273
+ }
1274
+
1275
+ .stat-card {
1276
+ padding: 1rem;
1277
+ }
1278
+
1279
+ .stat-icon {
1280
+ width: 50px;
1281
+ height: 50px;
1282
+ font-size: 1.5rem;
1283
+ }
1284
+
1285
+ .stat-number {
1286
+ font-size: 1.5rem;
1287
+ }
1288
+ }
1289
+
1290
+ /* Very narrow mobile - hide some columns only when necessary */
1291
+ @media (max-width: 400px) {
1292
+ .gems-table .description-cell,
1293
+ .gems-table .dependencies-cell {
1294
+ display: none;
1295
+ }
1296
+ }
1297
+
1298
+ /* Accessibility Improvements */
1299
+ @media (prefers-reduced-motion: reduce) {
1300
+ .gem-card-full,
1301
+ .action-btn,
1302
+ .stat-card {
1303
+ animation: none;
1304
+ transition: none;
1305
+ }
1306
+ }
1307
+
1308
+ /* Focus States */
1309
+ .action-btn:focus,
1310
+ .search-input:focus,
1311
+ .filter-select:focus,
1312
+ .reset-filters:focus,
1313
+ .footer-link:focus {
1314
+ outline: 2px solid #667eea;
1315
+ outline-offset: 2px;
1316
+ }
1317
+
1318
+ /* Print Styles */
1319
+ @media print {
1320
+ .page-header,
1321
+ .search-filters,
1322
+ .page-footer {
1323
+ display: none;
1324
+ }
1325
+
1326
+ .gem-metadata-index {
1327
+ background: white;
1328
+ padding: 0;
1329
+ }
1330
+
1331
+ .gem-metadata-index .gems-grid {
1332
+ grid-template-columns: 1fr;
1333
+ }
1334
+
1335
+ .gem-card-full {
1336
+ box-shadow: none;
1337
+ border: 1px solid #ccc;
1338
+ break-inside: avoid;
1339
+ }
1340
+ }
1341
+
1342
+ /* ========================================
1343
+ GEM CARD STYLING FOR GRID VIEW - CLEAN REWRITE
1344
+ ======================================== */
1345
+
1346
+ /* Primary gem card styling with specific selectors */
1347
+ .gem-metadata-index .gems-container .gems-grid .gem-card-full,
1348
+ .gem-metadata-index .gems-grid .gem-card-full {
1349
+ /* Layout and sizing */
1350
+ width: 100%;
1351
+ max-width: 100%;
1352
+ min-width: 0;
1353
+ box-sizing: border-box;
1354
+
1355
+ /* Card appearance */
1356
+ background: white;
1357
+ border: 1px solid #e5e7eb;
1358
+ border-radius: 12px;
1359
+ padding: 1.5rem;
1360
+
1361
+ /* Display properties */
1362
+ display: flex;
1363
+ flex-direction: column;
1364
+ justify-content: flex-start;
1365
+ align-items: stretch;
1366
+
1367
+ /* Effects and animations */
1368
+ transition: all 0.3s ease;
1369
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
1370
+ animation: fadeInUp 0.6s ease-out both;
1371
+ }
1372
+
1373
+ /* Hover effects for gem cards */
1374
+ .gem-metadata-index .gems-container .gems-grid .gem-card-full:hover,
1375
+ .gem-metadata-index .gems-grid .gem-card-full:hover {
1376
+ transform: translateY(-4px);
1377
+ box-shadow: 0 12px 30px -5px rgba(0, 0, 0, 0.15);
1378
+ border-color: #d1d5db;
1379
+ background: white;
1380
+ }
1381
+
1382
+ /* Unavailable gem cards */
1383
+ .gem-metadata-index .gems-container .gems-grid .gem-card-full.unavailable,
1384
+ .gem-metadata-index .gems-grid .gem-card-full.unavailable {
1385
+ opacity: 0.7;
1386
+ background: #f9fafb;
1387
+ border-color: #e5e7eb;
1388
+ }
1389
+
1390
+ /* ========================================
1391
+ ANIMATIONS
1392
+ ======================================== */
1393
+
1394
+ @keyframes fadeInUp {
1395
+ from {
1396
+ opacity: 0;
1397
+ transform: translateY(20px);
1398
+ }
1399
+ to {
1400
+ opacity: 1;
1401
+ transform: translateY(0);
1402
+ }
1403
+ }