sqa 0.0.32 → 0.0.38

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 (110) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +154 -1
  3. data/README.md +4 -0
  4. data/Rakefile +52 -10
  5. data/docs/advanced/index.md +1 -13
  6. data/docs/api/index.md +547 -61
  7. data/docs/api-reference/alphavantageapi.md +1057 -0
  8. data/docs/api-reference/apierror.md +31 -0
  9. data/docs/api-reference/index.md +221 -0
  10. data/docs/api-reference/notimplemented.md +27 -0
  11. data/docs/api-reference/sqa.md +267 -0
  12. data/docs/api-reference/sqa_backtest.md +171 -0
  13. data/docs/api-reference/sqa_backtest_results.md +530 -0
  14. data/docs/api-reference/sqa_badparametererror.md +13 -0
  15. data/docs/api-reference/sqa_config.md +538 -0
  16. data/docs/api-reference/sqa_configurationerror.md +13 -0
  17. data/docs/api-reference/sqa_datafetcherror.md +56 -0
  18. data/docs/api-reference/sqa_dataframe.md +779 -0
  19. data/docs/api-reference/sqa_dataframe_alphavantage.md +30 -0
  20. data/docs/api-reference/sqa_dataframe_data.md +325 -0
  21. data/docs/api-reference/sqa_dataframe_yahoofinance.md +25 -0
  22. data/docs/api-reference/sqa_ensemble.md +413 -0
  23. data/docs/api-reference/sqa_fpop.md +211 -0
  24. data/docs/api-reference/sqa_geneticprogram.md +325 -0
  25. data/docs/api-reference/sqa_geneticprogram_individual.md +114 -0
  26. data/docs/api-reference/sqa_marketregime.md +212 -0
  27. data/docs/api-reference/sqa_multitimeframe.md +227 -0
  28. data/docs/api-reference/sqa_patternmatcher.md +195 -0
  29. data/docs/api-reference/sqa_pluginmanager.md +55 -0
  30. data/docs/api-reference/sqa_portfolio.md +512 -0
  31. data/docs/api-reference/sqa_portfolio_position.md +220 -0
  32. data/docs/api-reference/sqa_portfolio_trade.md +332 -0
  33. data/docs/api-reference/sqa_portfoliooptimizer.md +248 -0
  34. data/docs/api-reference/sqa_riskmanager.md +388 -0
  35. data/docs/api-reference/sqa_seasonalanalyzer.md +121 -0
  36. data/docs/api-reference/sqa_sectoranalyzer.md +163 -0
  37. data/docs/api-reference/sqa_stock.md +661 -0
  38. data/docs/api-reference/sqa_strategy.md +178 -0
  39. data/docs/api-reference/sqa_strategy_bollingerbands.md +26 -0
  40. data/docs/api-reference/sqa_strategy_common.md +29 -0
  41. data/docs/api-reference/sqa_strategy_consensus.md +129 -0
  42. data/docs/api-reference/sqa_strategy_ema.md +41 -0
  43. data/docs/api-reference/sqa_strategy_kbs.md +154 -0
  44. data/docs/api-reference/sqa_strategy_macd.md +26 -0
  45. data/docs/api-reference/sqa_strategy_mp.md +41 -0
  46. data/docs/api-reference/sqa_strategy_mr.md +41 -0
  47. data/docs/api-reference/sqa_strategy_random.md +41 -0
  48. data/docs/api-reference/sqa_strategy_rsi.md +41 -0
  49. data/docs/api-reference/sqa_strategy_sma.md +41 -0
  50. data/docs/api-reference/sqa_strategy_stochastic.md +26 -0
  51. data/docs/api-reference/sqa_strategy_volumebreakout.md +26 -0
  52. data/docs/api-reference/sqa_strategygenerator.md +298 -0
  53. data/docs/api-reference/sqa_strategygenerator_pattern.md +264 -0
  54. data/docs/api-reference/sqa_strategygenerator_patterncontext.md +326 -0
  55. data/docs/api-reference/sqa_strategygenerator_profitablepoint.md +424 -0
  56. data/docs/api-reference/sqa_stream.md +256 -0
  57. data/docs/api-reference/sqa_ticker.md +175 -0
  58. data/docs/api-reference/string.md +135 -0
  59. data/docs/assets/images/advanced-workflow.svg +89 -0
  60. data/docs/assets/images/architecture.svg +107 -0
  61. data/docs/assets/images/data-flow.svg +138 -0
  62. data/docs/assets/images/getting-started-workflow.svg +88 -0
  63. data/docs/assets/images/strategy-flow.svg +78 -0
  64. data/docs/assets/images/system-architecture.svg +150 -0
  65. data/docs/concepts/index.md +292 -19
  66. data/docs/file_formats.md +250 -0
  67. data/docs/getting-started/index.md +1 -14
  68. data/docs/index.md +26 -23
  69. data/docs/llms.txt +109 -0
  70. data/docs/strategies/kbs.md +15 -14
  71. data/docs/strategy.md +381 -3
  72. data/docs/terms_of_use.md +1 -1
  73. data/examples/README.md +10 -0
  74. data/lib/api/alpha_vantage_api.rb +3 -7
  75. data/lib/sqa/backtest.rb +32 -0
  76. data/lib/sqa/config.rb +109 -28
  77. data/lib/sqa/data_frame/data.rb +13 -1
  78. data/lib/sqa/data_frame.rb +193 -26
  79. data/lib/sqa/errors.rb +79 -17
  80. data/lib/sqa/init.rb +70 -15
  81. data/lib/sqa/pattern_matcher.rb +4 -4
  82. data/lib/sqa/portfolio.rb +55 -1
  83. data/lib/sqa/sector_analyzer.rb +3 -11
  84. data/lib/sqa/stock.rb +180 -15
  85. data/lib/sqa/strategy.rb +62 -4
  86. data/lib/sqa/ticker.rb +106 -48
  87. data/lib/sqa/version.rb +1 -1
  88. data/lib/sqa.rb +4 -4
  89. data/mkdocs.yml +69 -81
  90. metadata +89 -21
  91. data/docs/README.md +0 -43
  92. data/examples/sinatra_app/Gemfile +0 -42
  93. data/examples/sinatra_app/Gemfile.lock +0 -268
  94. data/examples/sinatra_app/QUICKSTART.md +0 -169
  95. data/examples/sinatra_app/README.md +0 -471
  96. data/examples/sinatra_app/RUNNING_WITHOUT_TALIB.md +0 -90
  97. data/examples/sinatra_app/TROUBLESHOOTING.md +0 -95
  98. data/examples/sinatra_app/app.rb +0 -404
  99. data/examples/sinatra_app/config.ru +0 -5
  100. data/examples/sinatra_app/public/css/style.css +0 -723
  101. data/examples/sinatra_app/public/debug_macd.html +0 -82
  102. data/examples/sinatra_app/public/js/app.js +0 -107
  103. data/examples/sinatra_app/start.sh +0 -53
  104. data/examples/sinatra_app/views/analyze.erb +0 -306
  105. data/examples/sinatra_app/views/backtest.erb +0 -325
  106. data/examples/sinatra_app/views/dashboard.erb +0 -831
  107. data/examples/sinatra_app/views/error.erb +0 -58
  108. data/examples/sinatra_app/views/index.erb +0 -118
  109. data/examples/sinatra_app/views/layout.erb +0 -61
  110. data/examples/sinatra_app/views/portfolio.erb +0 -43
@@ -1,723 +0,0 @@
1
- /* Reset and Base Styles */
2
- * {
3
- margin: 0;
4
- padding: 0;
5
- box-sizing: border-box;
6
- }
7
-
8
- :root {
9
- --primary-color: #00d4ff;
10
- --secondary-color: #00a8cc;
11
- --success-color: #00ff88;
12
- --danger-color: #ff3366;
13
- --warning-color: #ffaa00;
14
- --dark-bg: #0a0e27;
15
- --card-bg: #151b3d;
16
- --card-bg-lighter: #1e2749;
17
- --text-primary: #e8eaf6;
18
- --text-secondary: #9fa8da;
19
- --border-color: #2a3154;
20
- --positive-color: #00ff88;
21
- --negative-color: #ff3366;
22
- --chart-bg: #0f1535;
23
- --grid-color: #2a3154;
24
- }
25
-
26
- body {
27
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
28
- background-color: var(--dark-bg);
29
- color: var(--text-primary);
30
- line-height: 1.6;
31
- }
32
-
33
- /* Navigation */
34
- .navbar {
35
- background: linear-gradient(135deg, var(--dark-bg) 0%, #16213e 100%);
36
- color: white;
37
- padding: 1rem 0;
38
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
39
- position: sticky;
40
- top: 0;
41
- z-index: 1000;
42
- }
43
-
44
- .nav-container {
45
- max-width: 1200px;
46
- margin: 0 auto;
47
- padding: 0 2rem;
48
- display: flex;
49
- justify-content: space-between;
50
- align-items: center;
51
- }
52
-
53
- .nav-brand {
54
- font-size: 1.5rem;
55
- font-weight: 700;
56
- display: flex;
57
- align-items: center;
58
- gap: 0.5rem;
59
- }
60
-
61
- .nav-brand i {
62
- color: var(--primary-color);
63
- }
64
-
65
- .nav-menu {
66
- display: flex;
67
- list-style: none;
68
- gap: 2rem;
69
- }
70
-
71
- .nav-link {
72
- color: white;
73
- text-decoration: none;
74
- font-weight: 500;
75
- transition: color 0.3s ease;
76
- display: flex;
77
- align-items: center;
78
- gap: 0.5rem;
79
- }
80
-
81
- .nav-link:hover {
82
- color: var(--primary-color);
83
- }
84
-
85
- /* Main Content */
86
- .main-content {
87
- min-height: calc(100vh - 200px);
88
- padding-bottom: 2rem;
89
- }
90
-
91
- /* Hero Section */
92
- .hero {
93
- background: linear-gradient(135deg, #1a237e 0%, #4a148c 100%);
94
- color: white;
95
- padding: 4rem 2rem;
96
- text-align: center;
97
- }
98
-
99
- .hero-content h1 {
100
- font-size: 3rem;
101
- margin-bottom: 1rem;
102
- font-weight: 700;
103
- }
104
-
105
- .hero-subtitle {
106
- font-size: 1.25rem;
107
- margin-bottom: 2rem;
108
- opacity: 0.9;
109
- }
110
-
111
- .ticker-search {
112
- max-width: 600px;
113
- margin: 2rem auto;
114
- }
115
-
116
- .search-form {
117
- display: flex;
118
- gap: 1rem;
119
- }
120
-
121
- .search-form input {
122
- flex: 1;
123
- padding: 1rem;
124
- border: none;
125
- border-radius: 8px;
126
- font-size: 1.1rem;
127
- outline: none;
128
- }
129
-
130
- .quick-links {
131
- margin-top: 3rem;
132
- }
133
-
134
- .quick-links h3 {
135
- margin-bottom: 1rem;
136
- font-weight: 600;
137
- }
138
-
139
- .ticker-buttons {
140
- display: flex;
141
- gap: 1rem;
142
- justify-content: center;
143
- flex-wrap: wrap;
144
- }
145
-
146
- .ticker-btn {
147
- background: rgba(255, 255, 255, 0.2);
148
- color: white;
149
- padding: 0.75rem 1.5rem;
150
- border-radius: 8px;
151
- text-decoration: none;
152
- font-weight: 600;
153
- transition: all 0.3s ease;
154
- backdrop-filter: blur(10px);
155
- }
156
-
157
- .ticker-btn:hover {
158
- background: rgba(255, 255, 255, 0.3);
159
- transform: translateY(-2px);
160
- }
161
-
162
- /* Buttons */
163
- .btn {
164
- padding: 0.75rem 1.5rem;
165
- border: none;
166
- border-radius: 8px;
167
- font-size: 1rem;
168
- font-weight: 600;
169
- cursor: pointer;
170
- transition: all 0.3s ease;
171
- text-decoration: none;
172
- display: inline-flex;
173
- align-items: center;
174
- gap: 0.5rem;
175
- }
176
-
177
- .btn-primary {
178
- background: var(--primary-color);
179
- color: white;
180
- }
181
-
182
- .btn-primary:hover {
183
- background: var(--secondary-color);
184
- transform: translateY(-2px);
185
- box-shadow: 0 4px 12px rgba(33, 150, 243, 0.3);
186
- }
187
-
188
- .btn-secondary {
189
- background: var(--card-bg-lighter);
190
- color: var(--text-primary);
191
- border: 2px solid var(--border-color);
192
- }
193
-
194
- .btn-secondary:hover {
195
- border-color: var(--primary-color);
196
- color: var(--primary-color);
197
- background: var(--card-bg);
198
- }
199
-
200
- .btn-large {
201
- padding: 1rem 2rem;
202
- font-size: 1.1rem;
203
- }
204
-
205
- .btn-small {
206
- padding: 0.5rem 1rem;
207
- font-size: 0.875rem;
208
- background: var(--card-bg-lighter);
209
- color: var(--text-primary);
210
- border: 1px solid var(--border-color);
211
- }
212
-
213
- .btn-small.active {
214
- background: var(--primary-color);
215
- color: var(--dark-bg);
216
- border-color: var(--primary-color);
217
- font-weight: 700;
218
- }
219
-
220
- /* Period Selector */
221
- .period-selector {
222
- background: var(--card-bg);
223
- padding: 1.5rem;
224
- border-radius: 8px;
225
- margin-bottom: 1.5rem;
226
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
227
- }
228
-
229
- .period-selector label {
230
- font-weight: 600;
231
- color: var(--text-primary);
232
- margin-bottom: 0.75rem;
233
- display: block;
234
- }
235
-
236
- .period-buttons {
237
- display: flex;
238
- gap: 0.5rem;
239
- flex-wrap: wrap;
240
- }
241
-
242
- .btn-period {
243
- padding: 0.5rem 1rem;
244
- font-size: 0.875rem;
245
- background: var(--card-bg-lighter);
246
- color: var(--text-primary);
247
- border: 1px solid var(--border-color);
248
- border-radius: 4px;
249
- cursor: pointer;
250
- transition: all 0.2s;
251
- font-family: inherit;
252
- }
253
-
254
- .btn-period:hover {
255
- background: var(--card-bg);
256
- border-color: var(--primary-color);
257
- color: var(--primary-color);
258
- }
259
-
260
- .btn-period.active {
261
- background: var(--primary-color);
262
- color: var(--dark-bg);
263
- border-color: var(--primary-color);
264
- font-weight: 700;
265
- }
266
-
267
- /* Container */
268
- .container {
269
- max-width: 1200px;
270
- margin: 0 auto;
271
- padding: 0 2rem;
272
- }
273
-
274
- /* Features Section */
275
- .features {
276
- padding: 4rem 0;
277
- background: var(--card-bg);
278
- }
279
-
280
- .features h2 {
281
- text-align: center;
282
- font-size: 2.5rem;
283
- margin-bottom: 3rem;
284
- color: var(--text-primary);
285
- }
286
-
287
- .feature-grid {
288
- display: grid;
289
- grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
290
- gap: 2rem;
291
- }
292
-
293
- .feature-card {
294
- padding: 2rem;
295
- background: var(--card-bg-lighter);
296
- border-radius: 12px;
297
- border: 1px solid var(--border-color);
298
- transition: all 0.3s ease;
299
- }
300
-
301
- .feature-card:hover {
302
- transform: translateY(-5px);
303
- box-shadow: 0 10px 30px rgba(0, 217, 255, 0.2);
304
- border-color: var(--primary-color);
305
- }
306
-
307
- .feature-icon {
308
- font-size: 3rem;
309
- color: var(--primary-color);
310
- margin-bottom: 1rem;
311
- }
312
-
313
- .feature-card h3 {
314
- font-size: 1.5rem;
315
- margin-bottom: 1rem;
316
- color: var(--text-primary);
317
- }
318
-
319
- .feature-card p {
320
- color: var(--text-secondary);
321
- line-height: 1.6;
322
- }
323
-
324
- /* Info Section */
325
- .info-section {
326
- padding: 4rem 0;
327
- background: var(--dark-bg);
328
- }
329
-
330
- .info-content h2 {
331
- font-size: 2rem;
332
- margin-bottom: 1.5rem;
333
- color: var(--text-primary);
334
- }
335
-
336
- .info-content p {
337
- font-size: 1.1rem;
338
- color: var(--text-secondary);
339
- margin-bottom: 1.5rem;
340
- line-height: 1.8;
341
- }
342
-
343
- .info-list {
344
- list-style: none;
345
- display: grid;
346
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
347
- gap: 1rem;
348
- margin-top: 2rem;
349
- }
350
-
351
- .info-list li {
352
- display: flex;
353
- align-items: center;
354
- gap: 0.75rem;
355
- font-size: 1rem;
356
- color: var(--text-primary);
357
- }
358
-
359
- .info-list i {
360
- color: var(--success-color);
361
- font-size: 1.2rem;
362
- }
363
-
364
- /* Dashboard */
365
- .dashboard {
366
- width: 100%;
367
- max-width: 100%;
368
- margin: 0 auto;
369
- padding: 2rem;
370
- }
371
-
372
- .dashboard-header {
373
- display: flex;
374
- justify-content: space-between;
375
- align-items: center;
376
- margin-bottom: 2rem;
377
- padding: 1.5rem;
378
- background: var(--card-bg);
379
- border-radius: 12px;
380
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
381
- border: 1px solid var(--border-color);
382
- }
383
-
384
- .ticker-info h1 {
385
- font-size: 2.5rem;
386
- font-weight: 700;
387
- color: var(--text-primary);
388
- margin-bottom: 0.5rem;
389
- }
390
-
391
- .price-info {
392
- display: flex;
393
- gap: 1rem;
394
- align-items: center;
395
- }
396
-
397
- .current-price {
398
- font-size: 2rem;
399
- font-weight: 600;
400
- }
401
-
402
- .price-change {
403
- font-size: 1.25rem;
404
- font-weight: 600;
405
- padding: 0.25rem 0.75rem;
406
- border-radius: 6px;
407
- }
408
-
409
- .price-change.positive {
410
- color: var(--positive-color);
411
- background: rgba(38, 166, 154, 0.1);
412
- }
413
-
414
- .price-change.negative {
415
- color: var(--negative-color);
416
- background: rgba(239, 83, 80, 0.1);
417
- }
418
-
419
- .header-actions {
420
- display: flex;
421
- gap: 1rem;
422
- }
423
-
424
- /* Metrics Grid */
425
- .metrics-grid {
426
- display: grid;
427
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
428
- gap: 1.5rem;
429
- margin-bottom: 2rem;
430
- }
431
-
432
- .metric-card {
433
- background: var(--card-bg);
434
- padding: 1.5rem;
435
- border-radius: 12px;
436
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
437
- border-left: 4px solid var(--primary-color);
438
- border: 1px solid var(--border-color);
439
- border-left: 4px solid var(--primary-color);
440
- }
441
-
442
- .metric-label {
443
- font-size: 0.875rem;
444
- color: var(--text-secondary);
445
- margin-bottom: 0.5rem;
446
- text-transform: uppercase;
447
- letter-spacing: 0.5px;
448
- }
449
-
450
- .metric-value {
451
- font-size: 1.75rem;
452
- font-weight: 700;
453
- color: var(--text-primary);
454
- }
455
-
456
- .metric-value.signal-buy {
457
- color: var(--success-color);
458
- }
459
-
460
- .metric-value.signal-sell {
461
- color: var(--danger-color);
462
- }
463
-
464
- .metric-value.signal-neutral {
465
- color: var(--warning-color);
466
- }
467
-
468
- .metric-signal {
469
- font-size: 0.875rem;
470
- margin-top: 0.5rem;
471
- padding: 0.25rem 0.5rem;
472
- border-radius: 4px;
473
- display: inline-block;
474
- }
475
-
476
- .metric-signal.signal-buy {
477
- background: rgba(76, 175, 80, 0.1);
478
- color: var(--success-color);
479
- }
480
-
481
- .metric-signal.signal-sell {
482
- background: rgba(244, 67, 54, 0.1);
483
- color: var(--danger-color);
484
- }
485
-
486
- .metric-signal.signal-neutral {
487
- background: rgba(255, 152, 0, 0.1);
488
- color: var(--warning-color);
489
- }
490
-
491
- /* Charts */
492
- .chart-container {
493
- background: var(--card-bg);
494
- padding: 1.5rem;
495
- border-radius: 12px;
496
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
497
- margin-bottom: 2rem;
498
- border: 1px solid var(--border-color);
499
- }
500
-
501
- .chart-header {
502
- display: flex;
503
- justify-content: space-between;
504
- align-items: center;
505
- margin-bottom: 1rem;
506
- }
507
-
508
- .chart-header h2,
509
- .chart-header h3 {
510
- display: flex;
511
- align-items: center;
512
- gap: 0.5rem;
513
- color: var(--text-primary);
514
- }
515
-
516
- .chart-header i {
517
- color: var(--primary-color);
518
- }
519
-
520
- .chart-controls {
521
- display: flex;
522
- gap: 0.5rem;
523
- }
524
-
525
- .chart {
526
- width: 100%;
527
- height: 500px;
528
- }
529
-
530
- .chart-small {
531
- width: 100%;
532
- height: 350px;
533
- }
534
-
535
- .indicators-grid {
536
- display: flex;
537
- flex-direction: column;
538
- gap: 1.5rem;
539
- margin-bottom: 2rem;
540
- }
541
-
542
- /* Strategy Results */
543
- .strategy-results {
544
- padding: 1rem 0;
545
- }
546
-
547
- .results-table {
548
- width: 100%;
549
- border-collapse: collapse;
550
- margin-top: 1rem;
551
- }
552
-
553
- .results-table thead {
554
- background: var(--card-bg-lighter);
555
- }
556
-
557
- .results-table th,
558
- .results-table td {
559
- padding: 1rem;
560
- text-align: left;
561
- border-bottom: 1px solid var(--border-color);
562
- color: var(--text-primary);
563
- }
564
-
565
- .results-table th {
566
- font-weight: 600;
567
- color: var(--text-secondary);
568
- text-transform: uppercase;
569
- font-size: 0.875rem;
570
- letter-spacing: 0.5px;
571
- }
572
-
573
- .results-table td {
574
- font-weight: 500;
575
- }
576
-
577
- .results-table tr:hover {
578
- background: var(--card-bg-lighter);
579
- }
580
-
581
- .results-table .positive {
582
- color: var(--positive-color);
583
- font-weight: 600;
584
- }
585
-
586
- .results-table .negative {
587
- color: var(--negative-color);
588
- font-weight: 600;
589
- }
590
-
591
- .hint {
592
- color: var(--text-secondary);
593
- font-style: italic;
594
- padding: 2rem;
595
- text-align: center;
596
- }
597
-
598
- .loading {
599
- text-align: center;
600
- padding: 2rem;
601
- color: var(--primary-color);
602
- font-size: 1.1rem;
603
- }
604
-
605
- .error {
606
- text-align: center;
607
- padding: 2rem;
608
- color: var(--danger-color);
609
- }
610
-
611
- /* Modal */
612
- .modal {
613
- display: none;
614
- position: fixed;
615
- z-index: 2000;
616
- left: 0;
617
- top: 0;
618
- width: 100%;
619
- height: 100%;
620
- background-color: rgba(0, 0, 0, 0.5);
621
- backdrop-filter: blur(5px);
622
- }
623
-
624
- .modal-content {
625
- background-color: var(--card-bg);
626
- margin: 15% auto;
627
- padding: 2rem;
628
- border-radius: 12px;
629
- width: 90%;
630
- max-width: 500px;
631
- box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
632
- border: 1px solid var(--border-color);
633
- }
634
-
635
- .modal-content h2 {
636
- margin-bottom: 1.5rem;
637
- color: var(--text-primary);
638
- }
639
-
640
- .modal-content input {
641
- width: 100%;
642
- padding: 1rem;
643
- border: 2px solid var(--border-color);
644
- border-radius: 8px;
645
- font-size: 1.1rem;
646
- margin-bottom: 1rem;
647
- outline: none;
648
- background: var(--card-bg-lighter);
649
- color: var(--text-primary);
650
- }
651
-
652
- .modal-content input:focus {
653
- border-color: var(--primary-color);
654
- background: var(--card-bg);
655
- }
656
-
657
- .close {
658
- color: var(--text-secondary);
659
- float: right;
660
- font-size: 2rem;
661
- font-weight: bold;
662
- cursor: pointer;
663
- transition: color 0.3s ease;
664
- }
665
-
666
- .close:hover {
667
- color: var(--text-primary);
668
- }
669
-
670
- /* Footer */
671
- .footer {
672
- background: var(--dark-bg);
673
- color: white;
674
- padding: 2rem 0;
675
- margin-top: 4rem;
676
- }
677
-
678
- .footer-content {
679
- max-width: 1200px;
680
- margin: 0 auto;
681
- padding: 0 2rem;
682
- text-align: center;
683
- }
684
-
685
- .footer-content p {
686
- margin-bottom: 0.5rem;
687
- opacity: 0.8;
688
- }
689
-
690
- .disclaimer {
691
- color: var(--warning-color);
692
- font-weight: 600;
693
- }
694
-
695
- /* Responsive */
696
- @media (max-width: 768px) {
697
- .hero-content h1 {
698
- font-size: 2rem;
699
- }
700
-
701
- .search-form {
702
- flex-direction: column;
703
- }
704
-
705
- .dashboard-header {
706
- flex-direction: column;
707
- align-items: flex-start;
708
- gap: 1rem;
709
- }
710
-
711
- .metrics-grid {
712
- grid-template-columns: 1fr;
713
- }
714
-
715
- .indicators-grid {
716
- grid-template-columns: 1fr;
717
- }
718
-
719
- .nav-menu {
720
- gap: 1rem;
721
- font-size: 0.875rem;
722
- }
723
- }