@kaikybrofc/omnizap-system 2.1.8

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 (166) hide show
  1. package/.env.example +534 -0
  2. package/LICENSE +21 -0
  3. package/README.md +431 -0
  4. package/RELEASE-v2.1.2.md +83 -0
  5. package/app/config/adminIdentity.js +87 -0
  6. package/app/config/baileysConfig.js +693 -0
  7. package/app/config/groupUtils.js +388 -0
  8. package/app/connection/socketController.js +992 -0
  9. package/app/controllers/messageController.js +354 -0
  10. package/app/modules/adminModule/groupCommandHandlers.js +1294 -0
  11. package/app/modules/adminModule/groupEventHandlers.js +355 -0
  12. package/app/modules/aiModule/catCommand.js +1006 -0
  13. package/app/modules/broadcastModule/noticeCommand.js +416 -0
  14. package/app/modules/gameModule/diceCommand.js +67 -0
  15. package/app/modules/menuModule/common.js +311 -0
  16. package/app/modules/menuModule/menus.js +59 -0
  17. package/app/modules/playModule/playCommand.js +1615 -0
  18. package/app/modules/quoteModule/quoteCommand.js +851 -0
  19. package/app/modules/rpgPokemonModule/rpgBattleCanvasRenderer.js +786 -0
  20. package/app/modules/rpgPokemonModule/rpgBattleService.js +2082 -0
  21. package/app/modules/rpgPokemonModule/rpgBattleService.test.js +760 -0
  22. package/app/modules/rpgPokemonModule/rpgEvolutionUtils.js +22 -0
  23. package/app/modules/rpgPokemonModule/rpgPokemonCommand.js +172 -0
  24. package/app/modules/rpgPokemonModule/rpgPokemonDomain.js +192 -0
  25. package/app/modules/rpgPokemonModule/rpgPokemonDomain.test.js +93 -0
  26. package/app/modules/rpgPokemonModule/rpgPokemonEvolution.test.js +46 -0
  27. package/app/modules/rpgPokemonModule/rpgPokemonMessages.js +746 -0
  28. package/app/modules/rpgPokemonModule/rpgPokemonRepository.js +1859 -0
  29. package/app/modules/rpgPokemonModule/rpgPokemonService.js +6738 -0
  30. package/app/modules/rpgPokemonModule/rpgProfileCanvasRenderer.js +354 -0
  31. package/app/modules/statsModule/globalRankingCommand.js +65 -0
  32. package/app/modules/statsModule/noMessageCommand.js +288 -0
  33. package/app/modules/statsModule/rankingCommand.js +60 -0
  34. package/app/modules/statsModule/rankingCommon.js +889 -0
  35. package/app/modules/stickerModule/addStickerMetadata.js +239 -0
  36. package/app/modules/stickerModule/convertToWebp.js +390 -0
  37. package/app/modules/stickerModule/stickerCommand.js +454 -0
  38. package/app/modules/stickerModule/stickerConvertCommand.js +156 -0
  39. package/app/modules/stickerModule/stickerTextCommand.js +657 -0
  40. package/app/modules/stickerPackModule/autoPackCollectorRuntime.js +20 -0
  41. package/app/modules/stickerPackModule/autoPackCollectorService.js +284 -0
  42. package/app/modules/stickerPackModule/semanticReclassificationEngine.js +466 -0
  43. package/app/modules/stickerPackModule/semanticReclassificationEngine.test.js +88 -0
  44. package/app/modules/stickerPackModule/semanticThemeClusterService.js +571 -0
  45. package/app/modules/stickerPackModule/stickerAssetClassificationRepository.js +449 -0
  46. package/app/modules/stickerPackModule/stickerAssetRepository.js +400 -0
  47. package/app/modules/stickerPackModule/stickerAssetReprocessQueueRepository.js +180 -0
  48. package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +4078 -0
  49. package/app/modules/stickerPackModule/stickerClassificationBackgroundRuntime.js +598 -0
  50. package/app/modules/stickerPackModule/stickerClassificationService.js +588 -0
  51. package/app/modules/stickerPackModule/stickerMarketplaceDriftService.js +102 -0
  52. package/app/modules/stickerPackModule/stickerPackCatalogHttp.js +7506 -0
  53. package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +1095 -0
  54. package/app/modules/stickerPackModule/stickerPackEngagementRepository.js +108 -0
  55. package/app/modules/stickerPackModule/stickerPackErrors.js +30 -0
  56. package/app/modules/stickerPackModule/stickerPackInteractionEventRepository.js +110 -0
  57. package/app/modules/stickerPackModule/stickerPackItemRepository.js +440 -0
  58. package/app/modules/stickerPackModule/stickerPackMarketplaceService.js +337 -0
  59. package/app/modules/stickerPackModule/stickerPackMessageService.js +296 -0
  60. package/app/modules/stickerPackModule/stickerPackRepository.js +442 -0
  61. package/app/modules/stickerPackModule/stickerPackService.js +788 -0
  62. package/app/modules/stickerPackModule/stickerPackServiceRuntime.js +51 -0
  63. package/app/modules/stickerPackModule/stickerPackUtils.js +97 -0
  64. package/app/modules/stickerPackModule/stickerStorageService.js +507 -0
  65. package/app/modules/stickerPackModule/stickerWorkerPipelineRuntime.js +233 -0
  66. package/app/modules/stickerPackModule/stickerWorkerTaskQueueRepository.js +205 -0
  67. package/app/modules/systemMetricsModule/pingCommand.js +421 -0
  68. package/app/modules/tiktokModule/tiktokCommand.js +798 -0
  69. package/app/modules/userModule/userCommand.js +1217 -0
  70. package/app/modules/waifuPicsModule/waifuPicsCommand.js +177 -0
  71. package/app/observability/metrics.js +734 -0
  72. package/app/services/captchaService.js +492 -0
  73. package/app/services/dbWriteQueue.js +572 -0
  74. package/app/services/groupMetadataService.js +279 -0
  75. package/app/services/lidMapService.js +663 -0
  76. package/app/services/messagePersistenceService.js +56 -0
  77. package/app/services/newsBroadcastService.js +351 -0
  78. package/app/services/pokeApiService.js +398 -0
  79. package/app/services/queueUtils.js +57 -0
  80. package/app/services/socketState.js +7 -0
  81. package/app/store/aiPromptStore.js +38 -0
  82. package/app/store/groupConfigStore.js +58 -0
  83. package/app/store/premiumUserStore.js +36 -0
  84. package/app/utils/antiLink/antiLinkModule.js +804 -0
  85. package/app/utils/http/getImageBufferModule.js +18 -0
  86. package/app/utils/json/jsonSanitizer.js +113 -0
  87. package/app/utils/json/jsonSanitizer.test.js +40 -0
  88. package/app/utils/logger/loggerModule.js +262 -0
  89. package/app/utils/systemMetrics/systemMetricsModule.js +91 -0
  90. package/database/index.js +2052 -0
  91. package/database/init.js +516 -0
  92. package/database/migrations/20260203_0001_sticker_packs.sql +54 -0
  93. package/database/migrations/20260210_0003_rpg_pokemon.sql +58 -0
  94. package/database/migrations/20260210_0004_rpg_shiny_biome.sql +9 -0
  95. package/database/migrations/20260210_0005_rpg_missions.sql +14 -0
  96. package/database/migrations/20260210_0006_rpg_world_pokedex_traits.sql +27 -0
  97. package/database/migrations/20260210_0007_rpg_raid_pvp.sql +56 -0
  98. package/database/migrations/20260210_0008_rpg_social_system.sql +195 -0
  99. package/database/migrations/20260211_0009_rpg_social_xp.sql +36 -0
  100. package/database/migrations/20260222_0010_remove_message_xp.sql +2 -0
  101. package/database/migrations/20260226_0011_sticker_asset_classification.sql +17 -0
  102. package/database/migrations/20260226_0012_sticker_pack_engagement.sql +16 -0
  103. package/database/migrations/20260226_0013_sticker_marketplace_intelligence.sql +19 -0
  104. package/database/migrations/20260226_0014_sticker_pack_publish_flow.sql +30 -0
  105. package/database/migrations/20260226_0014_sticker_worker_queues.sql +42 -0
  106. package/database/migrations/20260226_0015_sticker_auto_pack_curation_integrity.sql +18 -0
  107. package/database/migrations/20260226_0016_sticker_web_google_auth_persistence.sql +34 -0
  108. package/database/migrations/20260226_0017_sticker_web_admin_ban.sql +22 -0
  109. package/database/migrations/20260226_0018_sticker_web_admin_moderator.sql +18 -0
  110. package/database/migrations/20260227_0019_sticker_classification_v2_signals.sql +12 -0
  111. package/database/migrations/20260227_0020_semantic_theme_clusters.sql +35 -0
  112. package/docker-compose.yml +103 -0
  113. package/ecosystem.prod.config.cjs +35 -0
  114. package/eslint.config.js +61 -0
  115. package/index.js +437 -0
  116. package/ml/clip_classifier/Dockerfile +16 -0
  117. package/ml/clip_classifier/README.md +120 -0
  118. package/ml/clip_classifier/adaptive_scoring.py +40 -0
  119. package/ml/clip_classifier/classifier.py +654 -0
  120. package/ml/clip_classifier/embedding_store.py +481 -0
  121. package/ml/clip_classifier/env_loader.py +15 -0
  122. package/ml/clip_classifier/llm_label_expander.py +144 -0
  123. package/ml/clip_classifier/main.py +213 -0
  124. package/ml/clip_classifier/requirements.txt +10 -0
  125. package/ml/clip_classifier/similarity_engine.py +74 -0
  126. package/observability/alert-rules.yml +60 -0
  127. package/observability/grafana/dashboards/omnizap-mysql.json +136 -0
  128. package/observability/grafana/dashboards/omnizap-overview.json +170 -0
  129. package/observability/grafana/provisioning/dashboards/dashboards.yml +11 -0
  130. package/observability/grafana/provisioning/datasources/datasources.yml +15 -0
  131. package/observability/loki-config.yml +38 -0
  132. package/observability/mysql-exporter.cnf +5 -0
  133. package/observability/mysql-setup.sql +46 -0
  134. package/observability/prometheus.yml +32 -0
  135. package/observability/promtail-config.yml +84 -0
  136. package/package.json +109 -0
  137. package/public/api-docs/index.html +144 -0
  138. package/public/css/github-project-panel.css +297 -0
  139. package/public/css/stickers-admin.css +1272 -0
  140. package/public/css/styles.css +671 -0
  141. package/public/index.html +1311 -0
  142. package/public/js/apps/apiDocsApp.js +310 -0
  143. package/public/js/apps/createPackApp.js +2069 -0
  144. package/public/js/apps/homeApp.js +396 -0
  145. package/public/js/apps/stickersAdminApp.js +1744 -0
  146. package/public/js/apps/stickersApp.js +4830 -0
  147. package/public/js/catalog.js +1019 -0
  148. package/public/js/github-panel/components/CommitList.js +34 -0
  149. package/public/js/github-panel/components/ErrorState.js +16 -0
  150. package/public/js/github-panel/components/GithubProjectPanel.js +106 -0
  151. package/public/js/github-panel/components/ReleaseList.js +38 -0
  152. package/public/js/github-panel/components/SkeletonPanel.js +22 -0
  153. package/public/js/github-panel/components/StatCard.js +15 -0
  154. package/public/js/github-panel/index.js +15 -0
  155. package/public/js/github-panel/useGithubRepoData.js +154 -0
  156. package/public/js/github-panel/vendor/react.js +11 -0
  157. package/public/js/runtime/react-runtime.js +19 -0
  158. package/public/licenca/index.html +106 -0
  159. package/public/stickers/admin/index.html +23 -0
  160. package/public/stickers/create/index.html +47 -0
  161. package/public/stickers/index.html +48 -0
  162. package/public/termos-de-uso/index.html +125 -0
  163. package/scripts/cache-bust.mjs +107 -0
  164. package/scripts/deploy.sh +458 -0
  165. package/scripts/github-deploy-notify.mjs +174 -0
  166. package/scripts/release.sh +129 -0
@@ -0,0 +1,1272 @@
1
+ :root {
2
+ --bg: #0b1220;
3
+ --bg-soft: #0f172a;
4
+ --card: #111a2b;
5
+ --card-soft: #162238;
6
+ --line: rgba(255, 255, 255, 0.05);
7
+ --line-strong: rgba(255, 255, 255, 0.12);
8
+ --accent: #14b8a6;
9
+ --accent-soft: rgba(20, 184, 166, 0.14);
10
+ --danger: #f43f5e;
11
+ --danger-soft: rgba(244, 63, 94, 0.14);
12
+ --warning: #f59e0b;
13
+ --warning-soft: rgba(245, 158, 11, 0.12);
14
+ --text: #e6edf3;
15
+ --text-soft: #94a3b8;
16
+ --text-muted: #64748b;
17
+ --radius-sm: 10px;
18
+ --radius-md: 14px;
19
+ --radius-lg: 18px;
20
+ --shadow-1: 0 1px 0 rgba(255, 255, 255, 0.05) inset;
21
+ --shadow-2: 0 12px 30px rgba(2, 6, 23, 0.28);
22
+ --transition: 150ms ease;
23
+ }
24
+
25
+ * {
26
+ box-sizing: border-box;
27
+ }
28
+
29
+ html,
30
+ body {
31
+ margin: 0;
32
+ min-height: 100%;
33
+ }
34
+
35
+ body {
36
+ font-family: 'Manrope', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
37
+ background:
38
+ radial-gradient(1300px 660px at 12% -12%, rgba(20, 184, 166, 0.14), transparent 52%),
39
+ radial-gradient(900px 500px at 92% -18%, rgba(59, 130, 246, 0.1), transparent 55%),
40
+ var(--bg);
41
+ color: var(--text);
42
+ line-height: 1.4;
43
+ }
44
+
45
+ a {
46
+ color: var(--accent);
47
+ }
48
+
49
+ a:hover {
50
+ color: #22d3ee;
51
+ }
52
+
53
+ button,
54
+ input,
55
+ select,
56
+ textarea {
57
+ font: inherit;
58
+ }
59
+
60
+ button,
61
+ input,
62
+ textarea,
63
+ a {
64
+ -webkit-tap-highlight-color: rgba(20, 184, 166, 0.16);
65
+ }
66
+
67
+ button:focus-visible,
68
+ input:focus-visible,
69
+ a:focus-visible {
70
+ outline: 2px solid rgba(20, 184, 166, 0.62);
71
+ outline-offset: 2px;
72
+ }
73
+
74
+ .admin-app {
75
+ min-height: 100dvh;
76
+ }
77
+
78
+ .topbar {
79
+ position: fixed;
80
+ top: 0;
81
+ left: 0;
82
+ right: 0;
83
+ z-index: 70;
84
+ border-bottom: 1px solid var(--line);
85
+ backdrop-filter: blur(12px);
86
+ background: rgba(11, 18, 32, 0.86);
87
+ }
88
+
89
+ .topbar-inner {
90
+ max-width: 1440px;
91
+ margin: 0 auto;
92
+ min-height: 64px;
93
+ padding: 10px 20px;
94
+ display: flex;
95
+ justify-content: space-between;
96
+ align-items: center;
97
+ gap: 14px;
98
+ }
99
+
100
+ .topbar-left,
101
+ .topbar-actions {
102
+ min-width: 0;
103
+ display: flex;
104
+ align-items: center;
105
+ gap: 10px;
106
+ }
107
+
108
+ .brand-dot {
109
+ width: 10px;
110
+ height: 10px;
111
+ border-radius: 999px;
112
+ background: var(--accent);
113
+ box-shadow: 0 0 0 5px rgba(20, 184, 166, 0.16);
114
+ }
115
+
116
+ .brand-title {
117
+ margin: 0;
118
+ font-size: 13px;
119
+ font-weight: 800;
120
+ letter-spacing: 0.08em;
121
+ text-transform: uppercase;
122
+ }
123
+
124
+ .brand-sub {
125
+ margin: 2px 0 0;
126
+ color: var(--text-soft);
127
+ font-size: 11px;
128
+ }
129
+
130
+ .user-chip {
131
+ display: inline-flex;
132
+ align-items: center;
133
+ max-width: 240px;
134
+ height: 34px;
135
+ padding: 0 12px;
136
+ border-radius: 999px;
137
+ border: 1px solid var(--line);
138
+ background: rgba(15, 23, 42, 0.7);
139
+ color: var(--text);
140
+ font-size: 12px;
141
+ font-weight: 600;
142
+ white-space: nowrap;
143
+ overflow: hidden;
144
+ text-overflow: ellipsis;
145
+ }
146
+
147
+ .layout-wrap {
148
+ max-width: 1440px;
149
+ margin: 0 auto;
150
+ padding: 84px 20px 22px;
151
+ display: grid;
152
+ grid-template-columns: 250px minmax(0, 1fr);
153
+ gap: 18px;
154
+ min-width: 0;
155
+ }
156
+
157
+ .sidebar {
158
+ min-width: 0;
159
+ position: sticky;
160
+ top: 84px;
161
+ align-self: start;
162
+ border-radius: var(--radius-lg);
163
+ border: 1px solid var(--line);
164
+ background: linear-gradient(180deg, rgba(17, 26, 43, 0.95), rgba(15, 23, 42, 0.94));
165
+ box-shadow: var(--shadow-1), var(--shadow-2);
166
+ padding: 14px;
167
+ }
168
+
169
+ .nav-group {
170
+ display: grid;
171
+ gap: 8px;
172
+ }
173
+
174
+ .nav-item {
175
+ width: 100%;
176
+ border: 1px solid transparent;
177
+ background: rgba(15, 23, 42, 0.65);
178
+ color: var(--text-soft);
179
+ border-radius: 12px;
180
+ min-height: 42px;
181
+ padding: 0 12px;
182
+ display: flex;
183
+ align-items: center;
184
+ justify-content: space-between;
185
+ gap: 8px;
186
+ font-size: 13px;
187
+ font-weight: 700;
188
+ text-align: left;
189
+ cursor: pointer;
190
+ transition: border-color var(--transition), color var(--transition), background-color var(--transition), transform var(--transition);
191
+ }
192
+
193
+ .nav-item:hover {
194
+ border-color: rgba(20, 184, 166, 0.28);
195
+ color: var(--text);
196
+ }
197
+
198
+ .nav-item.active {
199
+ border-color: rgba(20, 184, 166, 0.5);
200
+ color: #dff8f4;
201
+ background: rgba(20, 184, 166, 0.18);
202
+ }
203
+
204
+ .nav-count {
205
+ border-radius: 999px;
206
+ border: 1px solid var(--line);
207
+ background: rgba(11, 18, 32, 0.6);
208
+ color: var(--text-soft);
209
+ padding: 2px 8px;
210
+ font-size: 11px;
211
+ font-weight: 700;
212
+ }
213
+
214
+ .sidebar-footer {
215
+ margin-top: 14px;
216
+ padding-top: 14px;
217
+ border-top: 1px solid var(--line);
218
+ display: grid;
219
+ gap: 8px;
220
+ }
221
+
222
+ .main {
223
+ min-width: 0;
224
+ }
225
+
226
+ .stack {
227
+ min-width: 0;
228
+ display: grid;
229
+ gap: 16px;
230
+ }
231
+
232
+ .metrics-grid {
233
+ display: grid;
234
+ gap: 12px;
235
+ grid-template-columns: repeat(4, minmax(0, 1fr));
236
+ }
237
+
238
+ .metric-card {
239
+ border-radius: var(--radius-md);
240
+ border: 1px solid var(--line);
241
+ background: linear-gradient(180deg, rgba(17, 26, 43, 0.95), rgba(14, 23, 38, 0.9));
242
+ box-shadow: var(--shadow-1);
243
+ padding: 14px;
244
+ min-width: 0;
245
+ transition: transform var(--transition), border-color var(--transition), background-color var(--transition);
246
+ }
247
+
248
+ .metric-card:hover {
249
+ transform: translateY(-1px);
250
+ border-color: rgba(148, 163, 184, 0.24);
251
+ }
252
+
253
+ .metric-label {
254
+ margin: 0;
255
+ font-size: 10px;
256
+ letter-spacing: 0.08em;
257
+ text-transform: uppercase;
258
+ color: var(--text-soft);
259
+ font-weight: 700;
260
+ }
261
+
262
+ .metric-value {
263
+ margin: 4px 0 8px;
264
+ font-size: clamp(1.36rem, 1.8vw, 1.82rem);
265
+ line-height: 1.15;
266
+ font-weight: 800;
267
+ letter-spacing: -0.02em;
268
+ }
269
+
270
+ .metric-foot {
271
+ display: flex;
272
+ align-items: flex-end;
273
+ justify-content: space-between;
274
+ gap: 8px;
275
+ }
276
+
277
+ .metric-trend {
278
+ margin: 0;
279
+ font-size: 11px;
280
+ color: var(--text-soft);
281
+ }
282
+
283
+ .trend-up {
284
+ color: #2dd4bf;
285
+ }
286
+
287
+ .trend-down {
288
+ color: #fda4af;
289
+ }
290
+
291
+ .trend-neutral {
292
+ color: var(--text-soft);
293
+ }
294
+
295
+ .sparkline {
296
+ display: flex;
297
+ align-items: flex-end;
298
+ gap: 3px;
299
+ }
300
+
301
+ .sparkbar {
302
+ width: 5px;
303
+ border-radius: 999px;
304
+ background: linear-gradient(180deg, #5eead4, #0891b2);
305
+ opacity: 0.92;
306
+ }
307
+
308
+ .tabs-strip {
309
+ overflow-x: auto;
310
+ display: flex;
311
+ gap: 8px;
312
+ padding: 5px;
313
+ border-radius: 14px;
314
+ border: 1px solid var(--line);
315
+ background: rgba(15, 23, 42, 0.62);
316
+ }
317
+
318
+ .tabs-strip::-webkit-scrollbar,
319
+ .mobile-list::-webkit-scrollbar,
320
+ .table-shell::-webkit-scrollbar,
321
+ .detail-list::-webkit-scrollbar,
322
+ .upload-grid::-webkit-scrollbar,
323
+ .code-block::-webkit-scrollbar,
324
+ .drawer-panel::-webkit-scrollbar {
325
+ height: 8px;
326
+ width: 8px;
327
+ }
328
+
329
+ .tabs-strip::-webkit-scrollbar-thumb,
330
+ .mobile-list::-webkit-scrollbar-thumb,
331
+ .table-shell::-webkit-scrollbar-thumb,
332
+ .detail-list::-webkit-scrollbar-thumb,
333
+ .upload-grid::-webkit-scrollbar-thumb,
334
+ .code-block::-webkit-scrollbar-thumb,
335
+ .drawer-panel::-webkit-scrollbar-thumb {
336
+ background: rgba(148, 163, 184, 0.36);
337
+ border-radius: 999px;
338
+ }
339
+
340
+ .tab-btn {
341
+ border: 1px solid transparent;
342
+ background: transparent;
343
+ color: var(--text-soft);
344
+ border-radius: 10px;
345
+ padding: 9px 12px;
346
+ min-height: 38px;
347
+ font-size: 12px;
348
+ font-weight: 700;
349
+ white-space: nowrap;
350
+ cursor: pointer;
351
+ transition: background-color var(--transition), border-color var(--transition), color var(--transition);
352
+ }
353
+
354
+ .tab-btn:hover {
355
+ color: var(--text);
356
+ background: rgba(30, 41, 59, 0.64);
357
+ }
358
+
359
+ .tab-btn.active {
360
+ border-color: rgba(20, 184, 166, 0.46);
361
+ background: rgba(20, 184, 166, 0.16);
362
+ color: #dcfffa;
363
+ }
364
+
365
+ .panel {
366
+ min-width: 0;
367
+ border-radius: var(--radius-lg);
368
+ border: 1px solid var(--line);
369
+ background: linear-gradient(180deg, rgba(17, 26, 43, 0.95), rgba(14, 23, 38, 0.92));
370
+ box-shadow: var(--shadow-1);
371
+ padding: 14px;
372
+ }
373
+
374
+ .panel.inner {
375
+ padding: 12px;
376
+ background: linear-gradient(180deg, rgba(22, 34, 56, 0.82), rgba(15, 23, 42, 0.76));
377
+ }
378
+
379
+ .panel-head {
380
+ min-width: 0;
381
+ display: flex;
382
+ justify-content: space-between;
383
+ align-items: flex-start;
384
+ gap: 12px;
385
+ margin-bottom: 12px;
386
+ }
387
+
388
+ .panel-head.slim {
389
+ margin-bottom: 10px;
390
+ }
391
+
392
+ .panel-title {
393
+ margin: 0;
394
+ font-size: clamp(1.02rem, 1.5vw, 1.52rem);
395
+ font-weight: 800;
396
+ letter-spacing: -0.015em;
397
+ }
398
+
399
+ .panel-head.slim .panel-title {
400
+ font-size: 1.02rem;
401
+ }
402
+
403
+ .panel-desc {
404
+ margin: 3px 0 0;
405
+ color: var(--text-soft);
406
+ font-size: 12px;
407
+ }
408
+
409
+ .section-grid {
410
+ min-width: 0;
411
+ display: grid;
412
+ gap: 14px;
413
+ }
414
+
415
+ .section-grid.two-col {
416
+ grid-template-columns: repeat(2, minmax(0, 1fr));
417
+ }
418
+
419
+ .search-form {
420
+ display: flex;
421
+ align-items: center;
422
+ gap: 8px;
423
+ width: min(100%, 520px);
424
+ }
425
+
426
+ .search-form.compact {
427
+ width: min(100%, 420px);
428
+ }
429
+
430
+ .search-input {
431
+ width: 100%;
432
+ min-width: 0;
433
+ height: 40px;
434
+ border-radius: 11px;
435
+ border: 1px solid var(--line-strong);
436
+ background: rgba(15, 23, 42, 0.88);
437
+ color: var(--text);
438
+ padding: 0 12px;
439
+ transition: border-color var(--transition), background-color var(--transition), box-shadow var(--transition);
440
+ }
441
+
442
+ .search-input::placeholder {
443
+ color: #6b7c93;
444
+ }
445
+
446
+ .search-input:hover {
447
+ border-color: rgba(148, 163, 184, 0.3);
448
+ }
449
+
450
+ .search-input:focus-visible {
451
+ border-color: rgba(20, 184, 166, 0.64);
452
+ box-shadow: 0 0 0 3px rgba(20, 184, 166, 0.14);
453
+ }
454
+
455
+ .primary-btn,
456
+ .outline-btn,
457
+ .danger-btn,
458
+ .subtle-btn,
459
+ .ghost-btn,
460
+ .icon-btn,
461
+ .menu-trigger {
462
+ appearance: none;
463
+ border: 1px solid transparent;
464
+ border-radius: 10px;
465
+ height: 38px;
466
+ display: inline-flex;
467
+ align-items: center;
468
+ justify-content: center;
469
+ gap: 6px;
470
+ padding: 0 12px;
471
+ cursor: pointer;
472
+ text-decoration: none;
473
+ font-size: 12px;
474
+ font-weight: 700;
475
+ transition:
476
+ background-color var(--transition),
477
+ border-color var(--transition),
478
+ color var(--transition),
479
+ transform var(--transition),
480
+ opacity var(--transition);
481
+ }
482
+
483
+ .primary-btn {
484
+ background: var(--accent);
485
+ color: #07131e;
486
+ border-color: transparent;
487
+ }
488
+
489
+ .primary-btn:hover:not(:disabled) {
490
+ background: #2dd4bf;
491
+ transform: translateY(-1px);
492
+ }
493
+
494
+ .outline-btn,
495
+ .subtle-btn,
496
+ .ghost-btn {
497
+ border-color: var(--line-strong);
498
+ color: var(--text);
499
+ background: rgba(15, 23, 42, 0.76);
500
+ }
501
+
502
+ .outline-btn:hover:not(:disabled),
503
+ .subtle-btn:hover:not(:disabled),
504
+ .ghost-btn:hover:not(:disabled) {
505
+ border-color: rgba(148, 163, 184, 0.35);
506
+ background: rgba(30, 41, 59, 0.84);
507
+ }
508
+
509
+ .danger-btn,
510
+ .ghost-btn.danger,
511
+ .subtle-btn.danger,
512
+ .row-menu-item.danger {
513
+ border-color: rgba(244, 63, 94, 0.42);
514
+ color: #fecdd3;
515
+ background: rgba(127, 29, 29, 0.12);
516
+ }
517
+
518
+ .danger-btn:hover:not(:disabled),
519
+ .ghost-btn.danger:hover:not(:disabled),
520
+ .subtle-btn.danger:hover:not(:disabled),
521
+ .row-menu-item.danger:hover:not(:disabled) {
522
+ background: rgba(244, 63, 94, 0.18);
523
+ border-color: rgba(244, 63, 94, 0.58);
524
+ }
525
+
526
+ .icon-btn {
527
+ width: 36px;
528
+ padding: 0;
529
+ border-color: var(--line-strong);
530
+ background: rgba(15, 23, 42, 0.8);
531
+ color: var(--text-soft);
532
+ }
533
+
534
+ .icon-btn:hover {
535
+ color: var(--text);
536
+ background: rgba(30, 41, 59, 0.88);
537
+ }
538
+
539
+ button:disabled,
540
+ a[aria-disabled='true'] {
541
+ opacity: 0.55;
542
+ cursor: not-allowed;
543
+ }
544
+
545
+ .table-shell {
546
+ min-width: 0;
547
+ overflow: auto;
548
+ border-radius: var(--radius-md);
549
+ border: 1px solid var(--line);
550
+ max-height: 420px;
551
+ background: rgba(11, 18, 32, 0.56);
552
+ }
553
+
554
+ .data-table {
555
+ width: 100%;
556
+ min-width: 620px;
557
+ border-collapse: collapse;
558
+ table-layout: fixed;
559
+ }
560
+
561
+ .data-table thead {
562
+ position: sticky;
563
+ top: 0;
564
+ z-index: 2;
565
+ background: rgba(17, 26, 43, 0.96);
566
+ }
567
+
568
+ .data-table th {
569
+ text-align: left;
570
+ font-size: 11px;
571
+ color: var(--text-soft);
572
+ letter-spacing: 0.045em;
573
+ text-transform: uppercase;
574
+ font-weight: 700;
575
+ padding: 10px 12px;
576
+ border-bottom: 1px solid var(--line);
577
+ white-space: nowrap;
578
+ }
579
+
580
+ .data-table td {
581
+ padding: 10px 12px;
582
+ border-bottom: 1px solid rgba(148, 163, 184, 0.08);
583
+ vertical-align: top;
584
+ font-size: 12px;
585
+ color: var(--text);
586
+ min-width: 0;
587
+ }
588
+
589
+ .data-table tbody tr {
590
+ transition: background-color var(--transition);
591
+ }
592
+
593
+ .data-table tbody tr:hover {
594
+ background: rgba(30, 41, 59, 0.34);
595
+ }
596
+
597
+ .data-table tr:last-child td {
598
+ border-bottom: 0;
599
+ }
600
+
601
+ .menu-wrap {
602
+ position: relative;
603
+ display: inline-flex;
604
+ }
605
+
606
+ .menu-trigger {
607
+ width: 34px;
608
+ padding: 0;
609
+ border-radius: 10px;
610
+ background: rgba(15, 23, 42, 0.8);
611
+ border-color: var(--line-strong);
612
+ color: var(--text-soft);
613
+ }
614
+
615
+ .menu-trigger:hover {
616
+ color: var(--text);
617
+ }
618
+
619
+ .row-menu {
620
+ position: absolute;
621
+ top: calc(100% + 6px);
622
+ right: 0;
623
+ width: max-content;
624
+ min-width: 178px;
625
+ z-index: 35;
626
+ border-radius: 12px;
627
+ border: 1px solid var(--line-strong);
628
+ background: rgba(15, 23, 42, 0.96);
629
+ backdrop-filter: blur(8px);
630
+ box-shadow: 0 14px 36px rgba(2, 6, 23, 0.48);
631
+ padding: 6px;
632
+ display: grid;
633
+ gap: 4px;
634
+ }
635
+
636
+ .row-menu-item {
637
+ width: 100%;
638
+ min-height: 34px;
639
+ border-radius: 8px;
640
+ border: 1px solid transparent;
641
+ background: transparent;
642
+ color: var(--text);
643
+ font-size: 12px;
644
+ font-weight: 600;
645
+ text-align: left;
646
+ display: inline-flex;
647
+ align-items: center;
648
+ padding: 0 10px;
649
+ text-decoration: none;
650
+ }
651
+
652
+ .row-menu-item:hover {
653
+ background: rgba(51, 65, 85, 0.48);
654
+ }
655
+
656
+ .row-title {
657
+ margin: 0;
658
+ font-size: 13px;
659
+ line-height: 1.35;
660
+ font-weight: 700;
661
+ }
662
+
663
+ .row-sub {
664
+ margin: 2px 0 0;
665
+ font-size: 12px;
666
+ color: #b6c2d3;
667
+ }
668
+
669
+ .row-meta {
670
+ margin: 2px 0 0;
671
+ font-size: 11px;
672
+ color: var(--text-muted);
673
+ }
674
+
675
+ .badge-row {
676
+ margin-top: 7px;
677
+ display: flex;
678
+ align-items: center;
679
+ flex-wrap: wrap;
680
+ gap: 6px;
681
+ }
682
+
683
+ .status-badge {
684
+ display: inline-flex;
685
+ align-items: center;
686
+ border-radius: 999px;
687
+ padding: 3px 9px;
688
+ border: 1px solid var(--line-strong);
689
+ background: rgba(51, 65, 85, 0.22);
690
+ font-size: 10px;
691
+ font-weight: 700;
692
+ color: var(--text-soft);
693
+ text-transform: lowercase;
694
+ }
695
+
696
+ .status-success {
697
+ border-color: rgba(45, 212, 191, 0.36);
698
+ background: rgba(20, 184, 166, 0.14);
699
+ color: #99f6e4;
700
+ }
701
+
702
+ .status-danger {
703
+ border-color: rgba(244, 63, 94, 0.45);
704
+ background: rgba(244, 63, 94, 0.15);
705
+ color: #fecdd3;
706
+ }
707
+
708
+ .status-warning {
709
+ border-color: rgba(245, 158, 11, 0.45);
710
+ background: rgba(245, 158, 11, 0.14);
711
+ color: #fcd34d;
712
+ }
713
+
714
+ .status-neutral {
715
+ border-color: var(--line-strong);
716
+ background: rgba(71, 85, 105, 0.14);
717
+ color: #cbd5e1;
718
+ }
719
+
720
+ .mono {
721
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
722
+ }
723
+
724
+ .muted {
725
+ color: var(--text-soft);
726
+ }
727
+
728
+ .break-all {
729
+ word-break: break-all;
730
+ }
731
+
732
+ .break-words {
733
+ word-break: break-word;
734
+ overflow-wrap: anywhere;
735
+ }
736
+
737
+ .pager {
738
+ display: flex;
739
+ justify-content: space-between;
740
+ align-items: center;
741
+ gap: 8px;
742
+ padding-top: 10px;
743
+ }
744
+
745
+ .pager-meta {
746
+ color: var(--text-soft);
747
+ font-size: 11px;
748
+ text-align: center;
749
+ flex: 1;
750
+ }
751
+
752
+ .mobile-list {
753
+ display: grid;
754
+ gap: 10px;
755
+ max-height: 520px;
756
+ overflow: auto;
757
+ min-width: 0;
758
+ }
759
+
760
+ .mobile-card {
761
+ min-width: 0;
762
+ border-radius: 12px;
763
+ border: 1px solid var(--line);
764
+ background: rgba(15, 23, 42, 0.76);
765
+ padding: 10px;
766
+ }
767
+
768
+ .mobile-card-foot {
769
+ margin-top: 8px;
770
+ display: flex;
771
+ justify-content: space-between;
772
+ align-items: center;
773
+ gap: 8px;
774
+ }
775
+
776
+ .selected-pack-head {
777
+ display: flex;
778
+ justify-content: space-between;
779
+ align-items: flex-start;
780
+ gap: 12px;
781
+ padding: 12px;
782
+ border-radius: 12px;
783
+ border: 1px solid var(--line);
784
+ background: rgba(15, 23, 42, 0.68);
785
+ }
786
+
787
+ .selected-pack-actions {
788
+ display: flex;
789
+ flex-wrap: wrap;
790
+ gap: 8px;
791
+ }
792
+
793
+ .detail-list {
794
+ margin-top: 10px;
795
+ display: grid;
796
+ gap: 8px;
797
+ max-height: 520px;
798
+ overflow: auto;
799
+ }
800
+
801
+ .detail-item {
802
+ min-width: 0;
803
+ display: grid;
804
+ grid-template-columns: 52px minmax(0, 1fr) auto;
805
+ gap: 10px;
806
+ border: 1px solid var(--line);
807
+ border-radius: 12px;
808
+ padding: 8px;
809
+ background: rgba(15, 23, 42, 0.7);
810
+ }
811
+
812
+ .detail-thumb {
813
+ width: 52px;
814
+ height: 52px;
815
+ border-radius: 10px;
816
+ border: 1px solid var(--line);
817
+ object-fit: cover;
818
+ background: rgba(15, 23, 42, 0.95);
819
+ }
820
+
821
+ .detail-content {
822
+ min-width: 0;
823
+ }
824
+
825
+ .detail-actions {
826
+ display: grid;
827
+ gap: 7px;
828
+ align-content: start;
829
+ }
830
+
831
+ .form-grid {
832
+ display: grid;
833
+ gap: 8px;
834
+ }
835
+
836
+ .upload-grid {
837
+ display: grid;
838
+ grid-template-columns: repeat(2, minmax(0, 1fr));
839
+ gap: 10px;
840
+ }
841
+
842
+ .upload-card {
843
+ min-width: 0;
844
+ border-radius: 12px;
845
+ border: 1px solid var(--line);
846
+ background: rgba(15, 23, 42, 0.75);
847
+ padding: 10px;
848
+ display: grid;
849
+ gap: 10px;
850
+ }
851
+
852
+ .upload-card-head {
853
+ display: flex;
854
+ align-items: flex-start;
855
+ justify-content: space-between;
856
+ gap: 10px;
857
+ }
858
+
859
+ .progress-wrap {
860
+ display: grid;
861
+ grid-template-columns: minmax(0, 1fr) auto;
862
+ gap: 8px;
863
+ align-items: center;
864
+ }
865
+
866
+ .progress-track {
867
+ width: 100%;
868
+ height: 8px;
869
+ border-radius: 999px;
870
+ background: rgba(51, 65, 85, 0.58);
871
+ overflow: hidden;
872
+ }
873
+
874
+ .progress-bar {
875
+ display: block;
876
+ height: 100%;
877
+ background: linear-gradient(90deg, #2dd4bf, #14b8a6);
878
+ }
879
+
880
+ .progress-meta {
881
+ font-size: 11px;
882
+ color: var(--text-soft);
883
+ }
884
+
885
+ .upload-meta {
886
+ display: flex;
887
+ justify-content: space-between;
888
+ align-items: center;
889
+ gap: 8px;
890
+ color: var(--text-soft);
891
+ font-size: 11px;
892
+ }
893
+
894
+ .upload-actions {
895
+ display: flex;
896
+ flex-wrap: wrap;
897
+ gap: 8px;
898
+ }
899
+
900
+ .upload-actions .menu-wrap {
901
+ margin-left: auto;
902
+ }
903
+
904
+ .kv-grid {
905
+ display: grid;
906
+ gap: 8px;
907
+ }
908
+
909
+ .kv-item {
910
+ border-radius: 10px;
911
+ border: 1px solid var(--line);
912
+ background: rgba(15, 23, 42, 0.66);
913
+ padding: 10px;
914
+ display: flex;
915
+ justify-content: space-between;
916
+ align-items: center;
917
+ gap: 8px;
918
+ }
919
+
920
+ .kv-key {
921
+ color: var(--text-soft);
922
+ font-size: 12px;
923
+ }
924
+
925
+ .kv-value {
926
+ font-size: 12px;
927
+ font-weight: 700;
928
+ color: var(--text);
929
+ text-align: right;
930
+ }
931
+
932
+ .code-block {
933
+ margin: 0;
934
+ border-radius: 12px;
935
+ border: 1px solid var(--line);
936
+ background: rgba(11, 18, 32, 0.7);
937
+ padding: 12px;
938
+ color: #cbd5e1;
939
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
940
+ font-size: 11px;
941
+ max-height: 340px;
942
+ overflow: auto;
943
+ }
944
+
945
+ .account-box {
946
+ border-radius: 12px;
947
+ border: 1px solid rgba(20, 184, 166, 0.32);
948
+ background: rgba(20, 184, 166, 0.1);
949
+ padding: 10px;
950
+ }
951
+
952
+ .account-box.warning {
953
+ border-color: rgba(245, 158, 11, 0.4);
954
+ background: rgba(245, 158, 11, 0.12);
955
+ }
956
+
957
+ .google-login-box {
958
+ margin-top: 10px;
959
+ }
960
+
961
+ .google-login-slot {
962
+ min-height: 42px;
963
+ }
964
+
965
+ .hint {
966
+ margin: 0;
967
+ font-size: 11px;
968
+ color: var(--text-soft);
969
+ }
970
+
971
+ .hint.warning {
972
+ color: #fcd34d;
973
+ }
974
+
975
+ .inline-alert {
976
+ margin-bottom: 12px;
977
+ border-radius: 12px;
978
+ border: 1px solid rgba(244, 63, 94, 0.38);
979
+ background: rgba(127, 29, 29, 0.22);
980
+ color: #fecdd3;
981
+ padding: 9px 11px;
982
+ font-size: 12px;
983
+ }
984
+
985
+ .empty,
986
+ .empty-box {
987
+ color: var(--text-soft);
988
+ text-align: center;
989
+ font-size: 12px;
990
+ }
991
+
992
+ .empty-box {
993
+ border-radius: 12px;
994
+ border: 1px dashed rgba(148, 163, 184, 0.26);
995
+ padding: 18px 12px;
996
+ }
997
+
998
+ .drawer {
999
+ position: fixed;
1000
+ inset: 0;
1001
+ z-index: 80;
1002
+ }
1003
+
1004
+ .drawer-backdrop {
1005
+ position: absolute;
1006
+ inset: 0;
1007
+ background: rgba(2, 6, 23, 0.62);
1008
+ }
1009
+
1010
+ .drawer-panel {
1011
+ position: absolute;
1012
+ top: 0;
1013
+ bottom: 0;
1014
+ left: 0;
1015
+ width: min(84vw, 300px);
1016
+ border-right: 1px solid var(--line);
1017
+ background: rgba(11, 18, 32, 0.96);
1018
+ backdrop-filter: blur(12px);
1019
+ padding: 14px;
1020
+ overflow: auto;
1021
+ display: grid;
1022
+ grid-auto-rows: min-content;
1023
+ gap: 10px;
1024
+ }
1025
+
1026
+ .drawer-head {
1027
+ display: flex;
1028
+ justify-content: space-between;
1029
+ align-items: center;
1030
+ }
1031
+
1032
+ .toast-stack {
1033
+ position: fixed;
1034
+ top: 74px;
1035
+ right: 20px;
1036
+ z-index: 90;
1037
+ width: min(92vw, 400px);
1038
+ }
1039
+
1040
+ .toast {
1041
+ border-radius: 12px;
1042
+ border: 1px solid var(--line);
1043
+ padding: 11px 12px;
1044
+ font-size: 12px;
1045
+ font-weight: 600;
1046
+ box-shadow: 0 12px 34px rgba(2, 6, 23, 0.42);
1047
+ }
1048
+
1049
+ .toast.success {
1050
+ border-color: rgba(20, 184, 166, 0.42);
1051
+ color: #bff8f1;
1052
+ background: rgba(20, 184, 166, 0.16);
1053
+ }
1054
+
1055
+ .toast.danger {
1056
+ border-color: rgba(244, 63, 94, 0.45);
1057
+ color: #fecdd3;
1058
+ background: rgba(244, 63, 94, 0.16);
1059
+ }
1060
+
1061
+ .desktop-only {
1062
+ display: block;
1063
+ }
1064
+
1065
+ .mobile-only {
1066
+ display: none;
1067
+ }
1068
+
1069
+ .skeleton {
1070
+ position: relative;
1071
+ overflow: hidden;
1072
+ }
1073
+
1074
+ .skeleton::after {
1075
+ content: '';
1076
+ position: absolute;
1077
+ inset: 0;
1078
+ transform: translateX(-100%);
1079
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.05), transparent);
1080
+ animation: shimmer 1.2s infinite;
1081
+ }
1082
+
1083
+ .skeleton-line {
1084
+ height: 10px;
1085
+ border-radius: 999px;
1086
+ background: rgba(71, 85, 105, 0.45);
1087
+ margin-bottom: 8px;
1088
+ }
1089
+
1090
+ .w-30 {
1091
+ width: 30%;
1092
+ }
1093
+
1094
+ .w-50 {
1095
+ width: 50%;
1096
+ }
1097
+
1098
+ .w-60 {
1099
+ width: 60%;
1100
+ }
1101
+
1102
+ .w-80 {
1103
+ width: 80%;
1104
+ }
1105
+
1106
+ .w-85 {
1107
+ width: 85%;
1108
+ }
1109
+
1110
+ .w-90 {
1111
+ width: 90%;
1112
+ }
1113
+
1114
+ @keyframes shimmer {
1115
+ 100% {
1116
+ transform: translateX(100%);
1117
+ }
1118
+ }
1119
+
1120
+ @media (max-width: 1250px) {
1121
+ .metrics-grid {
1122
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1123
+ }
1124
+
1125
+ .upload-grid {
1126
+ grid-template-columns: minmax(0, 1fr);
1127
+ }
1128
+ }
1129
+
1130
+ @media (max-width: 1024px) {
1131
+ .layout-wrap {
1132
+ grid-template-columns: minmax(0, 1fr);
1133
+ padding-top: 78px;
1134
+ }
1135
+
1136
+ .sidebar.desktop-only {
1137
+ display: none;
1138
+ }
1139
+
1140
+ .section-grid.two-col {
1141
+ grid-template-columns: minmax(0, 1fr);
1142
+ }
1143
+
1144
+ .topbar-actions .user-chip {
1145
+ max-width: 168px;
1146
+ }
1147
+
1148
+ .topbar-left .mobile-only {
1149
+ display: inline-flex !important;
1150
+ }
1151
+ }
1152
+
1153
+ @media (max-width: 768px) {
1154
+ .topbar-inner {
1155
+ padding-inline: 12px;
1156
+ min-height: 58px;
1157
+ }
1158
+
1159
+ .topbar-actions {
1160
+ gap: 6px;
1161
+ }
1162
+
1163
+ .topbar-actions .ghost-btn,
1164
+ .topbar-actions .user-chip {
1165
+ display: none;
1166
+ }
1167
+
1168
+ .layout-wrap {
1169
+ padding: 70px 10px 14px;
1170
+ gap: 12px;
1171
+ }
1172
+
1173
+ .stack {
1174
+ gap: 12px;
1175
+ }
1176
+
1177
+ .metrics-grid {
1178
+ grid-template-columns: minmax(0, 1fr);
1179
+ }
1180
+
1181
+ .panel {
1182
+ padding: 10px;
1183
+ border-radius: 14px;
1184
+ }
1185
+
1186
+ .panel-head {
1187
+ flex-direction: column;
1188
+ align-items: stretch;
1189
+ gap: 8px;
1190
+ }
1191
+
1192
+ .search-form,
1193
+ .search-form.compact {
1194
+ width: 100%;
1195
+ }
1196
+
1197
+ .search-form {
1198
+ flex-direction: column;
1199
+ align-items: stretch;
1200
+ }
1201
+
1202
+ .search-form .outline-btn,
1203
+ .search-form .primary-btn,
1204
+ .search-form .danger-btn,
1205
+ .search-form .subtle-btn {
1206
+ width: 100%;
1207
+ }
1208
+
1209
+ .selected-pack-head {
1210
+ flex-direction: column;
1211
+ }
1212
+
1213
+ .selected-pack-actions {
1214
+ width: 100%;
1215
+ }
1216
+
1217
+ .selected-pack-actions > * {
1218
+ flex: 1;
1219
+ justify-content: center;
1220
+ }
1221
+
1222
+ .detail-item {
1223
+ grid-template-columns: 44px minmax(0, 1fr);
1224
+ }
1225
+
1226
+ .detail-thumb {
1227
+ width: 44px;
1228
+ height: 44px;
1229
+ }
1230
+
1231
+ .detail-actions {
1232
+ grid-column: span 2;
1233
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1234
+ }
1235
+
1236
+ .detail-actions .outline-btn,
1237
+ .detail-actions .danger-btn {
1238
+ width: 100%;
1239
+ justify-content: center;
1240
+ }
1241
+
1242
+ .desktop-only {
1243
+ display: none !important;
1244
+ }
1245
+
1246
+ .mobile-only {
1247
+ display: block !important;
1248
+ }
1249
+
1250
+ .pager {
1251
+ flex-wrap: wrap;
1252
+ }
1253
+
1254
+ .pager .subtle-btn {
1255
+ flex: 1;
1256
+ }
1257
+
1258
+ .toast-stack {
1259
+ top: 64px;
1260
+ right: 10px;
1261
+ }
1262
+ }
1263
+
1264
+ @media (prefers-reduced-motion: reduce) {
1265
+ *,
1266
+ *::before,
1267
+ *::after {
1268
+ animation: none !important;
1269
+ transition: none !important;
1270
+ scroll-behavior: auto !important;
1271
+ }
1272
+ }