GameSentenceMiner 2.17.6__py3-none-any.whl → 2.18.0__py3-none-any.whl

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 (51) hide show
  1. GameSentenceMiner/ai/ai_prompting.py +51 -51
  2. GameSentenceMiner/anki.py +236 -152
  3. GameSentenceMiner/gametext.py +7 -4
  4. GameSentenceMiner/gsm.py +49 -10
  5. GameSentenceMiner/locales/en_us.json +7 -3
  6. GameSentenceMiner/locales/ja_jp.json +8 -4
  7. GameSentenceMiner/locales/zh_cn.json +8 -4
  8. GameSentenceMiner/obs.py +238 -59
  9. GameSentenceMiner/ocr/owocr_helper.py +1 -1
  10. GameSentenceMiner/tools/ss_selector.py +7 -8
  11. GameSentenceMiner/ui/__init__.py +0 -0
  12. GameSentenceMiner/ui/anki_confirmation.py +187 -0
  13. GameSentenceMiner/{config_gui.py → ui/config_gui.py} +102 -37
  14. GameSentenceMiner/ui/screenshot_selector.py +215 -0
  15. GameSentenceMiner/util/configuration.py +124 -22
  16. GameSentenceMiner/util/db.py +22 -13
  17. GameSentenceMiner/util/downloader/download_tools.py +2 -2
  18. GameSentenceMiner/util/ffmpeg.py +24 -30
  19. GameSentenceMiner/util/get_overlay_coords.py +34 -34
  20. GameSentenceMiner/util/gsm_utils.py +31 -1
  21. GameSentenceMiner/util/text_log.py +11 -9
  22. GameSentenceMiner/vad.py +31 -12
  23. GameSentenceMiner/web/database_api.py +742 -123
  24. GameSentenceMiner/web/static/css/dashboard-shared.css +241 -0
  25. GameSentenceMiner/web/static/css/kanji-grid.css +94 -2
  26. GameSentenceMiner/web/static/css/overview.css +850 -0
  27. GameSentenceMiner/web/static/css/popups-shared.css +126 -0
  28. GameSentenceMiner/web/static/css/shared.css +97 -0
  29. GameSentenceMiner/web/static/css/stats.css +192 -597
  30. GameSentenceMiner/web/static/js/anki_stats.js +6 -4
  31. GameSentenceMiner/web/static/js/database.js +209 -5
  32. GameSentenceMiner/web/static/js/goals.js +610 -0
  33. GameSentenceMiner/web/static/js/kanji-grid.js +267 -4
  34. GameSentenceMiner/web/static/js/overview.js +1176 -0
  35. GameSentenceMiner/web/static/js/shared.js +25 -0
  36. GameSentenceMiner/web/static/js/stats.js +154 -1459
  37. GameSentenceMiner/web/stats.py +2 -2
  38. GameSentenceMiner/web/templates/anki_stats.html +5 -0
  39. GameSentenceMiner/web/templates/components/navigation.html +3 -1
  40. GameSentenceMiner/web/templates/database.html +73 -1
  41. GameSentenceMiner/web/templates/goals.html +376 -0
  42. GameSentenceMiner/web/templates/index.html +13 -11
  43. GameSentenceMiner/web/templates/overview.html +416 -0
  44. GameSentenceMiner/web/templates/stats.html +46 -251
  45. GameSentenceMiner/web/texthooking_page.py +18 -0
  46. {gamesentenceminer-2.17.6.dist-info → gamesentenceminer-2.18.0.dist-info}/METADATA +5 -1
  47. {gamesentenceminer-2.17.6.dist-info → gamesentenceminer-2.18.0.dist-info}/RECORD +51 -41
  48. {gamesentenceminer-2.17.6.dist-info → gamesentenceminer-2.18.0.dist-info}/WHEEL +0 -0
  49. {gamesentenceminer-2.17.6.dist-info → gamesentenceminer-2.18.0.dist-info}/entry_points.txt +0 -0
  50. {gamesentenceminer-2.17.6.dist-info → gamesentenceminer-2.18.0.dist-info}/licenses/LICENSE +0 -0
  51. {gamesentenceminer-2.17.6.dist-info → gamesentenceminer-2.18.0.dist-info}/top_level.txt +0 -0
@@ -145,222 +145,8 @@
145
145
  flex-wrap: wrap;
146
146
  align-items: center;
147
147
  }
148
-
149
- /* Dashboard Cards Styles */
150
- .dashboard-container {
151
- display: grid;
152
- grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
153
- gap: 30px;
154
- margin-bottom: 40px;
155
- }
156
-
157
- .dashboard-card {
158
- background: var(--bg-secondary);
159
- border-radius: 12px;
160
- box-shadow: 0 4px 16px var(--shadow-color);
161
- border: 1px solid var(--border-color);
162
- padding: 24px;
163
- transition: all 0.3s ease;
164
- position: relative;
165
- overflow: hidden;
166
- }
167
-
168
- .dashboard-card:hover {
169
- transform: translateY(-2px);
170
- box-shadow: 0 8px 24px var(--shadow-color);
171
- }
172
-
173
- .dashboard-card::before {
174
- content: '';
175
- position: absolute;
176
- top: 0;
177
- left: 0;
178
- right: 0;
179
- height: 4px;
180
- background: linear-gradient(90deg, var(--accent-color), var(--success-color));
181
- border-radius: 12px 12px 0 0;
182
- }
183
-
184
- .dashboard-card.current-game::before {
185
- background: linear-gradient(90deg, var(--accent-color), var(--info-color));
186
- }
187
-
188
- .dashboard-card.all-games::before {
189
- background: linear-gradient(90deg, var(--success-color), var(--warning-color));
190
- }
191
-
192
- .dashboard-card-header {
193
- display: flex;
194
- align-items: center;
195
- justify-content: space-between;
196
- margin-bottom: 20px;
197
- }
198
-
199
- .dashboard-card-title {
200
- font-size: 20px;
201
- font-weight: 600;
202
- color: var(--text-primary);
203
- margin: 0;
204
- display: flex;
205
- align-items: center;
206
- gap: 10px;
207
- }
208
-
209
- .dashboard-card-icon {
210
- font-size: 24px;
211
- opacity: 0.8;
212
- }
213
-
214
- .dashboard-card-subtitle {
215
- font-size: 14px;
216
- color: var(--text-tertiary);
217
- margin: 4px 0 0 0;
218
- }
219
-
220
- .dashboard-stats-grid {
221
- display: grid;
222
- grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
223
- gap: 16px;
224
- margin-bottom: 20px;
225
- }
226
-
227
- .dashboard-stat-item {
228
- text-align: center;
229
- padding: 12px;
230
- background: var(--bg-tertiary);
231
- border-radius: 8px;
232
- transition: all 0.2s ease;
233
- position: relative;
234
- cursor: pointer;
235
- }
236
-
237
- .dashboard-stat-item:hover {
238
- background: var(--border-color);
239
- transform: scale(1.02);
240
- }
241
-
242
- .dashboard-stat-value {
243
- font-size: 24px;
244
- font-weight: bold;
245
- color: var(--text-primary);
246
- margin-bottom: 4px;
247
- display: block;
248
- }
249
-
250
- .dashboard-stat-label {
251
- font-size: 12px;
252
- color: var(--text-tertiary);
253
- text-transform: uppercase;
254
- letter-spacing: 0.5px;
255
- font-weight: 500;
256
- }
257
-
258
- .dashboard-progress-section {
259
- margin-top: 20px;
260
- padding-top: 20px;
261
- border-top: 1px solid var(--border-color);
262
- }
263
-
264
- .dashboard-progress-title {
265
- font-size: 14px;
266
- font-weight: 600;
267
- color: var(--text-secondary);
268
- margin-bottom: 12px;
269
- }
270
-
271
- .dashboard-progress-items {
272
- display: flex;
273
- justify-content: space-between;
274
- gap: 16px;
275
- }
276
-
277
- .dashboard-progress-item {
278
- text-align: center;
279
- flex: 1;
280
- }
281
-
282
- .dashboard-progress-value {
283
- font-size: 18px;
284
- font-weight: bold;
285
- margin-bottom: 4px;
286
- }
287
-
288
- .dashboard-progress-value.positive {
289
- color: var(--success-color);
290
- }
291
-
292
- .dashboard-progress-value.neutral {
293
- color: var(--text-secondary);
294
- }
295
-
296
- .dashboard-progress-label {
297
- font-size: 11px;
298
- color: var(--text-tertiary);
299
- text-transform: uppercase;
300
- letter-spacing: 0.5px;
301
- }
302
-
303
- .dashboard-streak-indicator {
304
- display: inline-flex;
305
- align-items: center;
306
- gap: 4px;
307
- font-size: 12px;
308
- color: var(--success-color);
309
- background: rgba(40, 167, 69, 0.1);
310
- padding: 4px 8px;
311
- border-radius: 12px;
312
- font-weight: 500;
313
- }
314
-
315
- .dashboard-streak-indicator::before {
316
- content: '🔥';
317
- font-size: 14px;
318
- }
319
-
320
- /* Tooltip Styles */
321
- .tooltip {
322
- position: relative;
323
- cursor: help;
324
- }
325
-
326
- .tooltip::before {
327
- content: attr(data-tooltip);
328
- position: absolute;
329
- bottom: 125%;
330
- left: 50%;
331
- transform: translateX(-50%);
332
- background: rgba(0, 0, 0, 0.9);
333
- color: white;
334
- padding: 8px 12px;
335
- border-radius: 6px;
336
- font-size: 12px;
337
- white-space: nowrap;
338
- opacity: 0;
339
- visibility: hidden;
340
- transition: all 0.3s ease;
341
- z-index: 1000;
342
- pointer-events: none;
343
- }
344
-
345
- .tooltip::after {
346
- content: '';
347
- position: absolute;
348
- bottom: 120%;
349
- left: 50%;
350
- transform: translateX(-50%);
351
- border: 4px solid transparent;
352
- border-top-color: rgba(0, 0, 0, 0.9);
353
- opacity: 0;
354
- visibility: hidden;
355
- transition: all 0.3s ease;
356
- z-index: 1000;
357
- }
358
-
359
- .tooltip:hover::before,
360
- .tooltip:hover::after {
361
- opacity: 1;
362
- visibility: visible;
363
- }
148
+ /* Dashboard card styles moved to dashboard-shared.css */
149
+ /* Tooltip styles are now only in shared.css */
364
150
 
365
151
  /* Loading State */
366
152
  .dashboard-loading {
@@ -657,279 +443,7 @@
657
443
  margin-bottom: 16px;
658
444
  }
659
445
 
660
- /* ================================
661
- Dashboard Cards Styles
662
- ================================ */
663
- .dashboard-container {
664
- display: grid;
665
- grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
666
- gap: 30px;
667
- margin-bottom: 40px;
668
- }
669
-
670
- .dashboard-card {
671
- background: var(--bg-secondary);
672
- border-radius: 12px;
673
- box-shadow: 0 4px 16px var(--shadow-color);
674
- border: 1px solid var(--border-color);
675
- padding: 24px;
676
- transition: all 0.3s ease;
677
- position: relative;
678
- overflow: hidden;
679
- }
680
-
681
- .dashboard-card:hover {
682
- transform: translateY(-2px);
683
- box-shadow: 0 8px 24px var(--shadow-color);
684
- }
685
-
686
- .dashboard-card::before {
687
- content: '';
688
- position: absolute;
689
- top: 0;
690
- left: 0;
691
- right: 0;
692
- height: 4px;
693
- background: linear-gradient(90deg, var(--accent-color), var(--success-color));
694
- border-radius: 12px 12px 0 0;
695
- }
696
-
697
- .dashboard-card.current-game::before {
698
- background: linear-gradient(90deg, var(--accent-color), var(--info-color));
699
- }
700
-
701
- .dashboard-card.all-games::before {
702
- background: linear-gradient(90deg, var(--success-color), var(--warning-color));
703
- }
704
-
705
- .dashboard-card.date-range::before {
706
- background: linear-gradient(90deg, var(--info-color), var(--accent-color));
707
- }
708
-
709
- .dashboard-card.date-range {
710
- margin-bottom: 30px;
711
- }
712
-
713
- .dashboard-card-header {
714
- display: flex;
715
- align-items: center;
716
- justify-content: space-between;
717
- margin-bottom: 20px;
718
- }
719
-
720
- .dashboard-card-title {
721
- font-size: 20px;
722
- font-weight: 600;
723
- color: var(--text-primary);
724
- margin: 0;
725
- display: flex;
726
- align-items: center;
727
- gap: 10px;
728
- }
729
-
730
- .dashboard-card-icon {
731
- font-size: 24px;
732
- opacity: 0.8;
733
- }
734
-
735
- .dashboard-card-subtitle {
736
- font-size: 14px;
737
- color: var(--text-tertiary);
738
- margin: 4px 0 0 0;
739
- }
740
-
741
- /* ================================
742
- Stats Grid
743
- ================================ */
744
- .dashboard-stats-grid {
745
- display: grid;
746
- grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
747
- gap: 16px;
748
- margin-bottom: 20px;
749
- }
750
-
751
- .dashboard-stat-item {
752
- text-align: center;
753
- padding: 12px;
754
- background: var(--bg-tertiary);
755
- border-radius: 8px;
756
- transition: all 0.2s ease;
757
- position: relative;
758
- cursor: pointer;
759
- }
760
-
761
- .dashboard-stat-item:hover {
762
- background: var(--border-color);
763
- transform: scale(1.02);
764
- }
765
-
766
- .dashboard-stat-value {
767
- font-size: 24px;
768
- font-weight: bold;
769
- color: var(--text-primary);
770
- margin-bottom: 4px;
771
- display: block;
772
- }
773
-
774
- .dashboard-stat-label {
775
- font-size: 12px;
776
- color: var(--text-tertiary);
777
- text-transform: uppercase;
778
- letter-spacing: 0.5px;
779
- font-weight: 500;
780
- }
781
-
782
- /* ================================
783
- Progress Section
784
- ================================ */
785
- .dashboard-progress-section {
786
- margin-top: 20px;
787
- padding-top: 20px;
788
- border-top: 1px solid var(--border-color);
789
- }
790
-
791
- .dashboard-progress-title {
792
- font-size: 14px;
793
- font-weight: 600;
794
- color: var(--text-secondary);
795
- margin-bottom: 12px;
796
- }
797
-
798
- .dashboard-progress-items {
799
- display: flex;
800
- justify-content: space-between;
801
- gap: 16px;
802
- }
803
-
804
- .dashboard-progress-item {
805
- text-align: center;
806
- flex: 1;
807
- }
808
-
809
- .dashboard-progress-value {
810
- font-size: 18px;
811
- font-weight: bold;
812
- margin-bottom: 4px;
813
- }
814
-
815
- .dashboard-progress-value.positive {
816
- color: var(--success-color);
817
- }
818
-
819
- .dashboard-progress-value.neutral {
820
- color: var(--text-secondary);
821
- }
822
-
823
- .dashboard-progress-label {
824
- font-size: 11px;
825
- color: var(--text-tertiary);
826
- text-transform: uppercase;
827
- letter-spacing: 0.5px;
828
- }
829
-
830
- /* ================================
831
- Streak Indicator
832
- ================================ */
833
- .dashboard-streak-indicator {
834
- display: inline-flex;
835
- align-items: center;
836
- gap: 4px;
837
- font-size: 12px;
838
- color: var(--success-color);
839
- background: rgba(40, 167, 69, 0.1);
840
- padding: 4px 8px;
841
- border-radius: 12px;
842
- font-weight: 500;
843
- }
844
-
845
- .dashboard-streak-indicator::before {
846
- content: '🔥';
847
- font-size: 14px;
848
- }
849
-
850
- /* ================================
851
- Date Range Card
852
- ================================ */
853
- .dashboard-date-range {
854
- display: flex;
855
- gap: 20px;
856
- }
857
-
858
- .dashboard-date-item {
859
- flex: 1;
860
- display: flex;
861
- flex-direction: column;
862
- gap: 6px;
863
- }
864
-
865
- .dashboard-date-item label {
866
- font-size: 13px;
867
- color: var(--text-secondary);
868
- font-weight: 500;
869
- }
870
-
871
- .dashboard-date-input {
872
- padding: 8px 12px;
873
- border: 1px solid var(--border-color);
874
- border-radius: 8px;
875
- background: var(--bg-tertiary);
876
- color: var(--text-primary);
877
- font-size: 14px;
878
- transition: all 0.2s ease;
879
- }
880
-
881
- .dashboard-date-input:focus {
882
- outline: none;
883
- border-color: var(--accent-color);
884
- box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.15);
885
- }
886
-
887
- /* ================================
888
- Tooltip Styles
889
- ================================ */
890
- .tooltip {
891
- position: relative;
892
- cursor: help;
893
- }
894
-
895
- .tooltip::before {
896
- content: attr(data-tooltip);
897
- position: absolute;
898
- bottom: 125%;
899
- left: 50%;
900
- transform: translateX(-50%);
901
- background: rgba(0, 0, 0, 0.9);
902
- color: white;
903
- padding: 8px 12px;
904
- border-radius: 6px;
905
- font-size: 12px;
906
- white-space: nowrap;
907
- opacity: 0;
908
- visibility: hidden;
909
- transition: all 0.3s ease;
910
- z-index: 1000;
911
- pointer-events: none;
912
- }
913
-
914
- .tooltip::after {
915
- content: '';
916
- position: absolute;
917
- bottom: 120%;
918
- left: 50%;
919
- transform: translateX(-50%);
920
- border: 4px solid transparent;
921
- border-top-color: rgba(0, 0, 0, 0.9);
922
- opacity: 0;
923
- visibility: hidden;
924
- transition: all 0.3s ease;
925
- z-index: 1000;
926
- }
927
-
928
- .tooltip:hover::before,
929
- .tooltip:hover::after {
930
- opacity: 1;
931
- visibility: visible;
932
- }
446
+ /* Dashboard card, stats grid, progress section, streak indicator, and date range styles are now in dashboard-shared.css */
933
447
 
934
448
  /* ================================
935
449
  Loading State
@@ -982,114 +496,7 @@
982
496
  transform: translateY(-1px);
983
497
  }
984
498
 
985
- /* ================================
986
- Popups
987
- ================================ */
988
- .dashboard-popup,
989
- .no-data-popup {
990
- position: fixed;
991
- top: 0;
992
- left: 0;
993
- right: 0;
994
- bottom: 0;
995
- display: flex;
996
- align-items: center;
997
- justify-content: center;
998
- background: rgba(0, 0, 0, 0.4);
999
- z-index: 2000;
1000
- }
1001
-
1002
- .hidden {
1003
- display: none;
1004
- }
1005
-
1006
- .dashboard-popup-content,
1007
- .no-data-content {
1008
- background: var(--bg-secondary);
1009
- border: 1px solid var(--border-color);
1010
- border-radius: 12px;
1011
- padding: 24px;
1012
- box-shadow: 0 8px 24px var(--shadow-color);
1013
- text-align: center;
1014
- max-width: 400px;
1015
- width: 90%;
1016
- }
1017
-
1018
- .dashboard-popup-icon {
1019
- font-size: 32px;
1020
- margin-bottom: 12px;
1021
- }
1022
-
1023
- .dashboard-popup-message,
1024
- .no-data-content p {
1025
- font-size: 14px;
1026
- color: var(--text-primary);
1027
- margin-bottom: 20px;
1028
- }
1029
-
1030
- .dashboard-popup-btn,
1031
- #closeNoDataPopup {
1032
- background: var(--accent-color);
1033
- color: white;
1034
- border: none;
1035
- padding: 10px 18px;
1036
- border-radius: 8px;
1037
- font-size: 14px;
1038
- cursor: pointer;
1039
- transition: all 0.2s ease;
1040
- }
1041
-
1042
- .dashboard-popup-btn:hover,
1043
- #closeNoDataPopup:hover {
1044
- background: #0056b3;
1045
- transform: translateY(-1px);
1046
- }
1047
-
1048
- /* Popup box */
1049
- .dashboard-popup-content {
1050
- background: var(--bg-secondary);
1051
- border-radius: 12px;
1052
- box-shadow: 0 8px 24px var(--shadow-color);
1053
- border: 1px solid var(--border-color);
1054
- padding: 24px;
1055
- max-width: 320px;
1056
- text-align: center;
1057
- animation: popupFadeIn 0.3s ease;
1058
- }
1059
-
1060
- .dashboard-popup-icon {
1061
- font-size: 36px;
1062
- margin-bottom: 12px;
1063
- }
1064
-
1065
- .dashboard-popup-message {
1066
- font-size: 14px;
1067
- color: var(--danger-color);
1068
- margin-bottom: 20px;
1069
- font-weight: 500;
1070
- }
1071
-
1072
- .dashboard-popup-btn {
1073
- padding: 10px 16px;
1074
- border-radius: 6px;
1075
- border: none;
1076
- background: var(--accent-color);
1077
- color: #fff;
1078
- font-size: 14px;
1079
- font-weight: 600;
1080
- cursor: pointer;
1081
- transition: all 0.2s ease;
1082
- }
1083
-
1084
- .dashboard-popup-btn:hover {
1085
- background: var(--accent-color-hover, #0056b3);
1086
- transform: translateY(-1px);
1087
- }
1088
-
1089
- @keyframes popupFadeIn {
1090
- from { transform: scale(0.95); opacity: 0; }
1091
- to { transform: scale(1); opacity: 1; }
1092
- }
499
+ /* Popup styles are now in popups-shared.css */
1093
500
 
1094
501
  /* Responsive Design for Goal Progress Chart */
1095
502
  @media (max-width: 768px) {
@@ -1235,3 +642,191 @@
1235
642
  .no-data-content button:hover {
1236
643
  background: #0056b3;
1237
644
  }
645
+
646
+ /* ================================
647
+ Goals Page Specific Styles
648
+ ================================ */
649
+ .dashboard-card.today-goals::before {
650
+ background: linear-gradient(90deg, #e6dc2e, #3be62f);
651
+ }
652
+
653
+ .dashboard-card.projection-card::before {
654
+ background: linear-gradient(90deg, #3be62f, #2ee6e0);
655
+ }
656
+
657
+ .no-targets-message {
658
+ text-align: center;
659
+ padding: 40px 20px;
660
+ color: var(--text-tertiary);
661
+ font-style: italic;
662
+ font-size: 14px;
663
+ }
664
+
665
+ .no-targets-message::before {
666
+ content: '⚙️';
667
+ display: block;
668
+ font-size: 48px;
669
+ margin-bottom: 16px;
670
+ opacity: 0.5;
671
+ }
672
+
673
+
674
+ /* Goal stat item with vertical progress/required layout */
675
+ .goal-stat-item {
676
+ display: flex;
677
+ flex-direction: column;
678
+ align-items: center;
679
+ gap: 0;
680
+ transition: all 0.3s ease;
681
+ padding: 20px 12px;
682
+ }
683
+
684
+ .goal-stat-item .goal-progress-value {
685
+ font-size: 1.8em;
686
+ font-weight: 600;
687
+ color: var(--text-secondary);
688
+ line-height: 1;
689
+ margin-bottom: 12px;
690
+ }
691
+
692
+ .goal-stat-item .goal-divider {
693
+ width: 90%;
694
+ height: 2px;
695
+ background: var(--border-color);
696
+ margin: 10px 0;
697
+ }
698
+
699
+ .goal-stat-item .goal-required-value {
700
+ font-size: 2.5em;
701
+ font-weight: 700;
702
+ color: var(--text-primary);
703
+ line-height: 1;
704
+ margin-top: 12px;
705
+ margin-bottom: 12px;
706
+ }
707
+
708
+ .goal-stat-item .dashboard-stat-label {
709
+ margin-top: 12px;
710
+ font-size: 13px;
711
+ }
712
+
713
+ /* Green highlight when goal is met */
714
+ .goal-stat-item.goal-met {
715
+ background: linear-gradient(135deg, rgba(34, 197, 94, 0.15) 0%, rgba(22, 163, 74, 0.1) 100%);
716
+ border: 2px solid rgba(34, 197, 94, 0.4);
717
+ box-shadow: 0 0 20px rgba(34, 197, 94, 0.2);
718
+ }
719
+
720
+ .goal-stat-item.goal-met .goal-progress-value,
721
+ .goal-stat-item.goal-met .goal-required-value {
722
+ color: #22c55e;
723
+ }
724
+
725
+ .goal-stat-item.goal-met .goal-divider {
726
+ background: rgba(34, 197, 94, 0.6);
727
+ height: 3px;
728
+ }
729
+
730
+ .goal-stat-item.goal-met .dashboard-stat-label {
731
+ color: #22c55e;
732
+ font-weight: 600;
733
+ }
734
+
735
+ /* Goal stat item - simple inline format showing TODAY / GOAL */
736
+ .goal-stat-item .dashboard-stat-value {
737
+ display: flex;
738
+ align-items: baseline;
739
+ justify-content: center;
740
+ gap: 8px;
741
+ }
742
+
743
+ .goal-stat-item .goal-separator {
744
+ font-size: 0.8em;
745
+ color: var(--text-tertiary);
746
+ font-weight: 400;
747
+ }
748
+
749
+ /* ================================
750
+ Pace Indicator Badges
751
+ ================================ */
752
+ .pace-badge {
753
+ display: inline-flex;
754
+ align-items: center;
755
+ justify-content: center;
756
+ padding: 3px 10px;
757
+ border-radius: 12px;
758
+ font-size: 11px;
759
+ font-weight: 700;
760
+ letter-spacing: 0.3px;
761
+ margin-left: 6px;
762
+ white-space: nowrap;
763
+ transition: all 0.3s ease;
764
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
765
+ vertical-align: middle;
766
+ }
767
+
768
+ .pace-badge:hover {
769
+ transform: scale(1.05);
770
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
771
+ }
772
+
773
+ /* Over-achieving - Green gradient */
774
+ .pace-badge.pace-ahead {
775
+ background: linear-gradient(135deg, #22c55e 0%, #10b981 100%);
776
+ color: #ffffff;
777
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
778
+ }
779
+
780
+ .pace-badge.pace-ahead:hover {
781
+ box-shadow: 0 4px 12px rgba(34, 197, 94, 0.4);
782
+ }
783
+
784
+ /* Perfect pace - Cyan */
785
+ .pace-badge.pace-perfect {
786
+ background: #2ee6e0;
787
+ color: #ffffff;
788
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
789
+ }
790
+
791
+ .pace-badge.pace-perfect:hover {
792
+ box-shadow: 0 4px 12px rgba(46, 230, 224, 0.4);
793
+ }
794
+
795
+ /* Slightly behind - Orange gradient */
796
+ .pace-badge.pace-behind-mild {
797
+ background: linear-gradient(135deg, #f59e0b 0%, #f97316 100%);
798
+ color: #ffffff;
799
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
800
+ }
801
+
802
+ .pace-badge.pace-behind-mild:hover {
803
+ box-shadow: 0 4px 12px rgba(245, 158, 11, 0.4);
804
+ }
805
+
806
+ /* Significantly behind - Red gradient */
807
+ .pace-badge.pace-behind {
808
+ background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
809
+ color: #ffffff;
810
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
811
+ }
812
+
813
+ .pace-badge.pace-behind:hover {
814
+ box-shadow: 0 4px 12px rgba(239, 68, 68, 0.4);
815
+ }
816
+
817
+ /* Responsive design for pace badges */
818
+ @media (max-width: 768px) {
819
+ .pace-badge {
820
+ font-size: 10px;
821
+ padding: 2px 8px;
822
+ margin-left: 4px;
823
+ }
824
+ }
825
+
826
+ @media (max-width: 480px) {
827
+ .pace-badge {
828
+ font-size: 9px;
829
+ padding: 2px 6px;
830
+ margin-left: 3px;
831
+ }
832
+ }