homebridge-eufy-security 4.4.2-beta.2 → 4.4.2-beta.20

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 (147) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/FUNDING.yml +1 -0
  3. package/README.md +14 -17
  4. package/dist/accessories/AutoSyncStationAccessory.js +26 -30
  5. package/dist/accessories/AutoSyncStationAccessory.js.map +1 -1
  6. package/dist/accessories/BaseAccessory.js +33 -46
  7. package/dist/accessories/BaseAccessory.js.map +1 -1
  8. package/dist/accessories/CameraAccessory.js +92 -167
  9. package/dist/accessories/CameraAccessory.js.map +1 -1
  10. package/dist/accessories/Device.js +11 -15
  11. package/dist/accessories/Device.js.map +1 -1
  12. package/dist/accessories/EntrySensorAccessory.js +7 -12
  13. package/dist/accessories/EntrySensorAccessory.js.map +1 -1
  14. package/dist/accessories/LockAccessory.js +20 -24
  15. package/dist/accessories/LockAccessory.js.map +1 -1
  16. package/dist/accessories/MotionSensorAccessory.js +7 -12
  17. package/dist/accessories/MotionSensorAccessory.js.map +1 -1
  18. package/dist/accessories/StationAccessory.js +40 -45
  19. package/dist/accessories/StationAccessory.js.map +1 -1
  20. package/dist/config.js +1 -4
  21. package/dist/config.js.map +1 -1
  22. package/dist/controller/LocalLivestreamManager.js +85 -89
  23. package/dist/controller/LocalLivestreamManager.js.map +1 -1
  24. package/dist/controller/recordingDelegate.js +116 -108
  25. package/dist/controller/recordingDelegate.js.map +1 -1
  26. package/dist/controller/snapshotDelegate.js +379 -0
  27. package/dist/controller/snapshotDelegate.js.map +1 -0
  28. package/dist/controller/streamingDelegate.js +202 -207
  29. package/dist/controller/streamingDelegate.js.map +1 -1
  30. package/dist/index.js +9 -7
  31. package/dist/index.js.map +1 -1
  32. package/dist/interfaces.js +1 -2
  33. package/dist/interfaces.js.map +1 -1
  34. package/dist/platform.js +145 -165
  35. package/dist/platform.js.map +1 -1
  36. package/dist/settings.js +26 -19
  37. package/dist/settings.js.map +1 -1
  38. package/dist/utils/Talkback.js +9 -13
  39. package/dist/utils/Talkback.js.map +1 -1
  40. package/dist/utils/configTypes.js +12 -7
  41. package/dist/utils/configTypes.js.map +1 -1
  42. package/dist/utils/ffmpeg.js +44 -52
  43. package/dist/utils/ffmpeg.js.map +1 -1
  44. package/dist/utils/interfaces.js +1 -5
  45. package/dist/utils/interfaces.js.map +1 -1
  46. package/dist/utils/utils.js +32 -134
  47. package/dist/utils/utils.js.map +1 -1
  48. package/dist/version.js +1 -4
  49. package/dist/version.js.map +1 -1
  50. package/eslint.config.mjs +25 -47
  51. package/homebridge-eufy-security.png +0 -0
  52. package/homebridge-ui/public/app.js +221 -0
  53. package/homebridge-ui/public/assets/devices/eufycam3pro_large.png +0 -0
  54. package/homebridge-ui/public/assets/devices/homebase3_large.png +0 -0
  55. package/homebridge-ui/public/assets/devices/homebasemini_large.jpg +0 -0
  56. package/homebridge-ui/public/assets/devices/indoorcamC210_large.png +0 -0
  57. package/homebridge-ui/public/assets/devices/indoorcamC220_large.png +0 -0
  58. package/homebridge-ui/public/assets/devices/indoorcamE30_large.png +0 -0
  59. package/homebridge-ui/public/assets/devices/solocamc35_large.png +0 -0
  60. package/homebridge-ui/public/assets/devices/solocame30_large.png +0 -0
  61. package/homebridge-ui/public/components/device-card.js +141 -0
  62. package/homebridge-ui/public/components/guard-modes.js +88 -0
  63. package/homebridge-ui/public/components/number-input.js +121 -0
  64. package/homebridge-ui/public/components/select.js +73 -0
  65. package/homebridge-ui/public/components/toggle.js +68 -0
  66. package/homebridge-ui/public/index.html +24 -14
  67. package/homebridge-ui/public/services/api.js +129 -0
  68. package/homebridge-ui/public/services/config.js +144 -0
  69. package/homebridge-ui/public/style.css +705 -0
  70. package/homebridge-ui/public/utils/countries.js +73 -0
  71. package/homebridge-ui/public/utils/device-images.js +69 -0
  72. package/homebridge-ui/public/utils/helpers.js +47 -0
  73. package/homebridge-ui/public/views/dashboard.js +211 -0
  74. package/homebridge-ui/public/views/device-detail.js +631 -0
  75. package/homebridge-ui/public/views/login.js +625 -0
  76. package/homebridge-ui/public/views/settings.js +389 -0
  77. package/homebridge-ui/public/views/unsupported-detail.js +216 -0
  78. package/homebridge-ui/server.js +567 -450
  79. package/package.json +19 -59
  80. package/dist/accessories/AutoSyncStationAccessory.d.ts +0 -42
  81. package/dist/accessories/AutoSyncStationAccessory.d.ts.map +0 -1
  82. package/dist/accessories/BaseAccessory.d.ts +0 -56
  83. package/dist/accessories/BaseAccessory.d.ts.map +0 -1
  84. package/dist/accessories/CameraAccessory.d.ts +0 -84
  85. package/dist/accessories/CameraAccessory.d.ts.map +0 -1
  86. package/dist/accessories/Device.d.ts +0 -19
  87. package/dist/accessories/Device.d.ts.map +0 -1
  88. package/dist/accessories/EntrySensorAccessory.d.ts +0 -25
  89. package/dist/accessories/EntrySensorAccessory.d.ts.map +0 -1
  90. package/dist/accessories/LockAccessory.d.ts +0 -45
  91. package/dist/accessories/LockAccessory.d.ts.map +0 -1
  92. package/dist/accessories/MotionSensorAccessory.d.ts +0 -25
  93. package/dist/accessories/MotionSensorAccessory.d.ts.map +0 -1
  94. package/dist/accessories/StationAccessory.d.ts +0 -86
  95. package/dist/accessories/StationAccessory.d.ts.map +0 -1
  96. package/dist/config.d.ts +0 -31
  97. package/dist/config.d.ts.map +0 -1
  98. package/dist/controller/LocalLivestreamManager.d.ts +0 -31
  99. package/dist/controller/LocalLivestreamManager.d.ts.map +0 -1
  100. package/dist/controller/SnapshotManager.d.ts +0 -64
  101. package/dist/controller/SnapshotManager.d.ts.map +0 -1
  102. package/dist/controller/SnapshotManager.js +0 -434
  103. package/dist/controller/SnapshotManager.js.map +0 -1
  104. package/dist/controller/recordingDelegate.d.ts +0 -27
  105. package/dist/controller/recordingDelegate.d.ts.map +0 -1
  106. package/dist/controller/streamingDelegate.d.ts +0 -52
  107. package/dist/controller/streamingDelegate.d.ts.map +0 -1
  108. package/dist/index.d.ts +0 -7
  109. package/dist/index.d.ts.map +0 -1
  110. package/dist/interfaces.d.ts +0 -15
  111. package/dist/interfaces.d.ts.map +0 -1
  112. package/dist/platform.d.ts +0 -94
  113. package/dist/platform.d.ts.map +0 -1
  114. package/dist/settings.d.ts +0 -23
  115. package/dist/settings.d.ts.map +0 -1
  116. package/dist/utils/Talkback.d.ts +0 -21
  117. package/dist/utils/Talkback.d.ts.map +0 -1
  118. package/dist/utils/configTypes.d.ts +0 -68
  119. package/dist/utils/configTypes.d.ts.map +0 -1
  120. package/dist/utils/ffmpeg.d.ts +0 -111
  121. package/dist/utils/ffmpeg.d.ts.map +0 -1
  122. package/dist/utils/interfaces.d.ts +0 -8
  123. package/dist/utils/interfaces.d.ts.map +0 -1
  124. package/dist/utils/utils.d.ts +0 -35
  125. package/dist/utils/utils.d.ts.map +0 -1
  126. package/dist/version.d.ts +0 -2
  127. package/dist/version.d.ts.map +0 -1
  128. package/homebridge-ui/configui/app/util/types.d.ts +0 -65
  129. package/homebridge-ui/configui/app/util/types.d.ts.map +0 -1
  130. package/homebridge-ui/configui/app/util/types.js +0 -18
  131. package/homebridge-ui/configui/app/util/types.js.map +0 -1
  132. package/homebridge-ui/public/3rdpartylicenses.txt +0 -561
  133. package/homebridge-ui/public/assets/devices/homebase2_large.jpg +0 -0
  134. package/homebridge-ui/public/assets/devices/homebase3_large.jpg +0 -0
  135. package/homebridge-ui/public/assets/images/homebridge-eufy-security.png +0 -0
  136. package/homebridge-ui/public/favicon.ico +0 -0
  137. package/homebridge-ui/public/main.f6423287e0411c87.js +0 -1
  138. package/homebridge-ui/public/polyfills.efa2f09ba3e49167.js +0 -1
  139. package/homebridge-ui/public/runtime.ccde331d62c423b3.js +0 -1
  140. package/homebridge-ui/public/styles.13e635bf7a488639.css +0 -5
  141. package/homebridge-ui/server.d.ts +0 -2
  142. package/homebridge-ui/server.d.ts.map +0 -1
  143. package/homebridge-ui/server.js.map +0 -1
  144. package/homebridge-ui/version.d.ts +0 -2
  145. package/homebridge-ui/version.d.ts.map +0 -1
  146. package/homebridge-ui/version.js +0 -5
  147. package/homebridge-ui/version.js.map +0 -1
@@ -0,0 +1,705 @@
1
+ /* ===== Eufy Security Plugin - Custom UI Styles ===== */
2
+ /* Bootstrap 5 is auto-injected by Homebridge UI */
3
+
4
+ :root {
5
+ --eufy-primary: #2d6ff7;
6
+ --eufy-primary-hover: #1a5ae0;
7
+ --eufy-success: #28a745;
8
+ --eufy-danger: #dc3545;
9
+ --eufy-warning: #ffc107;
10
+ --eufy-muted: #6c757d;
11
+ --eufy-card-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
12
+ --eufy-card-hover-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
13
+ --eufy-border-radius: 12px;
14
+ --eufy-transition: all 0.2s ease;
15
+ }
16
+
17
+ /* ===== Layout ===== */
18
+ #app {
19
+ max-width: 960px;
20
+ margin: 0 auto;
21
+ padding: 0 12px;
22
+ }
23
+
24
+ /* ===== Header ===== */
25
+ .eufy-header {
26
+ display: flex;
27
+ align-items: center;
28
+ justify-content: space-between;
29
+ padding: 16px 0;
30
+ margin-bottom: 8px;
31
+ border-bottom: 1px solid rgba(0, 0, 0, 0.08);
32
+ }
33
+
34
+ .eufy-header h4 {
35
+ margin: 0;
36
+ font-weight: 600;
37
+ font-size: 1.25rem;
38
+ }
39
+
40
+ .eufy-header__right {
41
+ display: flex;
42
+ align-items: center;
43
+ gap: 12px;
44
+ }
45
+
46
+ .eufy-cache-date {
47
+ font-size: 0.75rem;
48
+ color: #888;
49
+ white-space: nowrap;
50
+ }
51
+
52
+ .eufy-header .btn-group .btn {
53
+ padding: 6px 10px;
54
+ font-size: 0.85rem;
55
+ }
56
+
57
+ /* ===== Device Cards ===== */
58
+ .device-card {
59
+ border: 1px solid rgba(0, 0, 0, 0.1);
60
+ border-radius: var(--eufy-border-radius);
61
+ box-shadow: var(--eufy-card-shadow);
62
+ transition: var(--eufy-transition);
63
+ cursor: pointer;
64
+ overflow: hidden;
65
+ height: 100%;
66
+ background: var(--bs-body-bg, #fff);
67
+ }
68
+
69
+ .device-card:hover:not(.device-card--disabled) {
70
+ box-shadow: var(--eufy-card-hover-shadow);
71
+ transform: translateY(-2px);
72
+ }
73
+
74
+ .device-card--unsupported {
75
+ opacity: 0.5;
76
+ cursor: pointer;
77
+ }
78
+
79
+ /* ===== Unsupported Detail View ===== */
80
+ .unsupported-detail {
81
+ padding: 16px 0;
82
+ }
83
+
84
+ .unsupported-detail__table {
85
+ width: 100%;
86
+ font-size: 0.85rem;
87
+ margin: 16px 0;
88
+ border-collapse: collapse;
89
+ }
90
+
91
+ .unsupported-detail__table td {
92
+ padding: 8px 12px;
93
+ border-bottom: 1px solid rgba(0, 0, 0, 0.06);
94
+ }
95
+
96
+ .unsupported-detail__table td:first-child {
97
+ font-weight: 600;
98
+ width: 40%;
99
+ color: var(--eufy-muted);
100
+ }
101
+
102
+ .unsupported-detail__steps {
103
+ margin-top: 20px;
104
+ }
105
+
106
+ .unsupported-stepper {
107
+ display: flex;
108
+ align-items: center;
109
+ justify-content: center;
110
+ gap: 0;
111
+ margin-bottom: 14px;
112
+ }
113
+
114
+ .unsupported-stepper__step {
115
+ display: flex;
116
+ flex-direction: column;
117
+ align-items: center;
118
+ gap: 4px;
119
+ flex: 0 0 auto;
120
+ }
121
+
122
+ .unsupported-stepper__circle {
123
+ width: 28px;
124
+ height: 28px;
125
+ border-radius: 50%;
126
+ color: #fff;
127
+ display: flex;
128
+ align-items: center;
129
+ justify-content: center;
130
+ font-size: 0.78rem;
131
+ font-weight: 700;
132
+ background: var(--eufy-primary);
133
+ }
134
+
135
+ .unsupported-stepper__circle--success {
136
+ background: var(--bs-success, #198754);
137
+ }
138
+
139
+ .unsupported-stepper__circle--primary {
140
+ background: var(--bs-primary, #0d6efd);
141
+ }
142
+
143
+ .unsupported-stepper__circle--danger {
144
+ background: var(--bs-danger, #dc3545);
145
+ }
146
+
147
+ .unsupported-stepper__label {
148
+ font-size: 0.72rem;
149
+ font-weight: 600;
150
+ color: var(--eufy-muted);
151
+ text-transform: uppercase;
152
+ letter-spacing: 0.03em;
153
+ }
154
+
155
+ .unsupported-stepper__line {
156
+ flex: 1;
157
+ height: 2px;
158
+ background: var(--eufy-border, #dee2e6);
159
+ margin: 0 8px;
160
+ align-self: flex-start;
161
+ margin-top: 13px;
162
+ }
163
+
164
+ .unsupported-detail__actions {
165
+ display: flex;
166
+ gap: 12px;
167
+ }
168
+
169
+ .unsupported-detail__actions .btn {
170
+ flex: 1;
171
+ text-align: center;
172
+ }
173
+
174
+ .unsupported-detail__info {
175
+ font-size: 0.82rem;
176
+ padding: 12px 14px;
177
+ margin: 16px 0;
178
+ background: rgba(45, 111, 247, 0.06);
179
+ border-left: 3px solid var(--eufy-primary);
180
+ border-radius: 4px;
181
+ line-height: 1.6;
182
+ }
183
+
184
+ .unsupported-detail__info a {
185
+ color: var(--eufy-primary);
186
+ }
187
+
188
+ .unsupported-detail__dump-wrap {
189
+ position: relative;
190
+ }
191
+
192
+ .unsupported-detail__copy-btn {
193
+ position: absolute;
194
+ top: 8px;
195
+ right: 8px;
196
+ padding: 3px 10px;
197
+ font-size: 0.72rem;
198
+ border: 1px solid rgba(0, 0, 0, 0.15);
199
+ border-radius: 6px;
200
+ background: var(--bs-body-bg, #fff);
201
+ color: var(--eufy-muted);
202
+ cursor: pointer;
203
+ transition: var(--eufy-transition);
204
+ z-index: 1;
205
+ }
206
+
207
+ .unsupported-detail__copy-btn:hover {
208
+ border-color: var(--eufy-primary);
209
+ color: var(--eufy-primary);
210
+ }
211
+
212
+ .unsupported-detail__dump {
213
+ background: rgba(0, 0, 0, 0.04);
214
+ border: 1px solid rgba(0, 0, 0, 0.1);
215
+ border-radius: 8px;
216
+ padding: 12px 16px;
217
+ font-size: 0.78rem;
218
+ max-height: 100px;
219
+ overflow-y: auto;
220
+ white-space: pre-wrap;
221
+ word-break: break-word;
222
+ margin-bottom: 8px;
223
+ }
224
+
225
+ .device-card--ignored {
226
+ opacity: 0.6;
227
+ }
228
+
229
+ .device-card__image-wrap {
230
+ display: flex;
231
+ align-items: center;
232
+ justify-content: center;
233
+ padding: 16px 16px 8px;
234
+ height: 120px;
235
+ }
236
+
237
+ .device-card__image-wrap img {
238
+ max-height: 100%;
239
+ max-width: 100%;
240
+ object-fit: contain;
241
+ }
242
+
243
+ .device-card__body {
244
+ padding: 8px 16px 14px;
245
+ }
246
+
247
+ .device-card__name {
248
+ font-weight: 600;
249
+ font-size: 0.9rem;
250
+ margin-bottom: 4px;
251
+ white-space: nowrap;
252
+ overflow: hidden;
253
+ text-overflow: ellipsis;
254
+ }
255
+
256
+ .device-card__meta {
257
+ font-size: 0.75rem;
258
+ color: var(--eufy-muted);
259
+ margin-bottom: 8px;
260
+ }
261
+
262
+ .device-card__footer {
263
+ display: flex;
264
+ align-items: center;
265
+ justify-content: space-between;
266
+ padding: 0 16px 12px;
267
+ }
268
+
269
+ /* ===== Badges ===== */
270
+ .badge-unsupported {
271
+ font-size: 0.7rem;
272
+ background-color: var(--eufy-warning) !important;
273
+ color: #000;
274
+ }
275
+
276
+ /* ===== Toggle Switch ===== */
277
+ .eufy-toggle {
278
+ display: flex;
279
+ align-items: center;
280
+ justify-content: space-between;
281
+ padding: 12px 0;
282
+ border-bottom: 1px solid rgba(0, 0, 0, 0.06);
283
+ }
284
+
285
+ .eufy-toggle:last-child {
286
+ border-bottom: none;
287
+ }
288
+
289
+ .eufy-toggle__label {
290
+ display: flex;
291
+ align-items: center;
292
+ gap: 8px;
293
+ font-size: 0.9rem;
294
+ font-weight: 500;
295
+ }
296
+
297
+ .eufy-toggle__help {
298
+ display: inline-flex;
299
+ align-items: center;
300
+ justify-content: center;
301
+ width: 18px;
302
+ height: 18px;
303
+ border-radius: 50%;
304
+ background: rgba(0, 0, 0, 0.08);
305
+ color: var(--eufy-muted);
306
+ font-size: 0.65rem;
307
+ cursor: help;
308
+ font-weight: 700;
309
+ flex-shrink: 0;
310
+ }
311
+
312
+ /* ===== Discovery / Loading ===== */
313
+ .discovery-screen {
314
+ text-align: center;
315
+ padding: 60px 20px;
316
+ }
317
+
318
+ .discovery-screen__icon {
319
+ font-size: 3rem;
320
+ margin-bottom: 16px;
321
+ animation: pulse 2s ease-in-out infinite;
322
+ }
323
+
324
+ .discovery-screen__title {
325
+ font-size: 1.2rem;
326
+ font-weight: 600;
327
+ margin-bottom: 8px;
328
+ }
329
+
330
+ .discovery-screen__subtitle {
331
+ color: var(--eufy-muted);
332
+ font-size: 0.9rem;
333
+ margin-bottom: 24px;
334
+ }
335
+
336
+ @keyframes pulse {
337
+ 0%, 100% { opacity: 1; transform: scale(1); }
338
+ 50% { opacity: 0.6; transform: scale(1.05); }
339
+ }
340
+
341
+ /* ===== Login ===== */
342
+ .login-card {
343
+ margin: 0px auto;
344
+ }
345
+
346
+ .login-card .card {
347
+ border-radius: var(--eufy-border-radius);
348
+ box-shadow: var(--eufy-card-shadow);
349
+ border: 1px solid rgba(0, 0, 0, 0.1);
350
+ }
351
+
352
+ .login-card .card-header {
353
+ background: transparent;
354
+ border-bottom: 1px solid rgba(0, 0, 0, 0.06);
355
+ font-weight: 600;
356
+ padding: 16px 20px;
357
+ }
358
+
359
+ .login-card .card-body {
360
+ padding: 24px 20px;
361
+ }
362
+
363
+ .login-step-indicator {
364
+ display: flex;
365
+ justify-content: center;
366
+ gap: 8px;
367
+ margin-bottom: 20px;
368
+ }
369
+
370
+ .login-step-dot {
371
+ width: 8px;
372
+ height: 8px;
373
+ border-radius: 50%;
374
+ background: rgba(0, 0, 0, 0.15);
375
+ transition: var(--eufy-transition);
376
+ }
377
+
378
+ .login-step-dot--active {
379
+ background: var(--eufy-primary);
380
+ width: 24px;
381
+ border-radius: 4px;
382
+ }
383
+
384
+ .login-step-dot--done {
385
+ background: var(--eufy-success);
386
+ }
387
+
388
+ /* ===== Detail View ===== */
389
+ .detail-header {
390
+ display: flex;
391
+ align-items: center;
392
+ gap: 16px;
393
+ padding: 16px 0;
394
+ margin-bottom: 8px;
395
+ border-bottom: 1px solid rgba(0, 0, 0, 0.08);
396
+ }
397
+
398
+ .detail-header__image {
399
+ width: 64px;
400
+ height: 64px;
401
+ object-fit: contain;
402
+ }
403
+
404
+ .detail-header__info h5 {
405
+ margin: 0 0 4px;
406
+ font-weight: 600;
407
+ }
408
+
409
+ .detail-header__info small {
410
+ color: var(--eufy-muted);
411
+ }
412
+
413
+ .detail-section {
414
+ margin-bottom: 16px;
415
+ }
416
+
417
+ .detail-section__title {
418
+ font-size: 0.8rem;
419
+ text-transform: uppercase;
420
+ letter-spacing: 0.5px;
421
+ color: var(--eufy-muted);
422
+ font-weight: 600;
423
+ margin-bottom: 4px;
424
+ padding: 8px 0;
425
+ }
426
+
427
+ /* ===== Advanced Toggle ===== */
428
+ .advanced-toggle {
429
+ display: flex;
430
+ align-items: center;
431
+ gap: 6px;
432
+ color: var(--eufy-muted);
433
+ cursor: pointer;
434
+ font-size: 0.85rem;
435
+ padding: 12px 0;
436
+ border: none;
437
+ background: none;
438
+ width: 100%;
439
+ text-align: left;
440
+ }
441
+
442
+ .advanced-toggle:hover {
443
+ color: var(--eufy-primary);
444
+ }
445
+
446
+ .advanced-toggle__chevron {
447
+ transition: transform 0.2s;
448
+ font-size: 0.7rem;
449
+ }
450
+
451
+ .advanced-toggle__chevron--open {
452
+ transform: rotate(90deg);
453
+ }
454
+
455
+ /* ===== Settings ===== */
456
+ .settings-section {
457
+ padding: 16px 0;
458
+ border-bottom: 1px solid rgba(0, 0, 0, 0.06);
459
+ }
460
+
461
+ .settings-section:last-child {
462
+ border-bottom: none;
463
+ }
464
+
465
+ .settings-btn-row {
466
+ display: flex;
467
+ flex-wrap: wrap;
468
+ gap: 8px;
469
+ padding: 12px 0;
470
+ }
471
+
472
+ /* ===== Guard Modes ===== */
473
+ .guard-mode-grid {
474
+ display: grid;
475
+ grid-template-columns: 1fr 1fr;
476
+ gap: 12px;
477
+ }
478
+
479
+ .guard-mode-grid .form-group label {
480
+ font-size: 0.85rem;
481
+ font-weight: 500;
482
+ margin-bottom: 4px;
483
+ }
484
+
485
+ .guard-mode-grid .form-control,
486
+ .guard-mode-grid .form-select {
487
+ font-size: 0.85rem;
488
+ }
489
+
490
+ /* ===== Welcome Banner ===== */
491
+ .welcome-banner {
492
+ text-align: center;
493
+ padding: 24px 20px 16px;
494
+ }
495
+
496
+ .welcome-banner__title {
497
+ font-size: 1.1rem;
498
+ font-weight: 600;
499
+ margin-bottom: 8px;
500
+ }
501
+
502
+ .welcome-banner__text {
503
+ color: var(--eufy-muted);
504
+ font-size: 0.85rem;
505
+ line-height: 1.5;
506
+ max-width: 360px;
507
+ margin: 0 auto;
508
+ }
509
+
510
+ /* ===== Alert overrides ===== */
511
+ .alert-admin {
512
+ border-radius: var(--eufy-border-radius);
513
+ }
514
+
515
+ /* ===== Node.js Version Warning Banner ===== */
516
+ .node-version-banner {
517
+ display: flex;
518
+ align-items: flex-start;
519
+ gap: 12px;
520
+ padding: 14px 16px;
521
+ margin-bottom: 16px;
522
+ background: #fff3cd;
523
+ border: 1px solid #ffc107;
524
+ border-radius: var(--eufy-border-radius);
525
+ font-size: 0.85rem;
526
+ line-height: 1.5;
527
+ }
528
+
529
+ .node-version-banner__icon {
530
+ font-size: 1.3rem;
531
+ flex-shrink: 0;
532
+ margin-top: 1px;
533
+ }
534
+
535
+ .node-version-banner__content > strong {
536
+ display: block;
537
+ margin-bottom: 4px;
538
+ color: #664d03;
539
+ }
540
+
541
+ .node-version-banner__text {
542
+ color: #664d03;
543
+ }
544
+
545
+ .node-version-banner__text code {
546
+ background: rgba(0, 0, 0, 0.08);
547
+ padding: 1px 4px;
548
+ border-radius: 3px;
549
+ font-size: 0.8rem;
550
+ }
551
+
552
+ .node-version-banner__text a {
553
+ color: #664d03;
554
+ font-weight: 500;
555
+ }
556
+
557
+ /* ===== Number Input ===== */
558
+ .number-input-group {
559
+ display: flex;
560
+ align-items: center;
561
+ gap: 4px;
562
+ }
563
+
564
+ .number-input-group .btn {
565
+ padding: 4px 10px;
566
+ font-size: 0.85rem;
567
+ line-height: 1;
568
+ }
569
+
570
+ .number-input-group input {
571
+ width: 70px;
572
+ text-align: center;
573
+ font-size: 0.85rem;
574
+ }
575
+
576
+ /* ===== Progress bar for log download ===== */
577
+ .log-progress {
578
+ margin-top: 12px;
579
+ }
580
+
581
+ .log-progress .progress {
582
+ height: 8px;
583
+ border-radius: 4px;
584
+ }
585
+
586
+ /* ===== Responsive ===== */
587
+ @media (max-width: 576px) {
588
+ .guard-mode-grid {
589
+ grid-template-columns: 1fr;
590
+ }
591
+
592
+ .device-card__image-wrap {
593
+ height: 90px;
594
+ padding: 12px 12px 4px;
595
+ }
596
+ }
597
+
598
+ /* ===== Dark mode support ===== */
599
+ /* Homebridge UI applies .dark-mode on the body inside the plugin iframe */
600
+ body.dark-mode {
601
+ --eufy-card-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
602
+ --eufy-card-hover-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
603
+ --eufy-muted: #9ea7b3;
604
+ }
605
+
606
+ body.dark-mode .device-card {
607
+ border-color: rgba(255, 255, 255, 0.08);
608
+ background: rgba(255, 255, 255, 0.05);
609
+ }
610
+
611
+ body.dark-mode .device-card:hover:not(.device-card--disabled) {
612
+ box-shadow: var(--eufy-card-hover-shadow);
613
+ }
614
+
615
+ body.dark-mode .eufy-header {
616
+ border-bottom-color: rgba(255, 255, 255, 0.1);
617
+ }
618
+
619
+ body.dark-mode .eufy-toggle {
620
+ border-bottom-color: rgba(255, 255, 255, 0.08);
621
+ }
622
+
623
+ body.dark-mode .eufy-toggle__help {
624
+ background: rgba(255, 255, 255, 0.1);
625
+ color: rgba(255, 255, 255, 0.5);
626
+ }
627
+
628
+ body.dark-mode .detail-header {
629
+ border-bottom-color: rgba(255, 255, 255, 0.1);
630
+ }
631
+
632
+ body.dark-mode .login-card .card {
633
+ border-color: rgba(255, 255, 255, 0.1);
634
+ background: rgba(255, 255, 255, 0.05);
635
+ }
636
+
637
+ body.dark-mode .login-card .card-header {
638
+ border-bottom-color: rgba(255, 255, 255, 0.08);
639
+ }
640
+
641
+ body.dark-mode .login-step-dot {
642
+ background: rgba(255, 255, 255, 0.2);
643
+ }
644
+
645
+ body.dark-mode .settings-section {
646
+ border-bottom-color: rgba(255, 255, 255, 0.08);
647
+ }
648
+
649
+ body.dark-mode .advanced-toggle {
650
+ color: rgba(255, 255, 255, 0.5);
651
+ }
652
+
653
+ body.dark-mode .advanced-toggle:hover {
654
+ color: var(--eufy-primary);
655
+ }
656
+
657
+ body.dark-mode .device-card__meta {
658
+ color: var(--eufy-muted);
659
+ }
660
+
661
+ body.dark-mode .detail-header__info small {
662
+ color: var(--eufy-muted);
663
+ }
664
+
665
+ body.dark-mode .detail-section__title {
666
+ color: var(--eufy-muted);
667
+ }
668
+
669
+ body.dark-mode .welcome-banner__text {
670
+ color: var(--eufy-muted);
671
+ }
672
+
673
+ body.dark-mode .discovery-screen__subtitle {
674
+ color: var(--eufy-muted);
675
+ }
676
+
677
+ body.dark-mode .discovery-screen__title {
678
+ color: rgba(255, 255, 255, 0.9);
679
+ }
680
+
681
+ body.dark-mode .discovery-screen .text-muted {
682
+ color: var(--eufy-muted) !important;
683
+ }
684
+
685
+ body.dark-mode .node-version-banner {
686
+ background: rgba(255, 193, 7, 0.12);
687
+ border-color: rgba(255, 193, 7, 0.3);
688
+ }
689
+
690
+ body.dark-mode .node-version-banner__content strong {
691
+ color: #ffda6a;
692
+ }
693
+
694
+ body.dark-mode .node-version-banner__text {
695
+ color: #ffe69c;
696
+ }
697
+
698
+ body.dark-mode .node-version-banner__text code {
699
+ background: rgba(255, 255, 255, 0.1);
700
+ color: #ffe69c;
701
+ }
702
+
703
+ body.dark-mode .node-version-banner__text a {
704
+ color: #ffda6a;
705
+ }