@necrolab/dashboard 0.5.14 → 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 (120) 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 +119 -0
  15. package/src/assets/css/components/modals.scss +2 -2
  16. package/src/assets/css/components/search-groups.scss +28 -19
  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 +72 -75
  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 +61 -12
  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 -42
  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 +78 -37
  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 +102 -95
  83. package/src/components/ui/controls/atomic/MultiDropdown.vue +72 -94
  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 +5 -6
  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 +17 -31
  108. package/src/views/Console.vue +76 -176
  109. package/src/views/Editor.vue +217 -383
  110. package/src/views/FilterBuilder.vue +190 -373
  111. package/src/views/Login.vue +3 -28
  112. package/src/views/Profiles.vue +12 -22
  113. package/src/views/Tasks.vue +51 -38
  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 -2416
  117. package/exit +0 -209
  118. package/run +0 -177
  119. package/switch-branch.sh +0 -41
  120. /package/public/{reconnect-logo.png → img/reconnect-logo.png} +0 -0
@@ -8,6 +8,6 @@
8
8
  }
9
9
 
10
10
  .component-modal {
11
- background-color: oklch(0.15 0 0);
12
- border: 1px solid oklch(0.26 0 0);
11
+ background-color: var(--color-bg-modal);
12
+ border: 1px solid var(--color-border);
13
13
  }
@@ -5,43 +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
31
  }
26
32
 
27
33
  .tag-toggle {
28
34
  padding: 0;
29
- border: 0 solid transparent !important;
30
- border-top: 0 !important;
31
- border-bottom: 0 !important;
32
- border-left: 0 !important;
33
- border-right: 0 !important;
35
+ border: 0 !important;
34
36
  }
35
37
 
36
38
  .tag-toggle button {
37
39
  font-size: 0.875rem;
38
40
  padding: 0.5rem 0.75rem;
39
41
  min-width: fit-content;
40
- border: 0 solid transparent !important;
41
- border-top: 0 !important;
42
- border-bottom: 0 !important;
43
- border-left: 0 !important;
44
- border-right: 0 !important;
42
+ border: 0 !important;
45
43
  }
46
44
 
47
45
  .dropdown {
@@ -49,6 +47,17 @@
49
47
  min-width: 120px !important;
50
48
  }
51
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
+
52
61
  .dropdown-display {
53
62
  padding: 0 0.75rem;
54
63
  font-size: 0.875rem;
@@ -60,7 +69,7 @@
60
69
  flex: 1;
61
70
 
62
71
  &::placeholder {
63
- color: oklch(0.50 0 0);
72
+ @apply text-light-600;
64
73
  }
65
74
 
66
75
  &:focus {
@@ -69,12 +78,12 @@
69
78
  }
70
79
 
71
80
  &:hover {
72
- border-color: oklch(0.30 0 0);
81
+ @apply border-dark-650;
73
82
  }
74
83
 
75
84
  &:focus-within {
76
- border-color: oklch(0.72 0.15 145);
77
- outline: 1px solid oklch(0.72 0.15 145);
85
+ border-color: var(--color-primary);
86
+ outline: 1px solid var(--color-primary);
78
87
  outline-offset: 0;
79
88
  }
80
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,73 +3,56 @@
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";
9
+ @use "base/variables";
10
+ @use "base/mixins" as *;
10
11
  @use "components/buttons";
11
12
  @use "components/forms";
12
13
  @use "components/toasts";
13
14
  @use "components/modals";
14
15
  @use "components/tables";
15
16
  @use "components/search-groups";
17
+ @use "components/headers";
18
+ @use "components/utilities";
19
+ @use "components/accessibility";
16
20
 
17
21
  /* ==========================================================================
18
22
  BODY LAYOUT & BACKGROUND
19
23
  ========================================================================== */
20
24
 
25
+ html {
26
+ @apply bg-dark-300;
27
+ min-height: 100vh;
28
+ min-height: 100dvh;
29
+ }
30
+
21
31
  body {
22
- background-color: oklch(0.1822 0 0);
32
+ @apply bg-dark-300;
23
33
  position: relative;
24
34
  min-height: 100vh;
25
35
  min-height: 100dvh;
26
-
27
- &::before {
28
- content: "";
29
- position: fixed;
30
- top: 0;
31
- left: 0;
32
- right: 0;
33
- bottom: 0;
34
- background-image: url("@/assets/img/background.svg");
35
- background-position: center center;
36
- background-size: cover;
37
- background-repeat: no-repeat;
38
- -webkit-background-size: cover;
39
- z-index: -1;
40
- pointer-events: none;
41
- will-change: transform;
42
- -webkit-transform: translateZ(0);
43
- transform: translateZ(0);
44
-
45
- // Extend into safe areas only in PWA mode
46
- @media (display-mode: standalone) {
47
- top: -50px;
48
- left: -50px;
49
- right: -50px;
50
- bottom: -50px;
51
- }
52
- }
53
36
  }
54
37
 
55
38
  /* Global icon color consistency */
56
39
  svg {
57
- color: oklch(0.9 0 0) !important;
40
+ color: var(--color-text-primary) !important;
58
41
  }
59
42
 
60
- /* For stroke icons (Eye, etc) - stroke on svg element */
43
+ /* For stroke-based icons */
61
44
  svg[stroke] path,
62
45
  svg[stroke] circle,
63
46
  svg[stroke] line {
64
- stroke: oklch(0.9 0 0) !important;
47
+ stroke: var(--color-text-primary) !important;
65
48
  }
66
49
 
67
- /* For filled icons with explicit fill */
50
+ /* For fill-based icons */
68
51
  svg path[fill]:not([fill="none"]),
69
52
  svg circle[fill]:not([fill="none"]),
70
53
  svg rect[fill]:not([fill="none"]),
71
54
  svg polygon[fill]:not([fill="none"]) {
72
- fill: oklch(0.9 0 0) !important;
55
+ fill: var(--color-text-primary) !important;
73
56
  }
74
57
 
75
58
  /* For filled icons without explicit fill attribute */
@@ -77,46 +60,42 @@ svg:not([stroke]):not([fill="none"]) path:not([fill]),
77
60
  svg:not([stroke]):not([fill="none"]) circle:not([fill]),
78
61
  svg:not([stroke]):not([fill="none"]) rect:not([fill]),
79
62
  svg:not([stroke]):not([fill="none"]) polygon:not([fill]) {
80
- fill: oklch(0.9 0 0) !important;
63
+ fill: var(--color-text-primary) !important;
81
64
  }
82
65
 
83
- /* Badge icon color exceptions - override ALL global white rules */
84
66
  .enabled-badge svg,
85
67
  .enabled-badge-large svg {
86
- color: oklch(0.72 0.15 145) !important;
87
- fill: oklch(0.72 0.15 145) !important;
68
+ color: var(--color-primary) !important;
69
+ fill: var(--color-primary) !important;
88
70
  }
89
71
 
90
72
  .disabled-badge svg,
91
73
  .disabled-badge-large svg {
92
- color: oklch(0.60 0.20 25) !important;
93
- fill: oklch(0.60 0.20 25) !important;
74
+ color: var(--color-disabled) !important;
75
+ fill: var(--color-disabled) !important;
94
76
  }
95
77
 
96
78
  .enabled-badge svg *,
97
79
  .enabled-badge-large svg * {
98
- fill: oklch(0.72 0.15 145) !important;
99
- stroke: oklch(0.72 0.15 145) !important;
80
+ fill: var(--color-primary) !important;
81
+ stroke: var(--color-primary) !important;
100
82
  }
101
83
 
102
84
  .disabled-badge svg *,
103
85
  .disabled-badge-large svg * {
104
- fill: oklch(0.60 0.20 25) !important;
105
- stroke: oklch(0.60 0.20 25) !important;
86
+ fill: var(--color-disabled) !important;
87
+ stroke: var(--color-disabled) !important;
106
88
  }
107
89
 
108
90
  /* ==========================================================================
109
91
  PWA MODE FIXES
110
92
  ========================================================================== */
111
93
 
112
- // Add padding to all page headers in PWA mode to prevent hiding under navbar
113
94
  @media (display-mode: standalone) {
114
- // Accounts page header
115
95
  .flex.items-center.justify-between.pt-5.pb-2 {
116
96
  padding-top: 3.5rem !important;
117
97
  }
118
98
 
119
- // Console page header
120
99
  h4.mb-2.flex.items-center.gap-2.pt-5 {
121
100
  padding-top: 3.5rem !important;
122
101
  }
@@ -128,6 +107,7 @@ svg:not([stroke]):not([fill="none"]) polygon:not([fill]) {
128
107
 
129
108
  .smooth-hover {
130
109
  @apply transition-all duration-200;
110
+ @include scale-hover;
131
111
  }
132
112
 
133
113
  .status-indicator {
@@ -140,17 +120,16 @@ svg:not([stroke]):not([fill="none"]) polygon:not([fill]) {
140
120
  @apply ml-auto flex items-center gap-x-2 lg:hidden;
141
121
 
142
122
  button {
143
- @apply flex h-8 w-8 items-center justify-center rounded transition-all duration-150;
144
- background-color: oklch(0.2046 0 0);
145
- border: 2px solid oklch(0.2809 0 0);
146
- 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);
147
126
 
148
127
  &:hover,
149
128
  &:active {
150
- border-color: oklch(0.72 0.15 145);
151
- outline: 1px solid oklch(0.72 0.15 145);
129
+ border-color: var(--color-primary);
130
+ outline: 1px solid var(--color-primary);
152
131
  outline-offset: 0;
153
- color: oklch(0.9 0 0);
132
+ color: var(--color-text-primary);
154
133
  }
155
134
  }
156
135
  }
@@ -159,26 +138,39 @@ svg:not([stroke]):not([fill="none"]) polygon:not([fill]) {
159
138
  @apply h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent;
160
139
  }
161
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
+
162
153
  /* ==========================================================================
163
154
  LABEL & ICON STYLING
164
155
  ========================================================================== */
165
156
 
166
157
  .label-override {
167
158
  @apply mb-2 flex items-center text-xs;
168
- color: oklch(0.65 0 0);
159
+ color: var(--color-text-muted);
160
+ margin-top: 1rem;
169
161
 
170
162
  svg {
171
163
  @apply ml-2;
172
- color: oklch(0.65 0 0) !important;
164
+ color: var(--color-text-muted) !important;
173
165
  width: 16px;
174
166
  height: 16px;
175
- fill: oklch(0.65 0 0) !important;
167
+ fill: var(--color-text-muted) !important;
176
168
  }
177
169
  }
178
170
 
179
171
  .task-switches {
180
172
  h4 {
181
- color: oklch(0.9 0 0);
173
+ color: var(--color-text-primary);
182
174
  font-size: 0.8125rem;
183
175
  font-weight: 500;
184
176
  @apply mx-auto mb-2 flex items-center gap-x-2 text-center;
@@ -191,7 +183,7 @@ svg:not([stroke]):not([fill="none"]) polygon:not([fill]) {
191
183
  svg {
192
184
  width: 15px !important;
193
185
  height: 15px !important;
194
- color: oklch(0.9 0 0) !important;
186
+ color: var(--color-text-primary) !important;
195
187
  margin-left: 0.25rem !important;
196
188
  }
197
189
  }
@@ -204,33 +196,38 @@ svg:not([stroke]):not([fill="none"]) polygon:not([fill]) {
204
196
  max-height: calc(100vh - 12rem);
205
197
  min-height: 8rem;
206
198
  overflow: hidden;
207
- }
208
199
 
209
- @screen xl {
210
- .max-h-big {
200
+ @screen xl {
211
201
  max-height: calc(100vh - 11rem);
212
202
  }
213
203
  }
214
204
 
215
- @screen h-sm {
216
- .max-h-big {
217
- max-height: calc(100vh - 12rem);
218
- min-height: 8rem;
219
- }
220
- }
221
-
222
205
  /* ==========================================================================
223
206
  TRANSITIONS & ANIMATIONS
224
207
  ========================================================================== */
225
208
 
226
- .fade-enter-active,
227
- .fade-leave-active {
228
- 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);
229
225
  }
230
226
 
231
- .fade-enter-from,
232
- .fade-leave-to {
233
- opacity: 0;
227
+ .dropdown-fade-enter-to,
228
+ .dropdown-fade-leave-from {
229
+ @apply opacity-100;
230
+ transform: translateY(0) scale(1);
234
231
  }
235
232
 
236
233
  .will-change-auto {