@necrolab/dashboard 0.5.15 → 0.5.16

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 (121) hide show
  1. package/backend/api.js +2 -3
  2. package/eslint.config.js +46 -0
  3. package/index.html +2 -1
  4. package/package.json +5 -2
  5. package/src/App.vue +140 -170
  6. package/src/assets/css/base/mixins.scss +72 -0
  7. package/src/assets/css/base/reset.scss +0 -2
  8. package/src/assets/css/base/scroll.scss +43 -36
  9. package/src/assets/css/base/typography.scss +9 -10
  10. package/src/assets/css/base/variables.scss +43 -0
  11. package/src/assets/css/components/accessibility.scss +37 -0
  12. package/src/assets/css/components/buttons.scss +58 -15
  13. package/src/assets/css/components/forms.scss +31 -32
  14. package/src/assets/css/components/headers.scss +12 -20
  15. package/src/assets/css/components/modals.scss +2 -2
  16. package/src/assets/css/components/search-groups.scss +28 -22
  17. package/src/assets/css/components/tables.scss +5 -7
  18. package/src/assets/css/components/toasts.scss +7 -7
  19. package/src/assets/css/components/utilities.scss +220 -0
  20. package/src/assets/css/main.scss +66 -77
  21. package/src/components/Auth/LoginForm.vue +5 -84
  22. package/src/components/Editors/Account/Account.vue +8 -10
  23. package/src/components/Editors/Account/AccountCreator.vue +28 -59
  24. package/src/components/Editors/Account/AccountView.vue +38 -86
  25. package/src/components/Editors/Account/CreateAccount.vue +8 -50
  26. package/src/components/Editors/Profile/CreateProfile.vue +74 -131
  27. package/src/components/Editors/Profile/Profile.vue +15 -17
  28. package/src/components/Editors/Profile/ProfileCountryChooser.vue +16 -60
  29. package/src/components/Editors/Profile/ProfileView.vue +46 -96
  30. package/src/components/Editors/TagLabel.vue +16 -55
  31. package/src/components/Editors/TagToggle.vue +20 -8
  32. package/src/components/Filter/Filter.vue +62 -75
  33. package/src/components/Filter/FilterPreview.vue +161 -135
  34. package/src/components/Filter/PriceSortToggle.vue +36 -43
  35. package/src/components/Table/Header.vue +1 -1
  36. package/src/components/Table/Table.vue +45 -51
  37. package/src/components/Tasks/CheckStock.vue +7 -16
  38. package/src/components/Tasks/Controls/DesktopControls.vue +15 -60
  39. package/src/components/Tasks/Controls/MobileControls.vue +5 -20
  40. package/src/components/Tasks/CreateTaskAXS.vue +20 -118
  41. package/src/components/Tasks/CreateTaskTM.vue +33 -189
  42. package/src/components/Tasks/EventDetailRow.vue +21 -0
  43. package/src/components/Tasks/MassEdit.vue +6 -16
  44. package/src/components/Tasks/QuickSettings.vue +140 -216
  45. package/src/components/Tasks/ScrapeVenue.vue +4 -13
  46. package/src/components/Tasks/Stats.vue +19 -38
  47. package/src/components/Tasks/Task.vue +65 -268
  48. package/src/components/Tasks/TaskLabel.vue +9 -3
  49. package/src/components/Tasks/TaskView.vue +43 -63
  50. package/src/components/Tasks/Utilities.vue +10 -44
  51. package/src/components/Tasks/ViewTask.vue +23 -107
  52. package/src/components/icons/Close.vue +2 -8
  53. package/src/components/icons/Gear.vue +8 -8
  54. package/src/components/icons/Hash.vue +5 -0
  55. package/src/components/icons/Key.vue +2 -8
  56. package/src/components/icons/Pencil.vue +2 -8
  57. package/src/components/icons/Profile.vue +2 -8
  58. package/src/components/icons/Sell.vue +2 -8
  59. package/src/components/icons/Spinner.vue +4 -7
  60. package/src/components/icons/SquareCheck.vue +2 -8
  61. package/src/components/icons/SquareUncheck.vue +2 -8
  62. package/src/components/icons/Wildcard.vue +2 -8
  63. package/src/components/icons/index.js +3 -1
  64. package/src/components/ui/ActionButtonGroup.vue +113 -52
  65. package/src/components/ui/BalanceIndicator.vue +60 -0
  66. package/src/components/ui/EmptyState.vue +24 -0
  67. package/src/components/ui/EnableDisableToggle.vue +23 -0
  68. package/src/components/ui/FormField.vue +48 -48
  69. package/src/components/ui/IconLabel.vue +23 -0
  70. package/src/components/ui/InfoRow.vue +21 -54
  71. package/src/components/ui/Modal.vue +89 -56
  72. package/src/components/ui/Navbar.vue +60 -41
  73. package/src/components/ui/ReadonlyFieldsSection.vue +31 -0
  74. package/src/components/ui/ReconnectIndicator.vue +111 -124
  75. package/src/components/ui/SectionCard.vue +6 -14
  76. package/src/components/ui/Splash.vue +2 -10
  77. package/src/components/ui/StatusBadge.vue +26 -28
  78. package/src/components/ui/TaskToggle.vue +54 -0
  79. package/src/components/ui/controls/CountryChooser.vue +27 -64
  80. package/src/components/ui/controls/EyeToggle.vue +1 -1
  81. package/src/components/ui/controls/atomic/Checkbox.vue +40 -121
  82. package/src/components/ui/controls/atomic/Dropdown.vue +103 -139
  83. package/src/components/ui/controls/atomic/MultiDropdown.vue +71 -119
  84. package/src/components/ui/controls/atomic/Switch.vue +21 -84
  85. package/src/composables/useColorMapping.js +15 -0
  86. package/src/composables/useCopyToClipboard.js +1 -1
  87. package/src/composables/useDateFormatting.js +21 -0
  88. package/src/composables/useDeviceDetection.js +14 -0
  89. package/src/composables/useDropdownPosition.js +3 -4
  90. package/src/composables/useDynamicTableHeight.js +31 -0
  91. package/src/composables/useRowSelection.js +0 -3
  92. package/src/composables/useTicketPricing.js +16 -0
  93. package/src/composables/useWindowDimensions.js +21 -0
  94. package/src/libs/Filter.js +14 -20
  95. package/src/libs/panzoom.js +1 -5
  96. package/src/libs/utils/array.js +60 -0
  97. package/src/{stores/utils.js → libs/utils/dataGeneration.js} +2 -250
  98. package/src/libs/utils/eventUrl.js +40 -0
  99. package/src/libs/utils/string.js +28 -0
  100. package/src/libs/utils/time.js +20 -0
  101. package/src/libs/utils/validation.js +88 -0
  102. package/src/main.js +0 -2
  103. package/src/stores/connection.js +1 -4
  104. package/src/stores/logger.js +6 -12
  105. package/src/stores/sampleData.js +1 -2
  106. package/src/stores/ui.js +59 -36
  107. package/src/views/Accounts.vue +13 -24
  108. package/src/views/Console.vue +70 -172
  109. package/src/views/Editor.vue +211 -379
  110. package/src/views/FilterBuilder.vue +188 -371
  111. package/src/views/Login.vue +3 -28
  112. package/src/views/Profiles.vue +8 -15
  113. package/src/views/Tasks.vue +49 -36
  114. package/tailwind.config.js +82 -71
  115. package/workbox-config.cjs +47 -5
  116. package/docs/plans/2026-02-08-tailwind-consolidation.md +0 -2438
  117. package/exit +0 -209
  118. package/run +0 -177
  119. package/src/assets/css/base/color-fallbacks.scss +0 -10
  120. package/switch-branch.sh +0 -41
  121. /package/public/{reconnect-logo.png → img/reconnect-logo.png} +0 -0
@@ -5,46 +5,41 @@
5
5
  ========================================================================== */
6
6
 
7
7
  .unified-search-group {
8
- border: 2px solid oklch(0.2809 0 0);
8
+ border: 2px solid var(--color-border);
9
9
  border-radius: 0.5rem;
10
10
  overflow: hidden;
11
- background: oklch(0.2603 0 0);
11
+ background: var(--color-bg-input);
12
12
  transition: all 0.15s ease;
13
13
  display: flex;
14
14
 
15
15
  .tag-toggle,
16
16
  .dropdown,
17
- input {
18
- border: none !important;
19
- border-width: 0 !important;
17
+ input,
18
+ > button {
19
+ border: 0 !important;
20
20
  border-radius: 0 !important;
21
21
  height: 40px !important;
22
22
  background: transparent !important;
23
23
  box-shadow: none !important;
24
+ outline: 0 !important;
25
+ }
26
+
27
+ .tag-toggle,
28
+ .dropdown,
29
+ input {
24
30
  min-width: fit-content !important;
25
- outline: none !important;
26
- outline-width: 0 !important;
27
- outline-offset: 0 !important;
28
31
  }
29
32
 
30
33
  .tag-toggle {
31
34
  padding: 0;
32
- border: 0 solid transparent !important;
33
- border-top: 0 !important;
34
- border-bottom: 0 !important;
35
- border-left: 0 !important;
36
- border-right: 0 !important;
35
+ border: 0 !important;
37
36
  }
38
37
 
39
38
  .tag-toggle button {
40
39
  font-size: 0.875rem;
41
40
  padding: 0.5rem 0.75rem;
42
41
  min-width: fit-content;
43
- border: 0 solid transparent !important;
44
- border-top: 0 !important;
45
- border-bottom: 0 !important;
46
- border-left: 0 !important;
47
- border-right: 0 !important;
42
+ border: 0 !important;
48
43
  }
49
44
 
50
45
  .dropdown {
@@ -52,6 +47,17 @@
52
47
  min-width: 120px !important;
53
48
  }
54
49
 
50
+ .dropdown:not(.transparent):focus-within,
51
+ .dropdown:not(.transparent).opened,
52
+ .dropdown:not(.transparent):hover,
53
+ .dropdown:focus-within,
54
+ .dropdown.opened,
55
+ .dropdown:hover {
56
+ border: 0 !important;
57
+ outline: 0 !important;
58
+ box-shadow: none !important;
59
+ }
60
+
55
61
  .dropdown-display {
56
62
  padding: 0 0.75rem;
57
63
  font-size: 0.875rem;
@@ -63,7 +69,7 @@
63
69
  flex: 1;
64
70
 
65
71
  &::placeholder {
66
- color: oklch(0.50 0 0);
72
+ @apply text-light-600;
67
73
  }
68
74
 
69
75
  &:focus {
@@ -72,12 +78,12 @@
72
78
  }
73
79
 
74
80
  &:hover {
75
- border-color: oklch(0.30 0 0);
81
+ @apply border-dark-650;
76
82
  }
77
83
 
78
84
  &:focus-within {
79
- border-color: oklch(0.72 0.15 145);
80
- outline: 1px solid oklch(0.72 0.15 145);
85
+ border-color: var(--color-primary);
86
+ outline: 1px solid var(--color-primary);
81
87
  outline-offset: 0;
82
88
  }
83
89
  }
@@ -3,17 +3,15 @@
3
3
  ========================================================================== */
4
4
 
5
5
  .table-row-even {
6
- background-color: oklch(0.1822 0 0);
6
+ @apply bg-dark-300;
7
7
  }
8
8
 
9
9
  .table-row-odd {
10
- background-color: oklch(0.2046 0 0);
10
+ @apply bg-dark-400;
11
11
  }
12
12
 
13
13
  .table-component {
14
- @apply w-full rounded-lg;
15
- border: 1px solid oklch(0.26 0 0);
16
- overflow: visible !important;
17
- background-color: oklch(0.2046 0 0);
18
- box-shadow: 0 4px 12px oklch(0 0 0 / 0.2);
14
+ @apply w-full rounded-lg bg-dark-500;
15
+ border: 1px solid var(--color-border);
16
+ @apply shadow-sm;
19
17
  }
@@ -4,9 +4,9 @@
4
4
 
5
5
  .Toastify__toast-theme--colored.Toastify__toast--default,
6
6
  .Toastify__toast-theme--light {
7
- background: oklch(0.2046 0 0);
8
- border: 2px solid oklch(0.2809 0 0);
9
- color: oklch(0.90 0 0);
7
+ background: var(--color-bg-card);
8
+ @apply border-2 border-dark-550;
9
+ color: var(--color-text-primary);
10
10
  }
11
11
 
12
12
  .Toastify__toast-icon {
@@ -24,11 +24,11 @@
24
24
  margin-top: 1px;
25
25
  padding-left: 0.1rem;
26
26
  @apply flex border-solid w-6 h-6 items-center justify-center rounded-full;
27
- border: 2px solid oklch(0.90 0 0);
27
+ border: 2px solid var(--color-text-primary);
28
28
  }
29
29
 
30
30
  .Toastify__close-button.Toastify__close-button--light svg {
31
- color: oklch(0.90 0 0);
31
+ color: var(--color-text-primary);
32
32
  }
33
33
 
34
34
  .Toastify__close-button.Toastify__close-button--light svg path {
@@ -92,7 +92,7 @@
92
92
  }
93
93
 
94
94
  .Toastify__toast--error svg {
95
- color: oklch(0.68 0.18 25);
95
+ @apply text-red-300;
96
96
  }
97
97
 
98
98
  .Toastify__toast--error svg path {
@@ -100,7 +100,7 @@
100
100
  }
101
101
 
102
102
  .Toastify__toast--success .Toastify__progress-bar {
103
- background: oklch(0.72 0.15 145);
103
+ background: var(--color-primary);
104
104
  }
105
105
 
106
106
  .Toastify__progress-bar {
@@ -0,0 +1,220 @@
1
+ /* ==========================================================================
2
+ UTILITY CLASSES - Complex reusable patterns
3
+ Extracted from inline classes to improve maintainability
4
+ ========================================================================== */
5
+
6
+ @use "../base/mixins" as *;
7
+
8
+ /* Minimal form input - transparent background for use within labeled containers */
9
+ .form-input-minimal {
10
+ @apply w-full h-full text-sm text-white bg-transparent border-0 outline-none px-2 py-1;
11
+ @apply transition-colors duration-150;
12
+
13
+ &:focus {
14
+ @apply outline-none border-0 shadow-none;
15
+ }
16
+
17
+ &::placeholder {
18
+ @apply text-light-500;
19
+ }
20
+ }
21
+
22
+ /* Form field with label - LoginForm, QuickSettings pattern */
23
+ .form-field-labeled {
24
+ @apply text-white bg-dark-500 px-3 rounded-lg border-2 border-dark-550 flex items-center justify-between h-11 transition-[border-color] duration-150;
25
+
26
+ &:hover {
27
+ @apply border-dark-650;
28
+ }
29
+
30
+ &:focus-within {
31
+ @apply border-accent-green !important;
32
+ @include focus-ring-accent;
33
+ }
34
+ }
35
+
36
+ /* Smaller variant (h-10) for QuickSettings */
37
+ .form-field-labeled-sm {
38
+ @apply text-white bg-dark-500 px-3 rounded-lg border-2 border-dark-550 flex items-center justify-between h-10 transition-colors duration-150;
39
+
40
+ &:hover {
41
+ @apply border-dark-650;
42
+ }
43
+
44
+ &:focus-within {
45
+ @apply border-accent-green !important;
46
+ @include focus-ring-accent;
47
+ }
48
+
49
+ /* Dropdown opened state */
50
+ &:has(.dropdown.opened) {
51
+ @apply border-accent-green !important;
52
+ @include focus-ring-accent;
53
+ }
54
+ }
55
+
56
+ /* Action button with responsive sizing */
57
+ .btn-action-responsive {
58
+ @apply h-10 rounded-md text-xs flex items-center justify-center font-medium px-4;
59
+ @apply transition-all duration-150 btn-focus-ring;
60
+ @include dark-button-base;
61
+ @include scale-hover;
62
+ }
63
+
64
+ .btn-action-responsive:not(.bg-green-400):not(.bg-red-400):not(.bg-blue-400):hover {
65
+ @apply border-dark-700;
66
+ }
67
+
68
+ /* Console scroll button */
69
+ .console-scroll-btn {
70
+ @apply flex h-10 w-10 items-center justify-center rounded border-2 border-dark-550 bg-dark-400 shadow-sm transition-all duration-150 btn-focus-ring;
71
+
72
+ &:hover {
73
+ @apply border-accent-green;
74
+ @include focus-ring-accent;
75
+ }
76
+ }
77
+
78
+ /* Console main container with responsive heights */
79
+ .console-main {
80
+ @apply relative overflow-x-auto overflow-y-auto rounded border-2 border-dark-550 bg-dark-400 p-2 font-mono text-white;
81
+ height: calc(100vh - 18rem);
82
+ scroll-padding: 0.5rem;
83
+ -webkit-overflow-scrolling: touch;
84
+ overscroll-behavior: contain;
85
+ min-height: 12rem !important;
86
+ touch-action: pan-y pan-up pan-down;
87
+
88
+ @screen md {
89
+ height: calc(100vh - 16rem);
90
+ }
91
+
92
+ @screen lg {
93
+ height: calc(100vh - 14rem);
94
+ padding: 1.25rem;
95
+ }
96
+
97
+ @screen mobile-portrait {
98
+ height: calc(100vh - 19.5rem);
99
+ max-height: 50vh;
100
+ overflow: auto;
101
+ padding: 0.25rem;
102
+ font-size: 0.75rem;
103
+ line-height: 1rem;
104
+ }
105
+
106
+ @media (orientation: landscape) and (max-width: 1023px) {
107
+ height: calc(100vh - 10.5rem);
108
+ }
109
+
110
+ @media (max-width: 767px) and (orientation: landscape) {
111
+ height: auto;
112
+ max-height: 60vh;
113
+ }
114
+ }
115
+
116
+ /* FilterBuilder action button */
117
+ .filter-action-btn {
118
+ @apply flex h-8 items-center justify-center gap-1 rounded-md border border-dark-650 bg-dark-400 px-3 text-xs font-medium text-white transition-all duration-150 hover:border-dark-700 btn-focus-ring;
119
+ @include scale-hover;
120
+
121
+ svg {
122
+ @apply mr-1;
123
+ }
124
+ }
125
+
126
+ /* Checkbox base - atomic/Checkbox.vue pattern */
127
+ .checkbox-base {
128
+ @apply relative flex items-center justify-center cursor-pointer shrink-0 rounded-full border-2 bg-transparent transition-all duration-200 ease-out;
129
+ @apply focus-visible:outline focus-visible:outline-2 focus-visible:outline-accent-green focus-visible:outline-offset-2;
130
+
131
+ @media (hover: hover) {
132
+ &:hover {
133
+ @apply scale-105;
134
+ }
135
+ }
136
+ }
137
+
138
+ /* Task status badge */
139
+ .task-status-badge {
140
+ @apply mx-auto flex w-fit items-center justify-center rounded-lg border-2 border-dark-750 bg-dark-400 px-3 py-1.5 gap-1.5 max-w-full pointer-events-none;
141
+
142
+ @screen md {
143
+ padding-left: 0.5rem;
144
+ padding-right: 0.5rem;
145
+ padding-top: 0.25rem;
146
+ padding-bottom: 0.25rem;
147
+ gap: 0.25rem;
148
+ }
149
+
150
+ @screen sm {
151
+ border-width: 2px;
152
+ padding-left: 0.25rem;
153
+ padding-right: 0.25rem;
154
+ padding-top: 0.125rem;
155
+ padding-bottom: 0.125rem;
156
+ }
157
+ }
158
+
159
+ /* Stats/Queue badge pattern */
160
+ .stat-badge {
161
+ @apply flex h-10 min-w-0 items-center justify-between gap-2 rounded-lg px-3 text-sm bg-dark-400 border-2 border-dark-550;
162
+ }
163
+
164
+ /* Mobile control buttons */
165
+ .btn-control-mobile {
166
+ @apply flex h-10 w-20 items-center justify-center gap-x-1 rounded-md border border-dark-650 bg-dark-400 px-3 text-xs+ font-medium text-white transition-all duration-150 hover:border-dark-700 btn-focus-ring;
167
+ }
168
+
169
+ /* Desktop control button variants */
170
+ .btn-control-success {
171
+ @apply bg-green-400 disabled:opacity-70 border-none min-w-20 max-w-30 flex-grow xl:flex-initial flex text-white text-xs font-medium justify-center items-center rounded-md h-10 transition-all duration-200;
172
+ @include scale-hover-safe;
173
+ }
174
+
175
+ .btn-control-danger {
176
+ @apply bg-red-400 disabled:opacity-70 border-none min-w-20 max-w-30 flex-grow xl:flex-initial flex text-white text-xs font-medium justify-center items-center rounded-md h-10 transition-all duration-200;
177
+ @include scale-hover-safe;
178
+ }
179
+
180
+ /* Stat header with icon - Stats component badges */
181
+ .stat-header {
182
+ @apply flex items-center gap-1 whitespace-nowrap text-sm font-semibold text-light-300;
183
+ }
184
+
185
+ /* Empty state icon - EmptyState component, TaskView, FilterBuilder, Console */
186
+ .empty-state-icon {
187
+ @apply mb-3 h-12 w-12 text-dark-400 opacity-50;
188
+ }
189
+
190
+ /* Stat value display - Stats component badge values */
191
+ .stat-value {
192
+ @apply flex items-center justify-center whitespace-nowrap text-xs font-bold text-light-300;
193
+ }
194
+
195
+ /* Grid cell center - Profile/Account editor icon cells */
196
+ .grid-cell-center {
197
+ @apply col-span-1 flex items-center justify-center;
198
+ }
199
+
200
+ /* Transparent input - Console and Tasks search inputs */
201
+ .transparent-input {
202
+ @apply h-full w-full bg-transparent text-sm text-white outline-none;
203
+ }
204
+
205
+ /* High-frequency Tailwind pattern utilities */
206
+ .flex-center {
207
+ @apply flex items-center justify-center;
208
+ }
209
+
210
+ .text-secondary {
211
+ @apply text-xs text-light-500;
212
+ }
213
+
214
+ .text-tertiary {
215
+ @apply text-xs text-light-300;
216
+ }
217
+
218
+ .icon-md {
219
+ @apply h-4 w-4;
220
+ }
@@ -3,11 +3,11 @@
3
3
  Modular SCSS architecture with @use imports
4
4
  ========================================================================== */
5
5
 
6
- /* Module imports */
7
6
  @use "base/reset";
8
7
  @use "base/scroll";
9
8
  @use "base/typography";
10
- @use "base/color-fallbacks";
9
+ @use "base/variables";
10
+ @use "base/mixins" as *;
11
11
  @use "components/buttons";
12
12
  @use "components/forms";
13
13
  @use "components/toasts";
@@ -15,69 +15,44 @@
15
15
  @use "components/tables";
16
16
  @use "components/search-groups";
17
17
  @use "components/headers";
18
+ @use "components/utilities";
19
+ @use "components/accessibility";
18
20
 
19
21
  /* ==========================================================================
20
22
  BODY LAYOUT & BACKGROUND
21
23
  ========================================================================== */
22
24
 
23
25
  html {
24
- background-color: oklch(0.1822 0 0);
26
+ @apply bg-dark-300;
25
27
  min-height: 100vh;
26
28
  min-height: 100dvh;
27
29
  }
28
30
 
29
31
  body {
30
- background-color: oklch(0.1822 0 0);
32
+ @apply bg-dark-300;
31
33
  position: relative;
32
34
  min-height: 100vh;
33
35
  min-height: 100dvh;
34
-
35
- &::before {
36
- content: "";
37
- position: fixed;
38
- top: 0;
39
- left: 0;
40
- right: 0;
41
- bottom: 0;
42
- background-image: url("@/assets/img/background.svg");
43
- background-position: center center;
44
- background-size: cover;
45
- background-repeat: no-repeat;
46
- -webkit-background-size: cover;
47
- z-index: -1;
48
- pointer-events: none;
49
- will-change: transform;
50
- -webkit-transform: translateZ(0);
51
- transform: translateZ(0);
52
-
53
- // Extend into safe areas only in PWA mode
54
- @media (display-mode: standalone) {
55
- top: -50px;
56
- left: -50px;
57
- right: -50px;
58
- bottom: -50px;
59
- }
60
- }
61
36
  }
62
37
 
63
38
  /* Global icon color consistency */
64
39
  svg {
65
- color: oklch(0.9 0 0) !important;
40
+ color: var(--color-text-primary) !important;
66
41
  }
67
42
 
68
- /* For stroke icons (Eye, etc) - stroke on svg element */
43
+ /* For stroke-based icons */
69
44
  svg[stroke] path,
70
45
  svg[stroke] circle,
71
46
  svg[stroke] line {
72
- stroke: oklch(0.9 0 0) !important;
47
+ stroke: var(--color-text-primary) !important;
73
48
  }
74
49
 
75
- /* For filled icons with explicit fill */
50
+ /* For fill-based icons */
76
51
  svg path[fill]:not([fill="none"]),
77
52
  svg circle[fill]:not([fill="none"]),
78
53
  svg rect[fill]:not([fill="none"]),
79
54
  svg polygon[fill]:not([fill="none"]) {
80
- fill: oklch(0.9 0 0) !important;
55
+ fill: var(--color-text-primary) !important;
81
56
  }
82
57
 
83
58
  /* For filled icons without explicit fill attribute */
@@ -85,46 +60,42 @@ svg:not([stroke]):not([fill="none"]) path:not([fill]),
85
60
  svg:not([stroke]):not([fill="none"]) circle:not([fill]),
86
61
  svg:not([stroke]):not([fill="none"]) rect:not([fill]),
87
62
  svg:not([stroke]):not([fill="none"]) polygon:not([fill]) {
88
- fill: oklch(0.9 0 0) !important;
63
+ fill: var(--color-text-primary) !important;
89
64
  }
90
65
 
91
- /* Badge icon color exceptions - override ALL global white rules */
92
66
  .enabled-badge svg,
93
67
  .enabled-badge-large svg {
94
- color: oklch(0.72 0.15 145) !important;
95
- fill: oklch(0.72 0.15 145) !important;
68
+ color: var(--color-primary) !important;
69
+ fill: var(--color-primary) !important;
96
70
  }
97
71
 
98
72
  .disabled-badge svg,
99
73
  .disabled-badge-large svg {
100
- color: oklch(0.60 0.20 25) !important;
101
- fill: oklch(0.60 0.20 25) !important;
74
+ color: var(--color-disabled) !important;
75
+ fill: var(--color-disabled) !important;
102
76
  }
103
77
 
104
78
  .enabled-badge svg *,
105
79
  .enabled-badge-large svg * {
106
- fill: oklch(0.72 0.15 145) !important;
107
- stroke: oklch(0.72 0.15 145) !important;
80
+ fill: var(--color-primary) !important;
81
+ stroke: var(--color-primary) !important;
108
82
  }
109
83
 
110
84
  .disabled-badge svg *,
111
85
  .disabled-badge-large svg * {
112
- fill: oklch(0.60 0.20 25) !important;
113
- stroke: oklch(0.60 0.20 25) !important;
86
+ fill: var(--color-disabled) !important;
87
+ stroke: var(--color-disabled) !important;
114
88
  }
115
89
 
116
90
  /* ==========================================================================
117
91
  PWA MODE FIXES
118
92
  ========================================================================== */
119
93
 
120
- // Add padding to all page headers in PWA mode to prevent hiding under navbar
121
94
  @media (display-mode: standalone) {
122
- // Accounts page header
123
95
  .flex.items-center.justify-between.pt-5.pb-2 {
124
96
  padding-top: 3.5rem !important;
125
97
  }
126
98
 
127
- // Console page header
128
99
  h4.mb-2.flex.items-center.gap-2.pt-5 {
129
100
  padding-top: 3.5rem !important;
130
101
  }
@@ -136,6 +107,7 @@ svg:not([stroke]):not([fill="none"]) polygon:not([fill]) {
136
107
 
137
108
  .smooth-hover {
138
109
  @apply transition-all duration-200;
110
+ @include scale-hover;
139
111
  }
140
112
 
141
113
  .status-indicator {
@@ -148,17 +120,16 @@ svg:not([stroke]):not([fill="none"]) polygon:not([fill]) {
148
120
  @apply ml-auto flex items-center gap-x-2 lg:hidden;
149
121
 
150
122
  button {
151
- @apply flex h-8 w-8 items-center justify-center rounded transition-all duration-150;
152
- background-color: oklch(0.2046 0 0);
153
- border: 2px solid oklch(0.2809 0 0);
154
- color: oklch(0.82 0 0);
123
+ @apply flex h-8 w-8 items-center justify-center rounded transition-all duration-150 bg-dark-400;
124
+ border: 2px solid var(--color-border-light);
125
+ color: var(--color-text-secondary);
155
126
 
156
127
  &:hover,
157
128
  &:active {
158
- border-color: oklch(0.72 0.15 145);
159
- outline: 1px solid oklch(0.72 0.15 145);
129
+ border-color: var(--color-primary);
130
+ outline: 1px solid var(--color-primary);
160
131
  outline-offset: 0;
161
- color: oklch(0.9 0 0);
132
+ color: var(--color-text-primary);
162
133
  }
163
134
  }
164
135
  }
@@ -167,26 +138,39 @@ svg:not([stroke]):not([fill="none"]) polygon:not([fill]) {
167
138
  @apply h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent;
168
139
  }
169
140
 
141
+ /* Page button focus states - used in view files */
142
+ button.bg-dark-400,
143
+ button.bg-green-400,
144
+ button.bg-red-400 {
145
+ &:active,
146
+ &:focus {
147
+ @apply outline outline-1 outline-accent-green;
148
+ outline-offset: 0;
149
+ @apply border-accent-green !important;
150
+ }
151
+ }
152
+
170
153
  /* ==========================================================================
171
154
  LABEL & ICON STYLING
172
155
  ========================================================================== */
173
156
 
174
157
  .label-override {
175
158
  @apply mb-2 flex items-center text-xs;
176
- color: oklch(0.65 0 0);
159
+ color: var(--color-text-muted);
160
+ margin-top: 1rem;
177
161
 
178
162
  svg {
179
163
  @apply ml-2;
180
- color: oklch(0.65 0 0) !important;
164
+ color: var(--color-text-muted) !important;
181
165
  width: 16px;
182
166
  height: 16px;
183
- fill: oklch(0.65 0 0) !important;
167
+ fill: var(--color-text-muted) !important;
184
168
  }
185
169
  }
186
170
 
187
171
  .task-switches {
188
172
  h4 {
189
- color: oklch(0.9 0 0);
173
+ color: var(--color-text-primary);
190
174
  font-size: 0.8125rem;
191
175
  font-weight: 500;
192
176
  @apply mx-auto mb-2 flex items-center gap-x-2 text-center;
@@ -199,7 +183,7 @@ svg:not([stroke]):not([fill="none"]) polygon:not([fill]) {
199
183
  svg {
200
184
  width: 15px !important;
201
185
  height: 15px !important;
202
- color: oklch(0.9 0 0) !important;
186
+ color: var(--color-text-primary) !important;
203
187
  margin-left: 0.25rem !important;
204
188
  }
205
189
  }
@@ -212,33 +196,38 @@ svg:not([stroke]):not([fill="none"]) polygon:not([fill]) {
212
196
  max-height: calc(100vh - 12rem);
213
197
  min-height: 8rem;
214
198
  overflow: hidden;
215
- }
216
199
 
217
- @screen xl {
218
- .max-h-big {
200
+ @screen xl {
219
201
  max-height: calc(100vh - 11rem);
220
202
  }
221
203
  }
222
204
 
223
- @screen h-sm {
224
- .max-h-big {
225
- max-height: calc(100vh - 12rem);
226
- min-height: 8rem;
227
- }
228
- }
229
-
230
205
  /* ==========================================================================
231
206
  TRANSITIONS & ANIMATIONS
232
207
  ========================================================================== */
233
208
 
234
- .fade-enter-active,
235
- .fade-leave-active {
236
- transition: opacity 0.15s ease;
209
+ .dropdown-fade-enter-active {
210
+ @apply transition-all duration-300;
211
+ }
212
+
213
+ .dropdown-fade-leave-active {
214
+ @apply transition-all duration-200;
215
+ }
216
+
217
+ .dropdown-fade-enter-from {
218
+ @apply opacity-0;
219
+ transform: translateY(-8px) scale(0.95);
220
+ }
221
+
222
+ .dropdown-fade-leave-to {
223
+ @apply opacity-0;
224
+ transform: translateY(-4px) scale(0.98);
237
225
  }
238
226
 
239
- .fade-enter-from,
240
- .fade-leave-to {
241
- opacity: 0;
227
+ .dropdown-fade-enter-to,
228
+ .dropdown-fade-leave-from {
229
+ @apply opacity-100;
230
+ transform: translateY(0) scale(1);
242
231
  }
243
232
 
244
233
  .will-change-auto {