@homebridge-plugins/homebridge-eufy-security 4.7.2 → 5.0.0-beta.1
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.
- package/AUTHORS +4 -0
- package/CODE_OF_CONDUCT.md +30 -0
- package/CONTRIBUTING.md +77 -0
- package/README.md +152 -49
- package/SECURITY.md +30 -0
- package/config.schema.json +92 -3
- package/dist/account/ownership.js +290 -0
- package/dist/account/ownership.js.map +1 -0
- package/dist/account/persistence.js +274 -0
- package/dist/account/persistence.js.map +1 -0
- package/dist/account/temporary-authentication.js +348 -0
- package/dist/account/temporary-authentication.js.map +1 -0
- package/dist/configuration.js +167 -0
- package/dist/configuration.js.map +1 -0
- package/dist/device/member-evidence.js +66 -0
- package/dist/device/member-evidence.js.map +1 -0
- package/dist/device/member-trust.js +114 -0
- package/dist/device/member-trust.js.map +1 -0
- package/dist/device/snapshot.js +190 -0
- package/dist/device/snapshot.js.map +1 -0
- package/dist/diagnostics.js +2218 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/homekit/adapter.js +2 -0
- package/dist/homekit/adapter.js.map +1 -0
- package/dist/homekit/adapters/battery.js +208 -0
- package/dist/homekit/adapters/battery.js.map +1 -0
- package/dist/homekit/adapters/camera-controls.js +527 -0
- package/dist/homekit/adapters/camera-controls.js.map +1 -0
- package/dist/homekit/adapters/camera-streaming.js +1515 -0
- package/dist/homekit/adapters/camera-streaming.js.map +1 -0
- package/dist/homekit/adapters/contact.js +138 -0
- package/dist/homekit/adapters/contact.js.map +1 -0
- package/dist/homekit/adapters/doorbell.js +57 -0
- package/dist/homekit/adapters/doorbell.js.map +1 -0
- package/dist/homekit/adapters/information.js +55 -0
- package/dist/homekit/adapters/information.js.map +1 -0
- package/dist/homekit/adapters/lock.js +489 -0
- package/dist/homekit/adapters/lock.js.map +1 -0
- package/dist/homekit/adapters/motion.js +100 -0
- package/dist/homekit/adapters/motion.js.map +1 -0
- package/dist/homekit/adapters/registry.js +26 -0
- package/dist/homekit/adapters/registry.js.map +1 -0
- package/dist/homekit/adapters/security-system.js +425 -0
- package/dist/homekit/adapters/security-system.js.map +1 -0
- package/dist/homekit/adapters/siren.js +136 -0
- package/dist/homekit/adapters/siren.js.map +1 -0
- package/dist/homekit/adapters/smart-light.js +662 -0
- package/dist/homekit/adapters/smart-light.js.map +1 -0
- package/dist/homekit/coverage-matrix.js +119 -0
- package/dist/homekit/coverage-matrix.js.map +1 -0
- package/dist/homekit/device-control.js +175 -0
- package/dist/homekit/device-control.js.map +1 -0
- package/dist/homekit/reconciler.js +319 -0
- package/dist/homekit/reconciler.js.map +1 -0
- package/dist/homekit/representation.js +23 -0
- package/dist/homekit/representation.js.map +1 -0
- package/dist/index.js +4 -9
- package/dist/index.js.map +1 -1
- package/dist/media/contracts.js +2 -0
- package/dist/media/contracts.js.map +1 -0
- package/dist/media/last-successful-image.js +208 -0
- package/dist/media/last-successful-image.js.map +1 -0
- package/dist/media/live-stream.js +1003 -0
- package/dist/media/live-stream.js.map +1 -0
- package/dist/media/recording.js +560 -0
- package/dist/media/recording.js.map +1 -0
- package/dist/media/session-budget.js +39 -0
- package/dist/media/session-budget.js.map +1 -0
- package/dist/media/snapshot.js +406 -0
- package/dist/media/snapshot.js.map +1 -0
- package/dist/media/station-live-sessions.js +101 -0
- package/dist/media/station-live-sessions.js.map +1 -0
- package/dist/platform.js +97 -809
- package/dist/platform.js.map +1 -1
- package/dist/runtime/channel.js +375 -0
- package/dist/runtime/channel.js.map +1 -0
- package/dist/runtime/owner.js +682 -0
- package/dist/runtime/owner.js.map +1 -0
- package/dist/runtime/sdk-client.js +211 -0
- package/dist/runtime/sdk-client.js.map +1 -0
- package/dist/runtime/tracker.js +211 -0
- package/dist/runtime/tracker.js.map +1 -0
- package/dist/settings.js +1 -43
- package/dist/settings.js.map +1 -1
- package/dist/storage.js +59 -0
- package/dist/storage.js.map +1 -0
- package/dist/ui/dashboard.js +181 -0
- package/dist/ui/dashboard.js.map +1 -0
- package/dist/ui/device-image.js +22 -0
- package/dist/ui/device-image.js.map +1 -0
- package/dist/ui/runtime-channel-client.js +305 -0
- package/dist/ui/runtime-channel-client.js.map +1 -0
- package/dist/ui/server.js +259 -0
- package/dist/ui/server.js.map +1 -0
- package/homebridge-ui/public/app.css +1902 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T1250.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2070.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2080.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2081.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2103.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2117.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2118.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2119.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T211A.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2120.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2123.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2128.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2130.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2132.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2150.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2181.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2182.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2190.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2192.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2193.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2194.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2210.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2250.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2251.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2252.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2253.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2254.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2255.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2256.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2257.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2258.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2259.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2261.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2262.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2266.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2267.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2268.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2270.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2272.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2273.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2276.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2277.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2278.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2280.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2292.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2320.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2351.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2352.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2353.webp +0 -0
- package/homebridge-ui/public/assets/devices/life/life-T8L00.webp +0 -0
- package/homebridge-ui/public/assets/devices/life/life-T8L01.webp +0 -0
- package/homebridge-ui/public/assets/devices/life/life-T8L02.webp +0 -0
- package/homebridge-ui/public/assets/devices/life/life-T8L04.webp +0 -0
- package/homebridge-ui/public/assets/devices/life/life-T8L10.webp +0 -0
- package/homebridge-ui/public/assets/devices/life/life-T8L20.webp +0 -0
- package/homebridge-ui/public/assets/devices/life/life-T8L30.webp +0 -0
- package/homebridge-ui/public/assets/devices/life/life-T8L40.webp +0 -0
- package/homebridge-ui/public/assets/devices/mower/mower-T2801.webp +0 -0
- package/homebridge-ui/public/assets/devices/mower/mower-T280B.webp +0 -0
- package/homebridge-ui/public/assets/devices/mower/mower-T2880.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T7400.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T7401.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8001.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8002.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8010.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8021.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8023.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8025.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8030.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8110.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8111.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8112.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8113.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8114.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8122.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8123.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8124.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8130.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8131.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8134.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8140.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8141.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8150.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8151.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8152.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8153.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8160.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8161.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8162.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8170.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8171.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8172.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8173.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8200.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8200X.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8201.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8203.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8210.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8213.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8214.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8222.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8400.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8401.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8410.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8411.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8414.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8416.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8417.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8419.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8419N.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8420.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8420X.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8422.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8423.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8424.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8425.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8441.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8442.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8452.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T84A0.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T84A1.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8500.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8502.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8503.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8504.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8506.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8510.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8510P.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8520.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8520P.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8530.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8531.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T85D0.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T85L0.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T85P0.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T85V0.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8600.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T86P2.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8790.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T87B0.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T87B2.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8900.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8910.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8920.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8960.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8B0.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8E00.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8N00.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8W11C.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T90F0.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T90M0.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T90R0.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T90S0.webp +0 -0
- package/homebridge-ui/public/assets/icons/inventory.svg +1 -1
- package/homebridge-ui/public/assets/icons/troubleshoot.svg +1 -0
- package/homebridge-ui/public/assets/icons/warning.svg +1 -1
- package/homebridge-ui/public/assets/logo-dark.svg +10 -0
- package/homebridge-ui/public/assets/logo.svg +10 -0
- package/homebridge-ui/public/i18n/en.json +218 -0
- package/homebridge-ui/public/i18n/fr.json +218 -0
- package/homebridge-ui/public/index.html +377 -28
- package/homebridge-ui/public/js/app.js +1065 -0
- package/homebridge-ui/public/js/dashboard.js +385 -0
- package/homebridge-ui/public/js/legacy-settings.js +37 -0
- package/homebridge-ui/public/js/profile-wizard.js +68 -0
- package/homebridge-ui/server.js +2 -1393
- package/i18n/runtime/en.json +100 -0
- package/media/Snapshot-Unavailable.jpg +0 -0
- package/media/Snapshot-black.jpg +0 -0
- package/media/camera-disabled.jpg +0 -0
- package/media/camera-offline.jpg +0 -0
- package/package.json +29 -24
- package/.claude/CLAUDE.md +0 -175
- package/.claude/PRD.md +0 -241
- package/.claude/docs/debug-recording-lessons.md +0 -91
- package/.claude/docs/hksv-recording-fix.md +0 -160
- package/.claude/skills/architect/SKILL.md +0 -76
- package/.claude/skills/developer/SKILL.md +0 -59
- package/.claude/skills/new-device-support/SKILL.md +0 -212
- package/.claude/skills/new-device-support/check-device.mjs +0 -363
- package/.claude/skills/new-device-support/map-properties.mjs +0 -450
- package/.claude/skills/new-device-support/verify-device.mjs +0 -272
- package/.claude/skills/planner/SKILL.md +0 -100
- package/.claude/skills/qa/SKILL.md +0 -79
- package/.claude/skills/support/SKILL.md +0 -175
- package/.prettierignore +0 -7
- package/.prettierrc.json +0 -7
- package/FUNDING.yml +0 -1
- package/dist/accessories/AutoSyncStationAccessory.js +0 -157
- package/dist/accessories/AutoSyncStationAccessory.js.map +0 -1
- package/dist/accessories/BaseAccessory.js +0 -261
- package/dist/accessories/BaseAccessory.js.map +0 -1
- package/dist/accessories/CameraAccessory.js +0 -459
- package/dist/accessories/CameraAccessory.js.map +0 -1
- package/dist/accessories/Device.js +0 -65
- package/dist/accessories/Device.js.map +0 -1
- package/dist/accessories/EntrySensorAccessory.js +0 -48
- package/dist/accessories/EntrySensorAccessory.js.map +0 -1
- package/dist/accessories/GarageDoorAccessory.js +0 -160
- package/dist/accessories/GarageDoorAccessory.js.map +0 -1
- package/dist/accessories/LockAccessory.js +0 -142
- package/dist/accessories/LockAccessory.js.map +0 -1
- package/dist/accessories/MotionSensorAccessory.js +0 -48
- package/dist/accessories/MotionSensorAccessory.js.map +0 -1
- package/dist/accessories/SmartDropAccessory.js +0 -141
- package/dist/accessories/SmartDropAccessory.js.map +0 -1
- package/dist/accessories/StationAccessory.js +0 -373
- package/dist/accessories/StationAccessory.js.map +0 -1
- package/dist/config.js +0 -26
- package/dist/config.js.map +0 -1
- package/dist/controller/DebugRecordingManager.js +0 -402
- package/dist/controller/DebugRecordingManager.js.map +0 -1
- package/dist/controller/LocalLivestreamManager.js +0 -371
- package/dist/controller/LocalLivestreamManager.js.map +0 -1
- package/dist/controller/recordingDelegate.js +0 -252
- package/dist/controller/recordingDelegate.js.map +0 -1
- package/dist/controller/snapshotDelegate.js +0 -348
- package/dist/controller/snapshotDelegate.js.map +0 -1
- package/dist/controller/streamingDelegate.js +0 -389
- package/dist/controller/streamingDelegate.js.map +0 -1
- package/dist/interfaces.js +0 -2
- package/dist/interfaces.js.map +0 -1
- package/dist/media/Snapshot-Unavailable.png +0 -0
- package/dist/media/Snapshot-Unavailable.xcf +0 -0
- package/dist/media/Snapshot-black.png +0 -0
- package/dist/media/camera-disabled.png +0 -0
- package/dist/media/camera-offline.png +0 -0
- package/dist/media/media/Snapshot-Unavailable.png +0 -0
- package/dist/media/media/Snapshot-Unavailable.xcf +0 -0
- package/dist/media/media/Snapshot-black.png +0 -0
- package/dist/media/media/camera-disabled.png +0 -0
- package/dist/media/media/camera-offline.png +0 -0
- package/dist/utils/Talkback.js +0 -162
- package/dist/utils/Talkback.js.map +0 -1
- package/dist/utils/accessoriesStore.js +0 -210
- package/dist/utils/accessoriesStore.js.map +0 -1
- package/dist/utils/configTypes.js +0 -38
- package/dist/utils/configTypes.js.map +0 -1
- package/dist/utils/ffmpeg.js +0 -1111
- package/dist/utils/ffmpeg.js.map +0 -1
- package/dist/utils/interfaces.js +0 -8
- package/dist/utils/interfaces.js.map +0 -1
- package/dist/utils/utils.js +0 -224
- package/dist/utils/utils.js.map +0 -1
- package/dist/version.js +0 -2
- package/dist/version.js.map +0 -1
- package/homebridge-eufy-security.png +0 -0
- package/homebridge-ui/diagnosticsCrypto.js +0 -112
- package/homebridge-ui/public/app.js +0 -237
- package/homebridge-ui/public/assets/devices/4g_lte_cam_s330_large.png +0 -0
- package/homebridge-ui/public/assets/devices/4g_lte_starlight_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/BATTERY_DOORBELL_C30.png +0 -0
- package/homebridge-ui/public/assets/devices/BATTERY_DOORBELL_C31.png +0 -0
- package/homebridge-ui/public/assets/devices/batterydoorbell1080p_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/batterydoorbell2k_large.png +0 -0
- package/homebridge-ui/public/assets/devices/batterydoorbell2kdual_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/batterydoorbell_e340_large.png +0 -0
- package/homebridge-ui/public/assets/devices/eufy-security-client.png +0 -0
- package/homebridge-ui/public/assets/devices/eufyCamS4_large.png +0 -0
- package/homebridge-ui/public/assets/devices/eufycam2_large.png +0 -0
- package/homebridge-ui/public/assets/devices/eufycam2c_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycam2cpro_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycam2pro_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycam3_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycam3c_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycam3pro_large.png +0 -0
- package/homebridge-ui/public/assets/devices/eufycam_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycame330_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/flood_freeze_sensor_e20_t90F0_large.png +0 -0
- package/homebridge-ui/public/assets/devices/floodlight2_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/floodlight2pro_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/floodlight_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/floodlightcame340_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/garage_camera_t8452_large.png +0 -0
- package/homebridge-ui/public/assets/devices/homebase2_large.png +0 -0
- package/homebridge-ui/public/assets/devices/homebase3_large.png +0 -0
- package/homebridge-ui/public/assets/devices/homebase_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/homebasemini_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamC210_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamC220_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamC220_t8419N_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamE30_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamc120_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcammini_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamp24_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcams350_large.png +0 -0
- package/homebridge-ui/public/assets/devices/keypad_large.png +0 -0
- package/homebridge-ui/public/assets/devices/minibase_chime_T8023_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/motionsensor_large.png +0 -0
- package/homebridge-ui/public/assets/devices/nvr_s4_max_T8N00_large.png +0 -0
- package/homebridge-ui/public/assets/devices/pir_sensor_e20_large.png +0 -0
- package/homebridge-ui/public/assets/devices/poe_bullet_ptz_cam_s4_T8E00_large.png +0 -0
- package/homebridge-ui/public/assets/devices/sensor_large.png +0 -0
- package/homebridge-ui/public/assets/devices/siren_sensor_e20_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartdrop_t8790_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t8500_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t8500_wifibridge_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t8503_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t8504_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t8510P_t8520P_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t85D0_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t85L0_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t85P0_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t85V0_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_touch_and_wifi_t8502_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_touch_and_wifi_t8506_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_touch_and_wifi_t8520_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_touch_t8510_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_touch_t8510_wifibridge_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_video_t8530_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_video_t8531_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlockwifibridge_t8021_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/smartsafe_s10_t7400_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartsafe_s12_t7401_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smarttrack_card_t87B2_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smarttrack_link_t87B0_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smoke_alarm_e10_t90S0_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solocamc210_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solocamc35_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solocame20_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solocame30_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solocame40_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solocame42_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solocaml20_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solocams220_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solocams340_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solocams40_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/soloindoorcamc24_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solooutdoorcamc22_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solooutdoorcamc24_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/unknown.png +0 -0
- package/homebridge-ui/public/assets/devices/walllight_s100_large.png +0 -0
- package/homebridge-ui/public/assets/devices/walllight_s120_large.png +0 -0
- package/homebridge-ui/public/assets/devices/water_freeze_sensor_t8920_large.png +0 -0
- package/homebridge-ui/public/assets/devices/wireddoorbell1080p_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/wireddoorbell2k_large.png +0 -0
- package/homebridge-ui/public/assets/devices/wireddoorbelldual_large.jpg +0 -0
- package/homebridge-ui/public/assets/icons/attach.svg +0 -1
- package/homebridge-ui/public/assets/icons/battery_0.svg +0 -1
- package/homebridge-ui/public/assets/icons/battery_1.svg +0 -1
- package/homebridge-ui/public/assets/icons/battery_2.svg +0 -1
- package/homebridge-ui/public/assets/icons/battery_3.svg +0 -1
- package/homebridge-ui/public/assets/icons/battery_4.svg +0 -1
- package/homebridge-ui/public/assets/icons/battery_5.svg +0 -1
- package/homebridge-ui/public/assets/icons/battery_6.svg +0 -1
- package/homebridge-ui/public/assets/icons/copy.svg +0 -1
- package/homebridge-ui/public/assets/icons/delete.svg +0 -1
- package/homebridge-ui/public/assets/icons/download.svg +0 -1
- package/homebridge-ui/public/assets/icons/info.svg +0 -1
- package/homebridge-ui/public/assets/icons/refresh.svg +0 -1
- package/homebridge-ui/public/assets/icons/satellite_alt.svg +0 -1
- package/homebridge-ui/public/assets/icons/solar_power.svg +0 -1
- package/homebridge-ui/public/components/device-card.js +0 -174
- package/homebridge-ui/public/components/guard-modes.js +0 -88
- package/homebridge-ui/public/components/number-input.js +0 -121
- package/homebridge-ui/public/components/select.js +0 -73
- package/homebridge-ui/public/components/toggle.js +0 -68
- package/homebridge-ui/public/services/api.js +0 -250
- package/homebridge-ui/public/services/config.js +0 -144
- package/homebridge-ui/public/style.css +0 -818
- package/homebridge-ui/public/utils/countries.js +0 -73
- package/homebridge-ui/public/utils/device-images.js +0 -102
- package/homebridge-ui/public/utils/helpers.js +0 -115
- package/homebridge-ui/public/views/dashboard.js +0 -226
- package/homebridge-ui/public/views/device-detail.js +0 -654
- package/homebridge-ui/public/views/diagnostics.js +0 -402
- package/homebridge-ui/public/views/login.js +0 -650
- package/homebridge-ui/public/views/recordings.js +0 -319
- package/homebridge-ui/public/views/settings.js +0 -197
- package/homebridge-ui/public/views/unsupported-detail.js +0 -296
- package/media/Snapshot-Unavailable.png +0 -0
- package/media/Snapshot-Unavailable.xcf +0 -0
- package/media/Snapshot-black.png +0 -0
- package/media/camera-disabled.png +0 -0
- package/media/camera-offline.png +0 -0
- package/scripts/decrypt-diagnostics.mjs +0 -257
|
@@ -0,0 +1,1902 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The scales this sheet holds to. A value outside one of them is a defect, not a preference.
|
|
3
|
+
*
|
|
4
|
+
* Spacing is a 4px grid. 2px appears only as an optical nudge, never as a gap or padding step.
|
|
5
|
+
* Radius, edge intensity, text level, and easing are tokens; no rule states one of them as a literal.
|
|
6
|
+
* Weight is 400 body, 500 label, 600 emphasis, 700 heading.
|
|
7
|
+
* Depth is edges. A border carries structure and only a floating layer carries a shadow.
|
|
8
|
+
*/
|
|
9
|
+
:root {
|
|
10
|
+
color-scheme: light dark;
|
|
11
|
+
--accent: #00bfc4;
|
|
12
|
+
--accent-ink: #006f73;
|
|
13
|
+
--on-accent: #07383a;
|
|
14
|
+
--accent-soft: color-mix(in srgb, var(--accent) 12%, var(--panel));
|
|
15
|
+
|
|
16
|
+
/*
|
|
17
|
+
* The four text levels: default, supporting, metadata, and disabled.
|
|
18
|
+
*
|
|
19
|
+
* The supporting and disabled levels are mixed against the panel rather than stated, so a host theme that
|
|
20
|
+
* moves `--bs-body-color` carries all four levels with it. The mix is redeclared in the dark block because a
|
|
21
|
+
* custom property resolves `var()` where it is declared, not where it is used.
|
|
22
|
+
*/
|
|
23
|
+
--ink: var(--bs-body-color, #182033);
|
|
24
|
+
--ink-secondary: color-mix(in srgb, var(--ink) 78%, var(--panel));
|
|
25
|
+
--muted: var(--bs-secondary-color, #667085);
|
|
26
|
+
--ink-disabled: color-mix(in srgb, var(--muted) 55%, var(--panel));
|
|
27
|
+
|
|
28
|
+
--alert: #d99a21;
|
|
29
|
+
--fault: #b42318;
|
|
30
|
+
--ok: #1a7f4b;
|
|
31
|
+
|
|
32
|
+
/*
|
|
33
|
+
* The two edge intensities. `--line` divides and encloses; `--line-strong` is for a control the user must
|
|
34
|
+
* find without looking for it. Both are alpha over the surface, so an edge belongs to whatever it sits on.
|
|
35
|
+
*/
|
|
36
|
+
--line: rgb(23 32 44 / 11%);
|
|
37
|
+
--line-strong: rgb(23 32 44 / 19%);
|
|
38
|
+
|
|
39
|
+
--radius-sm: 4px;
|
|
40
|
+
--radius-control: 8px;
|
|
41
|
+
--radius-card: 12px;
|
|
42
|
+
--radius-panel: 16px;
|
|
43
|
+
--radius-pill: 999px;
|
|
44
|
+
|
|
45
|
+
--focus-ring: 2px solid var(--accent-ink);
|
|
46
|
+
--ease-out: cubic-bezier(0.23, 1, 0.32, 1);
|
|
47
|
+
|
|
48
|
+
/* The one shadow in the sheet, for a layer that floats over content it does not belong to. */
|
|
49
|
+
--shadow-overlay:
|
|
50
|
+
0 0 0 1px rgb(23 32 44 / 6%),
|
|
51
|
+
0 4px 12px rgb(23 32 44 / 10%);
|
|
52
|
+
|
|
53
|
+
--panel: #ffffff;
|
|
54
|
+
--tile-bg: #edf2f7;
|
|
55
|
+
--tile-ink: #17202c;
|
|
56
|
+
--tile-muted: #475569;
|
|
57
|
+
--tile-gradient: rgb(237 242 247 / 94%);
|
|
58
|
+
--tile-stripe: rgb(23 32 44 / 7%);
|
|
59
|
+
--tile-badge-bg: rgb(255 255 255 / 78%);
|
|
60
|
+
--tile-badge-border: rgb(23 32 44 / 28%);
|
|
61
|
+
--tile-badge-halo: rgb(4 8 14 / 85%);
|
|
62
|
+
--tile-image-filter: brightness(0.92) saturate(0.85) contrast(1.05);
|
|
63
|
+
--tile-scene-filter: brightness(0.88) saturate(0.95);
|
|
64
|
+
--tile-scene-gradient: rgb(23 32 44 / 82%);
|
|
65
|
+
|
|
66
|
+
/*
|
|
67
|
+
* The copy over a scene, which does not vary by theme.
|
|
68
|
+
*
|
|
69
|
+
* A product cutout sits on the tile's own surface and takes the theme's ink. A scene is a photograph under a
|
|
70
|
+
* dark gradient in both themes, so the name over it is light in both: taking the theme's ink there would put
|
|
71
|
+
* dark text on a dark photograph every time the interface is in light mode.
|
|
72
|
+
*/
|
|
73
|
+
--tile-scene-ink: #f4f7fb;
|
|
74
|
+
--tile-scene-muted: #d6deea;
|
|
75
|
+
--tile-scene-stripe: rgb(255 255 255 / 12%);
|
|
76
|
+
--tile-disabled-filter: brightness(0.82) grayscale(0.65) contrast(1.05);
|
|
77
|
+
--tile-icon-filter: none;
|
|
78
|
+
--tile-tooltip-bg: #ffffff;
|
|
79
|
+
--tile-tooltip-ink: #17202c;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
html,
|
|
83
|
+
body {
|
|
84
|
+
scrollbar-width: none;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
html::-webkit-scrollbar,
|
|
88
|
+
body::-webkit-scrollbar {
|
|
89
|
+
display: none;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
* {
|
|
93
|
+
box-sizing: border-box;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
body {
|
|
97
|
+
margin: 0;
|
|
98
|
+
overflow-x: hidden;
|
|
99
|
+
background: transparent;
|
|
100
|
+
color: var(--ink);
|
|
101
|
+
font:
|
|
102
|
+
14px/1.5 ui-sans-serif,
|
|
103
|
+
system-ui,
|
|
104
|
+
-apple-system,
|
|
105
|
+
BlinkMacSystemFont,
|
|
106
|
+
'Segoe UI',
|
|
107
|
+
sans-serif;
|
|
108
|
+
-webkit-font-smoothing: antialiased;
|
|
109
|
+
text-rendering: optimizeLegibility;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.shell {
|
|
113
|
+
width: min(100%, 720px);
|
|
114
|
+
height: auto !important;
|
|
115
|
+
max-height: none !important;
|
|
116
|
+
margin: 0 auto;
|
|
117
|
+
overflow: visible !important;
|
|
118
|
+
scrollbar-width: none;
|
|
119
|
+
padding: 4px 0 20px;
|
|
120
|
+
color: var(--ink);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.shell::-webkit-scrollbar {
|
|
124
|
+
display: none;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.masthead {
|
|
128
|
+
display: flex;
|
|
129
|
+
align-items: center;
|
|
130
|
+
gap: 12px;
|
|
131
|
+
margin-bottom: 20px;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.eufy-logo {
|
|
135
|
+
width: 100px;
|
|
136
|
+
flex: 0 0 auto;
|
|
137
|
+
padding: 4px;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.eufy-logo img {
|
|
141
|
+
display: block;
|
|
142
|
+
width: 100%;
|
|
143
|
+
height: 100%;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.eufy-logo .logo-dark {
|
|
147
|
+
display: none;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
h1,
|
|
151
|
+
h2,
|
|
152
|
+
p {
|
|
153
|
+
margin-top: 0;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
h1,
|
|
157
|
+
h2,
|
|
158
|
+
h3 {
|
|
159
|
+
text-wrap: balance;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
p,
|
|
163
|
+
small {
|
|
164
|
+
text-wrap: pretty;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
h1 {
|
|
168
|
+
margin-bottom: 0;
|
|
169
|
+
font-size: clamp(22px, 5vw, 30px);
|
|
170
|
+
line-height: 1.15;
|
|
171
|
+
letter-spacing: -0.035em;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
h2 {
|
|
175
|
+
margin-bottom: 0;
|
|
176
|
+
font-size: 18px;
|
|
177
|
+
line-height: 1.25;
|
|
178
|
+
letter-spacing: -0.01em;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.eyebrow {
|
|
182
|
+
margin-bottom: 4px;
|
|
183
|
+
color: var(--muted);
|
|
184
|
+
font-size: 10px;
|
|
185
|
+
font-weight: 700;
|
|
186
|
+
letter-spacing: 0.11em;
|
|
187
|
+
text-transform: uppercase;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.panel {
|
|
191
|
+
border: 1px solid var(--line);
|
|
192
|
+
border-radius: var(--radius-panel);
|
|
193
|
+
background: var(--panel);
|
|
194
|
+
padding: clamp(16px, 5vw, 32px);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.legacy-notice,
|
|
198
|
+
.update-pending {
|
|
199
|
+
margin-bottom: 16px;
|
|
200
|
+
border: 1px solid var(--line);
|
|
201
|
+
border-radius: var(--radius-panel);
|
|
202
|
+
background: var(--panel);
|
|
203
|
+
padding: clamp(16px, 4vw, 24px);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.dashboard {
|
|
207
|
+
margin: 0;
|
|
208
|
+
border: 0;
|
|
209
|
+
background: transparent;
|
|
210
|
+
padding: 0;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.dashboard-panel {
|
|
214
|
+
display: grid;
|
|
215
|
+
gap: 20px;
|
|
216
|
+
margin: 0;
|
|
217
|
+
border: 0;
|
|
218
|
+
background: transparent;
|
|
219
|
+
padding: 0;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.dashboard-panel-header {
|
|
223
|
+
display: grid;
|
|
224
|
+
grid-template-columns: auto auto minmax(0, 1fr);
|
|
225
|
+
align-items: center;
|
|
226
|
+
gap: 12px;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.dashboard-panel-header > div {
|
|
230
|
+
min-width: 0;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.dashboard-panel-header .summary {
|
|
234
|
+
margin: 4px 0 0;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.dashboard-page-back {
|
|
238
|
+
display: grid;
|
|
239
|
+
width: 40px;
|
|
240
|
+
min-height: 40px;
|
|
241
|
+
place-items: center;
|
|
242
|
+
border: 1px solid var(--line-strong);
|
|
243
|
+
border-radius: var(--radius-control);
|
|
244
|
+
background: var(--panel);
|
|
245
|
+
color: var(--ink);
|
|
246
|
+
padding: 0;
|
|
247
|
+
font-size: 22px;
|
|
248
|
+
line-height: 1;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.dashboard-page-icon {
|
|
252
|
+
width: 24px;
|
|
253
|
+
height: 24px;
|
|
254
|
+
opacity: 0.72;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.diagnostics-panel .summary {
|
|
258
|
+
margin-bottom: 0;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.diagnostics-status {
|
|
262
|
+
margin-bottom: 0;
|
|
263
|
+
color: var(--muted);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.diagnostics-panel select {
|
|
267
|
+
width: 100%;
|
|
268
|
+
min-height: 44px;
|
|
269
|
+
margin-top: 8px;
|
|
270
|
+
border: 1px solid var(--line-strong);
|
|
271
|
+
border-radius: var(--radius-control);
|
|
272
|
+
background: var(--panel);
|
|
273
|
+
color: var(--ink);
|
|
274
|
+
padding: 8px 12px;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.diagnostics-actions {
|
|
278
|
+
margin-top: 4px;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.diagnostics-stage {
|
|
282
|
+
display: grid;
|
|
283
|
+
gap: 12px;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.diagnostics-surface {
|
|
287
|
+
border: 1px solid var(--line);
|
|
288
|
+
border-radius: var(--radius-card);
|
|
289
|
+
background: var(--panel);
|
|
290
|
+
padding: clamp(16px, 4vw, 24px);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.diagnostics-question,
|
|
294
|
+
.diagnostics-direct,
|
|
295
|
+
.diagnostics-frequency,
|
|
296
|
+
.diagnostics-match {
|
|
297
|
+
display: grid;
|
|
298
|
+
gap: 16px;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
.diagnostics-question > strong,
|
|
302
|
+
.diagnostics-frequency > strong,
|
|
303
|
+
.diagnostics-match > strong {
|
|
304
|
+
font-size: clamp(17px, 4vw, 21px);
|
|
305
|
+
line-height: 1.35;
|
|
306
|
+
letter-spacing: -0.01em;
|
|
307
|
+
text-wrap: balance;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.diagnostics-match p {
|
|
311
|
+
margin-bottom: 0;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.diagnostics-choice-actions {
|
|
315
|
+
display: grid;
|
|
316
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
317
|
+
gap: 8px;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.diagnostics-choice-actions button {
|
|
321
|
+
width: 100%;
|
|
322
|
+
padding-inline: 16px;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
button.diagnostics-secondary-action {
|
|
326
|
+
border: 1px solid var(--line-strong);
|
|
327
|
+
background: transparent;
|
|
328
|
+
color: var(--ink);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
button.diagnostics-quiet-action {
|
|
332
|
+
display: inline-flex;
|
|
333
|
+
width: fit-content;
|
|
334
|
+
min-height: 40px;
|
|
335
|
+
align-items: center;
|
|
336
|
+
background: transparent;
|
|
337
|
+
color: var(--muted);
|
|
338
|
+
padding: 0;
|
|
339
|
+
font-size: 12px;
|
|
340
|
+
font-weight: 600;
|
|
341
|
+
text-decoration: underline;
|
|
342
|
+
text-underline-offset: 3px;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.diagnostics-guidance {
|
|
346
|
+
display: grid;
|
|
347
|
+
gap: 12px;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.diagnostics-guidance > div {
|
|
351
|
+
border-top: 1px solid color-mix(in srgb, var(--accent) 28%, var(--line));
|
|
352
|
+
padding-top: 8px;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.diagnostics-guidance p {
|
|
356
|
+
margin-bottom: 0;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.guidance-label {
|
|
360
|
+
display: block;
|
|
361
|
+
margin-bottom: 4px;
|
|
362
|
+
color: var(--accent-ink);
|
|
363
|
+
font-size: 10px;
|
|
364
|
+
font-weight: 700;
|
|
365
|
+
letter-spacing: 0.08em;
|
|
366
|
+
text-transform: uppercase;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
.diagnostics-actions button {
|
|
370
|
+
width: 100%;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.diagnostics-result p {
|
|
374
|
+
margin-bottom: 0;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.diagnostics-privacy {
|
|
378
|
+
color: var(--muted);
|
|
379
|
+
font-size: 12px;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.diagnostics-result {
|
|
383
|
+
display: grid;
|
|
384
|
+
gap: 8px;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.diagnostics-result a {
|
|
388
|
+
display: inline-block;
|
|
389
|
+
margin-top: 8px;
|
|
390
|
+
color: var(--accent-ink);
|
|
391
|
+
font-weight: 600;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
.diagnostics-result button {
|
|
395
|
+
width: 100%;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.diagnostics-manifest {
|
|
399
|
+
margin-top: 12px;
|
|
400
|
+
border-block: 1px solid var(--line);
|
|
401
|
+
padding-block: 8px;
|
|
402
|
+
font-size: 12px;
|
|
403
|
+
font-variant-numeric: tabular-nums;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.diagnostics-manifest ul {
|
|
407
|
+
margin: 8px 0;
|
|
408
|
+
padding-left: 20px;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
.diagnostics-review-confirm {
|
|
412
|
+
display: flex;
|
|
413
|
+
align-items: flex-start;
|
|
414
|
+
gap: 8px;
|
|
415
|
+
margin-top: 12px;
|
|
416
|
+
font-size: 12px;
|
|
417
|
+
cursor: pointer;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.advanced-fields {
|
|
421
|
+
display: grid;
|
|
422
|
+
grid-template-columns: 1fr;
|
|
423
|
+
gap: 20px;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
.advanced-field {
|
|
427
|
+
display: grid;
|
|
428
|
+
align-content: start;
|
|
429
|
+
gap: 8px;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
.advanced-field-label {
|
|
433
|
+
font-weight: 500;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.advanced-fields label {
|
|
437
|
+
display: grid;
|
|
438
|
+
align-content: start;
|
|
439
|
+
gap: 8px;
|
|
440
|
+
font-weight: 500;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.advanced-fields input {
|
|
444
|
+
width: 100%;
|
|
445
|
+
min-height: 44px;
|
|
446
|
+
border: 1px solid var(--line-strong);
|
|
447
|
+
border-radius: var(--radius-control);
|
|
448
|
+
background: var(--panel);
|
|
449
|
+
color: var(--ink);
|
|
450
|
+
padding: 8px 12px;
|
|
451
|
+
font: inherit;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
.advanced-fields small,
|
|
455
|
+
.advanced-device-help {
|
|
456
|
+
color: var(--muted);
|
|
457
|
+
font-size: 12px;
|
|
458
|
+
font-weight: 400;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
.advanced-device-help {
|
|
462
|
+
margin-bottom: 0;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.advanced-status {
|
|
466
|
+
min-height: 20px;
|
|
467
|
+
margin-bottom: 0;
|
|
468
|
+
color: var(--fault);
|
|
469
|
+
font-size: 12px;
|
|
470
|
+
font-weight: 600;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
.legacy-notice,
|
|
474
|
+
.update-pending {
|
|
475
|
+
display: grid;
|
|
476
|
+
grid-template-columns: auto minmax(0, 1fr) auto;
|
|
477
|
+
align-items: center;
|
|
478
|
+
gap: 16px;
|
|
479
|
+
border-left: 4px solid var(--alert);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
.notice-icon,
|
|
483
|
+
.status-icon {
|
|
484
|
+
width: 24px;
|
|
485
|
+
height: 24px;
|
|
486
|
+
opacity: 0.72;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
.legacy-notice p,
|
|
490
|
+
.update-pending p {
|
|
491
|
+
margin-bottom: 4px;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
.legacy-notice button {
|
|
495
|
+
width: auto;
|
|
496
|
+
padding-inline: 16px;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
.legacy-settings {
|
|
500
|
+
color: var(--muted);
|
|
501
|
+
font-size: 12px;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
.dashboard-status {
|
|
505
|
+
display: flex;
|
|
506
|
+
align-items: center;
|
|
507
|
+
justify-content: space-between;
|
|
508
|
+
gap: 16px;
|
|
509
|
+
flex-wrap: wrap;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
.dashboard-status > div:not(.dashboard-actions) {
|
|
513
|
+
min-width: 0;
|
|
514
|
+
flex: 1;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
.dashboard-status .status-icon {
|
|
518
|
+
flex: 0 0 auto;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
.dashboard-actions {
|
|
522
|
+
position: relative;
|
|
523
|
+
display: flex;
|
|
524
|
+
align-items: center;
|
|
525
|
+
gap: 8px;
|
|
526
|
+
flex: 0 0 auto;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
.dashboard-action {
|
|
530
|
+
position: relative;
|
|
531
|
+
display: grid;
|
|
532
|
+
width: 40px;
|
|
533
|
+
height: 40px;
|
|
534
|
+
min-height: 40px;
|
|
535
|
+
place-items: center;
|
|
536
|
+
border: 1px solid var(--line-strong);
|
|
537
|
+
border-radius: var(--radius-control);
|
|
538
|
+
background: var(--panel);
|
|
539
|
+
padding: 0;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
.dashboard-action img {
|
|
543
|
+
width: 20px;
|
|
544
|
+
height: 20px;
|
|
545
|
+
opacity: 0.72;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
.dashboard-action::after {
|
|
549
|
+
content: attr(aria-label);
|
|
550
|
+
position: absolute;
|
|
551
|
+
z-index: 20;
|
|
552
|
+
top: calc(100% + 8px);
|
|
553
|
+
right: 0;
|
|
554
|
+
width: max-content;
|
|
555
|
+
max-width: 192px;
|
|
556
|
+
border: 1px solid var(--line);
|
|
557
|
+
border-radius: var(--radius-control);
|
|
558
|
+
background: var(--panel);
|
|
559
|
+
color: var(--ink);
|
|
560
|
+
padding: 4px 8px;
|
|
561
|
+
box-shadow: var(--shadow-overlay);
|
|
562
|
+
font-size: 11px;
|
|
563
|
+
font-weight: 500;
|
|
564
|
+
line-height: 1.25;
|
|
565
|
+
opacity: 0;
|
|
566
|
+
pointer-events: none;
|
|
567
|
+
transform: translateY(-4px);
|
|
568
|
+
transition:
|
|
569
|
+
opacity 150ms var(--ease-out),
|
|
570
|
+
transform 150ms var(--ease-out);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
.dashboard-action[data-collecting] {
|
|
574
|
+
border-color: var(--accent);
|
|
575
|
+
background: color-mix(in srgb, var(--accent) 16%, var(--panel));
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
.dashboard-action:hover::after,
|
|
579
|
+
.dashboard-action:focus-visible::after {
|
|
580
|
+
opacity: 1;
|
|
581
|
+
transform: translateY(0);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/*
|
|
585
|
+
* The way into a diagnostic run, standing where a status pill used to. A pill saying "Connected" was decoration on
|
|
586
|
+
* the healthy path and a dead end on every other; this appears only where a run would explain something.
|
|
587
|
+
*/
|
|
588
|
+
.dashboard-diagnose {
|
|
589
|
+
flex: 0 0 auto;
|
|
590
|
+
/* Buttons are full width by default here, and this one sits inline beside the title. */
|
|
591
|
+
width: auto;
|
|
592
|
+
border: 1px solid var(--alert);
|
|
593
|
+
border-radius: var(--radius-pill);
|
|
594
|
+
background: color-mix(in srgb, var(--alert) 16%, var(--panel));
|
|
595
|
+
color: var(--ink);
|
|
596
|
+
padding: 6px 12px;
|
|
597
|
+
font: inherit;
|
|
598
|
+
font-size: 12px;
|
|
599
|
+
font-weight: 600;
|
|
600
|
+
cursor: pointer;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
.dashboard-diagnose:hover {
|
|
604
|
+
background: color-mix(in srgb, var(--alert) 26%, var(--panel));
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
.device-group + .device-group {
|
|
608
|
+
margin-top: 24px;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
.device-group > h2 {
|
|
612
|
+
margin-bottom: 8px;
|
|
613
|
+
font-size: 13px;
|
|
614
|
+
letter-spacing: 0.08em;
|
|
615
|
+
text-transform: uppercase;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/* The grid measures itself against this, so a row height can be stated as a fraction of a column width. */
|
|
619
|
+
.device-group {
|
|
620
|
+
container-type: inline-size;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
.device-grid {
|
|
624
|
+
display: grid;
|
|
625
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
626
|
+
/*
|
|
627
|
+
* A row is half a column tall, so a camera spanning two of them plus the gap between is exactly square and two
|
|
628
|
+
* short tiles stack into the height one camera holds. Stated in container units because the row has to follow
|
|
629
|
+
* the column, and the column is a fraction of a width only the container knows.
|
|
630
|
+
*/
|
|
631
|
+
grid-auto-rows: calc(((100cqw - 24px) / 3 - 12px) / 2);
|
|
632
|
+
/* Short tiles fill the space beside a camera rather than starting a row of their own. */
|
|
633
|
+
grid-auto-flow: row dense;
|
|
634
|
+
gap: 12px;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
.device-tile {
|
|
638
|
+
position: relative;
|
|
639
|
+
min-width: 0;
|
|
640
|
+
grid-row: span 2;
|
|
641
|
+
overflow: hidden;
|
|
642
|
+
border: 1px solid var(--line);
|
|
643
|
+
border-radius: var(--radius-card);
|
|
644
|
+
background: var(--tile-bg);
|
|
645
|
+
transition: border-color 150ms var(--ease-out);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
/*
|
|
649
|
+
* A device with no camera frame to show gets half the height, so two stack into the space one camera occupies.
|
|
650
|
+
*
|
|
651
|
+
* The square is the camera's, because a frame is what fills it and what the eye finds a camera by. A sensor's
|
|
652
|
+
* tile carries a product photograph that reads at any height and two lines of copy, so the other half is spent
|
|
653
|
+
* on nothing, and a household of sensors pushes the cameras off the screen.
|
|
654
|
+
*/
|
|
655
|
+
.device-tile:not([data-device-class='camera']) {
|
|
656
|
+
grid-row: span 1;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/* Half a tile is too little for the photograph to sit behind the copy, so it keeps to a strip beside it. */
|
|
660
|
+
.device-tile:not([data-device-class='camera']) .device-summary {
|
|
661
|
+
justify-content: center;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
.device-tile:not([data-device-class='camera']) .device-art img[data-device-artwork] {
|
|
665
|
+
inset: 8px 8px 8px auto;
|
|
666
|
+
width: 36%;
|
|
667
|
+
height: calc(100% - 16px);
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
.device-tile:not([data-device-class='camera']) .device-copy {
|
|
671
|
+
max-width: 60%;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/*
|
|
675
|
+
* The explanation on a short tile gives up the icon and the deep padding to fit, because the words are the point
|
|
676
|
+
* and the badge on the front face already carries the same icon.
|
|
677
|
+
*/
|
|
678
|
+
.device-tile:not([data-device-class='camera']) .diagnostic-panel {
|
|
679
|
+
gap: 2px;
|
|
680
|
+
padding: 12px;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
.device-tile:not([data-device-class='camera']) /*
|
|
684
|
+
* A device's settings are a page rather than a face on the tile, so they are read at the page's scale and have as
|
|
685
|
+
* much room as the device needs. The tile is the summary and the way in; nothing about its size bounds this.
|
|
686
|
+
*/
|
|
687
|
+
.device-panel .preference-grid {
|
|
688
|
+
gap: 20px;
|
|
689
|
+
max-width: 560px;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
.device-panel .preference-grid label,
|
|
693
|
+
.device-panel .preference-grid .setting-label,
|
|
694
|
+
.device-panel .preference-grid p {
|
|
695
|
+
font-size: 13px;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
.device-panel .preference-representation {
|
|
699
|
+
font-size: 13px;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/*
|
|
703
|
+
* A finger has no hover and no precision, so every row it can act on is at least 44px tall where the pointer is
|
|
704
|
+
* coarse. This is the whole interaction on an iPhone: there is no second way in.
|
|
705
|
+
*/
|
|
706
|
+
@media (pointer: coarse) {
|
|
707
|
+
.device-panel .preference-grid .toggle {
|
|
708
|
+
min-height: 44px;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/*
|
|
712
|
+
* The segment's fill is painted on its inner span, so the span is what grows. Giving the height to the label
|
|
713
|
+
* instead leaves the selected fill short of the row it sits in, which reads as the buttons being misaligned
|
|
714
|
+
* with the selection rather than as a tall label.
|
|
715
|
+
*/
|
|
716
|
+
.device-panel .snapshot-segment span {
|
|
717
|
+
display: grid;
|
|
718
|
+
min-height: 44px;
|
|
719
|
+
place-items: center;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
.dashboard-page-back {
|
|
723
|
+
min-width: 44px;
|
|
724
|
+
min-height: 44px;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
.diagnostic-panel img {
|
|
729
|
+
display: none;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
.device-tile-changed {
|
|
733
|
+
border-color: var(--alert);
|
|
734
|
+
box-shadow: 0 0 0 2px color-mix(in srgb, var(--alert) 24%, transparent);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
.device-tile-changed::after {
|
|
738
|
+
content: '';
|
|
739
|
+
position: absolute;
|
|
740
|
+
z-index: 5;
|
|
741
|
+
top: 12px;
|
|
742
|
+
left: 12px;
|
|
743
|
+
width: 8px;
|
|
744
|
+
height: 8px;
|
|
745
|
+
border: 2px solid var(--tile-bg);
|
|
746
|
+
border-radius: 50%;
|
|
747
|
+
background: var(--alert);
|
|
748
|
+
pointer-events: none;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
.device-summary {
|
|
752
|
+
position: relative;
|
|
753
|
+
display: flex;
|
|
754
|
+
width: 100%;
|
|
755
|
+
height: 100%;
|
|
756
|
+
min-height: 0;
|
|
757
|
+
flex-direction: column;
|
|
758
|
+
justify-content: flex-end;
|
|
759
|
+
gap: 8px;
|
|
760
|
+
overflow: hidden;
|
|
761
|
+
padding: 16px;
|
|
762
|
+
list-style: none;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
.device-open-control {
|
|
766
|
+
border: 0;
|
|
767
|
+
border-radius: 0;
|
|
768
|
+
background: transparent;
|
|
769
|
+
color: inherit;
|
|
770
|
+
font: inherit;
|
|
771
|
+
text-align: inherit;
|
|
772
|
+
cursor: pointer;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
.device-tile[data-artwork-scene] .device-art img[data-device-artwork] {
|
|
776
|
+
inset: 0;
|
|
777
|
+
width: 100%;
|
|
778
|
+
height: 100%;
|
|
779
|
+
object-fit: cover;
|
|
780
|
+
filter: var(--tile-scene-filter);
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
/*
|
|
784
|
+
* A scene fills the tile, so the name needs the gradient to start higher and finish darker than over a cutout,
|
|
785
|
+
* and to reach full strength above the copy rather than at the tile's floor: a two-stop ramp ending at 100% is
|
|
786
|
+
* still interpolating where the name and the status sit, which leaves them on whatever the photograph is doing.
|
|
787
|
+
*/
|
|
788
|
+
.device-tile[data-artwork-scene] .device-summary::after {
|
|
789
|
+
background: linear-gradient(to bottom, transparent 15%, var(--tile-scene-gradient) 78%);
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
.device-tile[data-artwork-scene] .device-copy {
|
|
793
|
+
color: var(--tile-scene-ink);
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
.device-tile[data-artwork-scene] .device-copy p {
|
|
797
|
+
color: var(--tile-scene-muted);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
/* A scene the user has withdrawn from HomeKit keeps the withdrawn treatment: the scene filter is narrower. */
|
|
801
|
+
.device-tile-disabled[data-artwork-scene] .device-art img[data-device-artwork] {
|
|
802
|
+
filter: var(--tile-disabled-filter);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
.device-tile[data-artwork-scene] .device-summary::before {
|
|
806
|
+
background: repeating-linear-gradient(
|
|
807
|
+
-45deg,
|
|
808
|
+
transparent 0,
|
|
809
|
+
transparent 12px,
|
|
810
|
+
var(--tile-scene-stripe) 12px,
|
|
811
|
+
var(--tile-scene-stripe) 20px
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
.device-summary::after {
|
|
816
|
+
content: '';
|
|
817
|
+
position: absolute;
|
|
818
|
+
z-index: 1;
|
|
819
|
+
inset: 0;
|
|
820
|
+
background: linear-gradient(to bottom, transparent 40%, var(--tile-gradient) 100%);
|
|
821
|
+
pointer-events: none;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
.device-tile-disabled .device-summary::before {
|
|
825
|
+
content: '';
|
|
826
|
+
position: absolute;
|
|
827
|
+
z-index: 1;
|
|
828
|
+
inset: 0;
|
|
829
|
+
background: repeating-linear-gradient(
|
|
830
|
+
-45deg,
|
|
831
|
+
transparent 0,
|
|
832
|
+
transparent 12px,
|
|
833
|
+
var(--tile-stripe) 12px,
|
|
834
|
+
var(--tile-stripe) 20px
|
|
835
|
+
);
|
|
836
|
+
pointer-events: none;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
.device-tile-disabled .device-art img[data-device-artwork] {
|
|
840
|
+
filter: var(--tile-disabled-filter);
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
/*
|
|
844
|
+
* The two grounds a tile can have, and why they are not one.
|
|
845
|
+
*
|
|
846
|
+
* A packaged product photograph is a cutout on a flat ground: it is contained, inset, and desaturated so the
|
|
847
|
+
* grid reads as a catalogue of devices. A camera's own last image is a scene, and a scene has no cutout to
|
|
848
|
+
* inset — contained, it would sit in a box inside a box, and desaturated it would lose the very detail that
|
|
849
|
+
* makes the camera recognisable. It covers the tile instead, and the gradient the name already sits on is what
|
|
850
|
+
* keeps that name legible over it.
|
|
851
|
+
*
|
|
852
|
+
* The placeholder is centred with its icon rather than sat on the tile's floor, where it printed on top of the
|
|
853
|
+
* device name for every device with no artwork on file.
|
|
854
|
+
*/
|
|
855
|
+
.device-art {
|
|
856
|
+
position: absolute;
|
|
857
|
+
z-index: 0;
|
|
858
|
+
inset: 0;
|
|
859
|
+
display: grid;
|
|
860
|
+
align-content: center;
|
|
861
|
+
justify-items: center;
|
|
862
|
+
gap: 8px;
|
|
863
|
+
background: var(--tile-bg);
|
|
864
|
+
color: var(--tile-ink);
|
|
865
|
+
font-weight: 700;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
.device-art img[data-device-artwork] {
|
|
869
|
+
position: absolute;
|
|
870
|
+
inset: 24px;
|
|
871
|
+
width: calc(100% - 48px);
|
|
872
|
+
height: calc(100% - 48px);
|
|
873
|
+
object-fit: contain;
|
|
874
|
+
opacity: 1;
|
|
875
|
+
filter: var(--tile-image-filter);
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
.device-art .device-class-icon {
|
|
879
|
+
width: 56px;
|
|
880
|
+
height: 56px;
|
|
881
|
+
opacity: 0.42;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
.device-art span {
|
|
885
|
+
overflow: hidden;
|
|
886
|
+
max-width: 90%;
|
|
887
|
+
font-size: 10px;
|
|
888
|
+
letter-spacing: 0.08em;
|
|
889
|
+
opacity: 0.75;
|
|
890
|
+
text-overflow: ellipsis;
|
|
891
|
+
text-transform: uppercase;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
.device-art[data-artwork-loaded] .device-class-icon,
|
|
895
|
+
.device-art[data-artwork-loaded] span {
|
|
896
|
+
opacity: 0;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
.device-copy {
|
|
900
|
+
z-index: 2;
|
|
901
|
+
min-width: 0;
|
|
902
|
+
color: var(--tile-ink);
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
.device-copy h3 {
|
|
906
|
+
overflow: hidden;
|
|
907
|
+
margin: 0 0 2px;
|
|
908
|
+
font-size: 17px;
|
|
909
|
+
font-weight: 600;
|
|
910
|
+
line-height: 1.2;
|
|
911
|
+
letter-spacing: -0.01em;
|
|
912
|
+
text-overflow: ellipsis;
|
|
913
|
+
text-wrap: nowrap;
|
|
914
|
+
white-space: nowrap;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
.device-copy p {
|
|
918
|
+
overflow: hidden;
|
|
919
|
+
margin: 0;
|
|
920
|
+
color: var(--tile-muted);
|
|
921
|
+
font-size: 13px;
|
|
922
|
+
line-height: 1.25;
|
|
923
|
+
text-overflow: ellipsis;
|
|
924
|
+
white-space: nowrap;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
/* A status displaces the model on the tile's second line, so it keeps that line's metrics and adds its dot. */
|
|
928
|
+
.device-copy p.device-status {
|
|
929
|
+
display: flex;
|
|
930
|
+
gap: 8px;
|
|
931
|
+
align-items: center;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
.device-status-dot {
|
|
935
|
+
flex: none;
|
|
936
|
+
width: 8px;
|
|
937
|
+
height: 8px;
|
|
938
|
+
border-radius: var(--radius-pill);
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
/* The flex container cannot ellipsis its own text, so the label carries the truncation the model line has. */
|
|
942
|
+
.device-status-label {
|
|
943
|
+
overflow: hidden;
|
|
944
|
+
text-overflow: ellipsis;
|
|
945
|
+
white-space: nowrap;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
/* One semantic per tone, named once, so the three rules below carry every one of them. */
|
|
949
|
+
.device-copy p.device-status-live {
|
|
950
|
+
--status-ink: var(--ok);
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
.device-copy p.device-status-alert {
|
|
954
|
+
--status-ink: var(--alert);
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
.device-copy p.device-status-fault {
|
|
958
|
+
--status-ink: var(--fault);
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
/*
|
|
962
|
+
* A coloured status label mixes toward the ink of whichever ground it sits on; its dot keeps the flat colour.
|
|
963
|
+
*
|
|
964
|
+
* No semantic clears contrast at 13px against both the pale panel and a scene's gradient, and the dot is a
|
|
965
|
+
* graphical mark rather than readable content, so only the word is mixed. A quiet status states nothing coloured
|
|
966
|
+
* and takes the second line's own muted ink, which needs no rule.
|
|
967
|
+
*/
|
|
968
|
+
.device-copy p:is(.device-status-live, .device-status-alert, .device-status-fault) {
|
|
969
|
+
color: color-mix(in srgb, var(--status-ink) 75%, var(--tile-ink));
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
.device-tile[data-artwork-scene]
|
|
973
|
+
.device-copy
|
|
974
|
+
p:is(.device-status-live, .device-status-alert, .device-status-fault) {
|
|
975
|
+
color: color-mix(in srgb, var(--status-ink) 75%, var(--tile-scene-ink));
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
.device-status-dot {
|
|
979
|
+
background: var(--status-ink, currentcolor);
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
.device-badges {
|
|
983
|
+
position: absolute;
|
|
984
|
+
z-index: 2;
|
|
985
|
+
top: 12px;
|
|
986
|
+
right: 12px;
|
|
987
|
+
display: flex;
|
|
988
|
+
flex-wrap: wrap;
|
|
989
|
+
gap: 4px;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
.device-badges span {
|
|
993
|
+
position: relative;
|
|
994
|
+
display: grid;
|
|
995
|
+
place-items: center;
|
|
996
|
+
width: 32px;
|
|
997
|
+
height: 32px;
|
|
998
|
+
border: 1px solid var(--tile-badge-border);
|
|
999
|
+
border-radius: var(--radius-pill);
|
|
1000
|
+
background: var(--tile-badge-bg);
|
|
1001
|
+
backdrop-filter: blur(5px);
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
.device-badges img {
|
|
1005
|
+
width: 16px;
|
|
1006
|
+
height: 16px;
|
|
1007
|
+
filter: var(--tile-icon-filter);
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
/*
|
|
1011
|
+
* The gauge carries no plate, so its own halo separates it from whatever is behind it instead.
|
|
1012
|
+
*
|
|
1013
|
+
* The second documented exception to one shadow: this states the glyph's edge against unknown artwork rather
|
|
1014
|
+
* than floating a layer over content, which is why it is not `--shadow-overlay`. The halo does not flip with the
|
|
1015
|
+
* theme because the glyph does not either.
|
|
1016
|
+
*/
|
|
1017
|
+
.device-badges .device-badge-battery {
|
|
1018
|
+
border: 0;
|
|
1019
|
+
background: transparent;
|
|
1020
|
+
backdrop-filter: none;
|
|
1021
|
+
filter: drop-shadow(0 1px 2px var(--tile-badge-halo));
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
/*
|
|
1025
|
+
* The gauge lies on its side with its terminal to the left, and takes the next step up the scale.
|
|
1026
|
+
*
|
|
1027
|
+
* With no plate around it the glyph is the whole indicator, so it carries at 18px where a plated badge reads at
|
|
1028
|
+
* 16px. It keeps the tile's own icon colour here, which is the ink of the pale panel a product cutout sits on.
|
|
1029
|
+
*/
|
|
1030
|
+
.device-badges .device-badge-battery img {
|
|
1031
|
+
width: 18px;
|
|
1032
|
+
height: 18px;
|
|
1033
|
+
transform: rotate(-90deg);
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
/*
|
|
1037
|
+
* Over a scene the glyph goes light whatever the theme, and gains a ring, because its ground is a photograph of
|
|
1038
|
+
* unknown luminance.
|
|
1039
|
+
*
|
|
1040
|
+
* The tile's two grounds are opposites — that frame, and the pale panel — so one glyph colour loses on one of
|
|
1041
|
+
* them. This is the same split `--tile-scene-ink` exists for, applied to the one icon that sits on both. On the
|
|
1042
|
+
* panel a plain shadow is enough and a ring would only dirty a flat surface.
|
|
1043
|
+
*/
|
|
1044
|
+
.device-tile[data-artwork-scene] .device-badges .device-badge-battery img {
|
|
1045
|
+
filter: invert(1);
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
.device-tile[data-artwork-scene] .device-badges .device-badge-battery {
|
|
1049
|
+
filter: drop-shadow(0 0 1px var(--tile-badge-halo)) drop-shadow(0 1px 2px var(--tile-badge-halo));
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
.device-badges .device-badge-troubleshoot {
|
|
1053
|
+
width: 36px;
|
|
1054
|
+
height: 36px;
|
|
1055
|
+
border: 0;
|
|
1056
|
+
background: transparent;
|
|
1057
|
+
backdrop-filter: none;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
.device-badges .device-badge-troubleshoot img {
|
|
1061
|
+
width: 28px;
|
|
1062
|
+
height: 28px;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
.device-badges span::after {
|
|
1066
|
+
content: attr(data-tooltip);
|
|
1067
|
+
position: absolute;
|
|
1068
|
+
z-index: 4;
|
|
1069
|
+
top: calc(100% + 8px);
|
|
1070
|
+
right: 0;
|
|
1071
|
+
width: max-content;
|
|
1072
|
+
max-width: 168px;
|
|
1073
|
+
border: 1px solid var(--line);
|
|
1074
|
+
border-radius: var(--radius-control);
|
|
1075
|
+
background: var(--tile-tooltip-bg);
|
|
1076
|
+
color: var(--tile-tooltip-ink);
|
|
1077
|
+
padding: 4px 8px;
|
|
1078
|
+
box-shadow: var(--shadow-overlay);
|
|
1079
|
+
font-size: 10px;
|
|
1080
|
+
font-weight: 500;
|
|
1081
|
+
line-height: 1.3;
|
|
1082
|
+
opacity: 0;
|
|
1083
|
+
pointer-events: none;
|
|
1084
|
+
transform: translateY(-4px);
|
|
1085
|
+
transition:
|
|
1086
|
+
opacity 150ms var(--ease-out),
|
|
1087
|
+
transform 150ms var(--ease-out);
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
.device-badges span:hover::after,
|
|
1091
|
+
.device-badges span:focus-visible::after {
|
|
1092
|
+
opacity: 1;
|
|
1093
|
+
transform: translateY(0);
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
.diagnostic-panel {
|
|
1097
|
+
display: grid;
|
|
1098
|
+
place-items: center;
|
|
1099
|
+
gap: 8px;
|
|
1100
|
+
width: 100%;
|
|
1101
|
+
padding: 16px;
|
|
1102
|
+
text-align: center;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
.diagnostic-panel img {
|
|
1106
|
+
width: 32px;
|
|
1107
|
+
height: 32px;
|
|
1108
|
+
filter: var(--tile-icon-filter);
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
.diagnostic-panel strong {
|
|
1112
|
+
font-size: 14px;
|
|
1113
|
+
font-weight: 600;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
.diagnostic-panel p {
|
|
1117
|
+
margin: 0;
|
|
1118
|
+
color: var(--tile-muted);
|
|
1119
|
+
font-size: 11px;
|
|
1120
|
+
line-height: 1.35;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
.preference-grid {
|
|
1124
|
+
display: grid;
|
|
1125
|
+
gap: 8px;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
.preference-grid p {
|
|
1129
|
+
margin: 0;
|
|
1130
|
+
color: var(--muted);
|
|
1131
|
+
font-size: 11px;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
/* What the device becomes, read before the switch that decides whether it becomes it. */
|
|
1135
|
+
.preference-representation {
|
|
1136
|
+
color: var(--tile-muted);
|
|
1137
|
+
font-weight: 600;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
.preference-grid label {
|
|
1141
|
+
display: grid;
|
|
1142
|
+
gap: 4px;
|
|
1143
|
+
color: var(--muted);
|
|
1144
|
+
font-size: 11px;
|
|
1145
|
+
cursor: default;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
.preference-grid .preference-changed {
|
|
1149
|
+
font-weight: 700;
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
.preference-grid .preference-changed .snapshot-description {
|
|
1153
|
+
font-weight: 400;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
.setting-label {
|
|
1157
|
+
display: flex;
|
|
1158
|
+
align-items: center;
|
|
1159
|
+
gap: 4px;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
.snapshot-setting {
|
|
1163
|
+
display: grid;
|
|
1164
|
+
gap: 8px;
|
|
1165
|
+
color: var(--muted);
|
|
1166
|
+
font-size: 11px;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
.snapshot-segments {
|
|
1170
|
+
display: grid;
|
|
1171
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
1172
|
+
overflow: hidden;
|
|
1173
|
+
border: 1px solid var(--line-strong);
|
|
1174
|
+
border-radius: var(--radius-control);
|
|
1175
|
+
background: var(--panel);
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
.snapshot-segments .snapshot-segment {
|
|
1179
|
+
position: relative;
|
|
1180
|
+
display: block;
|
|
1181
|
+
color: var(--muted);
|
|
1182
|
+
cursor: pointer;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
.snapshot-segment + .snapshot-segment {
|
|
1186
|
+
border-left: 1px solid var(--line);
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
.snapshot-segment input {
|
|
1190
|
+
position: absolute;
|
|
1191
|
+
width: 1px;
|
|
1192
|
+
min-height: 0;
|
|
1193
|
+
height: 1px;
|
|
1194
|
+
margin: 0;
|
|
1195
|
+
opacity: 0;
|
|
1196
|
+
pointer-events: none;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
.snapshot-segment span {
|
|
1200
|
+
display: block;
|
|
1201
|
+
padding: 8px 4px;
|
|
1202
|
+
font-size: 10px;
|
|
1203
|
+
font-weight: 600;
|
|
1204
|
+
text-align: center;
|
|
1205
|
+
transition:
|
|
1206
|
+
background 150ms var(--ease-out),
|
|
1207
|
+
color 150ms var(--ease-out);
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
.snapshot-segment input:checked + span {
|
|
1211
|
+
background: var(--accent);
|
|
1212
|
+
color: var(--on-accent);
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
.snapshot-description {
|
|
1216
|
+
min-height: 32px;
|
|
1217
|
+
margin: 0;
|
|
1218
|
+
color: var(--muted);
|
|
1219
|
+
font-size: 10px;
|
|
1220
|
+
line-height: 1.35;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
.preference-grid .toggle {
|
|
1224
|
+
grid-template-columns: 40px minmax(0, 1fr);
|
|
1225
|
+
align-items: center;
|
|
1226
|
+
cursor: pointer;
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
.preference-grid .toggle input {
|
|
1230
|
+
appearance: none;
|
|
1231
|
+
position: relative;
|
|
1232
|
+
width: 36px;
|
|
1233
|
+
min-height: 20px;
|
|
1234
|
+
height: 20px;
|
|
1235
|
+
margin: 0;
|
|
1236
|
+
border: 1px solid var(--line-strong);
|
|
1237
|
+
border-radius: var(--radius-pill);
|
|
1238
|
+
background: color-mix(in srgb, var(--muted) 28%, var(--panel));
|
|
1239
|
+
padding: 0;
|
|
1240
|
+
transition:
|
|
1241
|
+
background 140ms var(--ease-out),
|
|
1242
|
+
border-color 140ms var(--ease-out);
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
/* The knob, the one element in the sheet whose shadow states a physical position rather than a layer. */
|
|
1246
|
+
.preference-grid .toggle input::before {
|
|
1247
|
+
content: '';
|
|
1248
|
+
position: absolute;
|
|
1249
|
+
top: 2px;
|
|
1250
|
+
left: 2px;
|
|
1251
|
+
width: 14px;
|
|
1252
|
+
height: 14px;
|
|
1253
|
+
border-radius: 50%;
|
|
1254
|
+
background: var(--panel);
|
|
1255
|
+
box-shadow: 0 1px 2px rgb(0 0 0 / 22%);
|
|
1256
|
+
transition: transform 140ms var(--ease-out);
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
.preference-grid .toggle input:checked {
|
|
1260
|
+
border-color: var(--accent);
|
|
1261
|
+
background: var(--accent);
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
.preference-grid .toggle input:checked::before {
|
|
1265
|
+
transform: translateX(16px);
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
[hidden] {
|
|
1269
|
+
display: none !important;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
.first-setup {
|
|
1273
|
+
position: relative;
|
|
1274
|
+
margin-bottom: 16px;
|
|
1275
|
+
border: 1px solid var(--line);
|
|
1276
|
+
border-left: 4px solid var(--accent);
|
|
1277
|
+
border-radius: var(--radius-card);
|
|
1278
|
+
background: var(--accent-soft);
|
|
1279
|
+
padding: 16px 20px;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
.first-setup::before {
|
|
1283
|
+
content: '';
|
|
1284
|
+
position: absolute;
|
|
1285
|
+
top: 50%;
|
|
1286
|
+
left: -3px;
|
|
1287
|
+
width: 10px;
|
|
1288
|
+
height: 10px;
|
|
1289
|
+
border-top: 4px solid var(--accent);
|
|
1290
|
+
border-right: 4px solid var(--accent);
|
|
1291
|
+
background: var(--accent-soft);
|
|
1292
|
+
transform: translate(-50%, -50%) rotate(225deg);
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
.first-setup h2 {
|
|
1296
|
+
margin-bottom: 8px;
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
.first-setup p {
|
|
1300
|
+
margin-bottom: 8px;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
.first-setup-reason {
|
|
1304
|
+
color: var(--ink-secondary);
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
.first-setup a {
|
|
1308
|
+
color: var(--accent-ink);
|
|
1309
|
+
font-weight: 600;
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
.first-setup-confirmation {
|
|
1313
|
+
display: grid;
|
|
1314
|
+
gap: 12px;
|
|
1315
|
+
margin-top: 16px;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
.first-setup-confirmation label {
|
|
1319
|
+
display: flex;
|
|
1320
|
+
align-items: flex-start;
|
|
1321
|
+
gap: 12px;
|
|
1322
|
+
cursor: pointer;
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
.first-setup-confirmation input,
|
|
1326
|
+
.diagnostics-review-confirm input {
|
|
1327
|
+
appearance: none;
|
|
1328
|
+
display: grid;
|
|
1329
|
+
place-content: center;
|
|
1330
|
+
width: 18px;
|
|
1331
|
+
min-height: 18px;
|
|
1332
|
+
height: 18px;
|
|
1333
|
+
flex: 0 0 auto;
|
|
1334
|
+
margin-top: 2px;
|
|
1335
|
+
border: 2px solid var(--accent-ink);
|
|
1336
|
+
border-radius: var(--radius-sm);
|
|
1337
|
+
background: var(--panel);
|
|
1338
|
+
padding: 0;
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
.first-setup-confirmation input::before,
|
|
1342
|
+
.diagnostics-review-confirm input::before {
|
|
1343
|
+
content: '';
|
|
1344
|
+
width: 8px;
|
|
1345
|
+
height: 4px;
|
|
1346
|
+
border-bottom: 2px solid var(--on-accent);
|
|
1347
|
+
border-left: 2px solid var(--on-accent);
|
|
1348
|
+
transform: rotate(-45deg) scale(0);
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
.first-setup-confirmation input:checked,
|
|
1352
|
+
.diagnostics-review-confirm input:checked {
|
|
1353
|
+
border-color: var(--accent);
|
|
1354
|
+
background: var(--accent);
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
.first-setup-confirmation input:checked::before,
|
|
1358
|
+
.diagnostics-review-confirm input:checked::before {
|
|
1359
|
+
transform: rotate(-45deg) scale(1);
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
.status-row {
|
|
1363
|
+
display: flex;
|
|
1364
|
+
align-items: flex-start;
|
|
1365
|
+
justify-content: space-between;
|
|
1366
|
+
gap: 16px;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
.status {
|
|
1370
|
+
flex: 0 0 auto;
|
|
1371
|
+
border-radius: var(--radius-pill);
|
|
1372
|
+
background: var(--accent-soft);
|
|
1373
|
+
color: var(--accent-ink);
|
|
1374
|
+
padding: 4px 8px;
|
|
1375
|
+
font-size: 11px;
|
|
1376
|
+
font-weight: 600;
|
|
1377
|
+
font-variant-numeric: tabular-nums;
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
.summary {
|
|
1381
|
+
margin: 16px 0;
|
|
1382
|
+
color: var(--ink-secondary);
|
|
1383
|
+
font-size: 15px;
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
.handoff {
|
|
1387
|
+
border: 1px solid var(--line);
|
|
1388
|
+
border-left: 4px solid var(--accent);
|
|
1389
|
+
border-radius: var(--radius-card);
|
|
1390
|
+
background: var(--accent-soft);
|
|
1391
|
+
padding: 12px 16px;
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
.handoff p {
|
|
1395
|
+
margin: 4px 0 0;
|
|
1396
|
+
color: var(--ink-secondary);
|
|
1397
|
+
font-size: 12px;
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
.steps {
|
|
1401
|
+
display: grid;
|
|
1402
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
1403
|
+
gap: 8px;
|
|
1404
|
+
margin: 24px 0;
|
|
1405
|
+
padding: 0;
|
|
1406
|
+
list-style: none;
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
.steps li {
|
|
1410
|
+
display: grid;
|
|
1411
|
+
gap: 4px;
|
|
1412
|
+
border-top: 3px solid var(--line);
|
|
1413
|
+
padding-top: 8px;
|
|
1414
|
+
color: var(--muted);
|
|
1415
|
+
font-size: 11px;
|
|
1416
|
+
text-align: center;
|
|
1417
|
+
text-transform: uppercase;
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
.steps li.current {
|
|
1421
|
+
border-color: var(--accent);
|
|
1422
|
+
color: var(--accent-ink);
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
.steps span {
|
|
1426
|
+
font-size: 10px;
|
|
1427
|
+
font-variant-numeric: tabular-nums;
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
.authentication-form,
|
|
1431
|
+
.challenge-form {
|
|
1432
|
+
display: grid;
|
|
1433
|
+
gap: 16px;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
.authentication-form label,
|
|
1437
|
+
.challenge-form label {
|
|
1438
|
+
display: grid;
|
|
1439
|
+
gap: 8px;
|
|
1440
|
+
color: var(--muted);
|
|
1441
|
+
font-size: 12px;
|
|
1442
|
+
font-weight: 500;
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
.field-row {
|
|
1446
|
+
display: grid;
|
|
1447
|
+
grid-template-columns: minmax(90px, 0.35fr) minmax(0, 1fr);
|
|
1448
|
+
gap: 12px;
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
input {
|
|
1452
|
+
width: 100%;
|
|
1453
|
+
min-height: 44px;
|
|
1454
|
+
border: 1px solid var(--line-strong);
|
|
1455
|
+
border-radius: var(--radius-control);
|
|
1456
|
+
background: var(--panel);
|
|
1457
|
+
color: var(--ink);
|
|
1458
|
+
padding: 8px 12px;
|
|
1459
|
+
font: inherit;
|
|
1460
|
+
font-variant-numeric: tabular-nums;
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
.challenge-form {
|
|
1464
|
+
margin-top: 16px;
|
|
1465
|
+
border-top: 1px solid var(--line);
|
|
1466
|
+
padding-top: 16px;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
/* The plate the captcha image sits on, white in both themes because the image Eufy returns has a white ground. */
|
|
1470
|
+
.captcha {
|
|
1471
|
+
width: min(100%, 260px);
|
|
1472
|
+
min-height: 72px;
|
|
1473
|
+
justify-self: center;
|
|
1474
|
+
border: 1px solid var(--line-strong);
|
|
1475
|
+
border-radius: var(--radius-control);
|
|
1476
|
+
background: #ffffff;
|
|
1477
|
+
object-fit: contain;
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
.authentication-status {
|
|
1481
|
+
min-height: 20px;
|
|
1482
|
+
margin: 12px 0 0;
|
|
1483
|
+
color: var(--muted);
|
|
1484
|
+
font-weight: 600;
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
button {
|
|
1488
|
+
width: 100%;
|
|
1489
|
+
min-height: 44px;
|
|
1490
|
+
border: 0;
|
|
1491
|
+
border-radius: var(--radius-control);
|
|
1492
|
+
background: var(--accent);
|
|
1493
|
+
color: var(--on-accent);
|
|
1494
|
+
font: inherit;
|
|
1495
|
+
font-weight: 600;
|
|
1496
|
+
cursor: pointer;
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
.footnote {
|
|
1500
|
+
margin: 12px 4px 0;
|
|
1501
|
+
color: var(--muted);
|
|
1502
|
+
font-size: 11px;
|
|
1503
|
+
text-align: center;
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
/* One setting per row, so a control that needs width gets it and nothing sits half-read beside it. */
|
|
1507
|
+
/*
|
|
1508
|
+
* Two lists with a column of transfer buttons between them, sharing the parent's rows so the three columns line up.
|
|
1509
|
+
*
|
|
1510
|
+
* The buttons belong beside the lists, not beside the lists plus their titles: centred over the whole column they
|
|
1511
|
+
* sit below the middle of what they act on, by half a title. Subgrid puts each list's title and body in the
|
|
1512
|
+
* parent's own rows, which is what lets the buttons occupy the second row alone. Where subgrid is unavailable the
|
|
1513
|
+
* columns keep their own rows and the buttons centre as they did.
|
|
1514
|
+
*/
|
|
1515
|
+
.warm-up-transfer {
|
|
1516
|
+
display: grid;
|
|
1517
|
+
grid-template-columns: 1fr auto 1fr;
|
|
1518
|
+
grid-template-rows: auto 1fr;
|
|
1519
|
+
align-items: stretch;
|
|
1520
|
+
gap: 8px;
|
|
1521
|
+
font-weight: 400;
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
.warm-up-column {
|
|
1525
|
+
display: grid;
|
|
1526
|
+
grid-row: span 2;
|
|
1527
|
+
grid-template-rows: subgrid;
|
|
1528
|
+
gap: 8px;
|
|
1529
|
+
min-width: 0;
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
.warm-up-column > p {
|
|
1533
|
+
margin: 0;
|
|
1534
|
+
color: var(--muted);
|
|
1535
|
+
font-size: 12px;
|
|
1536
|
+
font-weight: 600;
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
.warm-up-column ul {
|
|
1540
|
+
list-style: none;
|
|
1541
|
+
margin: 0;
|
|
1542
|
+
/*
|
|
1543
|
+
* Four rows, then scroll: the list is long enough that showing all of it pushes the help text off-screen.
|
|
1544
|
+
* The height is the content of four rows at the current row metric, not a step on the spacing grid.
|
|
1545
|
+
*/
|
|
1546
|
+
min-height: 172px;
|
|
1547
|
+
max-height: 172px;
|
|
1548
|
+
/*
|
|
1549
|
+
* Centred in its row rather than filling it. The row is as tall as the button column beside it, which needs more
|
|
1550
|
+
* than four rows of list, so a list pinned to the top of that row sits above the buttons that act on it.
|
|
1551
|
+
*/
|
|
1552
|
+
align-self: center;
|
|
1553
|
+
overflow-y: auto;
|
|
1554
|
+
border: 1px solid var(--line-strong);
|
|
1555
|
+
border-radius: var(--radius-control);
|
|
1556
|
+
background: var(--panel);
|
|
1557
|
+
display: grid;
|
|
1558
|
+
align-content: start;
|
|
1559
|
+
gap: 2px;
|
|
1560
|
+
padding: 4px;
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
.warm-up-column li {
|
|
1564
|
+
margin: 0;
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
/* Concentric with the list that clips it: the list's 8px radius less its 4px padding. */
|
|
1568
|
+
.warm-up-column button {
|
|
1569
|
+
width: 100%;
|
|
1570
|
+
text-align: left;
|
|
1571
|
+
padding: 8px;
|
|
1572
|
+
border: 1px solid transparent;
|
|
1573
|
+
border-radius: var(--radius-sm);
|
|
1574
|
+
background: none;
|
|
1575
|
+
color: var(--ink);
|
|
1576
|
+
font: inherit;
|
|
1577
|
+
cursor: pointer;
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
/* Without this the click leaves no mark, so the user cannot tell whether the entry was taken. */
|
|
1581
|
+
.warm-up-column button[aria-pressed='true'] {
|
|
1582
|
+
border-color: var(--accent);
|
|
1583
|
+
background: color-mix(in srgb, var(--accent) 16%, transparent);
|
|
1584
|
+
color: var(--accent-ink);
|
|
1585
|
+
font-weight: 600;
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
.warm-up-controls {
|
|
1589
|
+
display: grid;
|
|
1590
|
+
/*
|
|
1591
|
+
* Both placed explicitly. Grid resolves items with a definite row before auto-placing the rest, so naming only
|
|
1592
|
+
* the row let this claim the first column and pushed both lists along one.
|
|
1593
|
+
*/
|
|
1594
|
+
grid-row: 2;
|
|
1595
|
+
grid-column: 2;
|
|
1596
|
+
align-content: center;
|
|
1597
|
+
gap: 8px;
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
.warm-up-arrow {
|
|
1601
|
+
width: 20px;
|
|
1602
|
+
height: 20px;
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
.warm-up-controls button {
|
|
1606
|
+
display: grid;
|
|
1607
|
+
place-items: center;
|
|
1608
|
+
min-width: 44px;
|
|
1609
|
+
min-height: 44px;
|
|
1610
|
+
border: 1px solid var(--line-strong);
|
|
1611
|
+
border-radius: var(--radius-control);
|
|
1612
|
+
background: var(--panel);
|
|
1613
|
+
color: var(--ink);
|
|
1614
|
+
font: inherit;
|
|
1615
|
+
cursor: pointer;
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
/*
|
|
1619
|
+
* The diagnostics entry in the masthead, which is the header shown before an account exists.
|
|
1620
|
+
*
|
|
1621
|
+
* The dashboard's own entry disappears with the dashboard, so on the setup and authentication screens this is
|
|
1622
|
+
* the only way to start collecting — and those are the screens a startup or sign-in failure is visible on.
|
|
1623
|
+
*/
|
|
1624
|
+
.masthead-action {
|
|
1625
|
+
margin-inline-start: auto;
|
|
1626
|
+
align-self: center;
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
/*
|
|
1630
|
+
* Every interactive state in the sheet, in one place and in cascade order: the filled default first, then each
|
|
1631
|
+
* variant that keeps its own surface.
|
|
1632
|
+
*
|
|
1633
|
+
* A variant is declared beside the rule that gives it its resting surface, far above here, so a `:hover` written
|
|
1634
|
+
* there would lose to the filled default's `:hover` on source order alone and repaint a secondary button in the
|
|
1635
|
+
* accent. Ordering them here is what keeps a "No" button from turning teal under the pointer.
|
|
1636
|
+
*/
|
|
1637
|
+
button {
|
|
1638
|
+
transition:
|
|
1639
|
+
background 150ms var(--ease-out),
|
|
1640
|
+
border-color 150ms var(--ease-out),
|
|
1641
|
+
transform 100ms var(--ease-out);
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
button:hover:not(:disabled) {
|
|
1645
|
+
background: color-mix(in srgb, var(--accent) 88%, var(--on-accent));
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
button:active:not(:disabled, .device-open-control) {
|
|
1649
|
+
transform: scale(0.97);
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
button:disabled {
|
|
1653
|
+
background: color-mix(in srgb, var(--accent) 28%, var(--panel));
|
|
1654
|
+
color: color-mix(in srgb, var(--on-accent) 60%, var(--panel));
|
|
1655
|
+
cursor: not-allowed;
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
button.diagnostics-secondary-action:hover:not(:disabled),
|
|
1659
|
+
.dashboard-page-back:hover:not(:disabled),
|
|
1660
|
+
.warm-up-controls button:hover:not(:disabled),
|
|
1661
|
+
.warm-up-column button:hover:not(:disabled),
|
|
1662
|
+
.warm-up-column button:focus-visible {
|
|
1663
|
+
border-color: var(--line-strong);
|
|
1664
|
+
background: color-mix(in srgb, var(--ink) 5%, var(--panel));
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
button.diagnostics-quiet-action:hover:not(:disabled) {
|
|
1668
|
+
background: transparent;
|
|
1669
|
+
color: var(--ink);
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
.dashboard-action:hover,
|
|
1673
|
+
.dashboard-action:focus-visible {
|
|
1674
|
+
background: color-mix(in srgb, var(--accent) 9%, var(--panel));
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
.device-open-control:hover {
|
|
1678
|
+
background: transparent;
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
/*
|
|
1682
|
+
* The tile is the dashboard's primary target and artwork covers everything but its edge, so the edge carries the
|
|
1683
|
+
* hover. A step in `--line` alone was too quiet to register as feedback; the accent in the edge is not.
|
|
1684
|
+
*/
|
|
1685
|
+
.device-tile:hover {
|
|
1686
|
+
border-color: color-mix(in srgb, var(--accent) 45%, var(--line-strong));
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
.warm-up-controls button:disabled,
|
|
1690
|
+
.warm-up-column button:disabled,
|
|
1691
|
+
button.diagnostics-secondary-action:disabled {
|
|
1692
|
+
border-color: var(--line);
|
|
1693
|
+
background: var(--panel);
|
|
1694
|
+
color: var(--ink-disabled);
|
|
1695
|
+
cursor: default;
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
/*
|
|
1699
|
+
* The one keyboard focus ring, on everything that takes focus.
|
|
1700
|
+
*
|
|
1701
|
+
* The device tiles are the dashboard's primary interaction and the diagnostics panel's buttons carry no class, so
|
|
1702
|
+
* both used to fall through to the user agent's own ring — a hairline with no offset, thinner and lower in
|
|
1703
|
+
* contrast than the ring the rest of the interface draws. Naming the focusables once is what keeps the ring from
|
|
1704
|
+
* drifting into a fourth variant.
|
|
1705
|
+
*/
|
|
1706
|
+
:is(button, input, select, textarea, a, [tabindex]):focus-visible {
|
|
1707
|
+
outline: var(--focus-ring);
|
|
1708
|
+
outline-offset: 2px;
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
input:focus-visible {
|
|
1712
|
+
border-color: var(--accent);
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
/*
|
|
1716
|
+
* The segmented control's ring, drawn inside.
|
|
1717
|
+
*
|
|
1718
|
+
* Its radio input is a 1px sliver and the group clips overflow, so a ring on the input is invisible and a ring
|
|
1719
|
+
* outside the label is cut off. The visible segment carries it, inset.
|
|
1720
|
+
*/
|
|
1721
|
+
.snapshot-segment input:focus-visible {
|
|
1722
|
+
outline: none;
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
.snapshot-segment input:focus-visible + span {
|
|
1726
|
+
outline: var(--focus-ring);
|
|
1727
|
+
outline-offset: -2px;
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1731
|
+
button:active {
|
|
1732
|
+
transform: none;
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
@media (max-width: 420px) {
|
|
1737
|
+
.status-row {
|
|
1738
|
+
display: grid;
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
.status {
|
|
1742
|
+
justify-self: start;
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
.field-row {
|
|
1746
|
+
grid-template-columns: 1fr;
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
.legacy-notice {
|
|
1750
|
+
display: grid;
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
.legacy-notice button {
|
|
1754
|
+
width: 100%;
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
@media (max-width: 760px) {
|
|
1759
|
+
.device-grid {
|
|
1760
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
1761
|
+
grid-auto-rows: calc(((100cqw - 12px) / 2 - 12px) / 2);
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
@media (max-width: 540px) {
|
|
1766
|
+
/*
|
|
1767
|
+
* Stacked rather than side by side: one list above, one below, and the buttons between them. Two lists abreast
|
|
1768
|
+
* leave nothing readable at this width, and the transfer reads along the axis it moves the device.
|
|
1769
|
+
*
|
|
1770
|
+
* Everything the wide layout pinned is undone here — the shared rows, the spans, and the column the buttons
|
|
1771
|
+
* claimed — because that arrangement exists only to line three columns up against each other.
|
|
1772
|
+
*/
|
|
1773
|
+
.warm-up-transfer {
|
|
1774
|
+
grid-template-columns: 1fr;
|
|
1775
|
+
grid-template-rows: auto;
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
.warm-up-column {
|
|
1779
|
+
grid-row: auto;
|
|
1780
|
+
grid-template-rows: auto 1fr;
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
.warm-up-column ul {
|
|
1784
|
+
align-self: stretch;
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
.warm-up-controls {
|
|
1788
|
+
grid-row: auto;
|
|
1789
|
+
grid-column: 1;
|
|
1790
|
+
grid-auto-flow: column;
|
|
1791
|
+
justify-content: center;
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
/* The chevrons point the way the device travels, which is now down the page rather than across it. */
|
|
1795
|
+
.warm-up-arrow {
|
|
1796
|
+
transform: rotate(90deg);
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1800
|
+
@media (max-width: 520px) {
|
|
1801
|
+
.advanced-fields {
|
|
1802
|
+
grid-template-columns: 1fr;
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
.diagnostics-actions button {
|
|
1806
|
+
width: 100%;
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1809
|
+
.diagnostics-choice-actions {
|
|
1810
|
+
display: grid;
|
|
1811
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
.diagnostics-choice-actions button {
|
|
1815
|
+
width: 100%;
|
|
1816
|
+
min-width: 0;
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
.device-grid {
|
|
1820
|
+
grid-template-columns: 1fr;
|
|
1821
|
+
/* One column is already a stack, so the row unit and the spans give way to the tile's own ratio. */
|
|
1822
|
+
grid-auto-rows: auto;
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
.device-tile,
|
|
1826
|
+
.device-tile:not([data-device-class='camera']) {
|
|
1827
|
+
grid-row: auto;
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
.device-summary {
|
|
1831
|
+
min-height: 0;
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
.device-tile {
|
|
1835
|
+
aspect-ratio: 2 / 1;
|
|
1836
|
+
min-height: 152px;
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
.device-art img[data-device-artwork] {
|
|
1840
|
+
inset: 12px 4% 12px auto;
|
|
1841
|
+
width: 76%;
|
|
1842
|
+
height: calc(100% - 24px);
|
|
1843
|
+
object-fit: contain;
|
|
1844
|
+
object-position: center right;
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
.diagnostic-panel {
|
|
1848
|
+
gap: 4px;
|
|
1849
|
+
padding: 32px 16px 8px;
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
.shell[data-theme='dark'] {
|
|
1855
|
+
color-scheme: dark;
|
|
1856
|
+
--accent: #00bfc4;
|
|
1857
|
+
--accent-ink: #67e1e4;
|
|
1858
|
+
--accent-soft: color-mix(in srgb, var(--accent) 18%, var(--panel));
|
|
1859
|
+
--ink: #edf1f7;
|
|
1860
|
+
--ink-secondary: color-mix(in srgb, var(--ink) 78%, var(--panel));
|
|
1861
|
+
--muted: #aab3c2;
|
|
1862
|
+
--ink-disabled: color-mix(in srgb, var(--muted) 55%, var(--panel));
|
|
1863
|
+
--alert: #d9a53f;
|
|
1864
|
+
--fault: #fda29b;
|
|
1865
|
+
--ok: #6cd39a;
|
|
1866
|
+
--line: rgb(255 255 255 / 10%);
|
|
1867
|
+
--line-strong: rgb(255 255 255 / 18%);
|
|
1868
|
+
--shadow-overlay: 0 0 0 1px rgb(255 255 255 / 9%);
|
|
1869
|
+
--panel: #262d39;
|
|
1870
|
+
--tile-bg: #17202c;
|
|
1871
|
+
--tile-ink: #f4f7fb;
|
|
1872
|
+
--tile-muted: #d6deea;
|
|
1873
|
+
--tile-gradient: rgb(8 14 24 / 90%);
|
|
1874
|
+
--tile-stripe: rgb(255 255 255 / 7%);
|
|
1875
|
+
--tile-badge-bg: rgb(8 14 24 / 72%);
|
|
1876
|
+
--tile-badge-border: rgb(255 255 255 / 36%);
|
|
1877
|
+
--tile-badge-halo: rgb(4 8 14 / 85%);
|
|
1878
|
+
--tile-image-filter: brightness(0.58) saturate(0.85) contrast(1.05);
|
|
1879
|
+
--tile-scene-filter: brightness(0.62) saturate(0.95);
|
|
1880
|
+
--tile-scene-gradient: rgb(4 8 14 / 88%);
|
|
1881
|
+
--tile-disabled-filter: brightness(0.48) grayscale(0.65) contrast(1.05);
|
|
1882
|
+
--tile-icon-filter: invert(1);
|
|
1883
|
+
--tile-tooltip-bg: #080e18;
|
|
1884
|
+
--tile-tooltip-ink: #f4f7fb;
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
.shell[data-theme='dark'] .notice-icon,
|
|
1888
|
+
.shell[data-theme='dark'] .status-icon,
|
|
1889
|
+
.shell[data-theme='dark'] .dashboard-page-icon,
|
|
1890
|
+
.shell[data-theme='dark'] .dashboard-action img,
|
|
1891
|
+
.shell[data-theme='dark'] .warm-up-arrow,
|
|
1892
|
+
.shell[data-theme='dark'] .device-class-icon {
|
|
1893
|
+
filter: invert(1);
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1896
|
+
.shell[data-theme='dark'] .eufy-logo .logo-light {
|
|
1897
|
+
display: none;
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
.shell[data-theme='dark'] .eufy-logo .logo-dark {
|
|
1901
|
+
display: block;
|
|
1902
|
+
}
|